wrolpi/docker-compose.yml
Roland fbb71e012d Replace nginx with Caddy for TLS termination and reverse proxying.
- Replace nginx with Caddy as the web server for both Docker and native
  (RPi/Debian) deployments. Caddy handles HTTPS termination, reverse
  proxying to all services (API, React app, Controller, Kiwix, Help, Map),
  and serves the media/download file browsers.
- Generate a Root CA and signed leaf certificates for HTTPS. The Root CA
  uses Name Constraints to restrict signing to local addresses only
  (.local, localhost, and RFC 1918 private IP ranges), mitigating MITM
  risk if the CA key is compromised.
- Add an HTTP landing page that guides users through one-time CA
  certificate installation on iOS, Android, macOS, Windows, Linux, and
  Firefox, with auto-redirect when the cert is already trusted.
- Add trailing-slash redirects for /controller, /docs, /media, and
  /download so bare paths don't fall through to the React catch-all.
- Add a Root CA download link on the Settings page under Configs.
- Update help.sh diagnostics for IPv6 listener detection and HTTP/2
  status codes.
- Remove all nginx config files and the https_proxy Docker container.
- Bump wrolpi-help submodule with certificate documentation.
2026-03-07 18:48:44 -07:00

176 lines
5.2 KiB
YAML

# Development containers, these should only be used if you are developing.
version: '3'
services:
db: # https://github.com/docker-library/docs/tree/master/postgres
image: postgres:12
environment:
- POSTGRES_DB=wrolpi
- POSTGRES_PASSWORD=wrolpi
ports:
- "5432:5432"
healthcheck:
test: [ 'CMD-SHELL', 'pg_isready -U postgres' ]
interval: 10s
volumes:
- ./pg_data:/var/lib/postgresql/data
controller: # WROLPi Controller Service
build:
context: .
dockerfile: docker/controller/Dockerfile
restart: unless-stopped
ports:
- "8087:8087"
volumes:
# Controller code (for development hot-reload)
- ./controller:/app/controller
# Docker socket for container management
- /var/run/docker.sock:/var/run/docker.sock
# Host system info (read-only)
- /proc:/host/proc:ro
- /sys:/host/sys:ro
# Config directory
- ${MEDIA_DIRECTORY:-./test}/config:/media/wrolpi/config
environment:
- DOCKERIZED=true
- MEDIA_DIRECTORY=/media/wrolpi
# Override CMD to enable auto-reload for development
command: ["uvicorn", "controller.main:app", "--host", "0.0.0.0", "--port", "8087", "--reload", "--reload-dir", "/app/controller"]
healthcheck:
test: [ 'CMD-SHELL', 'curl -f http://127.0.0.1:8087/api/health || exit 1' ]
interval: 30s
timeout: 5s
start_period: 10s
retries: 3
api:
depends_on:
db:
condition: service_healthy
controller:
condition: service_started
build:
context: .
dockerfile: docker/api/Dockerfile
environment:
# Sanic 25.x wants 'spawn' but our code uses 'fork' for multiprocessing.
# This tells Sanic to accept the existing start method.
- SANIC_START_METHOD_SET=1
volumes:
- './main.py:/opt/wrolpi/main.py'
- './wrolpi:/opt/wrolpi/wrolpi'
- './modules:/opt/wrolpi/modules'
- './scripts:/opt/wrolpi/scripts'
- './test:/opt/wrolpi/test'
- './test:/media/wrolpi'
- './alembic:/opt/wrolpi/alembic'
- './alembic.ini:/opt/wrolpi/alembic.ini'
ports:
- ${REACT_APP_API-0.0.0.0:8081}:8081
user: '${UID-1000}:${GID-1000}'
healthcheck:
test: [ 'CMD-SHELL', 'curl http://127.0.0.1:8081/api/echo' ]
interval: 2m
archive: # Python/Sanic wrapper around Singlefile and Readability.
build:
context: .
dockerfile: docker/archive/Dockerfile
volumes:
- './docker/archive/main.py:/app/main.py'
ports:
- '8083:8080'
healthcheck:
test: [ 'CMD-SHELL', 'curl http://127.0.0.1:8080/' ]
interval: 2m
app: # React App
depends_on:
- api
build:
context: .
dockerfile: docker/app/Dockerfile
volumes:
- './app/public:/app/public'
- './app/src:/app/src'
- './app/package.json:/app/package.json'
- '.env:/app/.env'
command: 'npm run start'
stdin_open: true
healthcheck:
test: [ 'CMD-SHELL', 'curl http://127.0.0.1:3000' ]
interval: 1m
user: '${UID-1000}:${GID-1000}'
environment:
# Force React to use Caddy port to connect to it's websocket.
- WDS_SOCKET_PORT=0
map: # https://github.com/Overv/openstreetmap-tile-server
image: overv/openstreetmap-tile-server:v1.6.0
volumes:
- 'openstreetmap-data:/var/lib/postgresql/12/main'
- 'openstreetmap-rendered-tiles:/var/lib/mod_tile'
- './modules/map/leaflet.html:/var/www/html/index.html'
- './modules/map/leaflet.js:/var/www/html/leaflet.js'
- './modules/map/leaflet.css:/var/www/html/leaflet.css'
command: 'run'
shm_size: 1g # Increase shared size to render large map tiles
healthcheck:
test: [ 'CMD-SHELL', 'curl http://127.0.0.1:80' ]
interval: 1m
web: # Caddy reverse proxy - handles HTTPS for all services.
depends_on:
- app
- zim
- help
- map
build:
context: .
dockerfile: docker/web/Dockerfile
ports:
- ${WEB_HOST-0.0.0.0}:${WEB_PORT-8080}:80
- ${WEB_HOST-0.0.0.0}:${WEB_HTTPS_PORT-8443}:443
- '8084:8084'
- '8085:8085'
- '8086:8086'
volumes:
- './docker/web/Caddyfile:/etc/caddy/Caddyfile'
- './icon.ico:/etc/caddy/favicon.ico'
- './icon.png:/etc/caddy/icon.png'
- './test:/opt/media'
environment:
- MEDIA_DIRECTORY=/opt/media
# Set EXTRA_SANS to include the host's LAN IP in the TLS certificate.
# Example: EXTRA_SANS=IP:10.0.0.5
- EXTRA_SANS=${EXTRA_SANS:-}
healthcheck:
test: [ 'CMD-SHELL', 'wget --spider http://127.0.0.1:80 || exit 1' ]
interval: 1m
zim: # kiwix-serve
build:
context: .
dockerfile: docker/zim/Dockerfile
volumes:
- './test:/media/wrolpi'
- './docker/zim/entrypoint.sh:/entrypoint.sh'
healthcheck:
test: [ 'CMD-SHELL', 'curl http://127.0.0.1:80' ]
interval: 1m
help: # The WROLPi Help documentation.
build:
context: .
dockerfile: docker/help/Dockerfile
volumes:
- './docker/help/wrolpi-help:/opt/wrolpi-help'
healthcheck:
test: [ 'CMD-SHELL', 'curl http://127.0.0.1:8086' ]
interval: 1m
volumes:
openstreetmap-data:
external: true
openstreetmap-rendered-tiles:
external: true