VPS Deployment

Run the RelayPlane proxy on your own VPS or dedicated server for full control over data residency, latency, and cost.

Who is this for? This guide is for teams that need to self-host the proxy — for compliance reasons, to reduce egress costs, or to co-locate it with their own infrastructure. If you just want to get started quickly, see the Quick Start guide instead.

Prerequisites

  • VPS running Ubuntu 22.04+ or Debian 12+ — any provider works (Hetzner, DigitalOcean, Linode, etc.)
  • Node.js 20+ — the proxy requires Node 20 LTS or newer
  • A domain name — needed for TLS. Point an A record at your server IP before running Certbot.
  • At least one AI provider API key — e.g. ANTHROPIC_API_KEY or OPENAI_API_KEY

1. Install Node.js

Use the NodeSource setup script to install Node 20 LTS on Debian/Ubuntu:

1# Install curl if needed
2sudo apt-get update && sudo apt-get install -y curl
3
4# Add NodeSource repo for Node 20
5curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
6
7# Install Node.js
8sudo apt-get install -y nodejs
9
10# Verify
11node --version # v20.x.x
12npm --version

2. Install the RelayPlane Proxy

Install the proxy globally so it can be managed as a system service:

1sudo npm install -g @relayplane/proxy
2
3# Verify the binary is available
4relayplane --version

3. Configure Environment Variables

Create a dedicated directory for the proxy and write an environment file:

1sudo mkdir -p /etc/relayplane
2sudo nano /etc/relayplane/.env
/etc/relayplane/.env
1# AI Provider Keys (add the ones you use)
2ANTHROPIC_API_KEY=sk-ant-...
3OPENAI_API_KEY=sk-...
4GOOGLE_AI_API_KEY=...
5XAI_API_KEY=...
6
7# Proxy port (nginx will forward to this)
8RELAYPLANE_PORT=4000
9
10# Optional: your RelayPlane cloud API key for telemetry
11RELAYPLANE_API_KEY=rp-...
12
13NODE_ENV=production
14LOG_LEVEL=info

Lock down the env file. It contains your API keys — restrict read access to root only:

sudo chmod 600 /etc/relayplane/.env

4. Run as a systemd Service

Create a systemd unit file so the proxy starts automatically on boot and restarts on failure:

/etc/systemd/system/relayplane.service
1[Unit]
2Description=RelayPlane Proxy
3After=network.target
4
5[Service]
6Type=simple
7User=nobody
8EnvironmentFile=/etc/relayplane/.env
9ExecStart=/usr/bin/relayplane start --port $RELAYPLANE_PORT
10Restart=on-failure
11RestartSec=5
12StandardOutput=journal
13StandardError=journal
14SyslogIdentifier=relayplane
15
16# Security hardening
17NoNewPrivileges=true
18PrivateTmp=true
19ProtectSystem=strict
20ProtectHome=true
21
22[Install]
23WantedBy=multi-user.target
1# Reload systemd and enable the service
2sudo systemctl daemon-reload
3sudo systemctl enable relayplane
4sudo systemctl start relayplane
5
6# Check it's running
7sudo systemctl status relayplane
8
9# Follow live logs
10sudo journalctl -u relayplane -f

Prefer PM2? Skip systemd and use pm2 start relayplane -- start --port 4000 with pm2 startup to persist across reboots.

4b. Alternatively — Run with PM2

PM2 is a popular process manager for Node.js that simplifies log rotation, clustering, and zero-downtime reloads:

1# Install PM2 globally
2sudo npm install -g pm2
3
4# Start the proxy, loading env from file
5pm2 start relayplane --name relayplane -- start --port 4000 --env-file /etc/relayplane/.env
6
7# Save the process list and generate startup script
8pm2 save
9pm2 startup # Follow the printed command to enable on boot
10
11# Useful PM2 commands
12pm2 status
13pm2 logs relayplane
14pm2 restart relayplane
15pm2 reload relayplane # zero-downtime reload

5. nginx Reverse Proxy

nginx terminates TLS and forwards traffic to the proxy on port 4000:

