nginx-basic/setup.sh
2019-01-05 03:10:50 -07:00

551 lines
19 KiB
Bash

#!/bin/bash
#######
### Update NGINX configuration '<tags>' with proper values and optionally copy
### to updated directory structure
#######
### text formatting ansi codes
err="\e[1;31m"
ok="\e[1;32m"
warn="\e[93m"
mag="\e[95m"
cyan="\e[96m"
norm="\e[0m"
### set variables
# clear variables
unset IP4
unset useCertbot
unset CertbotDomain
unset CertPath
unset KeyPath
unset CAChainPath
unset DHPath
# set variables
regexIP4="(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"
regexHostname="(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])"
serverNames_working=()
serverNames=()
detectedIP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
certbotFiles=(cert.pem chain.pem fullchain.pem privkey.pem)
generateDH=0
hostname=$(hostname)
configPath="./etc.${hostname}"
# set tags to update
tag_sslcert="<path/to/your_ssl_certificate_fullchain>"
tag_sslkey="<path/to/your_certificate_private_key.key>"
tag_dhparam="<path/to/your_dhparam.pem>"
tag_cachain="<path/to/your_CA_bundle.crt>"
### quick intro for the user
echo -e "\n${mag}This script will customize the provided NGINX template files for your"
echo "environment. You will be prompted for all necessary information. After that,"
echo "default error pages will be copied to your webroot and your NGINX configuration"
echo -e "directory structure will be customized.${norm}\n"
echo -e "${warn}You may accept the default option (listed in brackets) by simply"
echo "pressing ENTER (i.e. no answer)."
echo -e "You may exit this script at any prompt by typing 'X'${norm}\n"
### get local IP address
echo -e "\n${mag}In cases where this server will be acting as a (reverse) proxy,NGINX"
echo "needs to know it's own local IP address so that the logs can properly reflect"
echo -e "the IP of the remote system(s) instead of this server.${norm}\n"
while true; do
read -p "What is this NGINX machine's primary local IP4 address? (${detectedIP}) " inputIP
case "${inputIP}" in
'')
IP4="${detectedIP}"
break
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
# check IP for validity
if [[ "${inputIP}" =~ ^${regexIP4}$ ]]; then
IP4="${inputIP}"
break
else
echo -e "\n${err}Invalid IP4 format (xxx.xxx.xxx.xxx)${norm}"
fi
;;
esac
done
### get server names for this installation
echo -e "\n${mag}NIGNX needs to know what hostnames it should answer. You can pick as many"
echo "hostnames as you like. Please ensure you provide fully-qualified domain"
echo "names unless you are providing special names such as 'localhost' and fully"
echo "understand what that means in this context."
echo -e "\nIf you're setting up this system with SSL, then make sure your hostnames"
echo "match what appears on your certificates!"
echo -e "\n${warn}You will be prompted to enter one hostname at a time."
echo "Provide a blank-entry (hit enter) when you're done."
echo -e "'X' will exit the script, as always${norm}\n"
while true; do
read -p "Hostname for this server? " inputServerName
case "${inputServerName}" in
'')
# check that at least one name as been provided
if [ -z "${serverNames_working}" ]; then
echo -e "\n${err}You must provide at least one hostname${norm}"
else
break
fi
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
# check hostname for validity
if [[ ! "${inputServerName}" =~ ^${regexHostname}$ ]]; then
echo -e "\n${err}Invalid hostname${norm}"
else
serverNames_working+=("${inputServerName}")
fi
;;
esac
done
# create new array with unqiue values only
declare -A uniqueSN
for name in "${serverNames_working[@]}"; do
uniqueSN["${name}"]=""
done
for sn in "${!uniqueSN[@]}"; do
serverNames+=("${sn}")
done
### SSL related options
# using certbot?
echo -e "\n${mag}If you are using Certbot then you only need to provide the primary"
echo "domain name of your certificate and the script will auto-generate the paths"
echo "NGINX needs for find your certificate, CA-chain and private key."
echo -e"\nIf you haven't run Certbot yet, you can enter the domain you intend to use"
echo "as your primary domain and the paths will still be valid. You will have to"
echo -e "confirm that path when prompted by the script.${norm}\n"
while true; do
read -p "Are you using Certbot to handle your SSL certificates? (default: No) " yn
case "${yn}" in
[Yy]*)
useCertbot=1
break
;;
[Nn]|'')
useCertbot=0
unset CertbotDomain
break
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
echo -e "\n${err}Please answer (Y)es, (N)o, e(X)it or accept default${norm}"
;;
esac
done
# using Certbot: get primary domain name since that how Certbot determines paths
if [ "${useCertbot}" -eq 1 ]; then
while true; do
read -p "What is the primary domain for your Certbot Certificates? " inputCertbotDomain
case "${inputCertbotDomain}" in
'')
echo -e "\n${err}You cannot have an empty domain name${norm}"
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
# check hostname for validity
if [[ ! "${inputCertbotDomain}" =~ ^${regexHostname}$ ]]; then
echo -e "\n${err}Invalid hostname${norm}"
else
# check if Certbot files exist in path implied from hostname
echo -e "\n${cyan}Verifying Certbot files..."
echo -e "(/etc/letsencrypt/live/${inputCertbotDomain}/...)${norm}"
certbotBadFile=()
for certbotFile in "${certbotFiles[@]}"; do
if [ -f "/etc/letsencrypt/live/${inputCertbotDomain}/$certbotFile" ]; then
echo -e "File: ${certbotFile} -- ${ok}OK${norm}"
else
echo -e "File: ${certbotFile} -- ${err}X${norm}"
certbotBadFile+=("${certbotFile}")
fi
done
if [ -z "${certbotBadFile}" ]; then
echo -e "${cyan}Certbot files seem intact${norm}\n"
CertbotDomain="${inputCertbotDomain}"
break
else
echo -e "\n${err}The following files are missing from ${inputCertbotDomain}:"
echo -e "${warn}${certbotBadFile[@]}${norm}"
echo -e "${err}These files are all required for proper SSL operation of NGINX using Certbot.${norm}\n"
while true; do
read -p "Do you want to use these settings anyways? " yn
case "${yn}" in
[Yy]*)
CertbotDomain="${inputCertbotDomain}"
break
;;
[Nn]*)
break
;;
*)
;;
esac
done
fi
if [ -n "${CertbotDomain}" ]; then
break
fi
fi
;;
esac
done
fi
# Generate paths from CertbotDomain
if [ "${useCertbot}" -eq 1 ]; then
CertPath="/etc/letsencrypt/live/${CertbotDomain}/fullchain.pem"
KeyPath="/etc/letsencrypt/live/${CertbotDomain}/privkey.pem"
CAChainPath="/etc/letsencrypt/live/${CertbotDomain}/chain.pem"
fi
# only process manual certificate paths if NOT using Certbot
if [ "${useCertbot}" -eq 0 ]; then
echo -e "\n${mag}NGINX requires the full paths to your PEM formatted certificates, private keys"
echo "and your CA-chain in order to serve pages securely and properly over SSL."
echo "If you haven't generated/copied your certificates yet, you can enter the"
echo "paths where they will be located and confirm when prompted by the script."
# not using Certbot: get location of certificate
while true; do
read -p "What is the path to your primary SSL certificate? " inputCertPath
case "${inputCertPath}" in
'')
echo -e "\n${err}You cannot have an empty path to your SSL certificate${norm}"
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
# validate path
if [ -f "${inputCertPath}" ]; then
CertPath="${inputCertPath}"
break
else
echo -e "\n${warn}The file you specified doesn't exist${norm}"
while true; do
read -p "Do you want to use this path anyways? " yn
case $yn in
[Yy]*)
CertPath="${inputCertPath}"
break
;;
[Nn]*)
break
;;
*)
;;
esac
done
if [ -n "${CertPath}" ]; then
break
fi
fi
;;
esac
done
# not using Certbot: get location of private key
while true; do
read -p "What is the path to your primary SSL private key? " inputKeyPath
case "${inputKeyPath}" in
'')
echo -e "\n${err}You cannot have an empty path to your SSL private key${norm}"
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
# validate path
if [ -f "${inputKeyPath}" ]; then
KeyPath="${inputKeyPath}"
break
else
echo -e "\n${warn}The file you specified doesn't exist${norm}"
while true; do
read -p "Do you want to use this path anyways? " yn
case $yn in
[Yy]*)
KeyPath="${inputKeyPath}"
break
;;
[Nn]*)
break
;;
*)
;;
esac
done
if [ -n "${KeyPath}" ]; then
break
fi
fi
;;
esac
done
# not using Certbot: get location of CA Certificate Chain
while true; do
read -p "What is the path to your primary SSL CA Chain certificate? " inputCAChainPath
case "${inputCAChainPath}" in
'')
echo -e "\n${err}You cannot have an empty path to your SSL CA Chain certificate${norm}"
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
# validate path
if [ -f "${inputCAChainPath}" ]; then
CAChainPath="${inputCAChainPath}"
break
else
echo -e "\n${warn}The file you specified doesn't exist${norm}"
while true; do
read -p "Do you want to use this path anyways? " yn
case $yn in
[Yy]*)
CAChainPath="${inputCAChainPath}"
break
;;
[Nn]*)
break
;;
*)
;;
esac
done
if [ -n "${CAChainPath}" ]; then
break
fi
fi
;;
esac
done
fi
# dhparam: get location of DH Parameters file
echo -e "\n${mag}Generating your own Diffie-Hellman Parameters file helps make your SSL"
echo "communication more secure by helping create unique safe large-prime numbers"
echo "which are used to encrypt communication. You shouldn't use the any pre-supplied"
echo "dhparams.pem files that came with NGINX or your Linux install. You should generate your own. If you want this script to do that for you, please type"
echo -e "${warn}generate${mag} when at the prompt instead of a path${norm}\n"
while true; do
read -p "What is the path to your DH Parameters file? (default: /etc/ssl/certs/dhparam.pem) " inputDHPath
case "${inputDHPath}" in
'')
# verify default path exists
inputDHPath="/etc/ssl/certs/dhparam.pem"
if [ -f "${inputDHPath}" ]; then
DHPath="${inputDHPath}"
break
else
echo -e "\n${warn}The file you specified doesn't exist${norm}"
while true; do
read -p "Do you want to use this path anyways? " yn
case $yn in
[Yy]*)
DHPath="${inputDHPath}"
break
;;
[Nn]*)
break
;;
*)
;;
esac
done
if [ -n "${DHPath}" ]; then
break
fi
fi
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
generate)
generateDH=1
break
;;
*)
# validate path
if [ -f "${inputDHPath}" ]; then
DHPath="${inputDHPath}"
break
else
echo -e "\n${warn}The file you specified doesn't exist${norm}"
while true; do
read -p "Do you want to use this path anyways? " yn
case $yn in
[Yy]*)
DHPath="${inputDHPath}"
break
;;
[Nn]*)
break
;;
*)
;;
esac
done
if [ -n "${DHPath}" ]; then
break
fi
fi
;;
esac
done
### PHP-FPM related options
# get PHP-FPM usage status
echo -e "\n${mag}PHP-FPM allows your server to process and serve dynamic PHP content. If you"
echo "have PHP-FPM installed then NGINX needs to know how to access it. The following"
echo "questions will allow the script to auto-configure that for you. If you have"
echo "not yet installed PHP-FPM but intend to in the future, you can answer yes and"
echo "provide details for your intended setup so the script can still generate the"
echo -e "configuration for you.${norm}\n"
while true; do
read -p "Are you using PHP-FPM? (default: YES) " yn
case $yn in
[Yy]*|'')
usePHP=1
break
;;
[Nn]*)
usePHP=0
break
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
echo -e "\n${err}Please answer (Y)es, (N)o, e(X)it or accept default${norm}"
;;
esac
done
# get PHP-FPM version
if [ "${usePHP}" -eq 1 ]; then
while true; do
read -p "What version of PHP-FPM are you using? (default: 7.2) " inputPHPVersion
case $inputPHPVersion in
[[:digit:]]*|+[[:digit:]]*.[[:digit:]]*)
phpVersion="$inputPHPVersion"
break
;;
'')
phpVersion=7.2
break
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
echo -e "\n${err}That does not seem to be a valid version number${norm}"
;;
esac
done
fi
# get PHP-FPM TCP or Sockets configuration
echo -e "\n${mag}PHP-FPM can be set up to respond to requests via TCP or via UNIX sockets."
echo "If you have no idea what any of this means, then you're probably using the"
echo -e "default setup which is sockets${norm}\n"
while true; do
read -p "Is your PHP-FPM setup to listen via 'TCP' or 'sockets'? (default: sockets) " inputPHPType
case "${inputPHPType}" in
[Ss][Oo][Cc][Kk][Ee][Tt][Ss]*|'')
phpType='sockets'
break
;;
[Tt][Cc][Pp]*)
phpType='tcp'
break
;;
[Xx]*)
echo -e "\n${cyan}---exiting---\n${norm}"
exit 1
;;
*)
echo -e "\n${err}Please enter either 'tcp' or 'sockets' or 'X' to exit script${norm}"
;;
esac
done
: <<'COMMENTSECTION'
### Write configurations to template files
# let user know what's happening
echo -e "\n${mag}---------------------${norm}"
echo -e "${cyan}Updating template files now"
# copy template files to working versions
rm -rf "${configPath}"
cp -R ./etc "${configPath}"
# process SSL snippet
echo "updating SSL paths in snippet file"
sed -e "s%${tag_sslcert}%${CertPath}%" "${configPath}/nginx/snippets/ssl/ssl_certs.conf"
sed -e "s%${tag_sslkey}%${KeyPath}%" "${configPath}/nginx/snippets/ssl/ssl_certs.conf"
# process mozModern SSL configuration
echo "updating SSL configuration parameters file"
echo -e "s%${tag_dhparam}%${DHPath}%" "${configPath}/nginx/conf.d/mozModern_ssl.conf"
echo -e "s%${tag_cachain}%${CAChainPath}%" "${configPath}/nginx/conf.d/mozModern_ssl.conf"
COMMENTSECTION
# debug section
echo -e "\n${mag}---------------------${norm}"
echo "Local IP4: $IP4"
echo -e "${cyan}--------------------${norm}"
echo "Using Certbot: $useCertbot"
echo "CertbotDomain: $CertbotDomain"
echo -e "${cyan}--------------------${norm}"
echo "CertPath: $CertPath"
echo "KeyPath: $KeyPath"
echo "CA-Chain: $CAChainPath"
echo "DHPath: $DHPath"
echo "Generating DH Params? $generateDH"
echo -e "${cyan}--------------------${norm}"
echo "usePHP: $usePHP"
echo "PHP Version: $phpVersion"
echo "PHP listen type: $phpType"
echo -e "${mag}---------------------${norm}\n"
exit 0