build: run the app and streaming from one compose file

The app, session manager and streamer are built from source by a single
docker-compose.yml. Streaming is the opt-in "streaming" profile, enabled
by setting STREAMING_API_TOKEN. Replaces the separate production, dev and
streaming compose files.
This commit is contained in:
2026-10-13 19:22:31 -07:00
parent 05db4313ae
commit 70f3421418
6 changed files with 74 additions and 181 deletions
+12 -12
View File
@@ -1,8 +1,5 @@
# Flashpoint Web - Environment Template
# Copy to .env and fill in required values.
#
# Production: docker compose up -d
# Development: docker compose -f docker-compose.dev.yml up -d --build
# Dotcom Arcade - Environment Template
# Copy to .env and fill in required values, then: docker compose up -d --build
# ---------------------------------------------------------------------------
# Required
@@ -11,9 +8,9 @@ FLASHPOINT_HOST_PATH=/path/to/Flashpoint
JWT_SECRET=replace-with-a-secure-random-string
# ---------------------------------------------------------------------------
# Container Image (production only)
# Container Images
# ---------------------------------------------------------------------------
# Override image tag (image from Docker Hub: darkraise/flashpoint-web)
# Tag for the locally built images
# IMAGE_TAG=latest
# ---------------------------------------------------------------------------
@@ -43,7 +40,7 @@ LOG_LEVEL=info
OTEL_ENABLED=false
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
# OTEL_API_KEY=your-api-key-here
OTEL_SERVICE_NAME=flashpoint-web
OTEL_SERVICE_NAME=dotcom-arcade
OTEL_TRACES_ENABLED=true
OTEL_METRICS_ENABLED=true
# OTEL_METRICS_EXPORT_INTERVAL=60000
@@ -105,13 +102,16 @@ ENABLE_CACHE_PREWARM=true
# ---------------------------------------------------------------------------
# HOME_RECENT_HOURS=24
# ENABLE_CGI=false
# Streamed play for games that can't run in a browser, such as Java applets.
# Off unless both are set. See docs/09-deployment/environment-variables.md.
# STREAMING_API_URL=http://flashpoint-session-manager:8080
# Streamed play for games that can't run in a browser (Java, Shockwave, the
# original Flash Player, Windows games). Set a token (e.g. `openssl rand -hex 32`)
# and enable the profile. See docs/10-features/13-streaming.md.
# COMPOSE_PROFILES=streaming
# STREAMING_API_TOKEN=
# STREAM_PORT=8081
# MAX_SESSIONS=4
# Sign in users an authenticating reverse proxy (e.g. Authentik forward auth)
# names in a header. Off unless TRUSTED_HEADER_USERNAME and TRUSTED_PROXIES are
# both set. See docs/09-deployment/environment-variables.md.
# both set. See docs/10-features/14-proxy-sign-in.md.
# TRUSTED_HEADER_USERNAME=X-authentik-username
# TRUSTED_HEADER_EMAIL=X-authentik-email
# TRUSTED_PROXIES=192.0.2.10
-98
View File
@@ -1,98 +0,0 @@
# =============================================================================
# Flashpoint Web - Development Docker Compose
# =============================================================================
# Builds the single API + UI image locally from source.
#
# Usage:
# docker compose -f docker-compose.dev.yml up -d --build
#
# View logs:
# docker compose -f docker-compose.dev.yml logs -f
#
# User permissions:
# Set PUID/PGID to match your host user (run 'id -u' and 'id -g' to find)
# This ensures bind-mounted volumes have correct ownership
# =============================================================================
services:
flashpoint-web:
build:
context: .
dockerfile: ./Dockerfile
image: flashpoint-web:dev
container_name: flashpoint-web
restart: unless-stopped
ports:
# Serves both the UI and the API (/api, /game-proxy, /game-zip) on one port
- "${WEB_PORT:-80}:3100"
volumes:
# Read-write: the app records downloaded state in flashpoint.sqlite and
# writes downloaded game data under Data/Games.
- ${FLASHPOINT_HOST_PATH:?FLASHPOINT_HOST_PATH is required}:/data/flashpoint
# Holds user.db and the installed Ruffle. Without this mount an in-app
# Ruffle update is lost the next time the container is recreated.
- backend-db:/app/data
- ${LOGS_PATH:-./logs}:/app/logs
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- NODE_ENV=${NODE_ENV:-development}
- SERVE_FRONTEND=true
# Matches the read-only mount above. Set explicitly because the backend's
# fallback only points here when NODE_ENV=production.
- FLASHPOINT_PATH=/data/flashpoint
# Same reason as FLASHPOINT_PATH above: this container runs
# NODE_ENV=development, so the production default would put Ruffle outside
# the data volume and lose every update on recreate.
- RUFFLE_DATA_PATH=/app/data/ruffle
- TZ=${TZ:-UTC}
- DOMAIN=${DOMAIN:-http://localhost:${WEB_PORT:-80}}
- LOG_LEVEL=${LOG_LEVEL:-info}
# File I/O parallelism: images and ZIP reads run on libuv's threadpool,
# whose default of 4 throttles every filesystem request in the process.
- UV_THREADPOOL_SIZE=${UV_THREADPOOL_SIZE:-16}
- JWT_SECRET=${JWT_SECRET:?JWT_SECRET is required}
- ENABLE_LOCAL_DB_COPY=${ENABLE_LOCAL_DB_COPY:-false}
- SQLITE_CACHE_SIZE=${SQLITE_CACHE_SIZE:--64000}
- SQLITE_MMAP_SIZE=${SQLITE_MMAP_SIZE:-268435456}
- ENABLE_CACHE_PREWARM=${ENABLE_CACHE_PREWARM:-true}
# Auth & rate limiting
- JWT_EXPIRES_IN=${JWT_EXPIRES_IN:-1h}
- BCRYPT_SALT_ROUNDS=${BCRYPT_SALT_ROUNDS:-10}
- RATE_LIMIT_WINDOW_MS=${RATE_LIMIT_WINDOW_MS:-60000}
- RATE_LIMIT_MAX_REQUESTS=${RATE_LIMIT_MAX_REQUESTS:-100}
# Application
- HOME_RECENT_HOURS=${HOME_RECENT_HOURS:-24}
- ENABLE_CGI=${ENABLE_CGI:-false}
# Streamed play for games that can't run in a browser (off unless both are set)
- STREAMING_API_URL=${STREAMING_API_URL:-}
- STREAMING_API_TOKEN=${STREAMING_API_TOKEN:-}
# Sign in users named by an authenticating reverse proxy (off unless both are set)
- TRUSTED_HEADER_USERNAME=${TRUSTED_HEADER_USERNAME:-}
- TRUSTED_HEADER_EMAIL=${TRUSTED_HEADER_EMAIL:-}
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-}
# OpenTelemetry
- OTEL_ENABLED=${OTEL_ENABLED:-false}
- OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-}
- OTEL_API_KEY=${OTEL_API_KEY:-}
- OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-flashpoint-web}
- OTEL_TRACES_ENABLED=${OTEL_TRACES_ENABLED:-true}
- OTEL_METRICS_ENABLED=${OTEL_METRICS_ENABLED:-true}
- OTEL_METRICS_EXPORT_INTERVAL=${OTEL_METRICS_EXPORT_INTERVAL:-60000}
- OTEL_LOG_LEVEL=${OTEL_LOG_LEVEL:-info}
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:3100/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
- flashpoint-network
networks:
flashpoint-network:
driver: bridge
volumes:
backend-db:
driver: local
+60 -20
View File
@@ -1,25 +1,25 @@
# =============================================================================
# Flashpoint Web - Production Docker Compose
# Dotcom Arcade
# =============================================================================
# Single image serving both the API and the web UI.
# Uses a pre-built image from the container registry.
# The app serves the UI and API. With the "streaming" profile, a session
# manager also streams games that can't run in a browser (Java, Shockwave,
# Flash Player, Windows games), one container per player.
#
# Usage:
# 1. Copy .env.example to .env and configure required variables
# 2. docker compose up -d
# 1. Copy .env.example to .env and set the required variables
# 2. docker compose up -d --build
# 3. For streaming, set STREAMING_API_TOKEN and COMPOSE_PROFILES=streaming in
# .env, then run `docker compose up -d --build` again
#
# For local development with image building, use:
# docker compose -f docker-compose.dev.yml up -d --build
#
# User permissions:
# Set PUID/PGID to match your host user (run 'id -u' and 'id -g' to find)
# This ensures bind-mounted volumes have correct ownership
# Set PUID/PGID to your host user (`id -u`, `id -g`) so bind-mounted volumes
# get the right ownership.
# =============================================================================
services:
flashpoint-web:
image: darkraise/flashpoint-web:${IMAGE_TAG:-latest}
container_name: flashpoint-web
app:
build: .
image: dotcom-arcade:${IMAGE_TAG:-latest}
container_name: dotcom-arcade
restart: unless-stopped
ports:
# Serves both the UI and the API (/api, /game-proxy, /game-zip) on one port
@@ -56,8 +56,8 @@ services:
# Application
- HOME_RECENT_HOURS=${HOME_RECENT_HOURS:-24}
- ENABLE_CGI=${ENABLE_CGI:-false}
# Streamed play for games that can't run in a browser (off unless both are set)
- STREAMING_API_URL=${STREAMING_API_URL:-}
# Streamed play for games that can't run in a browser (off unless the token is set)
- STREAMING_API_URL=${STREAMING_API_URL:-http://session-manager:8080}
- STREAMING_API_TOKEN=${STREAMING_API_TOKEN:-}
# Sign in users named by an authenticating reverse proxy (off unless both are set)
- TRUSTED_HEADER_USERNAME=${TRUSTED_HEADER_USERNAME:-}
@@ -67,7 +67,7 @@ services:
- OTEL_ENABLED=${OTEL_ENABLED:-false}
- OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-}
- OTEL_API_KEY=${OTEL_API_KEY:-}
- OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-flashpoint-web}
- OTEL_SERVICE_NAME=${OTEL_SERVICE_NAME:-dotcom-arcade}
- OTEL_TRACES_ENABLED=${OTEL_TRACES_ENABLED:-true}
- OTEL_METRICS_ENABLED=${OTEL_METRICS_ENABLED:-true}
- OTEL_METRICS_EXPORT_INTERVAL=${OTEL_METRICS_EXPORT_INTERVAL:-60000}
@@ -94,8 +94,48 @@ services:
cpus: "0.5"
memory: 512M
networks:
- flashpoint-network
- arcade
# Starts a streamer container per player and proxies its stream at /stream/
session-manager:
profiles: [streaming]
build: streaming/session-manager
image: dotcom-arcade-session-manager:${IMAGE_TAG:-latest}
container_name: dotcom-arcade-session-manager
restart: unless-stopped
ports:
# Route /stream/ on the site to this port (see streaming/README.md)
- "${STREAM_PORT:-8081}:8081"
volumes:
# Starts and removes streamer containers. Docker socket access is
# effectively root on the host.
- /var/run/docker.sock:/var/run/docker.sock
- ${FLASHPOINT_HOST_PATH:?FLASHPOINT_HOST_PATH is required}:/flashpoint:ro
environment:
- FLASHPOINT_HOST_PATH
# The session manager refuses to start without it
- API_TOKEN=${STREAMING_API_TOKEN:-}
- STREAMER_IMAGE=dotcom-arcade-streamer:${IMAGE_TAG:-latest}
- STREAMER_NETWORK=dotcom-arcade-streams
- MAX_SESSIONS=${MAX_SESSIONS:-4}
- STREAM_PLATFORMS=${STREAM_PLATFORMS:-Java,Shockwave,Flash}
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
networks:
- arcade
- streams
# The image the session manager runs per player; built here, never started by compose
streamer:
profiles: [streaming]
build: streaming/streamer
image: dotcom-arcade-streamer:${IMAGE_TAG:-latest}
scale: 0
networks:
flashpoint-network:
driver: bridge
arcade:
name: dotcom-arcade
# Streamer containers: reachable only from the session manager, no internet access
streams:
name: dotcom-arcade-streams
internal: true
-30
View File
@@ -1,30 +0,0 @@
services:
session-manager:
build: session-manager
container_name: flashpoint-session-manager
restart: unless-stopped
ports:
- "${STREAM_PORT:-8081}:8081"
volumes:
# Starts and removes streamer containers
- /var/run/docker.sock:/var/run/docker.sock
- ${FLASHPOINT_HOST_PATH:?FLASHPOINT_HOST_PATH is required}:/flashpoint:ro
environment:
- FLASHPOINT_HOST_PATH
- API_TOKEN=${API_TOKEN:?API_TOKEN is required}
- MAX_SESSIONS=${MAX_SESSIONS:-4}
- STREAM_PLATFORMS=${STREAM_PLATFORMS:-Java,Shockwave,Flash}
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
networks:
- flashpoint
- streams
networks:
# Shared with flashpoint-web, which calls the internal API on port 8080
flashpoint:
name: flashpoint
# Streamer containers: reachable only from the session manager, no internet access
streams:
name: flashpoint-streams
internal: true
+2 -2
View File
@@ -12,8 +12,8 @@ function env(name: string, fallback?: string): string {
}
const driver = new DockerDriver({
image: env('STREAMER_IMAGE', 'flashpoint-streamer'),
network: env('STREAMER_NETWORK', 'flashpoint-streams'),
image: env('STREAMER_IMAGE', 'dotcom-arcade-streamer'),
network: env('STREAMER_NETWORK', 'dotcom-arcade-streams'),
flashpointHostPath: env('FLASHPOINT_HOST_PATH'),
uid: Number(env('PUID', '1000')),
gid: Number(env('PGID', '1000')),
-19
View File
@@ -1,19 +0,0 @@
services:
flashpoint-streamer:
build: .
container_name: flashpoint-streamer
shm_size: 1gb
ports:
- "${STREAMER_PORT:-3001}:3001"
volumes:
- ${FLASHPOINT_HOST_PATH:?FLASHPOINT_HOST_PATH is required}:/flashpoint:ro
environment:
- PUID=${PUID:-1000}
- PGID=${PGID:-1000}
- GAME_ID=${GAME_ID:-247a4c93-c252-49c8-8bc9-fb43d5c039df}
# Lock the display to the game window's size; the browser scales it to fit
- SELKIES_MANUAL_WIDTH=${GAME_WIDTH:-472}
- SELKIES_MANUAL_HEIGHT=${GAME_HEIGHT:-354}
- RESTART_APP=true
- NO_DECOR=true
- TITLE=Flashpoint