577 lines
20 KiB
Bash
577 lines
20 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
|
|
unset phpVersion
|
|
unset phpType
|
|
|
|
# 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
|
|
usePHP=1
|
|
hostname=$(hostname)
|
|
configPath="./etc.${hostname}"
|
|
|
|
# set tags and files to update
|
|
tag_servernames="<server name(s)>"
|
|
file_servernames="nginx/snippets/server_names.conf"
|
|
tag_sslcert="<path/to/your_ssl_certificate_fullchain>"
|
|
tag_sslkey="<path/to/your_certificate_private_key.key>"
|
|
file_ssl="nginx/snippets/ssl/ssl_certs.conf"
|
|
tag_dhparam="<path/to/your_dhparam.pem>"
|
|
tag_cachain="<path/to/your_CA_bundle.crt>"
|
|
file_mozmodern="nginx/conf.d/mozModern_ssl.conf"
|
|
file_buffers="nginx/conf.d/buffers.conf"
|
|
file_buffersPHP="nginx/conf.d/buffers_conf_php.insert"
|
|
|
|
|
|
### 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 machine's 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}To which hostnames should NGINX answer? You can pick as many hostnames as you"
|
|
echo "like. Please ensure you provide fully-qualified domain names unless you"
|
|
echo "understand the impact not doing so."
|
|
echo -e "\nIf you are setting up SSL on this system, then make sure the hostnames match"
|
|
echo "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, you only need to provide the primary domain name"
|
|
echo "of your certificate and the script will auto-generate the paths NGINX needs to"
|
|
echo "make everything work."
|
|
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 generated by this script will work after"
|
|
echo -e "you run Certbot. In that case, you will have to answer ${warn}'yes'${mag} when asked"
|
|
echo -e "${warn}'Do you want to use this domain setting anyways?'${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 should all be present in a functional Certbot install.${norm}\n"
|
|
while true; do
|
|
read -p "Do you want to use this domain setting 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}Having your own unique Diffie-Hellman Parameters file makes your SSL"
|
|
echo "communication more secure by helping to generate unique safe large prime"
|
|
echo "numbers. You shouldn't use any pre-installed dhparams.pem files. You should"
|
|
echo "always generate your own. If you haven't done that already and would like this"
|
|
echo -e "script to do it for you, please type ${warn}generate${mag} at the prompt instead"
|
|
echo -e "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
|
|
;;
|
|
[Gg][Ee][Nn][Ee][Rr][Aa][Tt][Ee]*)
|
|
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, NGINX needs to know how to access it. The following"
|
|
echo "questions will allow the script to auto-configure that for you."
|
|
echo -e "\nIf you have not yet installed PHP-FPM but intend to do so in the future, you"
|
|
echo -e "can answer ${warn}yes${mag} and provide details for your intended setup so the script can"
|
|
echo -e "generate a configuration that will work once your PHP-FPM is set up.${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
|
|
if [ "${usePHP}" -eq 1 ]; then
|
|
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 set up 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
|
|
fi
|
|
|
|
|
|
|
|
### 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
|
|
echo "copying files to dedicated directory for customization"
|
|
echo -e "${warn}${configPath}${norm}\n"
|
|
rm -rf "${configPath}"
|
|
cp -R ./etc "${configPath}"
|
|
|
|
# process server_names snippet
|
|
echo -e "updating ${warn}${configPath}/${file_servernames}${norm}"
|
|
for name in "${serverNames[@]}"; do
|
|
sed -i "/${tag_servernames}/a \ \ ${name}" "${configPath}/${file_servernames}"
|
|
done
|
|
sed -i "/${tag_servernames}/d" "${configPath}/${file_servernames}"
|
|
|
|
# process SSL snippet
|
|
echo "updating ${warn}${configPath}/${file_ssl}${norm}"
|
|
sed -i -e "s%${tag_sslcert}%${CertPath}%" "${configPath}/${file_ssl}"
|
|
sed -i -e "s%${tag_sslkey}%${KeyPath}%" "${configPath}/${file_ssl}"
|
|
|
|
# process mozModern SSL configuration
|
|
echo "updating ${warn}${configPath}/${file_mozmodern}${norm}"
|
|
sed -i -e "s%${tag_dhparam}%${DHPath}%" "${configPath}/${file_mozmodern}"
|
|
sed -i -e "s%${tag_cachain}%${CAChainPath}%" "${configPath}/${file_mozmodern}"
|
|
|
|
# if using PHP: process buffers.conf
|
|
if [ "${usePHP}" -eq 1 ]; then
|
|
echo "updating ${warn}${configPath}/${file_buffers}${norm}"
|
|
cat "${configPath}/${file_buffersPHP}" >> "${configPath}/${file_buffers}"
|
|
fi
|
|
|
|
|
|
# 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
|