Two-VPS Private Proxy Architecture: Nginx Reverse Proxy Over Wireguard VPN

Overview

  • Proxy VPS: Public VPS running Nginx reverse proxy with its own public IP.

  • Backend VPS: Origin VPS running your service (e.g., Gitea, Forgejo), completely private.

  • Wireguard VPN: Encrypted private tunnel connecting Proxy VPS and Backend VPS.

  • Traffic flow: Client → Proxy VPS → Wireguard VPN → Backend VPS (service).


Prerequisites

  • Two Linux VPS servers (Ubuntu recommended).

  • A domain or subdomain for your service.

  • Basic Linux command line knowledge.


1. Generate Wireguard Keys on Both VPSes

wg genkey | tee privatekey | wg pubkey > publickey
chmod 600 privatekey publickey
  • privatekey holds your private key.

  • publickey holds your public key.


2. Configure Wireguard on Proxy VPS

Create /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = <Proxy VPS private key>
Address = 10.200.200.1/24
ListenPort = 51820

[Peer]
PublicKey = <Backend VPS public key>
AllowedIPs = 10.200.200.2/32

Enable and start:

sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0

3. Configure Wireguard on Backend VPS

Create /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = <Backend VPS private key>
Address = 10.200.200.2/24

[Peer]
PublicKey = <Proxy VPS public key>
Endpoint = <Proxy VPS Public IP>:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

Enable and start:

sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0

4. Ensure Backend App Port Is Not Publicly Exposed

4.1 Bind the Service to the VPN IP

Configure your app (Gitea, forgejo, etc) to listen only on VPN IP 10.200.200.2.

Example for Gitea (app.ini):

[server]
HTTP_ADDR = 10.200.200.2
HTTP_PORT = 3000

This restricts the app to accept connections only over the secure VPN.

4.2 Firewall Configuration on Backend VPS

Block all incoming traffic except from Proxy VPS VPN IP on the service port (3000):

sudo ufw default deny incoming
sudo ufw allow from 10.200.200.1 to any port 3000 proto tcp
sudo ufw allow 22/tcp  # SSH access
sudo ufw enable
sudo ufw reload

Only the Proxy VPS can access your backend service port.

4.3 Verify Port Binding and Traffic Restrictions

Check that service is listening correctly:

sudo ss -tuln | grep 3000

Expected output shows service bound to 10.200.200.2:3000 or 127.0.0.1:3000, NOT all interfaces (0.0.0.0).

4.4 Optional: NAT Port Forwarding on Proxy VPS

Alternatively or additionally, on Proxy VPS use iptables to forward incoming public port 443 traffic to backend VPN IP + port 3000:

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 10.200.200.2:3000
sudo iptables -t nat -A POSTROUTING -j MASQUERADE

Add to Wireguard config /etc/wireguard/wg0.conf on Proxy VPS for automation:

PostUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 10.200.200.2:3000
PostUp = iptables -t nat -A POSTROUTING -j MASQUERADE
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 10.200.200.2:3000
PostDown = iptables -t nat -D POSTROUTING -j MASQUERADE

5. Configure Nginx on Proxy VPS

Install Nginx and configure /etc/nginx/sites-available/gitproxy:

server {
    listen 80;
    server_name git.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name git.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/git.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/git.yourdomain.com/privkey.pem;

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

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Enable site and reload Nginx:

sudo ln -s /etc/nginx/sites-available/gitproxy /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

6. Configure DNS and SSL

  • Point your domain DNS A record to Proxy VPS public IP.

  • Obtain SSL with Certbot on Proxy VPS:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d git.yourdomain.com

7. Test Your Setup

Visit:

https://git.yourdomain.com

Access your service securely via the Proxy VPS. Origin VPS IP remains hidden.


Summary Table

Step
Purpose

Wireguard key gen

Secure keys for VPN connection

Wireguard VPN config

Encrypted tunnel between VPSes

Bind app to VPN IP

Restrict app accessibility

Backend firewall rules

Allow service port only from Proxy VPN IP

Nginx reverse proxy

Proxy requests securely

DNS and SSL setup

Secure domain pointing and encryption

Last updated