We use cookies to enhance your experience. Dismiss this message or find out more.

HTTP to HTTPS With LetsEncrypt (Using Django, Nginx, & Gunicorn) March 14, 2017

Author: Akeem Spencer

Facebook https://spencertechconsulting.com/posts/HTTP-TO-HTTPS/ Twitter Linkedin Reddit

Read Time:

9 minutes

So you have a website you've just created from scratch, but need to have a secure connection. Furthermore, this website needs a mandatory CA lock to exchange ideas, messages, and currency transactions from customers or other businesses. This post will go through encrypting your site with an api called letsencrypt that was released to the public December of 2015. This post covers the process of configuring your Django & Nginx server while transitioning from a root HTTP to HTTPS header on the root of your domain. Having a secure website not only embellishes great security practices, but it creates the ability to share your content through other mediums. For instance, this posts' url can be publicly shared and forked thru twitter.com through its card-reader. The card reader bot authenticates the url to determine if your site is eligible for sharing through the document's meta tags: ![card_being_read][1] ###### usage of twitter's card reader: [twitter's card reader][2] Or you'd like to secure PayPal business transactions. To reaffirm transactions go smooth follow this tutorial to have your site secured if you are running a Ubuntu 16.04 environment or Linux-Debian platform. The following assumptions are taken into consideration: - Your domain host is valid and registered through a hosting provider like Go Daddy, NameCheap, HostGator or another trusted ISP grantor. - On my VPS, I'm using Nginx as a reverse proxy and Gunicorn as worker-server for the front-end followed by Django as my Database-to-HTML rendering machine. This tutorial will go through getting your certs configured on Nginx instead of Apache2 which is slightly unconventional. You can follow [Khophi's][3] excellent blog walkthrough to have you up to speed with a web-server of course if you're comfortable with PostgreSQL and Python. - At least 35 MBs or higher of memory for installing the letsencrypt package. Also, make sure the "a" records are pointing to the IP address or the IPV6 host address. Otherwise, let's begin: # Step 1 Install letsencrypt: ---------- For the ubuntu, we first must update all the packages so we have no versions incompatible with the incoming package. The SSL repository `letsencrypt` can be acquired through the package manager, inputting the following command: (venv)/home/user$ sudo apt-get update (venv)/home/user$ sudo apt-get install letsencrypt If you feel like taking ownership for installing the package manually you can download the source file from [here][4] and setup the package file with the following command (venv)/home/akeem$ python setup.py install --user Make sure the user has `sudo` admin privileges before getting into trouble. # Step 2: Obtain a SSL certificate: ---------- I have my remote VPS on digitalocean and their [tutorial][5] recommends using the webroot plugin to safely store the keys. `letsencrypt ` has a standalone feature where we can input the user's credentials to apply for the certification. Input the following command to continue on creating SSL CA file: (venv)/home/akeem$ sudo letsencrypt certonly -a standalone Your screen should automatically prompt you to a screen where you can file your email address and the root's domain address like below: ![CERTIFICATION][6] ![domain names][7] But please make sure you're using the same hostname as the one linked to the record and configured under the server's location root path. The process can be further automated by using the `letsencrypt-auto command`, read the manual for it for better understanding on which flags to use for certification. Once the authentication is completed, there should be a successful STDOUT to the terminal like this: IMPORTANT NOTES: If you lose your account credentials, you can recover through e-mails sent to sammy@digitalocean.com *Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/yoursite.com/fullchain.pem. Your cert will expire on 2016-03-15. To obtain a new version of the certificate in the future, simply run Let's Encrypt again. *Your account credentials have been saved in your Let's Encrypt configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Let's *Encrypt so making regular backups of this folder is ideal. *If like Let's Encrypt, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le If everything went well according to the plan, within the /etc/letsencrypt/live/`your_domain_name`, you should have all the certs within this directory: - fullchain.pem - privkey.pem - chain.pem - cert.pem Now it's time to configure the Nginx's site server. # Step 3: Configure the Nginx server ---------- Now that server is properly configured, we can transfer the HTTP get requests to the proper port which is 443. Make sure the port isn't used by any other applications by using the following command: (venv) /home/user$ fuser -v -n tcp 443 Hopefully, the stdout should result in a null printout. We have to add listening parameters to the 443 port and use a 301 return in one server for users who still have the root domain transcribed under a 'https:' root: My conf. file looks like the following: server { client_max_body_size 4M; listen 80 default_server; listen [::]:80 default_server; server_name yourwebsite.com www.yourwebsite.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2 default_server; listen[::]:443 ssl http2 default_server; ssl_certificate /etc/letsencrypt/live/yoursite/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/yoursite/privkey.pem; ssl_session_cache shared:SSL:50m; ssl_stapling_on; ssl_stapling_verify on; ssl_session_timeout 1d; ssl_ciphers: 'you-can-get-your-cipher-at-[mozilla ssl configuration][8]'; ssl_protocols TLSv1.2; ssl_prefer_server_ciphers on; add_header Strict-Transport-Security max-age=15768000; -----------REST-OF-CONFIGURE UNDERNEATH-------- There were some parameters like the `ssl-ciphers` I couldn't hand out because it's unique to me go to [mozilla's page][9] and you can generate ssl params to get a better gist of what to include in your website configuration and if you're operating on a server other than Nginx. # Step 4 (Recommended): Firewall Permissions. ---------- We have to open permission for users to access the 443 port. enable the ufw and add `Nginx Full` & `OpenSSL` to the walls by the following command: (venv)/home/user$ sudo ufw allow 'Nginx Full' (venv)/home/user$ sudo ufw (venv)/home/user$ sudo ufw delete allow 'Nginx HTTP If there are no errors, let's check if our configuration file is good to go by running the following command: (venv) /home/user$ sudo Nginx -t You should receive an output like this: Nginx: the configuration file /etc/Nginx/Nginx.conf syntax is ok Nginx: configuration file /etc/Nginx/Nginx.conf test is successful Restart the forward proxy and the nginx proxy system: (venv) /home/user$ sudo systemctl restart nginx (venv) /home/user$ sudo systemctl restart gunicorn If there are no errors check your website and you should see this rendered (if you're using Google Chrome): ![secure_lock][10] If you don't just write in the comments below and I'll try my best to give you the proper documentation. But we're not done, if you go onto https://www.ssllabs.com/ssltest/analyze.html?d=`your_website.com`, you're website maybe under a B+ rating. We have to configure extra parameters, specifically speaking the dhparam interpreted as the Diffe-Hellman parameter. Why you need to express this within your conf file lord knows, but just do it to get a stronger rating. CD into your /etc/ssl/certs directory and create the key using the following command: (venv)/home/user$ sudo openssl dhparam -out dhparam.pem 4096 This takes about 5-8 minutes so grab some coffee or something. After the key finished compiling add the additional encryption key within the `nginx.conf` file under the ssl_params: > You may also want to generate a snippet file for all these ssl params and `include` it within the server block so the file isn't so cluttered for good measures ... `ssl_dhparam /etc/ssl/certs/dhparam.pem;` ... Once you have the path properly located, check the browser for your rating by entering the url https://www.ssllabs.com/ssltest/analyze.html?`d=yoursite.com`. You should see an A+ grade certification. If you didn't get an A+ rating you may have compressed the dhparam key with a 2048 bit hash, try upgrading it with a 4096 hash from the previous step. # Step 6 (Optional) Renew the website: ---------- For brevity of this article, I've refrained from adding the step to renew the website using the cronjob. The SSL key will expire in 90 days so it's extremely advisable to renew your keys within 60 days. I set a notice within my calendar to update me with renewing my cert. file, but if you're neglectful and would like to automate the process follow Jeff Bradley's site on automating the [letscrypt reissuance][11]. Bear in mind his certs are generated using the webroot plugin whereas this tutorial used the standalone option so proceed depending on how your environment is structured. # What's Next: ---------- And now you're secured! Keep in mind, if you're uploading media files with the header from an unknown source or using scripts that are unsanitized, you'll receive a notice indicating the URI is not secure. Make sure if you have users uploading links or files from another unverified host, they upload HTTPS header documents only. Thank you for reading my post! Akeem Spencer [1]: https://spencertechconsulting.com/media/card_validated.JPG [2]: http://s-dev.twitter.com/validator [3]: https://blog.khophi.co/postgresql-django-nginx-gunicorn-virtualenvwrapper-16-04-lts-ubuntu-server/ [4]: http://http.debian.net/debian/pool/main/p/python-certbot/python-certbot_0.11.1.orig.tar.gz [5]: https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04/#how-to-use-the-webroot-plugin [6]: https://spencertechconsulting.com/media/cert_email.JPG [7]: https://spencertechconsulting.com/media/domain_names.JPG [8]: https://mozilla.github.io/server-side-tls/ssl-config-generator/ [9]: https://mozilla.github.io/server-side-tls/ssl-config-generator/ [10]: https://spencertechconsulting.com/media/secure_lock.JPG [11]: https://jeffbradberry.com/posts/2016/01/getting-started-with-lets-encrypt/

About The Author



Akeem Spencer is the owner, manager, and architect behind Spencer Tech Consulting. You can catch him at @UUID_Akeem or find him on LinkedIn @ Akeem Spencer. My hobbies include running, active boxing training intervals such as Shaun T Insanity Workouts, and giving it the best I've got in 2018 onwards, with projects both virtual and physical.