Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to setup Let's Encrypt for Nginx on Ubuntu 18.04 (including IPv6, HTTP/2 and A+ SSL rating)

How to setup Let's Encrypt for Nginx on Ubuntu 18.04 (including IPv6, HTTP/2 and A+ SLL rating)


Virtual hosts

Let's say you want to host domains first.com and second.com.

Create folders for their files:

mkdir /var/www/first
mkdir /var/www/second

Create a text file /etc/nginx/sites-available/first.conf containing:

server {
	listen 80 default_server;
	listen [::]:80 default_server ipv6only=on;

	server_name first.com www.first.com;
	root /var/www/first;

	index index.html;
	location / {
		try_files $uri $uri/ =404;
	}
}

Create a text file /etc/nginx/sites-available/second.conf containing:

server {
	listen 80;
	listen [::]:80;

	server_name second.com www.second.com;
	root /var/www/second;

	index index.html;
	location / {
		try_files $uri $uri/ =404;
	}
}

Note that only the first domain has the keywords default_server and ipv6only=on in the listen lines.

Replace the default virtual host:

sudo rm /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/first.conf /etc/nginx/sites-enabled/first.conf
sudo ln -s /etc/nginx/sites-available/second.conf /etc/nginx/sites-enabled/second.conf

sudo nginx -t
sudo systemctl stop nginx
sudo systemctl start nginx

Check that Nginx is running:

sudo systemctl status nginx

Expected results at this stage:

  • http://first.com and http://www.first.com serve the files from /var/www/first
  • http://second.com and http://www.second.com serve the files from /var/www/second
  • https://www.first.com and https://www.second.com don't work yet

Certbot

Install Certbot for Nginx:

sudo apt-get update
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install -y python-certbot-nginx

Setup the certificates & convert Virtual Hosts to HTTPS:

sudo certbot --nginx

It will ask for:

  • an email address
  • agreeing to its Terms of Service
  • which domains to use HTTPS for (it detects the list using server_name lines in your Nginx config)
  • whether to redirect HTTP to HTTPS (recommended) or not

You could stop here if all you want is HTTPS as this already gives you an A rating and maintains itself.

Test your site with SSL Labs using https://www.ssllabs.com/ssltest/analyze.html?d=www.YOUR-DOMAIN.com

Expected results at this stage:

  • http://first.com redirects to https://first.com
  • http://second.com redirects to https://second.com
  • http://www.first.com redirects to https://www.first.com
  • http://www.second.com redirects to https://www.second.com
  • https://first.com and https://www.first.com serve the files from /var/www/first
  • https://second.com and https://www.first.comserve the files from /var/www/second

Automatic renewal

There is nothing to do, Certbot installed a cron task to automatically renew certificates about to expire.

You can check renewal works using:

sudo certbot renew --dry-run

You can also check what certificates exist using:

sudo certbot certificates

HTTP/2

first.conf should now look something like this, now that Certbot edited it:

server {
	server_name first.com www.first.com;
	root /var/www/first.com;

	index index.html;
	location / {
		try_files $uri $uri/ =404;
	}

	listen [::]:443 ssl ipv6only=on; # managed by Certbot
	listen 443 ssl; # managed by Certbot
	ssl_certificate /etc/letsencrypt/live/first.com/fullchain.pem; # managed by Certbot
	ssl_certificate_key /etc/letsencrypt/live/first.com/privkey.pem; # managed by Certbot
	include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
	if ($host = www.first.com) {
		return 301 https://$host$request_uri;
	} # managed by Certbot

	if ($host = first.com) {
		return 301 https://$host$request_uri;
	} # managed by Certbot

	listen 80 default_server;
	listen [::]:80 default_server;

	server_name first.com www.first.com;
	return 404; # managed by Certbot
}

Certbot didn't add HTTP/2 support when it created the new server blocks, so replace these lines:

listen [::]:443 ssl ipv6only=on;
listen 443 ssl;

by this:

listen [::]:443 ssl http2 ipv6only=on;
listen 443 ssl http2;
gzip off;

There is already an open Github issue requesting Certbot to add http2 automatically, so hopefully this step can soon be removed.


Stronger settings for A+

Trusted certificate

The HTTPS server blocks in first.conf and second.conf contain these lines, added by Certbot:

ssl_certificate /etc/letsencrypt/live/YOUR-DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/YOUR-DOMAIN/privkey.pem;

The stronger settings use OCSP Stapling, so each virtual host will need a ssl_trusted_certificate as well.

Add this line (using the folder name that Certbot generated for your domain) after the ssl_certificate_key line:

ssl_trusted_certificate /etc/letsencrypt/live/YOUR-DOMAIN/chain.pem;

SSL

Now let's edit the shared SSL settings at /etc/letsencrypt/options-ssl-nginx.conf. It most likely looks like this initially:

ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_timeout 1440m;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";

If you tested with SSL Labs, you probably noticed that quite a few ciphers were flagged as "weak".

So replace the contents of the file with:

ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_timeout 1d;
ssl_session_tickets off;

ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;

ssl_stapling on;
ssl_stapling_verify on;

add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload;";
add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; script-src 'self'; img-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self';";
add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";

