Nginx reverse proxy

Posted on: 2023-12-22

When deploying infrastructure components, sometimes you have to install a lot of different moving parts. For example, I have a Portainer instance where dozens of Docker containers may live. One common request is that any connection going to these containers should be over an encrypted connection, or HTTPS. There are many ways to do this, including setting up SSL certificates on each container individually, or installing a product like Traefik where you can configure each host manually with port forwarding. In this post I will show you how you can configure a single Nginx reverse proxy host that will handle all redirects automatically, so that you don't need to configure anything when you deploy a new container.

In my network, I will have Portainer (although it could be any service including Kubernetes or Docker Swarm) installed on docker.example.com and I will install the reverse proxy on proxy.example.com. The first step to do is obtain a Let's Encrypt SSL certificate on the proxy host:

apt install certbot
certbot

Note that if your host is not accessible through the Internet, you may need to use one of the DNS plugins to do DNS-01 validation. Next, let's install Nginx on the same host:

apt install nginx
systemctl enable nginx

Once installed and activated, we need to configure Nginx. Edit the /etc/nginx/conf.d/reverse-proxy.conf file with this code:

server {
  listen 8000-9000 ssl;
  ssl_certificate /etc/letsencrypt/live/proxy.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/proxy.example.com/privkey.pem;
  location / {
    resolver 1.1.1.1;
    proxy_pass http://docker.example.com:$server_port$request_uri;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
  }
}

Here we're using the certificates from Let's Encrypt to provide an HTTPS connection, and we're forwarding any connection to the Docker host for any port between 8000 and 9000. This is important, because it means you should make sure you deploy all your containers on those ports.

The last step is to increase the number of default workers in the /etc/nginx/nginx.conf file, otherwise Nginx will not be able to listen on 1,000 ports all at once. Add the following configuration to that file:

events {
  worker_connections 4096;
}

And we're done. Restart Nginx with the systemctl restart nginx command and you should now have a working proxy. From now on, let's say you deploy a new container on http://docker.example.com:8001/, you can right away connect to https://proxy.example.com:8001/ and it will automatically send you to the right place without any configuration required.