A proxy that sets the username header twice, as when Authentik's nginx snippet and the documented lines are both present, made Node join the values into "brad, brad" and create an account of that name instead of signing in brad. Read each occurrence separately: identical repeats count once, and conflicting ones are refused. The docs now note Authentik's snippet already sets the headers.
14 KiB
Environment Variables
Configuration reference for all Flashpoint Web services.
Backend Variables
Location: backend/.env (local development)
Server:
| Variable | Default | Description |
|---|---|---|
NODE_ENV |
development | Environment: development, production, test |
Note: Port (3100) and bind address (0.0.0.0) are hardcoded in the backend. In Docker, use
API_PORTto map a different host port to the container.
Paths:
| Variable | Default | Description |
|---|---|---|
FLASHPOINT_PATH |
D:/Flashpoint (dev), /data/flashpoint (prod) |
Root Flashpoint directory. All other paths auto-derived. Edition (Infinity/Ultimate) auto-detected from version.txt. |
FLASHPOINT_GAMES_PATH |
<FLASHPOINT_PATH>/Data/Games |
Override game ZIP directory (rarely needed). |
APP_VERSION |
set by the Docker build | Release version the server reports on Settings → Update. Baked into the official image from the release tag; set it by hand for a non-Docker deployment, or update checks stay off. |
Authentication & Security:
| Variable | Default | Description |
|---|---|---|
JWT_SECRET |
auto-generated (dev) | Secret for JWT signing (required in production) |
JWT_EXPIRES_IN |
1h | Access token expiration (15m, 1h, 7d, etc.) |
BCRYPT_SALT_ROUNDS |
10 | Password hash cost (higher = more secure but slower) |
DOMAIN |
http://localhost:5173 | Allowed CORS origin(s), comma-separated (see below) |
COOKIE_SECURE |
auto | Secure flag on auth cookies: auto, true, false |
UV_THREADPOOL_SIZE |
16 | Concurrent file I/O threads (Node's own default is 4) |
DB_WORKER_COUNT |
4 | Read-only SQLite query workers (1-16) |
Generate secure JWT secret:
openssl rand -hex 64
COOKIE_SECURE — auth cookies over HTTP and HTTPS:
Browsers discard a cookie marked Secure when it arrives over plain HTTP, which
logs users straight back out. auto therefore decides per request: cookies are
marked Secure only on connections that actually used TLS, so one deployment can
serve a LAN over HTTP and the internet over HTTPS at the same time.
Detection reads X-Forwarded-Proto, which is trusted only from a proxy. Set
COOKIE_SECURE=true if your TLS-terminating proxy does not send that header, and
false only if you deliberately want the flag off everywhere.
DOMAIN — allowed origins:
DOMAIN accepts one origin or a comma-separated list, so a single deployment can
be reached over several addresses:
DOMAIN=http://192.168.0.118,https://flashpoint.example.com
The first entry is the primary origin, used where a single value is required. Requests from any listed origin are accepted, as are requests from hostnames in the domains table.
Two notes that save debugging time:
- Same-origin requests are always allowed, so
SERVE_FRONTEND=truedeployments work at any address without listing it here. You only needDOMAINwhen the UI is served from a different origin than the API, or behind a reverse proxy that rewrites theHostheader. - Default ports are normalized away:
http://host:80andhttp://hostare treated as the same origin, as arehttps://host:443andhttps://host. Non-default ports must be written out, for examplehttp://host:8080.
Rate Limiting:
| Variable | Default | Description |
|---|---|---|
RATE_LIMIT_WINDOW_MS |
60000 | Time window (ms) |
RATE_LIMIT_MAX_REQUESTS |
100 | Max requests per window |
Logging:
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL |
info | Level: error, warn, info, debug |
LOG_FILE |
/app/logs/backend.log (prod) |
Log file path (unset in dev = stdout only) |
Database Performance:
| Variable | Default | Description |
|---|---|---|
ENABLE_LOCAL_DB_COPY |
false | Copy flashpoint.sqlite locally (for network storage SMB/NFS) |
SQLITE_CACHE_SIZE |
-64000 | SQLite page cache size (negative = KB, -64000 = 64MB) |
SQLITE_MMAP_SIZE |
268435456 | Memory-mapped I/O size in bytes (256MB) |
ENABLE_CACHE_PREWARM |
true | Pre-load common queries on startup |
Game Content Serving:
| Variable | Default | Description |
|---|---|---|
ENABLE_CGI |
false | Enable PHP CGI execution for legacy game content |
HOME_RECENT_HOURS |
24 | Hours to look back for "recently added" games |
Frontend Serving:
The backend serves the built React UI in the single-image deployment, so the app and API share one origin.
| Variable | Default | Description |
|---|---|---|
SERVE_FRONTEND |
true in production, else false | Serve the built frontend and SPA fallback from the backend |
FRONTEND_DIST_PATH |
<backend>/../frontend/dist |
Location of the built frontend (rarely needed) |
RUFFLE_DATA_PATH |
/app/data/ruffle in production |
Where Ruffle is installed. Must sit on a mounted volume, or an in-app update is lost when the container is recreated |
Streaming:
Games that can't run in a browser, such as Java applets, can be streamed from a
server-side container by a separate session manager (flashpoint-ultimate-server).
The backend asks it which games are streamable and starts sessions for players.
Browsers reach each stream at /stream/<id>/ on this site, so the reverse proxy
in front of flashpoint-web must route /stream/ to the session manager,
including WebSocket upgrades. Saves for streamed games are kept in each
browser's IndexedDB.
| Variable | Default | Description |
|---|---|---|
STREAMING_API_URL |
- | Session manager's internal API, e.g. http://flashpoint-session-manager:8080 |
STREAMING_API_TOKEN |
- | Token the session manager expects. Streaming is off unless both are set |
Trusted Header Login:
When a reverse proxy such as Authentik (forward auth) authenticates users in
front of flashpoint-web, it can pass the signed-in username in a header so
users don't log in twice. The backend believes the header only on connections
from TRUSTED_PROXIES, checked against the connection's own address, not
X-Forwarded-For. The proxy must always set the header, overwriting anything a
client sends, and flashpoint-web must not be reachable from untrusted networks
except through it.
Users are matched by username, so an existing account of that name is signed in; otherwise an account is created (the first one as admin, as with registration). New accounts get a random password. While signed in through the proxy, users can set a password from Settings without knowing the current one, then log in with it when reaching flashpoint-web without the proxy, such as on a LAN.
| Variable | Default | Description |
|---|---|---|
TRUSTED_HEADER_USERNAME |
- | Header holding the username, e.g. X-authentik-username |
TRUSTED_HEADER_EMAIL |
- | Optional header holding the email used for new accounts |
TRUSTED_PROXIES |
- | Comma-separated proxy addresses or CIDR ranges allowed to set the header |
With nginx and Authentik's forward auth, each protected location needs these
lines once. Authentik's generated nginx snippet already includes them; adding
them again sends each header twice:
auth_request_set $authentik_username $upstream_http_x_authentik_username;
auth_request_set $authentik_email $upstream_http_x_authentik_email;
proxy_set_header X-authentik-username $authentik_username;
proxy_set_header X-authentik-email $authentik_email;
OpenTelemetry:
| Variable | Default | Description |
|---|---|---|
OTEL_ENABLED |
false | Enable distributed tracing and metrics |
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:4318 | OTLP collector endpoint |
OTEL_API_KEY |
- | API key for authentication |
OTEL_SERVICE_NAME |
flashpoint-web | Service name in traces/metrics |
OTEL_TRACES_ENABLED |
true | Enable trace export (when OTEL enabled) |
OTEL_METRICS_ENABLED |
true | Enable metrics export (when OTEL enabled) |
OTEL_METRICS_EXPORT_INTERVAL |
60000 | Metrics export interval (ms) |
OTEL_LOG_LEVEL |
info | OTEL SDK log level |
Frontend Variables
The frontend has no environment variables of its own. API calls use relative
paths (/api), so they resolve against whatever origin serves the app.
- Development: Vite dev server on port 5173 proxies
/apitohttp://localhost:3100 - Production: The backend serves the built UI and the API from the same origin
Docker Environment Variables
Location: .env in project root (used by docker-compose)
Required:
| Variable | Description |
|---|---|
FLASHPOINT_HOST_PATH |
Host path to Flashpoint installation (bind-mounted as ro) |
JWT_SECRET |
Secret for JWT signing (generate with openssl rand -hex 64) |
Port Mapping:
| Variable | Default | Description |
|---|---|---|
WEB_PORT |
80 | Host port mapped to the container (serves UI + API) |
Container Settings:
| Variable | Default | Description |
|---|---|---|
PUID |
1000 | Container user ID (match host user: id -u) |
PGID |
1000 | Container group ID (match host user: id -g) |
TZ |
UTC | Container timezone |
IMAGE_TAG |
latest | Docker image tag (production compose only) |
DATA_PATH |
./data | Host path for persistent data (production compose) |
LOGS_PATH |
./logs | Host path for log files |
All backend variables listed above are also passable via docker-compose. See
docker-compose.yml for the full list with defaults.
Docker Compose Setup
Create .env file:
cat > .env << EOF
FLASHPOINT_HOST_PATH=/path/to/flashpoint
JWT_SECRET=$(openssl rand -hex 64)
DOMAIN=https://flashpoint.example.com
WEB_PORT=80
LOG_LEVEL=warn
EOF
Start services:
docker compose up -d
Environment Templates
Development (backend/.env):
NODE_ENV=development
FLASHPOINT_PATH=D:/Flashpoint
JWT_SECRET=development-secret-change-in-production
DOMAIN=http://localhost:5173
RATE_LIMIT_MAX_REQUESTS=1000
LOG_LEVEL=debug
Production (.env for Docker):
FLASHPOINT_HOST_PATH=/data/flashpoint
JWT_SECRET=CHANGE-THIS-TO-A-RANDOM-64-CHARACTER-STRING
DOMAIN=https://flashpoint.example.com
WEB_PORT=80
LOG_LEVEL=warn
Validation and Defaults
Required Variables:
Backend (local dev):
FLASHPOINT_PATH(only this is required; others auto-derive)
Docker Production:
FLASHPOINT_HOST_PATH(must point to Flashpoint installation)JWT_SECRET(must be changed from default)
Verify configuration:
cd backend
node -e "require('dotenv').config(); console.log(process.env.FLASHPOINT_PATH)"
Security Best Practices
- Never commit .env files to version control
- Use strong JWT secrets (64+ characters) in production
- Restrict CORS origins to your domain only (no wildcards)
- Use HTTPS in production (update DOMAIN to https://)
- Limit exposed ports (don't expose all services)
- Rotate secrets periodically
- Use environment-specific files (.env.production, .env.development)
- Store secrets in secure management system (AWS Secrets Manager, HashiCorp Vault)
- Use read-only mounts for Flashpoint data in Docker