≡ Menu

How to configure Nginx with free Let’s Encrypt SSL certificate on Debian or Ubuntu Linux

How do I secure my Nginx web server with Let’s Encrypt free ssl certificate on my Ubuntu Linux 14.04 LTS or Debian Linux 8.x server?

Let’s Encrypt is a free, automated, and open certificate authority for your website or any other projects. You can grab free TLS/SSL certificate including wildcard certificate to create encrypted HTTPS session for your site visitors. In this tutorial, I will explain how to use Let’s Encrypt to install a free SSL certificate for Nginx web server along with how to properly deploy Diffie-Hellman on your nginx server to get SSL labs A+ score.

Say hello to acme.sh client

acme.sh is a shell script client for LetsEncrypt free Certificate. It is very easy to use and works great with both Apache and Nginx. It works in the following mode:

  • Webroot mode (use for existing server)
  • Standalone mode (no nginx installed)
  • Apache mode
  • Dns mode

Please note that LetsEncrypt certificates are only valid for 90 days. Automatic renewal functionality is a bit tricky and need to be done via cron job. The official nginx installer is not yet functional.

Our sample setup

Fig.01: Our sample Nginx TLS/SSL Security with Let's Encrypt on Ubuntu Linux

Fig.01: Our sample Nginx TLS/SSL Security with Let’s Encrypt on Ubuntu Linux

  1. Default Nginx config file : /etc/nginx/sites-available/default
  2. Nginx SSL certification directory : /etc/nginx/ssl/theos.in/
  3. Nginx DocumentRoot (root) path : /var/www/html/
  4. Nginx TLS/SSL Port: 443
  5. Our sample domain: theos.in
  6. Dedicated public IP: 74.86.26.69

Install acme.sh

First, install the git and bc packages with apt-get command:
$ sudo apt-get install git bc wget curl
Sample outputs:

Fig.02: Install git and bc on Ubuntu/Debian Linux

Fig.02: Install git and bc on Ubuntu/Debian Linux

Clone repo

Next, clone the acme.sh client, enter:
$ cd /tmp/
$ git clone https://github.com/Neilpang/acme.sh.git

Sample outputs:

Cloning into 'acme.sh'...
remote: Counting objects: 1578, done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 1578 (delta 3), reused 0 (delta 0), pack-reused 1563
Receiving objects: 100% (1578/1578), 503.02 KiB | 0 bytes/s, done.
Resolving deltas: 100% (645/645), done.
Checking connectivity... done.

To install acme.sh client to your system, enter:
$ cd acme.sh/
$ sudo ./acme.sh --install

Sample outputs:

[Fri Sep  2 13:08:52 UTC 2016] Installing to /root/.acme.sh
[Fri Sep  2 13:08:52 UTC 2016] Installed to /root/.acme.sh/acme.sh
[Fri Sep  2 13:08:52 UTC 2016] OK, Close and reopen your terminal to start using acme.sh
[Fri Sep  2 13:08:52 UTC 2016] Installing cron job
no crontab for root
no crontab for root
[Fri Sep  2 13:08:53 UTC 2016] Good, bash is installed, change the shebang to use bash as prefered.
[Fri Sep  2 13:08:53 UTC 2016] OK

After install, you must close current terminal and reopen again to make the alias take effect. Or simply type the following command:
$ sudo source ~/.bashrc
Test it (first become root user):
$ sudo -s
# acme.sh

All of the following command issued as a root user i.e. type the following command first:
$ sudo -s

Create /.well-known/acme-challenge/ directory

Type the following command (set D to actual DocumentRoot path as per your setup):
# D=/var/www/html
# mkdir -vp ${D}/.well-known/acme-challenge/
###---[ NOTE: Adjust permission as per your setup ]---###
# chown -R www-data:www-data ${D}/.well-known/acme-challenge/
# chmod -R 0555 ${D}/.well-known/acme-challenge/

Create directory to store SSL certicate

# mkdir -p /etc/nginx/ssl/theos.in/

Generate your dhparam.pem file

You need to use a strong Diffie-Hellman (DH) group, regardless of the server software you use. The simplest way of generating a new group is to use OpenSSL. Type the following command to create the dhparam.pem file:
# cd /etc/nginx/ssl/theos.in/
I suggest that you generate a 4096-bit group:
# openssl dhparam -out dhparams.pem 4096
Sample outputs:

Generating DH parameters, 4096 bit long safe prime, generator 2
This is going to take a long time
...............................................................+.........+.................................................................................................................................................................................+.............+......................................................................................................................................
..
.............................................................................................................+...................................................................................+.........+.......................................................................................................................................................................++*++*

Issue a certificate for theos.in domain

The syntax is as follows
acme.sh --issue -w /DocumentRootPath/ -d example.com
acme.sh --issue -w /DocumentRootPath/ -d example.com www.foo.com -d bar.com
acme.sh --issue -w /path/to/www/htmlRoot/ -d example.com -k 2048

Where,

  1. --issue : Issue a new certificate.
  2. -w /DocumentRootPath/ : Specifies the web root folder for web root mode.
  3. -d example.com : Specifies a domain, used to issue, renew or revoke etc. Can be used multiple times.
  4. -k 2048 : Specifies the domain key length.

To issue a certificate for theos.in and www.theos.in, enter:
# acme.sh --issue -w /var/www/html -d theos.in -d www.theos.in
For example, if you give “no” to “key-length”, it will use default length 2048. In this example set “key-length” to 4096
# acme.sh --issue -w /var/www/html -d theos.in -d www.theos.in -k 4096
Sample outputs:

