Cheng Hui's Website

Use Nginx Reverse Proxy to forward request to your Docker app

Introduction

Very often, we have a lot of Dockerized applications running on different ports on our server. While some of the applications may offer automatic domain name binding and SSL generation, but most of them are not.

In this post, we are going to use Nginx Reverse Proxy function to forward request to our Docker application, and use Let's Encrypt to generate a SSL certificate for our website.

Prerequisites

Before you begin with this tutorial, please make sure you have the following:

In this example, we are going to map https://demo.lchenghui.com to 123.233.61.13:3000

(1) Point domain DNS to server IP

We need to point our domain name to the server IP by adding an A Record in our domain management site.

Take Google Domains as an example, head over to DNS settings, Custom records, Manage Custom Records. Then add a new A Record that points to the server IP. TTL can be any or leave it default.

img

img

Quick Tips: If you want to point lchenghui.com instead, then fill in @ or leave it blank.

(2) Setup Nginx Reverse Proxy

First go to the Nginx sites-available path

cd /etc/nginx/sites-available/

Create a new file to store the configuration

touch demo

Edit the file

nano demo 
# You can edit the file using any text editor that you prefer, for instance vim
# vi demo

Then paste the following text into the demo file. You will need to change the server_name and proxy_pass.

server {
  server_name demo.lchenghui.com; # Change this to your website;
    location / {
      proxy_redirect off;
      proxy_pass http://127.0.0.1:3000; # Change this port to others if you want
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr; # Show real IP of the requester in the log file (if any)
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Exit nano application by pressing CTRL + x, then press Y to save the file.

For vim users, type :wq to exit the editor.

Next we need to create a symbolic link to Nginx sites-enabled folder. Symbolic link allows us to reflect the changes that we made on the file in a different path.

For example, if you add a new line in /etc/nginx/sites-available/demo, the new changes will be reflected in /etc/nginx/sites-enabled/demo too.

To create a symbolic link

sudo ln -s /etc/nginx/sites-available/demo /etc/nginx/sites-enabled/demo

You can then view the symbolic link created using the following command

cd /etc/nginx/sites-enabled/
ls -l

Before proceeding to the next step, it is good to test the Nginx configuration file

nginx -t

img

Quick Tips: In nginx, configuration files in sites-enabled folder will directly affect the content shown in our website. So it is a good practice to modify files in sites-available folder and create a symbolic link to sites-enabled folder.

(3) Let's Encrypt HTTPS

Even without enabling HTTPS, our web application is already accessible at http://demo.lchenghui.com without adding the port.

In this part, we will be using Let's Encrypt to get a free 90 days certificate for our website. The certificate itself is renewable at zero cost.

We will use snapd to install certbot, which is a free automated tool to deploy the certificate on our website.

To update the snapd version in our system

sudo snap install core; sudo snap refresh core

Install certbot using snap

sudo snap install --classic certbot

Add certbot to path

sudo ln -s /snap/bin/certbot /usr/bin/certbot

Run certbot

sudo certbot --nginx

Follow the on-screen instructions, such as filling your email (for renewal notification), acceptance of T&C, and whether or not to forward the HTTP request to HTTPS.

Depending on whether you have selected to redirect the HTTP request to HTTPS request, you can manually add the option if you chose No.

cd /etc/nginx/sites-available/
nano demo

And paste the following sniplets at the end of the file

server {
  listen 80;

  server_name demo.lchenghui.com;
  return 301 https://demo.lchenghui.com$request_uri;

}

Lastly, restart the Nginx web server

sudo systemctl restart nginx

By now, our website is reachable via HTTPS :lock:.

Bonus (Apache Virtual Host / Caddy)

Apache Web server

The similar way can be done by using Apache2 web server or Caddy.

For Apache2, we need to enable the required modules before we can use the reverse proxy feature.

sudo a2enmod

Then type in the following modules when the program asks for which module(s) to be activated

proxy proxy_ajp proxy_http rewrite deflate headers proxy_balancer proxy_connect proxy_html

Then we need to create a new configuration file under /etc/apache2/sites-available/ with the following content

<VirtualHost *:80>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.
        ServerName demo.lchenghui.com
        ServerAlias demo.lchenghui.com
        ProxyPreserveHost On
        ServerAdmin webmaster@localhost
        # DocumentRoot /var/www/html

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn
        Protocols h2 http/1.1
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        ProxyPass / http://0.0.0.0:3000/
        ProxyPassReverse / http://0.0.0.0:3000/

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
</VirtualHost>

Then enable HTTPS using certbot

sudo certbot --apache

Don't forget to restart the web server.

sudo systemctl restart apache2

Caddy

Caddy is an awesome program that let you focus on things that are more important (i.e., building your website / application). Caddy will take care of HTTPS and request forwarding with just a few lines of commands.

More information on Caddy