Files
config-public/server/app/webapp/docker-compose.yml
T
Lucas WintherandClaude Opus 5.5 665ac7d52f Render stack secrets from OpenBao in compose_stack
stack_secrets reads KV v2 on the target host and writes the stack's .env at
0600, failing loudly on a sealed vault, a bad token, a missing field or an
unsafe value. Adds an example OpenBao stack on app and moves webapp onto it;
metrics keeps a hand-placed .env.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 15:15:04 +02:00

60 lines
2.1 KiB
YAML

# A database-backed application: the stack that needs more than "sync and up".
#
# Every credential comes from .env, with no defaults. `${VAR:?message}` makes
# Compose refuse to start and say which variable is missing, which is strictly
# better than booting with an empty password. .env is never synced from this
# repository: the compose_stack role renders it on the host from OpenBao, from
# the stack_secrets in ansible/playbooks/webapp.yml.
services:
db:
container_name: webapp-db
image: postgres:17-alpine
restart: unless-stopped
# ./pgdata is deliberately NOT pre-created by the playbook: Postgres refuses
# to start unless its data directory is 0700 or 0750, and the image gets that
# right on first start. See "Common mistakes" in skills/adding-a-stack.
volumes:
- ./pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: webapp
POSTGRES_USER: webapp
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?missing from .env; see stack_secrets in webapp.yml}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U webapp"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
web:
container_name: webapp
# Built from the payload rather than pulled. stack_build in the playbook
# decides when a rebuild happens: on an update run, not on every deploy.
build:
context: ./app
image: example/webapp:local
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
DATABASE_URL: postgres://webapp:${POSTGRES_PASSWORD:?missing from .env; see stack_secrets in webapp.yml}@db:5432/webapp
SECRET_KEY: ${SECRET_KEY:?missing from .env; see stack_secrets in webapp.yml}
# Set by the role to stack_dest, so a path handed to a sibling container is
# the path on the host and not wherever the SSH session happened to land.
UPLOAD_HOST_DIR: ${PWD}/uploads
VIRTUAL_HOST: app.example.com
VIRTUAL_PORT: "8080"
LETSENCRYPT_HOST: app.example.com
volumes:
- ./uploads:/var/lib/webapp/uploads
networks:
- backend
- proxy-net
networks:
backend:
proxy-net:
external: true