Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Debian - Set Up Nginx Reverse Proxy

I use a reverse proxy so that I can host multiple sites on different servers within a NAT. I forward ports 80 and 443 on my router to my reverse proxy, which then takes care of redirecting the traffic to the relevant servers. However, they can also be useful as a gateway for monitoring/restricting traffic, or to have a single point to maintain all your SSL certificates.

The setup below assumes you wish to have SSL enabled, but will forward the traffic in the encrypted form so as to not cause confusion on the final server. This is because I have the servers redirect the user if they don't detect https.

Steps

Install nginx

sudo apt update && sudo apt install nginx -y

Run the following command to set up the proxy configuration.

sudo echo 'proxy_redirect          off;
proxy_set_header        Host            $host;
proxy_set_header        X-Real-IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;' | sudo tee /etc/nginx/proxy.conf

Adding A Site

For each site that you wish to proxy, run the following command after having changed the variables at the top:

DOMAIN="www.mydomain.com"
CONTAINER_IP="192.168.16.100"

echo "
server {
        listen 80;

        server_name `echo $DOMAIN`;

        access_log  /var/log/nginx/access.log;

        location / {
                proxy_pass      http://`echo $CONTAINER_IP`/;
                include         /etc/nginx/proxy.conf;
        }
}

server {
    listen 443 default_server ssl;

    ssl on;

    server_name `echo $DOMAIN`;

    access_log  /var/log/nginx/access.log;

    ssl_certificate      ssl/`echo $DOMAIN`.crt;
    ssl_certificate_key  ssl/`echo $DOMAIN`.key;

    ssl_protocols        TLSv1.2 TLSv1.3;
    ssl_ciphers RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    keepalive_timeout    60;
    ssl_session_cache    shared:SSL:10m;
    ssl_session_timeout  10m;

    location / {
        proxy_pass      https://`echo $CONTAINER_IP`/;
        include         /etc/nginx/proxy.conf;
    }
}" | sudo tee /etc/nginx/sites-enabled/$DOMAIN

This example includes TLSv1.3, which only works when you are using OpenSSL version 1.1.1 or higher. You can check this by running the command openssl version. If you are running an older version, just remove this protocol from the list.

Then add the relevant SSL certificate files at:

/etc/nginx/ssl/[www.mydomain.com].crt
/etc/nginx/ssl/[www.mydomain.com].key

Optional - Redirect HTTP Traffic Instead

If you want to redirect HTTP traffic to HTTPS, then change the first server directive to:

server {
    listen 80;
    server_name $DOMAIN;
    access_log  /var/log/nginx/access.log;

    location / {
        return 301 https://$DOMAIN$request_uri;
    }
}

You need to manually substitute the $DOMAIN variable, but not the $request_uri variable, which is actually for NGINX to dynamically input the request URI.

Reload Nginx

For your changes to take effect, you need to gracefully reload the configuration using the following command:

sudo invoke-rc.d nginx reload

If nginx fails to start, then check the log at /var/log/nginx/error.log. If the last line states: could not build the server_names_hash, you should increase server_names_hash_bucket_size: 32 then simply uncomment the server_names_hash_bucket_size line in /etc/nginx/nginx.conf on line 23.

Allowing EventSource / Server-sent Events

For my WebRTC project, I make use of a permanent stream connection between the server and the client. This requires that the messages go straight through, without any kind of buffering/chunking, which the proxy could interfere with. In order to get that to still work, add the following lines to the configuration of that specific site:

proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;

References

Last updated: 5th June 2024
First published: 5th December 2018