Nginx is a reverse proxy and webserver which can handle SSL connections for your applications and web content. It is actually very easy to get SSL up an running for free with Let’s Encrypt as your certification authority. Even if you can’t or don’t want to use nginx as your main webserver, your can simply terminate all ssl connections there and then connect locally via HTTP to your hosted applications.


Certbot does most of the work for you, it’s basicly a client for certificate authority server. In our example we will use ACME, which means certbot will place a magic file in our webspace which the CA-server can then query and therefore confirm that a certain DNS belong to this server.

Installing should, usually, work via the package manager:

apt install certbot

If everything else fails, you can install certbot via the python package manager:

python3 -m pip install cerbot

Preparing nginx 

Make sure nginx is availiable via HTTP. Be carefull if you have an HTTPS redirect, while most CAs will connect fine over HTTP (since they must asume you don’t have a certificate yet), some will not connect over a broken HTTPS connection, i.e. with an expired or self-signed certificate. If it is not yet installed, install it with:

apt install nginx

You need the location /.well-known/acme-challenge/, this location must be writable for nginx.

# inside ALL servers in sites-enabled/ or nginx.conf # 
# sites-enabled/ sometimes called vhosts.d/ or vservers.d/ #
location /.well-known/acme-challenge/ {
    alias /var/www/.well-known/acme-challenge/;

mkdir -p /var/www/.well-known/acme-challenge/
chown -R :www-data /var/www/.well-known/
chmod -R g+x /var/www/.well-known/
chmod g+rw /var/www/.well-known/acme-challenge/
systemctl reload nginx

Run Certbot 

Run certbot and follow the instructions:

certbot certonly --webroot -w /var/www -d domain.toplevel -d domain2.toplevel --rsa-key-size 2048

And you are done, certbot will suggest you a command line which you can add to your cron-tab for regular certificate renewal. Let’s Encrypt certificates are valid for 3 months, executing the renewal jobs every months will be safe. Don’t forget to also add an systemctl reload nginx to the crontab or the certificates won’t be reloaded.

Add SSL-Configuration in nginx 

The following lines must be added to http-block or all into server-block you want to use SSL, the location will be diffrent if you don’t use Let’s Encrypt (which is the default though):

ssl_certificate         /etc/letsencrypt/live/domain.toplevel/fullchain.pem;
ssl_certificate_key     /etc/letsencrypt/live/domain.toplevel/privkey.pem;

Also, you must add an SSL-listen directive to the relevant server blocks:

listen 443 ssl; # ipv4
listen [::]:443 ssl; # ipv6

Common Pitfalls 

HTTPS redirect 

If you employ a HTTP->HTTPS redirect on your page, make sure the acme-location block before the redirect or your renewal might fail if your certificate ever becomes invalid for whatever reason.

    listen 80 default;
    location /.well-known/acme-challenge/ {
        alias /var/www/.well-known/acme-challenge/;
    location /{
        return 302 https://$host$request_uri;


If you have basic auth or a deny-directive on one of your (sub-)domains you must disable thsoe in the acme-location block:

auth_basic off;
allow all;

Adding new Subdomains 

If you ever want to add more subdomains, add a –expand to the certbot command, otherwise certbot will create/symlink the new certificate with another name (something like domain.toplevel.002).

certbot certonly --webroot \
                 -w /var/www \
                 -d domain.toplevel \
                 -d domain2.toplevel \
                 --rsa-key-size 2048 \
                 --expand # <-- note this

Feel free to send me a mail to share your thoughts!