NGINX Installation


#1

Hi All,

I tried finding a definitive answer, but couldn’t find one. Does Let’s Encrypt currently support NGINX, and if so how exactly do I go about installing a cert on it? Can someone provide a guide to do this manually if needs be?

Cheers,
Rudi

EDIT: For those looking for my solution, scroll down :smiley:


#2

Hi @DrPain

I posted a quick howto today on how to do it : Howto: easy cert generation and renewal with nginx :smile:


#3

Thanks a lot, it’s going to be really useful :slight_smile:


Nginx + Wordpress - sec_error_unknown_issuer
#4

Awesome thank you so much, I will give it a read over. Good man!


#5

Ok so, maybe this will shed some light for others. I did try and use the documentation provided, but what confused the hell out of me was the naming convention. Now I am not a sysadmin, rather a developer “sysadmin-light”. I tried setting up the VHOST as suggested, but it just didn’t want to access that file. I watched the folder and they were being generated in there, and NGINX was serving them, but it just didn’t want to auth.

So I went back and I redid everything. This is what worked for me, using my example domain of “www.allroundtraders.co.za

1. Clone into the “letsencrypt” repo as per docs

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto --server \
https://acme-v01.api.letsencrypt.org/directory --help

2. Stop NGINX and run the standalone verification server, ok so not ideal but it worked. Follow the prompts

service nginx stop

./letsencrypt-auto certonly \
-a standalone \
-d www.allroundtraders.co.za \
-d allroundtraders.co.za \
--server https://acme-v01.api.letsencrypt.org/directory \
--agree-dev-preview

NOTE I noticed that when you run the above command it does indeed create the directory called “/etc/letsencrypt/live/www.allroundtraders.co.za/”, but if you have multiple domains in 1 request, the directory will be called after the first domain in the command.

IE: If I had “-d thatguy.co.za -d www.thatguy.co.za -d allroundtraders.co.za -d www.allroundtraders” Then it creates 1 cert containing all the domains as an alias, but it would be in the “/etc/letsencrypt/live/thatguy.co.za/”. It’s just something to keep in mind, keep the order in which you specify your multiple domains the same. Otherwise you will need to update all the certificate references in NGINX.

3. Start NGINX again

service nginx start

Now what got me confused was the naming convention of the key, cert and chain. After this succeeds, a fresh set of certs and keys are generated. Hazaaaa:

root@TheDirector:/ # ls /etc/letsencrypt/live/www.allroundtraders.co.za/
cert.pem  chain.pem  fullchain.pem  privkey.pem
root@TheDirector:/ # 

Note the cert.pem is what others may be familiar with as server.crt, the privkey.pem would then be what some are used to seeying as server.key. And then the chain.pem if you do SSL stapling, which you should. Would be the entire cert chain.

Now these are merely symlinks, which point to the new certs and keys as they get renewed / issued. This means that NGINX only needs point to these files ever. And will automatically point to the most current certificate set. Pretty cool guys!

4. Update NGINX VHOST as needed

Now you will need to update your NGINX VHOST to point to this cert set. This is what mine looks like, keep in mind that I reverse proxy to other servers, but the important part to note is the SSL specific parts:

# NON-SSL
server {
        server_name allroundtraders.co.za www.allroundtraders.co.za img.allroundtraders.co.za;
        if ($scheme = http) {
               return 301 https://$server_name$request_uri;
        }   
}

# SSL
server {

        listen  443;
        server_name  allroundtraders.co.za www.allroundtraders.co.za img.allroundtraders.co.za;

        ssl on;
        ssl_certificate /etc/letsencrypt/live/<YOUR_DOMAIN>/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.allroundtraders.co.za/privkey.pem;

        ssl_stapling on;
        ssl_stapling_verify on;
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";            
              

	location ~* /\.\./ {
                deny all;
                return 404;
        }

	location / {
	        proxy_pass http://app_servers;
		proxy_set_header Host      $host;
		proxy_set_header X-Real-IP $remote_addr;
       	}
}

NOTE: Remember to run nginx -t to test your NGINX config, before assuming everything you did is valid. It’s pretty good at pointing out mistakes.

Like I mentioned, I am a developer by trade, not a sysadmin. Rather a sysadmin-light, so if I am wrong in my statements above please feel free to correct me and help others by doing so.

So far I am pretty impressed guys! So close indeed!


Nginx: 400 Bad Request - The plain HTTP request was sent to HTTPS port
#6

Hi thanks for this it worked perfectly for me.
Now that I’ve used this method what command should I run in 90 days to renew them?


#7

Just a small change, to help get A+ rating on SSL Checker I had to make the following changes:

Change:

ssl_certificate /etc/letsencrypt/live/<YOUR_DOMAIN>/cert.pem;

To

ssl_certificate /etc/letsencrypt/live/<YOUR_DOMAIN>/fullchain.pem;

And remove:

ssl_trusted_certificate /etc/letsencrypt/live/<YOUR_DOMAIN>/fullchain.pem;

Then turn on HSTS

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

You can also add a redirect from http to https if you want by adding the following to your http (non-secure) server config:

if ($scheme = http) { return 301 https://$server_name$request_uri; }

For those that are interested, my full ssl config for nginx is:

listen 443 ssl spdy; ssl_certificate /etc/letsencrypt/live/<YOUR_SITE>/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/<YOUR_SITE>/privkey.pem; ssl_stapling on; ssl_stapling_verify on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; ssl_dhparam /etc/nginx/ssl/dhparams.pem; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m;

Feel free to point out any mistakes I’ve made :smile:


#8

I am glad to hear this has helped you as well. Hopefully the NGINX automation will be sorted soon. But if you need to –renew the certs for whatever reason. You would run the same command with one extra property

Using the example from the original post, this would then be:

./letsencrypt-auto certonly \
-a standalone \
--renew \
-d www.allroundtraders.co.za \
-d allroundtraders.co.za \
--server https://acme-v01.api.letsencrypt.org/directory \
--agree-dev-preview

#9

Thank you for the feedback, I have added some of the changes you suggested. It’s more concise thank you!


#10

I’m using elastic beanstalk, and I don’t understand the last step (4) that you outlined. How do I update the NGINX VHOST?


#11

You need to get a shell open, sudo edit the nginx config file for your website/domain…

I’m guessing you can ssh in? Never used elastic beanstalk myself.


#12

How can I create a certificate on my host machine and copy the certificates to docker containers that I am using? Is that possible? I’m really new to all of this so any advice would help. Thanks!


#13

I know a bit of docker, but my current setup doesn’t use it. You can generate the certs on the host and mount them into Docker with the “-v” volume switch. You would also renew them on the host itself.

This will work with the standalone version which tried to start a webserver, but you will need to stop nginx while doing this as you can only have 1 thing listening on port 80 at a time.

The documentation on mounting volumes on Docker:
https://docs.docker.com/engine/userguide/dockervolumes/

BETTER

I better solution is to mount a common directory and a vhost on nginx to handle the incoming challenge request. An example vhost for me is:

server {
        listen  80;
        server_name  heroesofthestorm.co.za www.heroesofthestorm.co.za img.heroesofthestorm.co.za;

	location '/.well-known/acme-challenge' {
  		default_type "text/plain";
		root        /tmp/letsencrypt-auto;
  	}

        # .... Rest of the locations
}

Give this article a read, this uses NGINX to manage the incomming request with the location mapping above: