Let's Encrypt and NGINX
We’re going to be setting up NGINX to use LET’S ENCRYPT and for this example we’re going to be pointing to a Guacamole server, which requires zero buffering of packets as it is using real time RDP data. So the config will take that into account. Additionally, we’re shooting for the highest rating possible on SSL Labs and only supporting the latest encryption standards!
UPDATE: I’ve gotten two reports that the cron job is failing so I changed it to what is recommended by Juan in the comments below
We’re going to start with 2 assumptions:
#1. You have configured your external DNS to point to this server…
#2. You’re port forwarding ports 80 and 443 to this server…
Let’s set a few variables for our install
EXTERNALFQDN=guac.domain.com
INTERNALFQDN=guac01.domain.local
EXTERNALFQDN is the external fully qualified domains name we’re passing traffic for
INTERNALFQDN is the internal host name of your Guacamole server
Install NGINX and Let’s Encrypt:
apt-get -y install nginx letsencrypt openssl
Make a directory to store your certs
mkdir -p /etc/nginx/ssl/$EXTERNALFQDN
Create a 4096 bit Diffie-Hellman Key (Go big or go home!)
openssl dhparam -out /etc/nginx/ssl/$EXTERNALFQDN/dhparam.pem 4096
Now let’s configure NGINX. Careful of the formatting here. ssl_ciphers should be one line if you copy and paste
cat > /etc/nginx/nginx.conf <<- EOM
user www-data;
worker_processes 4;
pid /run/nginx.pid;
events
{
worker_connections 768;
}
http
{
# My Certificates
#ssl_certificate /etc/nginx/ssl/$EXTERNALFQDN/fullchain.pem;
#ssl_certificate_key /etc/nginx/ssl/$EXTERNALFQDN/privkey.pem;
# SSL Performance Related
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# SSL Protocols and Ciphers
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.2;
ssl_ciphers "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:!AES128:!aNULL:!MD5:!eNULL:!EXPORT:!DES:!PSK:!RC4";
# DHE Key-Exchange
ssl_dhparam /etc/nginx/ssl/$EXTERNALFQDN/dhparam.pem;
# Random Security Stuff
server_tokens off;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security max-age=63072000;
# Common Proxy Settings
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
########################
# Default Config Stuff #
########################
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 4096; #Default:2048
include /etc/nginx/mime.types;
default_type application/octet-stream;
gzip on;
gzip_disable "msie6";
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
# REDIRECTS ALL PORT 80/HTTP to 443/HTTPS
server
{
listen 80;
listen [::]:80;
server_name $EXTERNALFQDN;
location ~ /.well-known/acme-challenge
{
root /var/www/html/;
}
#return 301 https://$host$request_uri;
}
# GUACAMOLE SERVER SETTINGS
server
{
listen 443 ssl;
listen [::]:443 ssl;
server_name $EXTERNALFQDN;
proxy_buffering off;
proxy_redirect off;
proxy_cookie_path /guacamole/ /;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
location ~ /.well-known/acme-challenge
{
root /var/www/html/;
}
location /
{
proxy_pass http://$INTERNALFQDN:8080/guacamole/;
}
}
}
EOM
Restart NGINX
service nginx restart
Request a cert from Let’s Encrypt
letsencrypt certonly -a webroot --webroot-path=/var/www/html -d $EXTERNALFQDN --rsa-key-size 4096
Link the Let’s Encrypt public and private keys to the NGINX Config
ln -s /etc/letsencrypt/live/$EXTERNALFQDN/fullchain.pem /etc/nginx/ssl/$EXTERNALFQDN/fullchain.pem
ln -s /etc/letsencrypt/live/$EXTERNALFQDN/privkey.pem /etc/nginx/ssl/$EXTERNALFQDN/privkey.pem
Update the NGINX config to use those certs and enforce 443 with redirection
sed -i 's/#ssl_certificate/ssl_certificate/g' /etc/nginx/nginx.conf
sed -i 's/#return 301/return 301/' /etc/nginx/nginx.conf
Restart NGINX
service nginx restart
Now we need to setup a cron job that runs every Sunday to check for certs that are near expiration and renew them automatically!
(crontab -l 2>/dev/null; echo '@weekly (certbot renew && service nginx restart) 2>&1 >/dev/null') | crontab -