Security & TLS

Terminate TLS in front of a self-hosted instance and lock down its secrets

Neither the frontend nor the backend terminates TLS. In production you put a reverse proxy in front of the stack to handle certificates, then point the frontend at the HTTPS endpoint. This page covers both, plus where production secrets should live.

Terminate TLS with a reverse proxy

Run Caddy, nginx, or Traefik in front of the stack. Caddy is the shortest path because it issues and renews Let’s Encrypt certificates on its own:

# Caddyfile
app.yourcompany.com  { reverse_proxy localhost:3000 }
api.yourcompany.com  { reverse_proxy localhost:8000 }

Put the proxy in front

Point the proxy at the frontend on localhost:3000 and the backend on localhost:8000. The full port list is in Requirements.

Point the frontend at HTTPS

Set VITE_HOST_API=https://api.yourcompany.com in .env. The frontend container reads it on start and writes it into config.js, so no rebuild is needed.

Restart the frontend

docker compose up -d frontend

Warning

VITE_HOST_API is applied when the frontend container starts, not at build time. If the browser still calls the old host after you change it, the container wasn’t recreated: rerun docker compose up -d frontend.

Keep secrets out of the compose file

For anything past a single trial host, store secrets in a dedicated manager instead of a plain .env:

  • AWS Secrets Manager
  • HashiCorp Vault
  • GCP Secret Manager

Rotate the dev-only default secrets from the Checklist first, then move them into the manager and inject them at deploy time.

Isolate the code executor

code-executor runs with privileged: true so it can sandbox evaluation code. Keep it on a host you control, an EC2 or GCE instance, never a managed-container platform that can’t grant that flag.

Dive deeper

Was this page helpful?

Questions & Discussion