webinoly/lib/site-ssl
Cristhian Martínez Ochoa b5f38ccd29 admin tools
Site folder now is named according to the domain:port assigned.
Fixed error with HSTS header for admin tools site.
2022-12-04 14:01:05 -07:00

289 lines
13 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# This is a library for Site Manager Plugin
# Functions for SSL On/Off
ssl_nginx() {
sudo sed -i '/listen 80/c \ listen 443 ssl http2;' /etc/nginx/sites-available/$domain
sudo sed -i '/listen \[::\]:80/c \ listen [::]:443 ssl http2;' /etc/nginx/sites-available/$domain
sudo sed -i '/server_name /r /opt/webinoly/templates/template-site-ssl' /etc/nginx/sites-available/$domain
# Headers
sudo sed -i '/header.conf;/c \ include common/headers.conf;' /etc/nginx/sites-available/$domain
sudo sed -i '/headers-http.conf/a \ include common/headers-https.conf;' /etc/nginx/sites-available/$domain # In case of Force-Redirect!
for pxy in "/etc/nginx/apps.d/${domain}"*-proxy.conf
do
[[ -f $pxy ]] && sudo sed -i '/headers-http.conf;/a \ include common/headers-https.conf;' $pxy
done
[[ -n $add_to_wildcard ]] && cert=$add_to_wildcard || cert=$domain
sudo sed -i "/WebinolySSLstart/,/WebinolySSLend/{s/domain.com/$cert/}" /etc/nginx/sites-available/$domain
# Custom SSL files
if [[ -n $ssl_crt && -n $ssl_key ]]; then
sudo sed -i '/WebinolySSLstart/a \ # WebinolySSLCustomCert' /etc/nginx/sites-available/$domain
sudo sed -i "/fullchain.pem/c \ ssl_certificate $ssl_crt;" /etc/nginx/sites-available/$domain
sudo sed -i "/privkey.pem/c \ ssl_certificate_key $ssl_key;" /etc/nginx/sites-available/$domain
sudo chmod 777 $ssl_crt
sudo chmod 777 $ssl_key
sudo chmod 755 $(dirname -- $ssl_crt)
sudo chmod 755 $(dirname -- $ssl_key)
sudo chown -R root:root $(dirname -- $ssl_crt)
# Not duplicate: Custom cert function does not run the same way as LE requests.
# For some unknown reason this condition doesn't work in oneline as we usually do!
if [[ $(is_force_redirect $domain) == "www" ]]; then
wp_db_update $domain "https://www.${domain}"
else
wp_db_update $domain "https://${domain}"
fi
if [[ -n $ssl_ocsp && -f $ssl_ocsp ]]; then
sudo sed -i "/ssl_trusted_certificate/c \ ssl_trusted_certificate $ssl_ocsp;" /etc/nginx/sites-available/$domain
sudo chmod 777 $ssl_ocsp
sudo chmod 755 $(dirname -- $ssl_ocsp)
else
sudo sed -i '/WebinolySSLstart/,/WebinolySSLend/{/ssl_stapling/d}' /etc/nginx/sites-available/$domain
sudo sed -i '/WebinolySSLstart/,/WebinolySSLend/{/ssl_trusted_certificate/d}' /etc/nginx/sites-available/$domain
fi
fi
# HTTP to HTTPS Redirection
[[ $subdomain == "true" ]] && local sername="server_name $domain;" || local sername="server_name $domain www.$domain;"
[[ -n $wildcard ]] && sername="server_name $domain *.$domain;"
sudo sed -i '1r /opt/webinoly/templates/template-site-sslredirect' /etc/nginx/sites-available/$domain
sudo sed -i "/#server_name;/c \ $sername" /etc/nginx/sites-available/$domain
# In case this domain is used as tools-site or default-site
if [[ $(conf_read default-site) == $domain ]]; then
sudo webinoly -default-site=default > /dev/null 2>&1
sudo webinoly -default-site=$domain > /dev/null 2>&1
echo "${gre}${dim}Default Site updated with SSL!${end}"
fi
if [[ $(conf_read tools-site) == $domain ]]; then
sudo webinoly -tools-site=default > /dev/null 2>&1
sudo webinoly -tools-site=$domain > /dev/null 2>&1
echo "${gre}${dim}Tools Site updated with SSL!${end}"
fi
}
site_ssl_on() {
local cermail=$(conf_read mail)
local path=$domain
# Some validations to prevent errors when creating certs.
check_for_nginx_tool_ssl -ask
if [[ -n $root && -f /etc/nginx/sites-available/$root ]]; then
path=$root
elif [[ -n $root && ! -f /etc/nginx/sites-available/$root ]]; then
echo "${red}[ERROR] Root path domain is not a valid domain or is not found/hosted in this server!${end}"
exit 1
fi
if [[ -n $manual && $manual != "http" && $manual != "dns" ]]; then
echo "${red}[ERROR] Invalid value for manual option!${end}"
exit 1
elif [[ ! -d /var/www/$path/htdocs && -z $root_path && -z $manual ]]; then
echo "${red}[ERROR] Seems like you are trying to request an SSL Certificate for a Parked/Mapped Domain."
echo "Please, use the '-root=domain.com' parameter to specify the main domain."
echo ""
echo "If your site is using the Reverse Proxy configuration, please use the '-root-path=/opt/app' option.${end}"
exit 1
elif [[ -n $root_path && ! -d $root_path ]]; then
echo "${red}[ERROR] Invalid root path!${end}"
exit 1
elif [[ ! -f /etc/letsencrypt/live/$domain/fullchain.pem && $ssl == "force-renewal" ]]; then
echo "${red}[ERROR] Cert you're trying to renew not found!${end}"
exit 1
fi
echo "${gre}"
echo "*************************************************************************************************"
echo "** Please, be careful with the number of intents or certificates you try to get. **"
echo "** Lets Encrypt provides rate limits to ensure fair usage by as many people as possible. **"
echo "** **"
echo "** If you are getting errors or having issues when trying to get a new certificate **"
echo "** read about the Let's Encrypt rate limit - https://letsencrypt.org/docs/rate-limits/ **"
echo "*************************************************************************************************"
echo "${end}"
[[ $subdomain == "false" ]] && echo "${blu}Please, be sure that${end} $domain ${blu}and${end} www.$domain ${blu}are both currently pointing (DNS) to this server. ${end}"
[[ $subdomain == "true" ]] && echo "${blu}Please, be sure that the${end} $domain ${blu}subdomain is currently pointing (DNS) to this server. ${end}"
# We need an email to notify each renew intent (cron)
while [[ -z $cermail ]]
do
echo "${blu}"
read -p "Please, enter an email to register your new certificate: ${end}" cermail
email_update $cermail
[[ $(conf_read mail) != $cermail ]] && cermail=""
done
# Create new certificate
local param="--email $cermail --no-eff-email --agree-tos --staple-ocsp"
[[ $must_staple == "on" ]] && param="$param --must-staple"
[[ -n $test_cert ]] && param="$param --test-cert"
[[ $ssl == "force-renewal" ]] && param="$param --force-renewal"
[[ $subdomain == "true" ]] && local domset="-d $domain" || local domset="-d $domain -d www.$domain"
# Must-Staple issue: https://trac.nginx.org/nginx/ticket/812
# Also: https://blog.apnic.net/2019/01/15/is-the-web-ready-for-ocsp-must-staple/
if [[ -n $wildcard ]]; then
local domset="-d $domain -d *.$domain"
local manual="dns"
fi
# Custom Root-Path mode for local Reverse Proxy sites
if [[ ( ! -f /etc/letsencrypt/live/$domain/fullchain.pem || $ssl == "force-renewal" ) && -n $root_path ]]; then
conf_write temp-path $root_path
sudo certbot certonly --manual --preferred-challenges=http --manual-auth-hook /opt/webinoly/lib/ex-ssl-authentication --manual-cleanup-hook /opt/webinoly/lib/ex-ssl-cleanup $domset $param
conf_delete temp-path
# Normal and manual certs
elif [[ ! -f /etc/letsencrypt/live/$domain/fullchain.pem || $ssl == "force-renewal" ]]; then
if [[ -n $manual ]]; then
sudo certbot certonly --manual --preferred-challenges=$manual $domset $param
else
sudo certbot certonly --webroot -w /var/www/$path/htdocs/ $domset $param
fi
# Existing cert
elif [[ -f /etc/letsencrypt/live/$domain/fullchain.pem ]]; then
echo "${blu}Certificate for${end} $domain ${blu}already exist and found, wait while we configure your server to use it!${end}"
[[ -z $test_cert && $(is_ssl_staging $domain) == "true" ]] && echo "${red}[WARNING] Cert found is a staging cert for testing.${end}"
[[ -n $test_cert && $(is_ssl_staging $domain) != "true" ]] && echo "${red}[WARNING] Test-Cert was requested and cert found is a real/normal cert.${end}"
fi
# SSL Nginx Conf
if [[ -f /etc/letsencrypt/live/$domain/fullchain.pem && $ssl != "force-renewal" ]]; then
ssl_nginx
# Auto-Renew Certificate
if [[ ! -f /var/spool/cron/crontabs/root ]]; then
sudo touch /var/spool/cron/crontabs/root
sudo chmod 600 /var/spool/cron/crontabs/root
sudo chown root:crontab /var/spool/cron/crontabs/root
fi
local cronmail=$( sudo grep -F "MAILTO=" /var/spool/cron/crontabs/root )
local cronrene=$( sudo grep -F "certbot renew" /var/spool/cron/crontabs/root )
[[ -z $cronmail && -n $cermail && -z $cronrene ]] && echo "MAILTO=${cermail}" | sudo tee -a /var/spool/cron/crontabs/root > /dev/null
[[ -z $cronrene ]] && echo '15 3 * * 7 certbot renew' | sudo tee -a /var/spool/cron/crontabs/root > /dev/null
# We use this script instead of the post-hook in crontab to restart Nginx
# Most of the times certs are renewed via the certbot systemctl timer - sudo systemctl list-timers
# The cronjob renew is just a double-check, so this solution is better because is covering both scenarios
if [[ ! -f /etc/letsencrypt/renewal-hooks/deploy/99-webinoly-deploy ]]; then
cp /opt/webinoly/templates/general/certbot-deploy-hook /etc/letsencrypt/renewal-hooks/deploy/99-webinoly-deploy
sudo chmod -f 744 /etc/letsencrypt/renewal-hooks/deploy/99-webinoly-deploy
fi
# For some unknown reason this condition doesn't work in oneline as we usually do!
if [[ $(is_force_redirect $domain) == "www" ]]; then
wp_db_update $domain "https://www.${domain}"
else
wp_db_update $domain "https://${domain}"
fi
echo "${gre}SSL have been successfully enabled for your site${blu} $domain${end}"
elif [[ -f /etc/letsencrypt/live/$domain/fullchain.pem && $ssl == "force-renewal" ]]; then
echo "${gre}SSL Cert${blu} $domain ${gre}has been Forced to Renew!${end}"
elif [[ ! -f /etc/letsencrypt/live/$domain/fullchain.pem ]]; then
echo "${red}"
echo "[ERROR] Unable to create the new certificate!"
echo "${end}"
exit 1
fi
[[ -n $test_cert || $(is_ssl_staging $domain) == "true" ]] && echo "${red}[WARNING] Let's Encrypt Staging Environment is enabled, this SSL Cert is just for testing purpose and should not be used in production enviroments.${end}"
}
ssl_revoke() {
[[ $(is_ssl_staging $domain) == "true" ]] && local param="--test-cert" || local param=""
sudo certbot revoke --cert-path /etc/letsencrypt/live/$domain/cert.pem --delete-after-revoke --non-interactive $param
if [[ ! -f /etc/letsencrypt/live/$domain/cert.pem ]]; then
echo "${gre}"
echo "SSL Cert for your site${blu} $domain ${gre}has been completely removed and revoked!${end}"
else
echo "${red}[ERROR] Cert cannot be revoked!${dim} (A common cause is that expired certs cannot be revoked)${end}"
if [[ ${revoke,,} == "force" ]]; then
ans="Y"
else
echo "${blu}Do you want to delete this cert [y/N]? ${end}"
while read -r -n 1 -s ans; do
answer=${ans:-n}
[[ $ans = [YyNn] ]] && break
done
fi
[[ $ans == [Yy] ]] && sudo certbot delete -n --cert-name $domain
if [[ ! -f /etc/letsencrypt/live/$domain/cert.pem ]]; then
echo "${gre}"
echo "SSL Cert for your site${blu} $domain ${gre}has been successfully removed!${end}"
else
echo "${red}[ERROR] Cert cannot be removed!${end}"
exit 1
fi
fi
}
site_ssl_off() {
# Don't ask if SSL is Custom
[[ $(is_ssl_le $domain) != "true" ]] && revoke="off"
sudo sed -i '/listen 443/c \ listen 80;' /etc/nginx/sites-available/$domain
sudo sed -i '/listen \[::\]:443/c \ listen [::]:80;' /etc/nginx/sites-available/$domain
sudo sed -i '/WebinolySSLstart/,/WebinolySSLend/{/.*/d}' /etc/nginx/sites-available/$domain
sudo sed -i '/WebinolySSLredirectStart/,/WebinolySSLredirectEnd/{/.*/d}' /etc/nginx/sites-available/$domain
# Headers
sudo sed -i '/headers.conf;/c \ include common/header.conf;' /etc/nginx/sites-available/$domain
sudo sed -i '/WebinolyWWWredirectStart/,/WebinolyWWWredirectEnd/{/headers-https.conf;/d}' /etc/nginx/sites-available/$domain # In case of Force-Redirect
for pxy in "/etc/nginx/apps.d/${domain}"*-proxy.conf
do
[[ -f $pxy ]] && sudo sed -i '/CacheStaticFiles/,/expires max;/{/headers-https.conf;/d}' $pxy
done
# In case this domain is used as tools-site or default-site
if [[ $(conf_read default-site) == $domain ]]; then
sudo webinoly -default-site=default > /dev/null 2>&1
sudo webinoly -default-site=$domain > /dev/null 2>&1
echo "${gre}${dim}Default Site updated with SSL!${end}"
fi
if [[ $(conf_read tools-site) == $domain ]]; then
sudo webinoly -tools-site=default > /dev/null 2>&1
sudo webinoly -tools-site=$domain > /dev/null 2>&1
echo "${gre}${dim}Tools Site updated with SSL!${end}"
fi
[[ -z $no_db_update && $(is_force_redirect $domain) != "www" ]] && wp_db_update $domain "http://${domain}"
[[ -z $no_db_update && $(is_force_redirect $domain) == "www" ]] && wp_db_update $domain "http://www.${domain}"
# Check if exist to not try to revoke a cert that don't exist, for example a site with a cert added to a wildcard! (-add-to-wildcard)
if [[ -f /etc/letsencrypt/renewal/${domain}.conf ]]; then
if [[ -n $revoke && $revoke =~ ^(on|off|force)$ ]]; then
[[ $revoke =~ ^(on|force)$ ]] && answer="Y" || answer="N"
else
echo "${blu}Select 'Y' to revoke and delete all the certificate files."
echo "Select 'N' if you only want to deactivate this certificate momentary and you will activate it later again."
echo "${gre}"
echo "Do you want to delete and revoke this certificate [y/N]? "
while read -r -n 1 -s answer; do
answer=${answer:-n}
[[ $answer = [YyNn] ]] && break
done
echo "${end}"
fi
fi
echo "${gre}SSL has been successfully disabled for your site${blu} $domain${end}"
[[ $answer == [Yy] ]] && ssl_revoke
echo "" # To exit successfully, other way the || in the main function is triggered!
}