Now restart Nginx, and test the domain again with SSL Labs using https://www.ssllabs.com/ssltest/analyze.html?d=www.YOUR-DOMAIN.com&latest: it should now be rated A+, congratulations! ๐Ÿ™‚


Conclusion

You could further improve using content-specific features like Content Security Policy and Subresource Integrity, and Brotli compression to replace gzip.

Online testing tools:

Useful links:

If Let's Encrypt is useful to you, consider donating to Let's Encrypt or donating to the EFF.

@DavidOD

This comment has been minimized.

Show comment
Hide comment
@DavidOD

DavidOD Jan 19, 2017

awesome post. THANK YOU!

DavidOD commented Jan 19, 2017

awesome post. THANK YOU!

@gerchen

This comment has been minimized.

Show comment
Hide comment
@gerchen

gerchen commented Jan 20, 2017

Thanks!

@kakopappa

This comment has been minimized.

Show comment
Hide comment
@kakopappa

kakopappa Jan 24, 2017

Found a lazy way :)

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
sudo ./letsencrypt-auto --nginx

kakopappa commented Jan 24, 2017

Found a lazy way :)

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
sudo ./letsencrypt-auto --nginx

@andresmgsl

This comment has been minimized.

Show comment
Hide comment
@andresmgsl

andresmgsl Jan 29, 2017

Really thankful

andresmgsl commented Jan 29, 2017

Really thankful

@MCeddy

This comment has been minimized.

Show comment
Hide comment
@MCeddy

MCeddy Mar 2, 2017

Thank you :)

MCeddy commented Mar 2, 2017

Thank you :)

@boriscy

This comment has been minimized.

Show comment
Hide comment
@boriscy

boriscy Mar 21, 2017

Thanks it worked really well.

boriscy commented Mar 21, 2017

Thanks it worked really well.

@texeltexel2009

This comment has been minimized.

Show comment
Hide comment
@texeltexel2009

texeltexel2009 Mar 21, 2017

Great! Thx :) ๐Ÿ‘

texeltexel2009 commented Mar 21, 2017

Great! Thx :) ๐Ÿ‘

@rlam3

This comment has been minimized.

Show comment
Hide comment
@rlam3

rlam3 Mar 23, 2017

does this work for 14.04 too?
And what if I have cloudflare in front of nginx? How would this differ?

rlam3 commented Mar 23, 2017

does this work for 14.04 too?
And what if I have cloudflare in front of nginx? How would this differ?

@cecilemuller

This comment has been minimized.

Show comment
Hide comment
@cecilemuller

cecilemuller Jun 2, 2017

@rlam3 Sorry I only saw your comment now, Gists don't get notifications unfortunately. To answer your question, yes 14.04 is mostly the same except systemctl commands should be service commands instead, e.g. service nginx reload instead of systemctl reload nginx.

Owner

cecilemuller commented Jun 2, 2017

@rlam3 Sorry I only saw your comment now, Gists don't get notifications unfortunately. To answer your question, yes 14.04 is mostly the same except systemctl commands should be service commands instead, e.g. service nginx reload instead of systemctl reload nginx.

@hshhhhh

This comment has been minimized.

Show comment
Hide comment
@hshhhhh

hshhhhh Jun 7, 2017

@cecilemuller thank you a lot!

hshhhhh commented Jun 7, 2017

@cecilemuller thank you a lot!

@MastroMicio

This comment has been minimized.

Show comment
Hide comment
@MastroMicio

MastroMicio Jun 10, 2017

thank you! this is perfect!

MastroMicio commented Jun 10, 2017

thank you! this is perfect!

@blbwd

This comment has been minimized.

Show comment
Hide comment
@blbwd

blbwd Jun 17, 2017

Shall I need to run this code separately for each of my domain?

certbot certonly --webroot --agree-tos --no-eff-email --email YOUR@EMAIL.COM -w /var/www/letsencrypt -d www.domain.com -d domain.com

blbwd commented Jun 17, 2017

Shall I need to run this code separately for each of my domain?

certbot certonly --webroot --agree-tos --no-eff-email --email YOUR@EMAIL.COM -w /var/www/letsencrypt -d www.domain.com -d domain.com

@cecilemuller

This comment has been minimized.

Show comment
Hide comment
@cecilemuller

cecilemuller Jun 18, 2017

@blbwd You can either do run the command once per domain with a single -d, or a single command with multiple -d (maximum 100 domains per certificate): both ways are fine.

The main difference is how it counts requests in regards to the API rate limits:

  • with multiple -d, it creates a single certificate for all domains specified, so it counts as only one request

  • if you ran the command separately for each domain, it creates a separated certificate for each domain, and each domain counts as one request.

Owner

cecilemuller commented Jun 18, 2017

@blbwd You can either do run the command once per domain with a single -d, or a single command with multiple -d (maximum 100 domains per certificate): both ways are fine.

The main difference is how it counts requests in regards to the API rate limits:

  • with multiple -d, it creates a single certificate for all domains specified, so it counts as only one request

  • if you ran the command separately for each domain, it creates a separated certificate for each domain, and each domain counts as one request.

@blbwd

This comment has been minimized.

Show comment
Hide comment
@blbwd

