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 (
SameSiteattributes). Without HTTPS, authentication cookies won't work on a VPS. - Domain routing: Route
app.yourdomain.comto the UI (port 8015) andapi.yourdomain.comto the API (port 8150). - Security: Backend services stay bound to
127.0.0.1and 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:
- Obtain SSL certificates from Let's Encrypt
- Automatically update your nginx config for HTTPS
- 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
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
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
- Open
https://app.yourdomain.com— you should see the Fystack login page - Open browser DevTools (F12) → Network tab
- Sign up / sign in and check that API requests go to
https://api.yourdomain.com - 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:
| Setting | Value | Where |
|---|---|---|
cors.allow_origins | https://app.yourdomain.com | config.yaml |
cookie.same_site | strict | config.yaml |
API_BASE_URL | https://api.yourdomain.com | dev/.env or env var |
app.root_url | https://app.yourdomain.com | config.yaml |
| nginx SSL | Configured for both domains | /etc/nginx/sites-available/fystack |
| DNS A records | Both point to VPS IP | Your DNS provider |
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
- Troubleshooting — Fix CORS, CSRF, and other common issues