Table of Contents
A reverse proxy allows multiple services to share the same port by routing incoming requests based on domain or path. This is commonly used with web apps, APIs, and Docker containers on a VPS.
Step 1: Understand How a Reverse Proxy Works
The reverse proxy listens on a public port (usually 80 or 443) and forwards requests internally to different services running on separate ports.
Step 2: Install Nginx
Nginx is a lightweight and reliable reverse proxy.
sudo apt update
sudo apt install nginx -y
Start and enable Nginx:
sudo systemctl enable nginx
sudo systemctl start nginx
Step 3: Run Services on Different Internal Ports
Ensure each service runs on a unique local port.
# Example
App 1 → localhost:3000
App 2 → localhost:4000
Step 4: Configure Nginx for Domain-Based Routing
Create a new server block configuration.
sudo nano /etc/nginx/sites-available/app1.conf
server {
listen 80;
server_name app1.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Enable the configuration:
sudo ln -s /etc/nginx/sites-available/app1.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 5: Add a Second Service on the Same Port
Repeat the process for another domain.
sudo nano /etc/nginx/sites-available/app2.conf
server {
listen 80;
server_name app2.example.com;
location / {
proxy_pass http://localhost:4000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Enable and reload Nginx:
sudo ln -s /etc/nginx/sites-available/app2.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 6: Verify Reverse Proxy Setup
Test each domain in the browser or via curl.
curl http://app1.example.com
curl http://app2.example.com
Both services should be accessible through port 80.
Step 7: Secure Services with HTTPS
For production environments, secure services with SSL.
You may also want to review this related article: Fix Port Already in Use Error on Linux
Optional Step: Path-Based Routing
Route services using URL paths instead of domains.
location /api/ {
proxy_pass http://localhost:3000;
}