blbwd Jun 19, 2017

It works. I am running the script to get certificate separately for each domain. Now when I set automatic renewal, will single cron will renew all of my certificates which I have generated separately for each domain?

blbwd commented Jun 19, 2017

It works. I am running the script to get certificate separately for each domain. Now when I set automatic renewal, will single cron will renew all of my certificates which I have generated separately for each domain?

@cecilemuller

This comment has been minimized.

Show comment
Hide comment
@cecilemuller

cecilemuller Jun 19, 2017

@blbwd Yes, a single certbot renew --noninteractive command will attempt to renew all certificates that are near expiration, even if they were generated separately for each domain (because Certbot keeps track of the domains it generated certificates for, so it knows the list).

You can check it by running certbot renew --dry-run (which merely pretends to renew), it should mention all the certificates.

Owner

cecilemuller commented Jun 19, 2017

@blbwd Yes, a single certbot renew --noninteractive command will attempt to renew all certificates that are near expiration, even if they were generated separately for each domain (because Certbot keeps track of the domains it generated certificates for, so it knows the list).

You can check it by running certbot renew --dry-run (which merely pretends to renew), it should mention all the certificates.

@blbwd

This comment has been minimized.

Show comment
Hide comment
@blbwd

blbwd Jun 20, 2017

Thanks a lot. It is working. You have a such great technical and helpful person I had ever known.

blbwd commented Jun 20, 2017

Thanks a lot. It is working. You have a such great technical and helpful person I had ever known.

@cecilemuller

This comment has been minimized.

Show comment
Hide comment
@cecilemuller

cecilemuller Jun 20, 2017

Thanks ๐Ÿ˜ƒ

Owner

cecilemuller commented Jun 20, 2017

Thanks ๐Ÿ˜ƒ

@RobinCsl

This comment has been minimized.

Show comment
Hide comment
@RobinCsl

RobinCsl Jun 28, 2017

Thank you very much. Really helpful!!!
I would like to add that if you are loading index.php by default, leave the lines concerning the location of how the server needs to interpret php files.

RobinCsl commented Jun 28, 2017

Thank you very much. Really helpful!!!
I would like to add that if you are loading index.php by default, leave the lines concerning the location of how the server needs to interpret php files.

@dinofizz

This comment has been minimized.

Show comment
Hide comment
@dinofizz

dinofizz Jul 5, 2017

This is the most concise and helpful write-up I have found! Thank you for taking the time to publish this.

dinofizz commented Jul 5, 2017

This is the most concise and helpful write-up I have found! Thank you for taking the time to publish this.

@josethomazini

This comment has been minimized.

Show comment
Hide comment
@josethomazini

josethomazini Jul 7, 2017

It just works! Thank you!

josethomazini commented Jul 7, 2017

It just works! Thank you!

@rajeevkannav

This comment has been minimized.

Show comment
Hide comment
@rajeevkannav

rajeevkannav Jul 25, 2017

Hello, Thanks for this awesome thing.

Just one Question Why we are not writing server_name mydomain.com;
like server_name mydomain.com www.mydomain.com; single Line ?? this will save two code blocks and iterations

Thanks in advance

rajeevkannav commented Jul 25, 2017

Hello, Thanks for this awesome thing.

Just one Question Why we are not writing server_name mydomain.com;
like server_name mydomain.com www.mydomain.com; single Line ?? this will save two code blocks and iterations

Thanks in advance

@restmount

This comment has been minimized.

Show comment
Hide comment
@restmount

restmount Aug 1, 2017

Thanks!
Save my time.

restmount commented Aug 1, 2017

Thanks!
Save my time.

@astr0naugh7

This comment has been minimized.

Show comment
Hide comment
@astr0naugh7

astr0naugh7 Aug 6, 2017

Hi,
This worked great for me. Now I want to add another domain onto the same server using it's own SSL cert. How can I edit this to allow for multiple domains/subdirectories? With this current setup, I can't get to the IP as it just 301s to the domain I first setup with this. Is it possible to do that? I would really like to have multiple domains on this one server.

Thanks again.

astr0naugh7 commented Aug 6, 2017

Hi,
This worked great for me. Now I want to add another domain onto the same server using it's own SSL cert. How can I edit this to allow for multiple domains/subdirectories? With this current setup, I can't get to the IP as it just 301s to the domain I first setup with this. Is it possible to do that? I would really like to have multiple domains on this one server.

Thanks again.

@diegoddox

This comment has been minimized.

Show comment
Hide comment
@diegoddox

diegoddox Aug 14, 2017

Awesome, thanks a lot!

diegoddox commented Aug 14, 2017

Awesome, thanks a lot!

@crw

This comment has been minimized.

Show comment
Hide comment
@crw

crw Aug 17, 2017

Came to say, thanks so much! This was extremely helpful.

@astr0naugh7: try this, not sure if it works yet:

location / {
    return 301 https://$server_name$request_uri;
}

Regardless, plumbing the nginx docs might help.

crw commented Aug 17, 2017

Came to say, thanks so much! This was extremely helpful.

@astr0naugh7: try this, not sure if it works yet:

location / {
    return 301 https://$server_name$request_uri;
}

