Lets Encrypt (Free SSL) Nginx Ubuntu 16 Guide Using Webroot method with https rollover (from source).

in letsencrypt •  8 years ago  (edited)

Premise

This guide assumes you have a website on an nginx server, and wish to start forwarding some or all of your traffic to HTTPS. We also assume nginx is being configured from the nginx/conf.d/domain.conf files, and not nginx.conf directly. Since the advent of https://letsencrypt.org/ getting an SSL Certificate for your domain is now free, but you have to figure out how to jump through all the hoops. This guide was tested on Ubuntu 16.04 LTS.
This method will configure your existing server setup to answer lets encrypt challenges, while forwarding other traffic to the https portion of your site.
This also assumes you understand sudo (what and where to apply it) and have access to root user activities.

Step 1: Log into your web server and configure NGINX. This assumes your web server is already configured to serve http files. This is the important bit (in your nginx/conf.d/domain.conf file):

server {
  #Modify your existing listen 80; directive to
  # match this for your current web server.
  listen 443 ssl;
  #give your server a unique exact match to hit.  
  #it could easily be subdomain.example.com
  server_name www.example.com;
  #this is a file location.  I use the .com in my folder names and it is common to do so.
  root /var/www/example.com;
  index index.php;
#these are commented out until lets encrypt has run for the first time.
#these are based on default locations lets encrypt puts the files.
#nginx will choke trying to load these files if they don't exist,
#hence commenting out for first run.
#  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
#  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
#  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

#Your other web server locations etc....
        location ~ \.(hh|php) { ... }
        location / { index index.php;   ... }
}
#Here is where the new magic happens
server {
  listen 80;
  listen 443 ssl;
  #this will match anything (example.com, sdm.example.com, www.example.com)
  #this is a catchall.  This server block needs to appear 
  #below the one it redirects to, because
  #nginx will match this one before the exact match otherwise.
  #put any subdomains above this server block.
  server_name .example.com;
  root /var/www/example.com;
#Commented out for first run
#  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
#  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
#  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

#This bit is important.  lets encrypts (certbot) makes a folder
# to serve an acme challenge In other words, it makes a file 
# and tells LetsEncrypt.org to check for it.  If the file is accessible
#Then it is assumed you have control over the domain and will issue an ssl cert.
#if the .well-known location is accessed, 
#whatever is in it is served as is on 80 or 443.
  location /.well-known {
    allow all;
  }
#this redirects all other requests (port 80 or 443) to our exact matched 
#server (or subdomain) on port 443
  location / {
    return 301 https://www.example.com$request_uri;
  }
}

