Deploy a 'Reverse Proxy' with Nginx on a Raspberry Pi - Blog AstronautMarkus

Nginx logo with Raspberry Pi background

"Do you have more than one server on your network and want to set up a proxy to choose which server will handle each request? Learn how to do it with Nginx on a Raspberry Pi."

nginxreverse proxyraspberry piserversnetworkinglinuxtutorialsslletsencryptself-hostingdevopsenglish

Published: September 30, 2025

Deploy a Reverse Proxy on your network using Nginx on a Raspberry Pi

Welcome to this post, where we’ll explain how to create a basic configuration of an Nginx server acting as a reverse proxy on a Raspberry Pi. This configuration is useful for managing multiple web services on a local network, allowing requests to be directed to a specific server based on the requested URL.

What is a Reverse Proxy?

A reverse proxy is a server that receives requests from clients and forwards them to one or more backend servers. Unlike a forward proxy, which acts on behalf of the client, a reverse proxy acts on behalf of the server. This is useful for load distribution, improving security, and managing multiple web services.

Network Scenario Example

Imagine the following situation:

  • Your internet service provider (ISP) assigns you the public IP address:
    203.0.113.1
  • In your local network you have several servers:
    • Server 1: 192.168.1.101
    • Server 2: 192.168.1.102
    • Raspberry Pi (with Nginx): 192.168.1.100 (the only IP visible from the internet)

Now, you want:

The Raspberry Pi will act as an intermediary, receiving all external requests and, thanks to Nginx, redirecting them to the corresponding server based on the requested domain.

Reverse Proxy Example

This image illustrates how requests are directed through the reverse proxy on the Raspberry Pi, redirecting to the first or second server depending on the requested URL.

Note:
For this to work, you must have configured your DNS service, e.g., Cloudflare so that website1.example.com and website2.example.com point to the public IP 203.0.113.1, which is your ISP’s IP. After that, redirect all HTTP/HTTPS requests to the Raspberry Pi (192.168.1.100) from your router, using DMZ or port forwarding rules.

Prerequisites

  • Raspberry Pi: Any recent model should work, at least 1GB of RAM for acceptable performance.
  • Distribution of choice: For this example we’ll use Raspberry Pi OS based on Debian 12.
  • Terminal access: Either directly or via SSH.
  • Nginx installed: Web server that will act as reverse proxy. We’ll explain how to install it below.
  • One or more servers: Apart from the Raspberry Pi, you’ll need at least one other machine to act as a backend server. It can be another Raspberry Pi, a local server, or any computer on the same network.
  • nano or vim: A text editor to modify configuration files.
  • Certbot (optional): Tool to obtain free SSL certificates from Let’s Encrypt.

0. Requirements Installation:

If you already have Nginx installed, you can skip the installation section.

0.1 Nginx Installation

To install Nginx on your Raspberry Pi, open a terminal and run the following commands:

sudo apt update
sudo apt install nginx

0.2 Enable Nginx:

To enable Nginx on your Raspberry Pi, run the following command:

sudo systemctl enable --now nginx

Once this is done, when entering the local IP address of the Raspberry Pi, in our example http://192.168.1.100 if everything went well, we’ll see a screen with an Nginx welcome message like the following image:

Nginx default page

With this we have Nginx ready for the Reverse Proxy, now we can replicate this same procedure on the rest of the servers or machines, the installation process is the same for all machines in our configuration, we just need to make sure they can communicate with each other, or that ports 80/443 are open.

Note: Make sure there are no other services using ports 80/443 on the Raspberry Pi or other servers, other than Nginx to avoid conflicts.

0.3 Verify communication between servers:

If you want to make sure your machines can “talk to each other”, you can run the following command from your Raspberry Pi:

ping 192.168.1.101 // Example server 1
ping 192.168.1.102 // Example server 2

If everything goes well, you should receive responses from each of the servers, indicating they can communicate with each other.

PING 192.168.1.101 (192.168.1.101) 56(84) bytes of data.
64 bytes from 192.168.1.101: icmp_seq=1 ttl=64 time=0.145 ms
64 bytes from 192.168.1.101: icmp_seq=2 ttl=64 time=0.190 ms
64 bytes from 192.168.1.101: icmp_seq=3 ttl=64 time=0.234 ms
64 bytes from 192.168.1.101: icmp_seq=4 ttl=64 time=0.210 ms

--- 192.168.1.101 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3032ms
rtt min/avg/max/mdev = 0.145/0.195/0.234/0.033 ms

Something like this should appear, not necessarily identical, the important thing is that you receive responses from all servers. You can also do the process in reverse, running pings from the other servers to the Raspberry Pi, ideally bidirectional communication to avoid connectivity problems.