Regardless, plumbing the nginx docs might help.

@crw

This comment has been minimized.

Show comment
Hide comment
@crw

crw Aug 17, 2017

Oh also, @cecilemuller: why no

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

I spend like 30 minutes a server generating the damn dhparam.pem file; is it not necessary to do so?

crw commented Aug 17, 2017

Oh also, @cecilemuller: why no

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

I spend like 30 minutes a server generating the damn dhparam.pem file; is it not necessary to do so?

@pankaj884

This comment has been minimized.

Show comment
Hide comment
@pankaj884

pankaj884 Aug 21, 2017

I tried this many times, and it's not working out. How can I debug what's the issue?

pankaj884 commented Aug 21, 2017

I tried this many times, and it's not working out. How can I debug what's the issue?

@jwilleke

This comment has been minimized.

Show comment
Hide comment
@jwilleke

jwilleke Aug 28, 2017

+1 pankaj884 I tried this many times, and it's not working out. How can I debug what's the issue?
I keep getting:
urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://www.example.com/

jwilleke commented Aug 28, 2017

+1 pankaj884 I tried this many times, and it's not working out. How can I debug what's the issue?
I keep getting:
urn:acme:error:unauthorized :: The client lacks sufficient authorization :: Invalid response from http://www.example.com/

@frenchbread

This comment has been minimized.

Show comment
Hide comment
@frenchbread

frenchbread Aug 29, 2017

Thanks @cecilemuller. This helped a lot!

In addition, how would you add to this NGINX config an instance that works on port :8000 "locally" on a server and should be reverce-proxied to public :8000 port. Including same redirections as with :80 ?

frenchbread commented Aug 29, 2017

Thanks @cecilemuller. This helped a lot!

In addition, how would you add to this NGINX config an instance that works on port :8000 "locally" on a server and should be reverce-proxied to public :8000 port. Including same redirections as with :80 ?

@nadj

This comment has been minimized.

Show comment
Hide comment
@nadj

nadj Sep 8, 2017

Hi @cecilemuller, thank you for a great tutorial.
Unfortunately I need some help, something really strange is happening on my server.
After the config file is set as you shown I have https enabled, but I'm unable to renew the certificate.
The error from sudo certbot renew --dry-run

Invalid response from
http://www.mydomain.com/.well-known/acme-challenge/bThHYfp4L-ohGk9k1stBWztze5dj3RsvgRWA6gBI24o

Tried to put a file to /var/www/letscencrypt/.wellknown/acme-challenge/test
And I can't access it from http://www.mydomain.com/.well-known/acme-challenge/test I get redirected to https and my site is showing a 404 error

However I can access the test file from http://mydomain.com/.well-known/acme-challenge/test and it shows me the content.

I commented out everything except the ## Serves https://www.mydomain.com code block and it works as described above. I'm refreshing the server with sudo service nginx reload
I can't figure out whats happening here

nginx version is 1.10.3, server is Ubuntu 16.04.3 LTS

Can you give me some advice?
Thanks in advance

nadj commented Sep 8, 2017

Hi @cecilemuller, thank you for a great tutorial.
Unfortunately I need some help, something really strange is happening on my server.
After the config file is set as you shown I have https enabled, but I'm unable to renew the certificate.
The error from sudo certbot renew --dry-run

Invalid response from
http://www.mydomain.com/.well-known/acme-challenge/bThHYfp4L-ohGk9k1stBWztze5dj3RsvgRWA6gBI24o

Tried to put a file to /var/www/letscencrypt/.wellknown/acme-challenge/test
And I can't access it from http://www.mydomain.com/.well-known/acme-challenge/test I get redirected to https and my site is showing a 404 error

However I can access the test file from http://mydomain.com/.well-known/acme-challenge/test and it shows me the content.

I commented out everything except the ## Serves https://www.mydomain.com code block and it works as described above. I'm refreshing the server with sudo service nginx reload
I can't figure out whats happening here

nginx version is 1.10.3, server is Ubuntu 16.04.3 LTS

Can you give me some advice?
Thanks in advance

@crspybits

This comment has been minimized.

Show comment
Hide comment
@crspybits

crspybits Sep 10, 2017

Yes indeed, thanks!

I tried the test you recommended and it gave an "A" rating. I haven't tried the "content-specific features like Content Security Policy and Subresource Integrity". Here's my .conf so far:
https://github.com/crspybits/SyncServerII/blob/master/nginx.conf

crspybits commented Sep 10, 2017

Yes indeed, thanks!

I tried the test you recommended and it gave an "A" rating. I haven't tried the "content-specific features like Content Security Policy and Subresource Integrity". Here's my .conf so far:
https://github.com/crspybits/SyncServerII/blob/master/nginx.conf

@yifeikong

This comment has been minimized.

Show comment
Hide comment
@yifeikong

yifeikong Oct 8, 2017

By default, 'renew' will reuse the options used to create obtain or most recently successfully renew each certificate lineage.

I wish I could create a cert via --standalone and then renew it using --wwwroot.

yifeikong commented Oct 8, 2017

By default, 'renew' will reuse the options used to create obtain or most recently successfully renew each certificate lineage.

