Skip to main content

Reverse Proxy Setup

A reverse proxy (nginx) is required for VPS deployments. It handles SSL termination, routes traffic to the correct services, and keeps your backend ports unexposed.

Why You Need a Reverse Proxy

  • HTTPS: Browsers require HTTPS for secure cookie handling (SameSite attributes). Without HTTPS, authentication cookies won't work on a VPS.
  • Domain routing: Route app.yourdomain.com to the UI (port 8015) and api.yourdomain.com to the API (port 8150).
  • Security: Backend services stay bound to 127.0.0.1 and are never directly exposed to the internet.

Architecture

Step 1: Install nginx

# Ubuntu/Debian
sudo apt update
sudo apt install -y nginx

Step 2: Install Certbot (Let's Encrypt)

sudo apt install -y certbot python3-certbot-nginx

Step 3: Configure nginx

Create the nginx configuration:

sudo nano /etc/nginx/sites-available/fystack
# Fystack UI
server {
listen 80;
server_name app.yourdomain.com;

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

# Fystack API
server {
listen 80;
server_name api.yourdomain.com;

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

# WebSocket support (needed for real-time updates)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

Enable the configuration:

sudo ln -s /etc/nginx/sites-available/fystack /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default # Remove default site
sudo nginx -t # Test configuration
sudo systemctl reload nginx

Step 4: Get SSL Certificates

sudo certbot --nginx -d app.yourdomain.com -d api.yourdomain.com

Certbot will:

  1. Obtain SSL certificates from Let's Encrypt
  2. Automatically update your nginx config for HTTPS
  3. Set up auto-renewal

After certbot runs, your nginx config will be updated with SSL settings and automatic HTTP → HTTPS redirects.

Step 5: Update Fystack Configuration

After setting up the reverse proxy with HTTPS, make sure your config.yaml matches:

CORS

cors:
allow_origins: https://app.yourdomain.com
cookie:
same_site: strict

App URLs

app:
root_url: https://app.yourdomain.com
sign_in_url: https://app.yourdomain.com/auth
# ... update all URLs to use https://app.yourdomain.com

API_BASE_URL

The UI container needs to know where the API is. From the project root, create (or update) dev/.env:

echo "API_BASE_URL=https://api.yourdomain.com" > dev/.env
note

The dev/.env file is loaded by dev/docker-compose.yaml. Since Docker Compose resolves env_file paths relative to the compose file's directory, this works when you run docker compose -f ./dev/docker-compose.yaml from the project root.

Recreate Services

After updating config, recreate the affected services:

cd fystack-selfhost-scripts

# Recreate Apex to pick up config.yaml changes
docker compose -f ./dev/docker-compose.yaml up -d --force-recreate apex

# Recreate UI to pick up API_BASE_URL change
docker compose -f ./dev/docker-compose.yaml up -d --force-recreate fystack-ui-community

Verify

  1. Open https://app.yourdomain.com — you should see the Fystack login page
  2. Open browser DevTools (F12) → Network tab
  3. Sign up / sign in and check that API requests go to https://api.yourdomain.com
  4. Check that no CORS errors appear in the Console tab

The CORS + CSRF Checklist

If you're getting errors after setting up the reverse proxy, run through this checklist:

SettingValueWhere
cors.allow_originshttps://app.yourdomain.comconfig.yaml
cookie.same_sitestrictconfig.yaml
API_BASE_URLhttps://api.yourdomain.comdev/.env or env var
app.root_urlhttps://app.yourdomain.comconfig.yaml
nginx SSLConfigured for both domains/etc/nginx/sites-available/fystack
DNS A recordsBoth point to VPS IPYour DNS provider
Common Mistake

Using http:// instead of https:// in any of these settings will cause CSRF cookie failures. All URLs must use https:// when SSL is configured.

Single Domain Setup (Alternative)

If you prefer using a single domain with path-based routing:

server {
listen 80;
server_name fystack.yourdomain.com;

# API routes
location /api/ {
proxy_pass http://127.0.0.1:8150;
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";
}

# UI (everything else)
location / {
proxy_pass http://127.0.0.1:8015;
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;
}
}

With a single-domain setup:

  • Set API_BASE_URL=https://fystack.yourdomain.com
  • Set cors.allow_origins: https://fystack.yourdomain.com
  • Use cookie.same_site: strict (since everything is on the same domain)

SSL Certificate Renewal

Certbot sets up automatic renewal. Verify it's working:

sudo certbot renew --dry-run

Certificates auto-renew every 60-90 days.

Next Steps