0.4 Using nano or vim

To edit configuration files on your Raspberry Pi, you can use text editors like nano or vim. Both are available in most Linux distributions.

If you’re not sure, you can run:

sudo apt install nano vim

for this example for simplicity, we’ll use nano, this is personal preference.

0.5 Install Certbot (optional)

If you want to enable HTTPS on your server, that is the green padlock that browsers show in the address bar, you can use Certbot to obtain a free SSL certificate from Let’s Encrypt.

To install Certbot, run the following commands:

sudo apt install certbot python3-certbot-nginx

This will install Certbot and the necessary dependencies for it to work with Nginx.

With this, we’ll have all the dependencies and verify communication between servers. Once these steps are completed, we can proceed to configure Nginx.

1. Nginx Configuration (Incoming server, Raspberry Pi):

To start with our Nginx configuration, we must create a configuration file for our entry server, or the Raspberry Pi, which will receive requests from our Router, that is, requests from visitors.

1.1 Create .conf file

We’re going to consider that our domain is example.com, for this example we’ll do two things. 1. Serve a front-end page to the URL http://example.com 2. We’ll set up an API or backend service for this same page, using a subdomain, http://api.example.com.

sudo nano /etc/nginx/sites-available/example.com.conf

Now, you can paste the following code in the terminal:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://192.168.1.101;
        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;
    }
}

This will make Nginx listen on port 80 and forward requests to the corresponding backend server’s IP address. Make sure the IP address and domain name are correct and properly configured in your network. In our example we said our domain was example.com and the backend server was at 192.168.1.101.

After creating the configuration file, we need to create a symbolic link in the sites-enabled directory so Nginx can use this configuration.

sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/

Tip: If you’re already in sites-available, don’t do ln -s directly to example.com.conf, do it with the full path, from /etc/nginx/sites-available/example.com.conf to /etc/nginx/sites-enabled/example.com.conf or it will give you an error.

open() “/etc/nginx/example.com.conf” failed (40: Too many levels of symbolic links) Just in case.

Now, Nginx will take our configuration into account when restarting or reloading. First to confirm everything is fine, we can run the following command:

sudo nginx -t

If everything goes well, this should respond with something like:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If there’s an error, check the configuration file to make sure there are no typos or syntax errors. They could also be other configurations in the main nginx.conf file, or some other file, be careful with that.

1.3 Restart Nginx

Finally, to apply the changes, restart Nginx with the following command:

sudo systemctl restart nginx

Now, Nginx should be configured as a reverse proxy for the domain http://example.com, redirecting requests to the backend server at 192.168.1.101. You can repeat this process for each domain or subdomain you want to configure, making sure to change the backend server’s IP address as needed. In our case we’ll consider that the subdomain api.example.com points to 192.168.1.102 and repeat this same process.

In summary, the configuration file for api.example.com would look like this:

server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://192.168.1.102;
        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;
    }
}

Same as the previous one, but pointing to another domain and another backend server hehe.

2. Nginx Configuration (Backend Server):

The configuration process on backend servers is similar to the Raspberry Pi, but with some differences. Here, Nginx won’t act as a reverse proxy, but will serve content directly, or if you want to make a reverse proxy to some internal service, like a Docker, a Node.js application, etc. you can also do it. First we’ll show a basic configuration, serving static files.

2.1 Create .conf file on backend servers

On each backend server, create a configuration file for Nginx. For example, on server 1 (/etc/nginx/sites-available/example.com.conf):

sudo nano /etc/nginx/sites-available/example.com.conf

Then, paste the following code:

server {
    listen 80;
    server_name example.com;

    location / {
        root /var/www/example.com;
        index index.html;
    }
}

The fun thing here is that you don’t need to worry so much about HTTPS, details and all that, that’s done on the Raspberry Pi, since it’s the one that receives external requests. Here we only worry about serving the content.

The same previous process of creating a symbolic link in the sites-enabled directory:

sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/

Then, verify the configuration:

sudo nginx -t

And restart Nginx:

sudo systemctl restart nginx

Now, if a person accesses http://example.com, Nginx on the Raspberry Pi will redirect the request to the backend server, which will serve content from /var/www/example.com.

Amazing, right? Now you can repeat this process on the second backend server, changing the domain name and content path as needed.

Extra: Proxy Pass to an internal service

If instead of serving static files, you want Nginx on the backend server to act as a reverse proxy for an internal service (for example, a Node.js application running on port 3000), you can configure Nginx as follows:

server {
    listen 80;
    server_name api.example.com;
    location / {
        proxy_pass http://localhost:3000;
        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;
    }
}

These are the basic tags for Nginx to work correctly as a reverse proxy, ensuring HTTP headers are properly maintained. You can modify or add more configurations according to your application’s needs, if you want to choose another port, like 8080, 5000, 4321, whatever you need. The important thing is that the service is running and Nginx (Raspberry Pi) can communicate with it.

What happens if you proxy_pass to a service that’s not running?

If you perform the above process, like doing a proxy_pass to localhost:3000, but this service is not running, Nginx will return a 502 Bad Gateway error, indicating it couldn’t connect to the backend service. Make sure the service is active and listening on the correct port to avoid this error.

Nginx 502 Error

How horrible, right? you can even take advantage of this, create a maintenance view, or something like that, but well, someday I’ll write a post about error handling in Nginx.

3. Enable HTTPS with Certbot (optional)

If you want to enable HTTPS in your Nginx configuration, you can use Certbot to obtain free SSL certificates from Let’s Encrypt. Here I’ll explain how to do it.

We’ll do this only on the Raspberry Pi, since it’s the one that receives external requests. For backend services, it’s not necessary, unless you want to do it for some specific reason.

3.1 Obtain SSL certificates

To obtain an SSL certificate for your domain, run the following command on the Raspberry Pi:

certbot certonly --nginx -d example.com -d api.example.com

using the specific nginx options so Certbot uses Nginx, since it can work with Apache and other web servers. The -d parameter is used to specify the domains you want to generate certificates for. You can add as many domains as you need by repeating the -d parameter. The certonly parameter indicates that you only want to obtain the certificate without automatically modifying the Nginx configuration. If you don’t specify certonly, Certbot will try to modify the Nginx configuration to enable HTTPS automatically, if you’re a ‘purist’ you might prefer to do it manually, as in this example.

3.2 Certificate location

The certificates generated by Certbot are stored in the /etc/letsencrypt/live/your_domain/ directory. Here you’ll find the following files:

/etc/letsencrypt/live/example.com/
├── cert.pem         # Public certificate
├── chain.pem        # Certificate chain
├── fullchain.pem    # Complete certificate (certificate + chain)
└── privkey.pem      # Private key

For Nginx configuration, you’ll generally use fullchain.pem and privkey.pem.

3.3 Configure Nginx to use HTTPS

After obtaining the certificates, you must configure Nginx to use HTTPS. Open your site’s configuration file on the Raspberry Pi:

sudo nano /etc/nginx/sites-available/example.com.conf

You can modify our previous configuration to look like this:

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri; # With this fragment the system will redirect HTTP to HTTPS automatically. Cool trick right?
}

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    location / {
        root /var/www/example.com;
        index index.html;
    }
}

Repeat this process for each domain or subdomain you want to configure, making sure to change the certificate paths as needed.

For the subdomain api.example.com, the configuration would be similar:

server {
    listen 80;
    server_name api.example.com;
    return 301 https://$host$request_uri; # Redirect HTTP to HTTPS
}

server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    location / {
        proxy_pass http://localhost:3000;
        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;
    }
}

The important things to have SSL are:

-Have the certificate files in the correct path -Have the listen 443 ssl; block -Have the ssl_certificate and ssl_certificate_key directives pointing to the correct files -(Optional) Redirect HTTP to HTTPS to improve security and avoid problems with your end users

3.4 Verify configuration and restart Nginx

After modifying the configuration, verify everything is correct:

sudo nginx -t

If the test is successful, restart Nginx to apply the changes:

sudo systemctl restart nginx

Now simply if you visit https://example.com or https://api.example.com, you should see the green padlock in the address bar, indicating the connection is secure.

Congratulations, you have successfully configured a reverse proxy with Nginx on a Raspberry Pi, redirecting requests to multiple backend servers and enabling HTTPS for a secure connection. This configuration is ideal for managing multiple web services on a local network, providing an additional layer of security and flexibility.

Remember you can always modify and adapt this configuration according to the specific needs of your network and services. Good luck with your network architecture!

Conclusion

In this tutorial, we’ve covered the necessary steps to implement a reverse proxy with Nginx on a Raspberry Pi, including HTTPS configuration with Let’s Encrypt. This is a powerful and flexible solution for managing multiple web services securely. With this configuration, you can direct traffic efficiently and securely, improving user experience and your network’s security. You can also scale it according to what you need, adding more backend servers or adjusting configurations according to your specific needs. Remember to always keep the Raspberry Pi and Nginx running for the reverse proxy to work correctly, otherwise, the web pages won’t load.

Until next time!