Https certificate

In this website, we use https. If you’re using http connect, you can come to our https website: https://shuyuwu.me

We use certbot from Let’s encrypt to get the certificate. This is a free service, so we do not need to pay a few hundred dollars to some Certificate authority like DigiCert. By the way, “Let’s encrypt”, the non-profit certificate authority, is initiated by professor J. Alex Halderman from the University of Michigan. You can see the announcement at https://michigan.it.umich.edu/news/2020/12/04/after-five-years-lets-encrypt-a-non-profit-based-on-tech-developed-at-michigan-has-helped-to-secure-the-internet/ from the website of umich.

The website of certbot provides a user-friendly dashboard for us to configure based on our website setup.

So, how do we get the certificate, given that we’re running Nginx inside docker? This is different from running nginx directly on the server, because now the process that occupies port 80 is not Nginx, but docker. As a result, you can not choose “My HTTP website is running Nginx on ubuntu 20”. Instead, you need to choose “My HTTP website is running Other on ubuntu 20”.

Following the step it’s straightforward to get the certificate, but you need to install it on your website in order to finish the process. Given that you can’t move the certificate when it’s issued to you, you can not copy the certificate into docker container. You must keep the certificate locally on the server.

Our solution is as follow: we can still use Nginx locally on the server, but instead of writing complex configure file (we already done it in docker), we only do one simple thing: forward the traffic from port 80 (http port) to port 443 (https port). We write the following configuration file in Nginx locally:

nginx.conf:

# Run nginx worker processes using user www-data, which should have been created after installing Nginx.
user www-data;

# Start as many workers as there are CPU cores.
worker_processes auto;

# Configure connection processing.
events {
        # Maximum number of simultaneous connections per worker process.
        worker_connections 1000;
}

# Configure the HTTP server.
http {
        # Directly copy data between file descriptors instead of storing it in a buffer.
        sendfile on;

        # Send the response headers and the beginning of a file in a single packet.
        tcp_nopush on;

        # Map file extensions to MIME types.
        include /etc/nginx/mime.types;

        # Specify where logs should be written.
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        # Compress HTML data before sending it in responses.
        gzip on;

        # Include site-specific config files.
        include /etc/nginx/conf.d/*.conf;
}

conf.d/main.conf:

server {
    listen 443 ssl;
    server_name shuyuwu.me;

    # SSL certificate paths, already downloaded in privious step
    ssl_certificate /etc/letsencrypt/live/shuyuwu.me/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/shuyuwu.me/privkey.pem;

    # SSL configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';

    # Reverse proxy configuration
    location / {
    proxy_pass http://localhost:80;  # Replace with your Docker container's address
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_redirect off;
}

Do not listen 80, because port 80 is already occupied by docker. You just listen to port 443.

In this way, the certificate is installed after we start the Nginx service.

Finally, let’s review how the traffic is sent. There’re many steps!

  1. run python3 manage.py runserver which is done in docker (specified in the Dockerfile). The traffic is at localhost:8000 of the docker container
  2. With the Nginx service inside docker container, the traffic is forwarded to 0.0.0.0:80 of the docker container
  3. We have expose 80 in the Dockerfile. Also, we specified -p 80:80 parameter option when running the docker. The traffic is sent to 0.0.0.0:80 of the local machine, which is our server in this case. With the configuration of Nginx and https certificates, the traffic is further forwarded to 0.0.0.0:443 of the local machine
  4. In AWS EC2 instance, we set the security group so that port 80 and 443 is reachable in the “inbound rule”. In this case, you can access both http://shuyuwu.me (port 80) and https://shuyuwu.me (port 443) now. It’s also OK to not set port 80 in the inbound rule, or make a redirection. In this case, only port 443 is reachable.