I wish I could create a cert via --standalone and then renew it using --wwwroot.

@blbwd

This comment has been minimized.

Show comment
Hide comment
@blbwd

blbwd Oct 8, 2017

I installed SSL on my 4 domains on the same day but suddenly certificates of 2 domains expired. I already run "certbot renew --dry-run" but in vain. For those 2 domains it is showing that certificate has been expired 21 days ago. Please suggest.

blbwd commented Oct 8, 2017

I installed SSL on my 4 domains on the same day but suddenly certificates of 2 domains expired. I already run "certbot renew --dry-run" but in vain. For those 2 domains it is showing that certificate has been expired 21 days ago. Please suggest.

@cecilemuller

This comment has been minimized.

Show comment
Hide comment
@cecilemuller

cecilemuller Oct 8, 2017

Sorry @blbwd, better ask at the Certbot repository or on Stackoverflow instead.

The best advice I could give is looking at the output of the dry run command to see if it gives an error (like if it's able to connect), or even run certbot renew to see if it has an error only when it tries to truly renew the certificate (instead of a mere test run).

There should also be some log files in /var/log/letsencrypt you could look at when looking for errors, but they're very verbose.

And if it does renew but doesn't show up in the browser, restart the web server service (although reloading should be enough) and clear your browser cache.

Owner

cecilemuller commented Oct 8, 2017

Sorry @blbwd, better ask at the Certbot repository or on Stackoverflow instead.

The best advice I could give is looking at the output of the dry run command to see if it gives an error (like if it's able to connect), or even run certbot renew to see if it has an error only when it tries to truly renew the certificate (instead of a mere test run).

There should also be some log files in /var/log/letsencrypt you could look at when looking for errors, but they're very verbose.

And if it does renew but doesn't show up in the browser, restart the web server service (although reloading should be enough) and clear your browser cache.

@cecilemuller

This comment has been minimized.

Show comment
Hide comment
@cecilemuller

cecilemuller Oct 8, 2017

@binarykitchen Sorry I haven't tried 17, I'm only using the LTS versions

Owner

cecilemuller commented Oct 8, 2017

@binarykitchen Sorry I haven't tried 17, I'm only using the LTS versions

@blbwd

This comment has been minimized.

Show comment
Hide comment
@blbwd

blbwd Oct 9, 2017

The dry run command did not show any error and all the renew process was done successfully. Tanks a lot for your suggestion to restart server. All the 2 certificates started working as soon as I restarted my nginx server.

blbwd commented Oct 9, 2017

The dry run command did not show any error and all the renew process was done successfully. Tanks a lot for your suggestion to restart server. All the 2 certificates started working as soon as I restarted my nginx server.

@cecilemuller

This comment has been minimized.

Show comment
Hide comment
@cecilemuller

cecilemuller Oct 9, 2017

I'm glad it worked ๐Ÿ˜ƒ

Owner

cecilemuller commented Oct 9, 2017

I'm glad it worked ๐Ÿ˜ƒ

@nemchik

This comment has been minimized.

Show comment
Hide comment
@nemchik

nemchik Oct 30, 2017

Is there any reason why X-Frame-Options could not be SAMEORIGIN? Making that change doesn't seem to affect my score on SSLTest.

nemchik commented Oct 30, 2017

Is there any reason why X-Frame-Options could not be SAMEORIGIN? Making that change doesn't seem to affect my score on SSLTest.

@cecilemuller

This comment has been minimized.

Show comment
Hide comment
@cecilemuller

cecilemuller Nov 2, 2017

@nemchik No reason against it, SAMEORIGIN is fine too if the site needs iframes.

Owner

cecilemuller commented Nov 2, 2017

@nemchik No reason against it, SAMEORIGIN is fine too if the site needs iframes.

@mobambi

This comment has been minimized.

Show comment
Hide comment
@mobambi

mobambi Nov 14, 2017

I followed this guide and it works well. Thanks
But after this, when I'm trying to access phpmyadmin page, it returns 403 Forbidden nginx/1.10.3 (Ubuntu)...
Can anyone help me with this problem?

mobambi commented Nov 14, 2017

I followed this guide and it works well. Thanks
But after this, when I'm trying to access phpmyadmin page, it returns 403 Forbidden nginx/1.10.3 (Ubuntu)...
Can anyone help me with this problem?

@fugroup

This comment has been minimized.

Show comment
Hide comment
@fugroup

fugroup Jan 4, 2018

Thanks! Works great.

fugroup commented Jan 4, 2018

Thanks! Works great.

@dinvisible1

This comment has been minimized.

Show comment
Hide comment
@dinvisible1

dinvisible1 Jan 16, 2018

Firstly great stuff, I tried setting it up with odoo 10 on a vps but seem to be having some trouble with it, due to the sensitivity of the project can you provide some insight on how to get it working? ill gladly redact any sensitive info if successful to help other.

dinvisible1 commented Jan 16, 2018

Firstly great stuff, I tried setting it up with odoo 10 on a vps but seem to be having some trouble with it, due to the sensitivity of the project can you provide some insight on how to get it working? ill gladly redact any sensitive info if successful to help other.

@salfredogonzalez

This comment has been minimized.

Show comment
Hide comment
@salfredogonzalez

salfredogonzalez Jan 16, 2018

Thanks, i just need another fix that is not established here that it was open the firewall rules,
sudo ufw status
sudo ufw allow 'Nginx Full'
sudo ufw delete 'Nginx HTTP'
And works great!

salfredogonzalez commented Jan 16, 2018

Thanks, i just need another fix that is not established here that it was open the firewall rules,
sudo ufw status
sudo ufw allow 'Nginx Full'
sudo ufw delete 'Nginx HTTP'
And works great!

@tinusg

This comment has been minimized.

Show comment
Hide comment
@tinusg

tinusg Jan 17, 2018

If you ever run into the issue where your acme-challenge folder seems to be publicly accessible (works in your browser), but Letsencrypt still returns 404 during the CA challenge, you should check to see if your IPV6 configuration is working correctly. I had added AAAA records to my DNS server, but accidentally removed listen [::]:80; from my site settings.

Oh and don't forget to add [::]:443 ssl; to your site settings when Letsencrypt is done. It doesn't do that automatically.

tinusg commented Jan 17, 2018

If you ever run into the issue where your acme-challenge folder seems to be publicly accessible (works in your browser), but Letsencrypt still returns 404 during the CA challenge, you should check to see if your IPV6 configuration is working correctly. I had added AAAA records to my DNS server, but accidentally removed listen [::]:80; from my site settings.

Oh and don't forget to add [::]:443 ssl; to your site settings when Letsencrypt is done. It doesn't do that automatically.

@dheerajbhaskar

This comment has been minimized.

Show comment
Hide comment
@dheerajbhaskar

dheerajbhaskar Jan 19, 2018

Amazing post, this worked for me :)

dheerajbhaskar commented Jan 19, 2018

Amazing post, this worked for me :)

