Reverse proxy with NGINX and letsencrypt tutorial

If you want to expose a web application, a backend interface, or just secure your website you should always use a reverse proxy. A reverse proxy will listen for client web requests and forwards them directly to your app or website. In this tutorial, I will explain how you can easily set up a reverse proxy with NGINX. And I will show you how you can easily secure any app or website with trusted HTTPS certificates from letsencrypt.


Install NGINX reverse proxy on Linux

First, we will install NGINX on Linux. I’m using Ubuntu 20.04 LTS in this example, but you can find installation instructions for other distributions in the official documentation. On Ubuntu, you simply need to update your package sources and install the package “nginx”.

sudo apt update
sudo apt install nginx

After you have installed NGINX, you can find the configuration files in the /etc/nginx folder.


Expose a sample web app in NGINX reverse proxy

I’ve prepared a sample web application, which will just print “Hello World”. It’s an unsecured web application that will run on port 5000 and is only listening for internal connections. This is a perfect example when you want to secure any web application with trusted HTTPS certificates to securely expose it to the public internet.

Note, you should never allow direct access to your app, otherwise, users could possibly just bypass the reverse proxy. I’ve changed the listening address from 0.0.0.0 to 127.0.0.1, that our app is only accepting connections from localhost.  Or you can simply add a firewall rule, that prevents access from outside to your web application. This is important because we want to force all users to use the reverse proxy instead of accessing our web application directly!

To enable the reverse proxy feature in NGINX, we will create a new “default” configuration file in the /etc/nginx/sites-enabled directory.

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name research.the-digital-life.com;

        location / {
                proxy_pass http://127.0.0.1:5000;
        }
}

The proxy_pass argument will forward all incoming client requests to this server to our app. You can easily change the protocol, IP, or port to whatever your app or website is listening to.

If you want to specify further arguments, you can do this within the server {} section or directly in the location / {} section. For example, I will add the proxy_set_header directive to pass the Host-Header which may be required by some apps or websites exposed by the proxy.

        location / {
                proxy_pass http://127.0.0.1:5000;
		proxy_set_header Host $host
        }

Expose the app in NGINX reverse proxy with trusted HTTPS certificates from letsencrypt

Now, let’s obtain trusted HTTPS certificates for our application. It’s also best practice to redirect all unencrypted HTTP connections to HTTPS. This is relatively easy with certbot and letsencrypt certificates. The certbot will obtain free certificates and also handle the renewal process automatically. To do that we will install certbot and also a plugin for our NGINX server.

sudo apt install certbot python3-certbot-nginx

Once we have installed those packages, we can obtain our certificates.

sudo certbot --nginx -d research.the-digital-life.com

It will ask you if you want to redirect all traffic from HTTP to HTTPS. Select yes (2). This automatically makes some changes to our NGINX default configuration.

server {

  server_name research.the-digital-life.com;
 
  location / {
    proxy_pass http://127.0.0.1:5000;
  }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/research.the-digital-life.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/research.the-digital-life.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = research.the-digital-life.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

  listen 80 default_server;
  listen [::]:80 default_server;

  server_name research.the-digital-life.com;
    return 404; # managed by Certbot
}

Let’s also check the auto-renewal.

certbot renew --dry-run

Learn how to set up a webserver with docker in just 15 minutes

Leave a Comment

I accept the Privacy Policy