CS 347: Forcing HTTPS
When your browser sends an HTTP request from your local computer to a remote server and the server sends back a response, malicious users on the network could capture or sniff the messages. The headers and bodies of HTTP messages are readable. This is bad. Your messages might contain trade secrets, personal information that could lead to identity theft, or the details of a coup that you are plotting to overthrow a corrupt government.
These days, HTTP messages should always be encrypted using the secure HTTP (or HTTPS) protocol. Even the federal government of the United States of America recommends exclusive use of HTTPS.
When you visit a website served over HTTPS, the browser first communicates with the server to fetch its certificate. A certificate provides two important pieces of information. First, it states that the server is recognized as a legitimate representative of the domain. Second, it provides a public key. The browser sends back a message encrypted by this public key to the server. Only the server can decrypt it, using its private key. Through this initial encrypted message, the server and client agree on another temporary encryption key known only to themselves. Both parties use this key to encrypt messages before sending them and decrypt messages after they’ve been received. Malicious sniffers will be unable to read any of the messages they intercept in the middle of the network.
You are administering a server this semester, and you therefore have the responsibility of encrypting your responses and forcing clients to encrypt their requests. Follow these steps to get your sites served over HTTPS:
- Install Certbot on your droplet with this command: Certbot is a utility from Let’s Encrypt, an organization that grants free certificates.
sudo apt install certbot
- Before Let’s Encrypt will grant you a certificate, it will require you to prove that you have control over the domain whose certificate you are requesting. There are various ways to offer this proof, one of which is to add DNS records. Visit Namecheap in your browser, manage your domain, open the Advanced DNS tab, and find the Add New Record button. Leave the page open.
- Back in your terminal, request a certificate that will apply to your domain and all subdomains with this command: You will be asked to add a TXT record with a prompt like this:
sudo certbot certonly \ --manual \ --preferred-challenges=dns \ -d YOUR-DOMAIN-NAME \ -d *.YOUR-DOMAIN-NAME
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Please deploy a DNS TXT record under the name _acme-challenge.YOUR-DOMAIN-NAME with the following value: MOPRS-xQq_yES6SZOsy6wM45wFrBOfslOdRxng5eDp8 Before continuing, verify the record is deployed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Back in Namecheap, add a new TXT record. Enter_acme-challenge
for the host, and the nonsense string for the value. Use your nonsense string, not the one above. Save the record and pause for half a minute before continuing back in the terminal. You may be asked to add additional TXT records. Do not delete the first one as you add the second. - If the request succeeds, the certificate will be stored in
/etc/letsencrypt/live
. If the request fails, delete the TXT records on Namecheap and try running step 3 again. - Apache must be configured a bit before it can handle encryption. Enable its secure sockets layer (SSL) plugin with this command:
sudo a2enmod ssl
- Run
sudo YOUR-EDITOR /etc/letsencrypt/options-ssl-apache.conf
and add this content:This file is normally generated by Certbot, but not when adding a certificate manually. Boo.SSLEngine on # Intermediate configuration, tweak to your needs SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 SSLHonorCipherOrder off SSLOptions +StrictRequire # Add vhost name to log entries: LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
- Modify your Apache configuration. You want any HTTP traffic on port 80 to get redirected to HTTPS on port 443. Additionally, you want the virtual host listening on port 443 to load in the certificate: Replace
# Redirect all HTTP traffic to HTTPS. <VirtualHost *:80> ServerName project1.YOUR-DOMAIN-NAME Redirect / https://project1.YOUR-DOMAIN-NAME/ </VirtualHost> # Secure HTTP typically runs on port 443. <VirtualHost *:443> ServerAdmin webmaster@localhost ServerName project1.YOUR-DOMAIN-NAME DocumentRoot /home/YOUR-DROPLET-USERNAME/YOUR-PROJECT1-DIRECTORY # Allow access to all files. <Directory /home/YOUR-DROPLET-USERNAME/YOUR-PROJECT1-DIRECTORY> Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLCertificateFile /etc/letsencrypt/live/YOUR-DOMAIN-NAME/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/YOUR-DOMAIN-NAME/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf </VirtualHost>
YOUR-DROPLET-USERNAME
,YOUR-DOMAIN-NAME
, andYOUR-PROJECT1-DIRECTORY
with their actual values. - Restart Apache with this command:
sudo service apache2 restart
When you visit http://project1.YOUR-DOMAIN-NAME
, the browser should automically redirect to https://project1.YOUR-DOMAIN-NAME
.