@besnik

This comment has been minimized.

Show comment
Hide comment
@besnik

besnik Jan 23, 2018

Thank you, very good work!

besnik commented Jan 23, 2018

Thank you, very good work!

@yuryroot

This comment has been minimized.

Show comment
Hide comment
@yuryroot

yuryroot Jan 25, 2018

@cecilemuller Thank you for awesome detailed instructions!

yuryroot commented Jan 25, 2018

@cecilemuller Thank you for awesome detailed instructions!

@kiritAyya

This comment has been minimized.

Show comment
Hide comment
@kiritAyya

kiritAyya Jan 25, 2018

I have been trying this gist for a while now, and the response for the certbot command i keep getting is invalid response. If I try to access the /.well-known folder from the browser i get a 403 forbidden from nginx. Could someone help me with this?

kiritAyya commented Jan 25, 2018

I have been trying this gist for a while now, and the response for the certbot command i keep getting is invalid response. If I try to access the /.well-known folder from the browser i get a 403 forbidden from nginx. Could someone help me with this?

@giantas

This comment has been minimized.

Show comment
Hide comment
@giantas

giantas Jan 25, 2018

Why is it creating a folder named ~ in the current path?

giantas commented Jan 25, 2018

Why is it creating a folder named ~ in the current path?

@spn89

This comment has been minimized.

Show comment
Hide comment
@spn89

spn89 Feb 4, 2018

Created a user just to say awesome guide.

spn89 commented Feb 4, 2018

Created a user just to say awesome guide.

@vwal

This comment has been minimized.

Show comment
Hide comment
@vwal

vwal Feb 8, 2018

I have the following as default server config (named 00.default since the sites are loaded in alpha order) in nginx, and have created /var/www/nginx/_undefined/htdocs/.well-known/ directory for certbot to use for its verification. This way I can use certbot certonly -a webroot --webroot-path=/var/www/nginx/_undefined/htdocs -d somenewdomain.com command while I don't yet have that domain otherwise configured in nginx.