Give your nginx a good ol restart and should be able to navigate to www.example.com/.well-known and get a 404. I recommend you create a test file named index.html and drop it into the /var/www/example.com/.well-known and goto www.example.com/.well-known/index.html. The test file should be served to you. If not you have something wrong. If you are receiving an error about http being requested when it should be https, then you need to search in all your nginx config files (/etc/nginx/conf.d/*.conf as well as /etc/nginx/nginx.conf) for the directive "ssl on"; Remove all instances of it, because this forces ssl to be on for the whole virtual server, even in a catchall in another config file. Just make sure you are using listen 443 ssl; (not listen 443;) and your ssl will function as expected.

Step 2: Download the newest certbot. If you don't have git installed install it now.

This method was selected because the repo apparently has an old version.

//if you don't have it installed already.
$ sudo apt-get install git
//navigate to a folder you want to put certbot in.  /home/yourname/programs is the directory i cloned to
$mkdir /home/yourname/programs
$cd /home/yourname/programs
//current repo at the time of this writing.
$git clone https://github.com/certbot/certbot.git

Now run certbot in certonly mode. It will also install dependencies (and ask for root password) the first time it has been run.

$/home/yourname/programs/certbot/letsencrypt-auto-source/letsencrypt-auto certonly --webroot -w /var/www/example.com -d example.com -d www.example.com -d subdomain.example.com

This will create the certificates in the folders mentioned in the nginx config file, in this case: /etc/letsencrypt/live/example.com/[certs].pem
They point to certs in the archive folder with symlinks so that when they renew, you don't need any major changes.

Step 3: Activate

Uncomment the commented out ssl_certificate, ssl_certificate_key, and ssl_trusted_certificate, in both (all) relevant server blocks. They will not need to be commented again because nginx will have cert files to load (even if they are expired), and not having files to load crashes nginx on load.

#in other words this:
#  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
#  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

#should look like something like this in all relevent server blocks:
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

Restart nginx again

$systemctl restart nginx

If you can goto your shiny new https://domain.example.com (or https://www.example.com or whatever you made it), and you can see the green lock, you are where you want to be. Otherwise check the error messages being thrown as to why lets encrypt cannot access the necessary areas of your server. You can also verify the rollover by going to http://somethingnonexistant.example.com and watch it roll to https://www.example.com.
Places to start looking for issues include /var/log/nginx/error.log (you may need to make sure this file isn't changed in /etc/nginx/nginx.conf).

Step 4: auto renew.

Run the letsencrypt with the command renew
Certs are good for 90 days and only automatically renew if they are within 30 days of expiring.
Hooks are only triggered on renewal, not if all certs are skipped.

$/home/yourname/programs/certbot/letsencrypt-auto-source/letsencrypt-auto renew

It should spit out some information about you not needing to be ready to renew (shows output for renewal of 2 separate domains, so repeat certonly --webroot -w /var/www/domain2.com -d domain2.com -d www.domain2.com -d subdomainN.domain2.com).

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/example.com.conf
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/domain2.com.conf
-------------------------------------------------------------------------------

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/example.com/fullchain.pem (skipped)
  /etc/letsencrypt/live/domain2.com/fullchain.pem (skipped)
No renewals were attempted.

Now you just need to add it to a crontab to run twice a day (this is recommended by letsencrypt in case a cert gets revoked by letsencrypt and needs to be reissued earlier than expiration).
Open up sudo crontab -e and add 1 of the lines below
Should look something like

# Schedule for 3am or 3pm (3,15) on the 0 minute
0 3,15 * * * /bin/sh /home/yourname/programs/certbot/letsencrypt-auto-source/letsencrypt-auto renew
# OR if you want to log the results
0 3,15 * * * /bin/sh /home/yourname/programs/certbot/letsencrypt-auto-source/letsencrypt-auto renew > /var/log/letsencrypt.log
# OR with nginx restart.
0 3,15 * * * /bin/sh /home/yourname/programs/certbot/letsencrypt-auto-source/letsencrypt-auto renew --post-hook "systemctl restart nginx"
# OR with nginx restart and logging
0 3,15 * * * /bin/sh /home/yourname/programs/certbot/letsencrypt-auto-source/letsencrypt-auto renew --post-hook "systemctl restart nginx" > /var/log/letsencrypt.log

Pick one of the above and customize to suite your needs. The post-hook (in this case nginx restart via systemctl) only fires if certs were renewed, and is ignored if no certs were due for renewal. (the exception is standalone mode, so that the server IP can be bound after a pre-hook stops nginx and a post hook restarts it).

Troubleshooting

Pretty much everything that can go wrong will generally be logged in /var/log/nginx/error.log. journalctl -xe may be helpful as well. Also, restarting nginx using /etc/init.d/nginx restart spits out an [Ok] or [Failure] instead of being silent and /etc/init.d/nginx configtest can tell you if changes you just made will crash nginx on a restart.
When runnig $letsencrypt-auto it will tell you if it succeeded, or failed and why (check for access to http://domain.com/.well-known/ with a test index.html file, make sure there is no redirects - you will see them in letsencrypts output, run lets encrypt as root and crontab -e as root. .well-known is owned by root (created that way by letsencrypt-auto) and has 755 perms but nginx did not have any issues with serving the challenge content. The folder may need to exist before nginx is (re)started).

Conclusion

This should allow your server to continually accept the letsencrypt challenges while allowing all your other traffic to be rolled to https. This should also keep your cert good, maintenance free, and regular free, pretty much forever. Good luck and let me know if my guide needs any tweaking or adjustments.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Congratulations @piisawheel314! You have received a personal award!

Happy Birthday - 1 Year on Steemit Happy Birthday - 1 Year on Steemit
Click on the badge to view your own Board of Honor on SteemitBoard.

For more information about this award, click here

By upvoting this notification, you can help all Steemit users. Learn how here!

Congratulations @piisawheel314! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 3 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!