Both the frontend and backend sit behind their own Nginx container that handles TLS. Only the Nginx containers are exposed externally — the app containers talk to each other on the internal Docker network.
End users
|
HTTPS :443
|
+------------------+
| nginx-frontend | TLS termination
+------------------+
|
HTTP :5000
|
+------------------+
| Flask frontend | web UI, auth, admin
+------------------+
|
(HTTPS to backend URL)
|
+------------------+
| nginx-backend | TLS termination
+------------------+
|
HTTP :8000
|
+------------------+
| FastAPI backend | forecasting, agents, LLM
+------------------+
Everything runs on one host. This is the default and what most people want.
./scripts/build_containers.sh --singleThat uses docker/docker-compose.yml and brings up all four containers. The frontend talks to the backend at https://nginx-backend:8443 over the internal Docker network.
Verify it's up:
curl -k https://localhost/auth/login # should return 200
curl -k https://localhost:8443/health # should return {"status":"ok"}If you want the frontend on one machine and the backend on another, you run each side separately.
./scripts/build_containers.sh --distributed --role backendThis uses docker/docker-compose.backend.yml and brings up just the backend and its Nginx proxy. The backend Nginx listens on port 8443.
./scripts/build_containers.sh --distributed --role frontendThis uses docker/docker-compose.distributed.yml as an override and drops
the backend and nginx-backend services. After the frontend starts, log in and
configure the backend URL, SSL verification setting, username, and key under
Admin → API Config.
If no certificate exists, the Nginx entrypoint generates one automatically using openssl req -x509. The cert is valid for 365 days and includes SANs for SSL_DOMAIN, localhost, and 127.0.0.1.
Certificates are stored in:
data_forecaster/certs/frontend/server.crtandserver.keydata_forecaster/certs/backend/server.crtandserver.key
Existing certificates are never overwritten. If you want a fresh one, delete the files and restart.
Drop your server.crt and server.key into the certs/frontend/ or certs/backend/ directories before starting the containers. The entrypoint will detect them and skip generation.
Set SSL_DOMAIN in your shell when starting Compose to match your hostname:
SSL_DOMAIN=forecaster.example.comThis becomes the CN and primary SAN on the generated certificate.
The frontend talks to the backend over HTTPS. Configure whether the frontend verifies the backend certificate under Admin → API Config.
Turn verification off for the default self-signed certificate, and turn it on when the backend uses a CA-signed certificate.
| Variable | Used by | Default | Purpose |
|---|---|---|---|
SSL_DOMAIN |
nginx | localhost |
CN/SAN for self-signed certs |
HTTP_PORT |
nginx-frontend | 80 |
HTTP port (redirects to HTTPS) |
FRONTEND_HTTPS_PORT |
nginx-frontend | 443 |
Frontend HTTPS port |
BACKEND_HTTPS_PORT |
nginx-backend | 8443 |
Backend HTTPS port |
CORS_ALLOWED_ORIGINS |
backend | http://localhost:5000,... |
Comma-separated allowed origins |
FLASK_ENV |
frontend | production in Compose |
Flask runtime mode |
The frontend stores the active backend URL, SSL verification setting, username, and encrypted key in its SQLite database via Admin → API Config.
scripts/build_containers.sh is a wrapper around docker-compose so you don't have to remember the file paths:
# Single-machine
./scripts/build_containers.sh --single
# Distributed — frontend host
./scripts/build_containers.sh --distributed --role frontend
# Distributed — backend host
./scripts/build_containers.sh --distributed --role backend
# Other actions
./scripts/build_containers.sh --single --down # stop everything
./scripts/build_containers.sh --single --logs # tail logs
./scripts/build_containers.sh --single --no-build # up without rebuildingSSL_ERROR_RX_RECORD_TOO_LONG — The Nginx config is missing the ssl keyword on the listen directive. This was a bug in an earlier version; make sure you're using the current docker/nginx/conf.d/*.conf.template files.
Frontend can't reach backend (401) — Check that the API credentials match. If you rotated the key on the backend, update it in Admin → API Config on the frontend.
Frontend can't reach backend (SSL error) — Disable SSL verification under Admin → API Config when using the default self-signed backend certificate.
Backend healthcheck fails on startup — The backend takes ~25 seconds to initialize (ChromaDB + LLM setup). The healthcheck has a 40-second start period, but if your machine is slow, increase start_period in docker-compose.yml.
Stale database after changing backend credentials — Rotate or create the backend API user from Admin → API Keys, then update Admin → API Config. For a full reset:
docker compose down -v
rm -f data_forecaster/data/backend.db
docker compose up -d --build