server {
    listen 10.11.11.40:80;
    server_name _undefined;

    root /var/www/nginx/_undefined/htdocs;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

vwal commented Feb 8, 2018

I have the following as default server config (named 00.default since the sites are loaded in alpha order) in nginx, and have created /var/www/nginx/_undefined/htdocs/.well-known/ directory for certbot to use for its verification. This way I can use certbot certonly -a webroot --webroot-path=/var/www/nginx/_undefined/htdocs -d somenewdomain.com command while I don't yet have that domain otherwise configured in nginx.

server {
    listen 10.11.11.40:80;
    server_name _undefined;

    root /var/www/nginx/_undefined/htdocs;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}
@jerome-diver

This comment has been minimized.

Show comment
Hide comment
@jerome-diver

jerome-diver Feb 20, 2018

hi,
when you use webroot technic for renewale certificats/keys, does it really need to reload nginx http server ?
I read many tutorial, it is the one who create script for reload server http.
Is it necessary to do it ?

jerome-diver commented Feb 20, 2018

hi,
when you use webroot technic for renewale certificats/keys, does it really need to reload nginx http server ?
I read many tutorial, it is the one who create script for reload server http.
Is it necessary to do it ?

@jerome-diver

This comment has been minimized.

Show comment
Hide comment
@jerome-diver

jerome-diver Feb 20, 2018

@vwal, you can create a separate config file for nginx and include it in server scope.
this new letsencrypt.conf file (in root config directory of nginx) should be:
location ^~ /.wel-known/acme-challenge {
root /var/www/nginx/_undefined/htdocs;
default_type "text/plain";
}
and nevermind where is the root of the http server on port 80... this would assume a redirection specifically for your letsencrypt certbot robot authentication calls.
I do it and it works for me.

jerome-diver commented Feb 20, 2018

@vwal, you can create a separate config file for nginx and include it in server scope.
this new letsencrypt.conf file (in root config directory of nginx) should be:
location ^~ /.wel-known/acme-challenge {
root /var/www/nginx/_undefined/htdocs;
default_type "text/plain";
}
and nevermind where is the root of the http server on port 80... this would assume a redirection specifically for your letsencrypt certbot robot authentication calls.
I do it and it works for me.

@sebthemonster

This comment has been minimized.

Show comment
Hide comment
@sebthemonster

sebthemonster Feb 23, 2018

Thanks a lot. Your guide is awesome.

The option --no-eff-email is unrecognized in last version of certbot (0.10.2).

sebthemonster commented Feb 23, 2018

Thanks a lot. Your guide is awesome.

The option --no-eff-email is unrecognized in last version of certbot (0.10.2).

@Vanthiyadevan

This comment has been minimized.

Show comment
Hide comment
@Vanthiyadevan

Vanthiyadevan Mar 4, 2018

Nice Efforts man. Seeing a good A+ SSL Certificates made my day. Thanks a ton.

Vanthiyadevan commented Mar 4, 2018

Nice Efforts man. Seeing a good A+ SSL Certificates made my day. Thanks a ton.

@OsoianMarcel

This comment has been minimized.

Show comment
Hide comment
@OsoianMarcel

OsoianMarcel Mar 12, 2018

Very good tutorial. Thank you.

OsoianMarcel commented Mar 12, 2018

Very good tutorial. Thank you.

@someburner

This comment has been minimized.

Show comment
Hide comment
@someburner

someburner Mar 22, 2018

Found this guide nice and useful / to the point. But I remembered hearing about LE's new support for wildcard subdomains and gave that a shot. If anyone's interested in that check out my fork. And it worked even having just done this guide using non-wildcard. Certbot automatically linked to the new cert.

someburner commented Mar 22, 2018

Found this guide nice and useful / to the point. But I remembered hearing about LE's new support for wildcard subdomains and gave that a shot. If anyone's interested in that check out my fork. And it worked even having just done this guide using non-wildcard. Certbot automatically linked to the new cert.

@rob-gonz

This comment has been minimized.

Show comment
Hide comment
@rob-gonz

rob-gonz Mar 31, 2018

Really appreciate. Thank you for taking the time to share this.

rob-gonz commented Mar 31, 2018

Really appreciate. Thank you for taking the time to share this.

@slavensaka

This comment has been minimized.

Show comment
Hide comment
@slavensaka

slavensaka Apr 3, 2018

Works splendid! Thank you! Helped me secure multiple nginx servers.

slavensaka commented Apr 3, 2018

Works splendid! Thank you! Helped me secure multiple nginx servers.

@roppa

This comment has been minimized.

Show comment
Hide comment
@roppa

roppa Apr 3, 2018

This is awesome, thank you so much!

roppa commented Apr 3, 2018

This is awesome, thank you so much!

@namaggarwal

This comment has been minimized.

Show comment
Hide comment
@namaggarwal

namaggarwal Apr 22, 2018

Thank you so much for this. It worked like charm

namaggarwal commented Apr 22, 2018

Thank you so much for this. It worked like charm

@kv9991

This comment has been minimized.

Show comment
Hide comment
@kv9991

kv9991 Apr 25, 2018

best certbot tutorial. thanks

kv9991 commented Apr 25, 2018

best certbot tutorial. thanks

@OsoianMarcel

This comment has been minimized.

Show comment
Hide comment
@OsoianMarcel

OsoianMarcel May 10, 2018

Thank you very much, I'm using this tutorial each time I need letsencrypt.
P.S. Works fine for apache2 too.

OsoianMarcel commented May 10, 2018

Thank you very much, I'm using this tutorial each time I need letsencrypt.
P.S. Works fine for apache2 too.

@junjielee

This comment has been minimized.

Show comment
Hide comment
@junjielee

junjielee May 21, 2018

Thank, it's very useful

junjielee commented May 21, 2018

Thank, it's very useful

@oleksiif

This comment has been minimized.

Show comment
Hide comment
@oleksiif

oleksiif May 22, 2018

awesome thank you!

oleksiif commented May 22, 2018

awesome thank you!

@LarryWachira

This comment has been minimized.

Show comment
Hide comment
@LarryWachira

LarryWachira May 30, 2018

Thanks a million! Very well explained.

LarryWachira commented May 30, 2018

Thanks a million! Very well explained.

@umarali

This comment has been minimized.

Show comment
Hide comment
@umarali

umarali May 30, 2018

Life saver! Thanks very much!

umarali commented May 30, 2018

Life saver! Thanks very much!

@maikdiepenbroek

This comment has been minimized.

Show comment
Hide comment
@maikdiepenbroek

maikdiepenbroek Jun 27, 2018

Easy to follow and effective guide, thanks ๐Ÿ‘

maikdiepenbroek commented Jun 27, 2018

Easy to follow and effective guide, thanks ๐Ÿ‘

@bennetcq

This comment has been minimized.

Show comment
Hide comment
@bennetcq

bennetcq Jun 29, 2018

Nearly perfect for me! Thanks!
-----when edit /etc/letsencrypt/options-ssl-nginx.conf----
must delete or comment as followed----
#add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; script-src 'self'; img-src 'self'; style-src 'self'; base-ur$
#add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
#add_header X-Frame-Options SAMEORIGIN;
#add_header X-Content-Type-Options nosniff;
#add_header X-XSS-Protection "1; mode=block";

if uncomment above code, only result in SSL A, not A+

bennetcq commented Jun 29, 2018

Nearly perfect for me! Thanks!
-----when edit /etc/letsencrypt/options-ssl-nginx.conf----
must delete or comment as followed----
#add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; script-src 'self'; img-src 'self'; style-src 'self'; base-ur$
#add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
#add_header X-Frame-Options SAMEORIGIN;
#add_header X-Content-Type-Options nosniff;
#add_header X-XSS-Protection "1; mode=block";

if uncomment above code, only result in SSL A, not A+

@cecilemuller

This comment has been minimized.

Show comment
Hide comment
@cecilemuller

cecilemuller Jun 29, 2018

@bennetcq Please use a markdown block for the comment (either start every line with a tab, either wrap the group of lines with 4 ticks) because the question is quite hard to read with that huge text.

Are you asking why you're getting only A rating when the add_header lines start with # ? If so, that's because the settings are being ignored by Nginx, # symbols in configs are for writing arbitrary comments.

Also the Content-Security-Policy line in your code looks incomplete, see the one form the tutorial:

add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload;";
add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; script-src 'self'; img-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self';";
add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
Owner

cecilemuller commented Jun 29, 2018

@bennetcq Please use a markdown block for the comment (either start every line with a tab, either wrap the group of lines with 4 ticks) because the question is quite hard to read with that huge text.

Are you asking why you're getting only A rating when the add_header lines start with # ? If so, that's because the settings are being ignored by Nginx, # symbols in configs are for writing arbitrary comments.

Also the Content-Security-Policy line in your code looks incomplete, see the one form the tutorial:

add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload;";
add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; script-src 'self'; img-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self';";
add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
@apex8

This comment has been minimized.

Show comment
Hide comment
@apex8

apex8 Jul 3, 2018

Hi @cecilemuller,
thanks for this guide, helped me a lot. There is one thing in /etc/letsencrypt/options-ssl-nginx.conf that doesn't seem to work for me.
I have a virtual host operating as a proxy to my fritz box configuration page.
Having

add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; script-src 'self'; img-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self';";

enabled results in an empty page when I access the fritz box sub domain.
When I comment this line everything works as intended.
Do you have any suggestion how I could fix that?

Regards

EDIT: I just noticed that even when I disable the mentioned line I get an A+ rating.

apex8 commented Jul 3, 2018

Hi @cecilemuller,
thanks for this guide, helped me a lot. There is one thing in /etc/letsencrypt/options-ssl-nginx.conf that doesn't seem to work for me.
I have a virtual host operating as a proxy to my fritz box configuration page.
Having

add_header Content-Security-Policy "default-src 'none'; frame-ancestors 'none'; script-src 'self'; img-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self';";

enabled results in an empty page when I access the fritz box sub domain.
When I comment this line everything works as intended.
Do you have any suggestion how I could fix that?

Regards

EDIT: I just noticed that even when I disable the mentioned line I get an A+ rating.

@MagePsycho

This comment has been minimized.

Show comment
Hide comment
@MagePsycho

MagePsycho Jul 15, 2018

letsencrypt-auto --nginx vs certbot --nginx which one is the better approach to install?

MagePsycho commented Jul 15, 2018

letsencrypt-auto --nginx vs certbot --nginx which one is the better approach to install?

@MagePsycho

This comment has been minimized.

Show comment
Hide comment
@MagePsycho

MagePsycho Jul 15, 2018

There is nothing to do, Certbot installed a cron task to automatically renew certificates about to expire.
But when I checked with

sudo crontab -e

There was nothing.

Can you please confirm with the auto-renewal process.

MagePsycho commented Jul 15, 2018

There is nothing to do, Certbot installed a cron task to automatically renew certificates about to expire.
But when I checked with

sudo crontab -e

There was nothing.

Can you please confirm with the auto-renewal process.

@JamesSwift

This comment has been minimized.

Show comment
Hide comment
@JamesSwift

JamesSwift Sep 13, 2018

A very handy reference. I made a simple script to set-up my web server, and manage adding and removing domains with this technique. You might find it useful: https://github.com/JamesSwift/SharedServerTools

JamesSwift commented Sep 13, 2018

A very handy reference. I made a simple script to set-up my web server, and manage adding and removing domains with this technique. You might find it useful: https://github.com/JamesSwift/SharedServerTools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment