{"id":18,"date":"2017-02-21T14:52:00","date_gmt":"2017-02-21T14:52:00","guid":{"rendered":""},"modified":"2021-02-22T01:13:32","modified_gmt":"2021-02-22T01:13:32","slug":"lets-encrypt-free-grade-ssl-on-nginx","status":"publish","type":"post","link":"https:\/\/www.tech-and-dev.com\/blog\/2017\/02\/lets-encrypt-free-grade-ssl-on-nginx.html","title":{"rendered":"Let&#8217;s Encrypt Free A+ Grade SSL On Nginx &#038; Ubuntu 16.04"},"content":{"rendered":"<div dir=\"ltr\" style=\"text-align: left;\">\n<div dir=\"ltr\" style=\"text-align: left;\">\n<div style=\"clear: both; text-align: center;\"><a style=\"margin-left: 1em; margin-right: 1em;\" href=\"https:\/\/www.tech-and-dev.com\/blog\/wp-content\/uploads\/2021\/02\/logo-letsencrypt-nginx.png\"><img decoding=\"async\" src=\"https:\/\/www.tech-and-dev.com\/blog\/wp-content\/uploads\/2021\/02\/logo-letsencrypt-nginx.png\" border=\"0\" \/><\/a><\/div>\n<h2 style=\"text-align: left;\">Prerequisites:<\/h2>\n<p><a href=\"https:\/\/www.tech-and-dev.com\/blog\/2017\/01\/23\/installing-lemp-ubuntu-16-04-nginx-mariadb-php-7\/\" target=\"_blank\" rel=\"noopener\">LEMP on Ubuntu 16.04<\/a><\/p>\n<h2 style=\"text-align: left;\">Start by updating apt indexes<\/h2>\n<pre>sudo apt-get update<\/pre>\n<p>&nbsp;<\/p>\n<h2 style=\"text-align: left;\">Install Let&#8217;s Encrypt Package<\/h2>\n<p>(Known as certbot on Github (https:\/\/github.com\/certbot\/certbot))<\/p>\n<pre>sudo apt-get install letsencrypt<\/pre>\n<p><a name=\"more\"><\/a>I&#8217;ll assume the domain name we are working on is called <b>mysite.com<\/b> and you have installed and configured Nginx from the tutorial mentioned above.<\/p>\n<p>Open Nginx Configuration file<\/p>\n<pre>sudo vi \/etc\/nginx\/sites-available\/mysite.com<\/pre>\n<p>&nbsp;<\/p>\n<h2 style=\"text-align: left;\">Make .well-known directory accessible<\/h2>\n<p>We do this because Let&#8217;s Encrypt will use .well-known directory to validate the SSL.<br \/>\nAdd it before denying hidden files (Entire configuration file is below)<\/p>\n<pre>\u00a0\u00a0\u00a0 location ~ \/.well-known {<\/pre>\n<p>allow all;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<h2 style=\"text-align: left;\">Test Nginx Syntax<\/h2>\n<pre>sudo nginx -t<\/pre>\n<p>&nbsp;<\/p>\n<h2 style=\"text-align: left;\">Reload Nginx<\/h2>\n<pre>sudo systemctl reload nginx<\/pre>\n<p>&nbsp;<\/p>\n<h2 style=\"text-align: left;\">Generate the Certificate<\/h2>\n<pre>sudo letsencrypt certonly -a webroot --webroot-path=\/var\/www\/mysite.com\/html -d mysite.com -d www.mysite.com<\/pre>\n<p>The results will be similar to the following:<\/p>\n<blockquote><p>IMPORTANT NOTES:<br \/>\n&#8211; Congratulations! Your certificate and chain have been saved at<br \/>\n\/etc\/letsencrypt\/live\/mysite.com\/fullchain.pem. Your<br \/>\ncert will expire on 2017-05-17. To obtain a new version of the<br \/>\ncertificate in the future, simply run Let&#8217;s Encrypt again.<br \/>\n&#8211; If you like Let&#8217;s Encrypt, please consider supporting our work by:<\/p>\n<p>Donating to ISRG \/ Let&#8217;s Encrypt:\u00a0\u00a0 https:\/\/letsencrypt.org\/donate<br \/>\nDonating to EFF:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 https:\/\/eff.org\/donate-le<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<h2 style=\"text-align: left;\">Generate a 2048 or 4096 bits Diffie Hellman Symmetric Key<\/h2>\n<p>I&#8217;ll generate the Diffie Hellman in Nginx installation to keep things organized, you can create it anywhere you want (If you create it somewhere else, make sure to edit the configuration file below to reflect your changes)<\/p>\n<pre>sudo mkdir \/etc\/nginx\/ssl\r\nsudo openssl dhparam -out \/etc\/nginx\/ssl\/dhparam.pem 4096<\/pre>\n<p>This might take a while (4096 bits might take around 30 minutes on a modern CPU), but once it&#8217;s done, you will have a 4096 bits symmetric key<\/p>\n<h2 style=\"text-align: left;\">Configuring Nginx to Read the Generated Certificates<\/h2>\n<p>By default Let&#8217;s Encrypt will store all the certificates (expired and running) in<br \/>\n<b><span style=\"color: purple;\">\/etc\/letsencrypt\/archive\/mysite.com<\/span><\/b><br \/>\nHowever, to avoid changing the nginx configuration file everytime, letsencrypt plugin will create a symlink to the latest generated certificate in<br \/>\n<span style=\"color: purple;\"><b>\/etc\/letsencrypt\/live\/mysite.com<\/b><\/span><\/p>\n<p>Let&#8217;s open Nginx configuration file:<\/p>\n<pre>sudo vi \/etc\/nginx\/sites-available\/mysite.com<\/pre>\n<p>And add\/modify the new SSL location<\/p>\n<pre>listen 443 ssl http2 default_server;\r\nssl_certificate \/etc\/letsencrypt\/live\/mysite.com\/fullchain.pem;\r\nssl_certificate_key \/etc\/letsencrypt\/live\/mysite.com\/privkey.pem;<\/pre>\n<p>Improve SSL Security to get Grade A+ on SslLabs<br \/>\nPaste the following below the certificates<\/p>\n<pre>#From cipherli.st\r\nssl_protocols TLSv1 TLSv1.1 TLSv1.2;\r\nssl_prefer_server_ciphers on;\r\nssl_ciphers \"EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH\";\r\nssl_ecdh_curve secp384r1; # Requires nginx &gt;= 1.1.0\r\nssl_session_cache shared:SSL:10m;\r\nssl_session_tickets off; # Requires nginx &gt;= 1.5.9\r\nssl_stapling on; # Requires nginx &gt;= 1.3.7\r\nssl_stapling_verify on; # Requires nginx =&gt; 1.3.7\r\nresolver $DNS-IP-1 $DNS-IP-2 valid=300s;\r\nresolver_timeout 5s;\r\n##If you're not aware of how preload works, keep it disabled for now\r\n##More info on preload can be found in\r\n##blog.mozilla.org\/security\/2012\/11\/01\/preloading-hsts\r\n##&amp;\r\n##hstspreload.org\r\n#add_header Strict-Transport-Security \"max-age=63072000; includeSubDomains; preload\";\r\nadd_header Strict-Transport-Security \"max-age=63072000; includeSubDomains;\";\r\nadd_header X-Frame-Options DENY;\r\nadd_header X-Content-Type-Options nosniff;\r\n#Add Diffie Hellman that we have previously generated \r\nssl_dhparam \/etc\/nginx\/ssl\/dhparam.pem;<\/pre>\n<p>Make sure to replace <b><span style=\"color: purple;\">$DNS-IP-1<\/span> <span style=\"color: #38761d;\">$DNS-IP-2<\/span><\/b> with your DNS IPs, if you don&#8217;t know or don&#8217;t have any, you can replace them by Google&#8217;s DNS <b><span style=\"color: purple;\">8.8.8.8<\/span> <\/b>&amp;<b> <span style=\"color: #38761d;\">8.8.4.4<\/span><\/b><span style=\"color: #38761d;\">\u00a0<\/span><\/p>\n<p>The entire configuration file will look like:<\/p>\n<pre>server {\r\n\u00a0\u00a0\u00a0 # Redirect to www\r\n\u00a0\u00a0\u00a0 server_name mysite.com;\r\n\u00a0\u00a0\u00a0 rewrite ^\/(.*)$ http:\/\/www.mysite.com\/$1 permanent;\r\n}<\/pre>\n<p>server {<br \/>\n# Domain name<br \/>\nserver_name www.mysite.com;<\/p>\n<p># Location of files<br \/>\nroot \/var\/www\/mysite.com\/html;<br \/>\n# Location of access &amp; error Logs<br \/>\naccess_log \/var\/log\/nginx\/www.mysite.com.access.log;<br \/>\nerror_log \/var\/log\/nginx\/www.mysite.com.error.log;<\/p>\n<p># Listen to Port 80 (http)<br \/>\nlisten 80 default_server;<\/p>\n<p>#Listen on SSL<br \/>\nlisten 443 ssl http2 default_server;<\/p>\n<p># ssl on;<br \/>\nssl_certificate \/etc\/letsencrypt\/live\/mysite.com\/fullchain.pem;<br \/>\nssl_certificate_key \/etc\/letsencrypt\/live\/mysite.com\/privkey.pem;<\/p>\n<p>#From cipherli.st<br \/>\nssl_protocols TLSv1 TLSv1.1 TLSv1.2;<br \/>\nssl_prefer_server_ciphers on;<br \/>\nssl_ciphers &#8220;EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH&#8221;;<br \/>\nssl_ecdh_curve secp384r1; # Requires nginx &gt;= 1.1.0<br \/>\nssl_session_cache shared:SSL:10m;<br \/>\nssl_session_tickets off; # Requires nginx &gt;= 1.5.9<br \/>\nssl_stapling on; # Requires nginx &gt;= 1.3.7<br \/>\nssl_stapling_verify on; # Requires nginx =&gt; 1.3.7<br \/>\nresolver 8.8.8.8 8.8.4.4 valid=300s;<br \/>\nresolver_timeout 5s;<br \/>\n##If you&#8217;re not aware of how preload works, keep it disabled for now<br \/>\n##More info on preload can be found in<br \/>\n##blog.mozilla.org\/security\/2012\/11\/01\/preloading-hsts<br \/>\n##&amp;<br \/>\n##hstspreload.org\/<br \/>\n#add_header Strict-Transport-Security &#8220;max-age=63072000; includeSubDomains; preload&#8221;;<br \/>\nadd_header Strict-Transport-Security &#8220;max-age=63072000; includeSubDomains;&#8221;;<br \/>\nadd_header X-Frame-Options DENY;<br \/>\nadd_header X-Content-Type-Options nosniff;<br \/>\n#Add Diffie Hellman that we have previously generated<br \/>\nssl_dhparam \/etc\/nginx\/ssl\/dhparam.pem;<\/p>\n<p># Default file to serve. If the first file isn&#8217;t found,<br \/>\nindex index.php index.html index.htm;<\/p>\n<p># Don&#8217;t log favicons<br \/>\nlocation = \/favicon.ico {<br \/>\nlog_not_found off;<br \/>\naccess_log off;<br \/>\n}<\/p>\n<p># Configuring robots.txt<br \/>\nlocation = \/robots.txt {<br \/>\nallow all;<br \/>\nlog_not_found off;<br \/>\naccess_log off;<br \/>\n}<\/p>\n<p># Configure 404 Pages<br \/>\nerror_page 404 \/404.html;<\/p>\n<p># Error 50x Pages<br \/>\nerror_page 500 502 503 504 \/50x.html;<br \/>\nlocation = \/50x.html {<br \/>\nroot \/usr\/share\/nginx\/www;<br \/>\n}<\/p>\n<p>location ~ \/.well-known {<br \/>\nallow all;<br \/>\n}<\/p>\n<p># Denying all attempts to access hidden files .abcde<br \/>\nlocation ~ \/. {<br \/>\ndeny all;<br \/>\n}<\/p>\n<p># Expiry date headers for static files and turn off logging.<br \/>\nlocation ~* ^.+.(js|css|swf|xml|txt|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {<br \/>\naccess_log off; log_not_found off; expires 30d;<br \/>\n}<\/p>\n<p># Rewrite rules, sends everything through index.php<br \/>\nlocation \/ {<br \/>\ntry_files $uri $uri\/ \/index.php?q=$uri&amp;$args;<br \/>\n}<\/p>\n<p># Deny access to PHP Files in the uploads directory<br \/>\nlocation ~* \/(?:uploads|files)\/.*.php$ {<br \/>\ndeny all;<br \/>\n}<\/p>\n<p># Enable PHP Support<br \/>\nlocation ~ .php$ {<br \/>\ninclude snippets\/fastcgi-php.conf;<br \/>\nfastcgi_pass unix:\/run\/php\/php7.0-fpm.sock;<br \/>\n}<\/p>\n<p># Enable Rewrite Rules for Yoast SEO SiteMap<br \/>\nrewrite ^\/sitemap_index.xml$ \/index.php?sitemap=1 last;<br \/>\nrewrite ^\/([^\/]+?)-sitemap([0-9]+)?.xml$ \/index.php?sitemap=$1&amp;sitemap_n=$2 last;<\/p>\n<p># Add trailing slash to *\/wp-admin requests.<br \/>\nrewrite \/wp-admin$ $scheme:\/\/$host$uri\/ permanent;<br \/>\n}<\/p>\n<p>Test Nginx Syntax<\/p>\n<\/div>\n<pre>sudo nginx -t<\/pre>\n<p>Reload Nginx<\/p>\n<pre>sudo systemctl reload nginx<\/pre>\n<p>&nbsp;<\/p>\n<h2 style=\"text-align: left;\">Renew Certificates Automatically<\/h2>\n<p>In order to renew the certificates automatically, we will setup a cron job. By default, Let&#8217;s Encrypt only renew a certificate 1 month before it expires (after 2 months out of 3), otherwise it will skip renewal. Therefore, we can run the cron job once every week (or less if you wish), and Let&#8217;s Encrypt will automatically skip or renew all the certificates.<\/p>\n<p>Open crontab as Root<\/p>\n<pre>sudo crontab -e<\/pre>\n<p>Append the following 2 lines at the end of the file<\/p>\n<pre>0 0 * * 0 letsencrypt renew\u00a0 &gt;&gt; \/var\/log\/letsEncryptAutoRenew.log\r\n0 0 * * 0 systemctl reload nginx<\/pre>\n<p>Configure the Ubuntu Firewall To Allow HTTPS<\/p>\n<pre>sudo ufw allow 'Nginx HTTPS'<\/pre>\n<p>or<\/p>\n<pre>sudo ufw allow 'Nginx Full'\r\nsudo ufw delete allow 'Nginx HTTP'<\/pre>\n<p>&nbsp;<\/p>\n<h2 style=\"text-align: left;\">Test your site SSL on SSL Labs<\/h2>\n<p><a href=\"https:\/\/www.ssllabs.com\/ssltest\/analyze.html?d=mysite.com\" target=\"_blank\" rel=\"noopener\">https:\/\/www.ssllabs.com\/ssltest\/analyze.html?d=mysite.com<\/a><\/p>\n<p>Questions or comments? Leave them below!<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Prerequisites: LEMP on Ubuntu 16.04 Start by updating apt indexes sudo apt-get update &nbsp; Install Let&#8217;s Encrypt Package (Known as certbot on Github (https:\/\/github.com\/certbot\/certbot)) sudo apt-get install letsencrypt I&#8217;ll assume the domain name we are working on is called mysite.com and you have installed and configured Nginx from the tutorial mentioned above. Open Nginx Configuration [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[6,27,28,4],"tags":[],"class_list":["post-18","post","type-post","status-publish","format-standard","hentry","category-linux","category-nginx","category-security","category-ubuntu"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/posts\/18","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/comments?post=18"}],"version-history":[{"count":3,"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/posts\/18\/revisions"}],"predecessor-version":[{"id":382,"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/posts\/18\/revisions\/382"}],"wp:attachment":[{"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/media?parent=18"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/categories?post=18"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tech-and-dev.com\/blog\/wp-json\/wp\/v2\/tags?post=18"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}