In this tutorial, we will go through:
- Installing and configuring NGINX,
- Installing and configuring SSL/TLS,
- Configuring NGINX as a reverse proxy for:
- A whole site,
- A directory of a site.
Requirements:
sudo apt update && sudo apt upgrade -y sudo apt install nginx -y sudo nano /etc/nginx/sites-available/default
Change the following configuration with your domain:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
server_name example.com www.example.com;
}
Check the configuration and restart the server:
nginx -t && nginx -s reload
Access your website in a browser and note that it is labeled as an insecure connection.
SSL/TLS
Install Certbot and run it against your domain:
sudo apt-get install certbot python3-certbot-nginx -y sudo certbot --nginx

Only on the first run will it ask that many questions.
Alternatively, you can specify the domain directly to skip a step:
sudo certbot --nginx -d example.com -d example2.com
Reload the server and refresh the browser to verify that it automatically redirects to a secure connection:
nginx -s reload
The browser will redirect from HTTP://example.com to HTTPS://example.com.
Create a cron job under the root user to automatically renew the certificate before it expires every 90 days:
sudo su crontab -e
Append:
0 12 * * * /usr/bin/certbot renew --quiet
REVERSE PROXY
To avoid CPU overload from multiple encrypted sessions, it is recommended to use a regular HTTP connection internally when possible (e.g. within a restricted VLAN).
Edit the virtual server configuration:
sudo nano /etc/nginx/sites-available/default
Applying the reverse proxy to the root of the website.
Look for the location { … } block and update it as follows:
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
This configuration forwards traffic to the specified host and port. The example above forwards to localhost on port 5000, which could be a Docker application listening on that port.
The lines in orange are optional and pass metadata to the backend application if needed.
Applying the reverse proxy to a directory of the website.
Add a location block for the target directory:
location /proxied_page/ {
proxy_pass http://192.168.1.7;
}
In this example, the reverse proxy applies only to the proxied_page directory and forwards requests to another host (192.168.1.7) on the private network over the default HTTP port.
BONUS: Reverse Proxy with Apache
sudo a2enmod proxy sudo a2enmod proxy_http sudo a2enmod proxy_balancer sudo a2enmod lbmethod_byrequests
Add the following lines to your site configuration file as needed:
ProxyPreserveHost On ProxyPass / http://10.1.1.1:8080/ ProxyPass /directory http://192.168.1.1/ ProxyPass /another_directory http://172.16.1.1/dir/
Restart the service:
sudo apachectl configtest sudo systemctl restart apache2.service
The reverse proxy can also act as a load balancer:
<Proxy balancer://cluster>
BalancerMember http://webserver1
BalancerMember http://webserver2
</Proxy>
ProxyPreserveHost On
ProxyPass / balancer://cluster/
ProxyPassReverse / balancer://cluster/
You can also apply health checks to the cluster members:
<Proxy balancer://cluster>
BalancerMember "http://webserver1" hcmethod=HEAD hcinterval=1 hcpasses=9 hcuri=/app/status
BalancerMember "http://webserver2" hcmethod=HEAD hcinterval=1 hcpasses=9 hcuri=/app/status
</Proxy>
On the backend host (where the web application runs), if it is also running Apache:
- Logs will show the remote IP address of the reverse proxy server for all clients.
- To fix this, the mod_remoteip module must be enabled and configured as follows.
sudo a2enmod remoteip sudo nano /etc/apache2/apache2.conf
Append the line:
RemoteIPHeader X-Forwarded-For
Update the following line.
From:
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
To:
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
Then check the configuration and apply the changes:
sudo apachectl configtest && sudo systemctl restart apache2