1sudo apt-get install -y nginx
/etc/nginx/sites-available/relayplane
1server {
2 listen 80;
3 server_name proxy.yourdomain.com;
4
5 # Redirect all HTTP to HTTPS
6 return 301 https://$host$request_uri;
7}
8
9server {
10 listen 443 ssl http2;
11 server_name proxy.yourdomain.com;
12
13 ssl_certificate /etc/letsencrypt/live/proxy.yourdomain.com/fullchain.pem;
14 ssl_certificate_key /etc/letsencrypt/live/proxy.yourdomain.com/privkey.pem;
15 ssl_protocols TLSv1.2 TLSv1.3;
16 ssl_ciphers HIGH:!aNULL:!MD5;
17
18 # Increase timeouts for long LLM responses
19 proxy_read_timeout 120s;
20 proxy_send_timeout 120s;
21
22 location / {
23 proxy_pass http://127.0.0.1:4000;
24 proxy_http_version 1.1;
25 proxy_set_header Host $host;
26 proxy_set_header X-Real-IP $remote_addr;
27 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
28 proxy_set_header X-Forwarded-Proto $scheme;
29
30 # Required for streaming responses (SSE / chunked)
31 proxy_buffering off;
32 proxy_cache off;
33 }
34}
1# Enable the site and reload nginx
2sudo ln -s /etc/nginx/sites-available/relayplane /etc/nginx/sites-enabled/relayplane
3sudo nginx -t # test config
4sudo systemctl reload nginx

6. TLS with Let's Encrypt

Certbot issues and auto-renews a free TLS certificate from Let's Encrypt:

1# Install Certbot
2sudo apt-get install -y certbot python3-certbot-nginx
3
4# Obtain a certificate (nginx plugin handles nginx config automatically)
5sudo certbot --nginx -d proxy.yourdomain.com
6
7# Certbot adds a cron/systemd timer — verify auto-renewal works
8sudo certbot renew --dry-run

DNS must resolve first. Make sure proxy.yourdomain.com points to your server IP before running Certbot, or the ACME challenge will fail.

7. Firewall Rules

Expose only ports 80 and 443 externally. The proxy port (4000) should only be reachable from localhost:

1# Allow SSH, HTTP, HTTPS
2sudo ufw allow OpenSSH
3sudo ufw allow 'Nginx Full'
4
5# Block direct access to proxy port from outside
6sudo ufw deny 4000
7
8# Enable firewall
9sudo ufw enable
10sudo ufw status

8. Point Your AI Tools at the Proxy

Once the proxy is running and nginx is serving HTTPS, update your tools to route through it:

~/.claude/settings.json (Claude Code)
1{
2 "env": {
3 "ANTHROPIC_BASE_URL": "https://proxy.yourdomain.com/anthropic"
4 }
5}
.env (any app using OpenAI SDK)
1OPENAI_BASE_URL=https://proxy.yourdomain.com/openai
2OPENAI_API_KEY=your-real-key # still required by the SDK
~/.cursor/mcp.json (Cursor)
1{
2 "mcpServers": {
3 "relayplane": {
4 "command": "relayplane",
5 "args": ["mcp"],
6 "env": {
7 "RELAYPLANE_BASE_URL": "https://proxy.yourdomain.com"
8 }
9 }
10 }
11}

9. Health Check & Smoke Test

1# Proxy health endpoint
2curl https://proxy.yourdomain.com/health
3
4# Expected response
5# {"status":"ok","version":"1.x.x"}
6
7# Quick smoke test — route a real request through the proxy
8curl https://proxy.yourdomain.com/anthropic/v1/messages \
9 -H "x-api-key: $ANTHROPIC_API_KEY" \
10 -H "anthropic-version: 2023-06-01" \
11 -H "content-type: application/json" \
12 -d '{
13 "model": "claude-3-haiku-20240307",
14 "max_tokens": 32,
15 "messages": [{"role":"user","content":"ping"}]
16 }'

Updating the Proxy

The proxy ships as an npm package. To update:

1# Install latest version
2sudo npm install -g @relayplane/proxy@latest
3
4# Restart the service (systemd)
5sudo systemctl restart relayplane
6
7# Or with PM2
8pm2 restart relayplane

Pin your version in production. Use @relayplane/proxy@1.8.33 (exact version) rather than @latest so updates are intentional, not automatic.

Troubleshooting

  • 502 Bad Gateway from nginx

    The proxy isn't running or crashed. Check sudo systemctl status relayplane or pm2 logs relayplane.

  • Streaming responses time out

    Ensure proxy_read_timeout and proxy_buffering off are set in your nginx config. LLM streams can run for 30–60s.

  • Certbot fails with "Connection refused"

    Port 80 must be open. Check sudo ufw status and ensure nginx is listening on 80 before running Certbot.

  • 401 Unauthorized from provider

    The API key in /etc/relayplane/.env is missing or invalid. Confirm with sudo systemctl show relayplane --property=Environment.

Next Steps