Fig.03: Issue a certificate

Fig.03: Issue a certificate

Configure TLS/SSL on Nginx web Server

Edit nginx.conf or /etc/nginx/sites-available/default as follows:
# vi /etc/nginx/sites-available/default
Add the following configuration directives

## START: SSL/HTTPS theos.in ###
server {
    #------- Start SSL config with http2 support ----#
    listen 74.86.26.69:443 http2;
    server_name theos.in;
    ssl on;
    ssl_certificate /etc/nginx/ssl/theos.in/theos.in.cer;
    ssl_certificate_key /etc/nginx/ssl/theos.in/theos.in.key;
    ssl_session_timeout 30m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
    ssl_session_cache shared:SSL:10m;
    ssl_dhparam /etc/nginx/ssl/theos.in/dhparams.pem;
    ssl_prefer_server_ciphers on;
 
    ## Improves TTFB by using a smaller SSL buffer than the nginx default
    ssl_buffer_size 8k;
 
    ## Enables OCSP stapling
    ssl_stapling on;
    resolver 8.8.8.8;
    ssl_stapling_verify on;
 
    ## Send header to tell the browser to prefer https to http traffic
    add_header Strict-Transport-Security max-age=31536000;
 
    ## SSL logs ##
    access_log /var/log/nginx/theos.in/ssl_access.log;
    error_log /var/log/nginx/theos.in/ssl_error.log;
    #-------- END SSL config -------##
 
    # Add rest of your config below like document path and more ##
}
## END SSL theos.in ######

Save and close the file.

Install the issued certificate to Nginx web server

Type the following command:
# acme.sh --installcert -d theos.in --keypath /etc/nginx/ssl/theos.in/theos.in.key --fullchainpath /etc/nginx/ssl/theos.in/theos.in.cer --reloadCmd 'systemctl reload nginx'
Sample outputs:

[Fri Sep  2 15:19:56 UTC 2016] Installing key to:/etc/nginx/ssl/theos.in/theos.in.key
[Fri Sep  2 15:19:56 UTC 2016] Installing full chain to:/etc/nginx/ssl/theos.in/theos.in.cer
[Fri Sep  2 15:19:56 UTC 2016] Run Le_ReloadCmd: systemctl reload nginx
[Fri Sep  2 15:19:56 UTC 2016] Reload success

Open port 443

Type the following ufw command:
# ufw allow proto tcp from any to 74.86.26.69 port 443

Test it

Type the following url:
https://theos.in
Or visit SSL labs to test your TLS/SSL config:

Fig.03: SSL Labs A+ score

Fig.03: SSL Labs A+ score

How do I renew a certificate?

Type the following command:
# acme.sh --renew -d theos.in
Sample outputs:

[Fri Sep  2 15:23:16 UTC 2016] Renew: 'theos.in'
[Fri Sep  2 15:23:16 UTC 2016] Skip, Next renewal time is: Mon Nov 21 15:07:55 UTC 2016
[Fri Sep  2 15:23:16 UTC 2016] Add '--force' to force to renew.

A note about cron job

A cron job will try to do renewal a certificate for you too. This is installed by default as follows (no action required on your part):

0 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
Share this tutorial on:
{ 7 comments… add one }
  • ling March 10, 2016, 7:27 am

    Another dream comes true.
    I was hoping such a tool for a long time, good for our wallets.
    Thanks (the procedure worked fine for me).

  • Washington March 10, 2016, 5:54 pm

    Hi, I followed the steps in this guide till I got unable to load Private Key, after I run:

    le issue /usr/share/nginx/html themain.com www.thedomain.com,other.thedomain.com 4096
    Outputs:

    unable to load Private Key
    139662025688736:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:703:Expecting: ANY PRIVATE KEY
    printf: usage: printf [-v var] format [arguments]
    unable to load Private Key
    139831152248480:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:703:Expecting: ANY PRIVATE KEY
    printf: usage: printf [-v var] format [arguments]
    unable to load key file
    140545094272672:error:0906D06C:PEM routines:PEM_read_bio:no start line:pem_lib.c:703:Expecting: ANY PRIVATE KEY
    Register account Error.
  • pixel March 10, 2016, 6:06 pm

    I follow your blog since about a year, but I want to thank you today for this great howto. I didn’t even knew the existence of let’s encrypt, this is a great service and you write a great guide to use it. Thank you :)

  • Tom March 10, 2016, 7:01 pm

    Thanks. It is working for me. But, why do I need to create /.well-known/acme-challenge/ directory in /home/mydomain/ ? What is the purpose of the /.well-known/acme-challenge/ ?

  • Istimsak March 14, 2016, 3:48 pm

    Interesting howto article. If you don’t mind me asking, what inspired you to write this howto, what did you see in “lets encrypt” that made you share such valuable information?

  • facio April 7, 2016, 10:31 am

    It’s better to do:
    chmod -R 0555 /var/www/html/.well-known/acme-challenge/
    instead of
    chmod -R 0444 /var/www/html/.well-known/acme-challenge/
    because chmod 0444 will fail domain validation.

Security: Are you a robot or human?

Leave a Comment

You can use these HTML tags and attributes: <strong> <em> <pre> <code> <a href="" title="">


   Tagged with: , , ,