Reverse proxy and TLS
Run the panel and API on one site so the session cookie (HttpOnly, SameSite=Strict) works. Send /api/* to the API (port 4000) and everything else to the panel (port 3000). Both must allow WebSocket upgrades: the browser live console uses /api/servers/:id/live and agents use their own sockets.
Settings to apply with any proxy:
ini
WEB_ORIGIN=https://panel.example.com
NEXT_PUBLIC_API_URL=https://panel.example.com
TRUST_PROXY=1
NODE_ENV=production # already set for the API container; makes cookies SecureAfter changing NEXT_PUBLIC_API_URL, rebuild: docker compose up --build -d.
Keep API_BIND and WEB_BIND on 127.0.0.1 when the proxy runs on the same host. If the proxy is on another host, bind to a private interface and firewall the ports.
text
panel.example.com {
handle /api/* {
reverse_proxy 127.0.0.1:4000
}
handle {
reverse_proxy 127.0.0.1:3000
}
}nginx
server {
listen 443 ssl http2;
server_name panel.example.com;
# ssl_certificate / ssl_certificate_key ...
client_max_body_size 1100m; # file uploads go through the API (limit is 1 GiB)
location /api/ {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_request_buffering off;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}yaml
# On the api service
- "traefik.http.routers.fledge-api.rule=Host(`panel.example.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.fledge-api.tls.certresolver=letsencrypt"
- "traefik.http.services.fledge-api.loadbalancer.server.port=4000"
# On the web service
- "traefik.http.routers.fledge-web.rule=Host(`panel.example.com`)"
- "traefik.http.routers.fledge-web.tls.certresolver=letsencrypt"
- "traefik.http.services.fledge-web.loadbalancer.server.port=3000"Checklist
curl -I https://panel.example.comshows the panel'sContent-Security-PolicyandX-Frame-Optionsheaders.- The console shows live output (WebSockets work) and file uploads of a few hundred MB succeed.
- Type a range into Settings → Panel → Security → Administrator IP allow-list: the editor tells you which address the API sees for you. It must be your real address, not the proxy's (otherwise
TRUST_PROXYis wrong). - Node agents use the same HTTPS URL as the panel; see Connect a node.
- If you use object storage, its endpoint is reachable from nodes and browsers, with TLS outside private networks.
