# Compose file using the prebuilt multi-arch image from GHCR # (published by .github/workflows/docker-publish.yml for amd64 + arm64). # No local build needed: # docker compose -f docker-compose.ghcr.yml up -d # Defaults to ghcr.io/d0linger/parkrr; override PARKRR_IMAGE only with an image # you trust. Pin a release with PARKRR_TAG=1.2 or immutable image content with # PARKRR_TAG=1.2@sha256: using the published image digest. # # IMPORTANT: the `app` service below is kept byte-for-byte in sync with the # `app` service in docker-compose.yml — same environment, volumes, ports and # healthcheck, only `build:` swapped for the GHCR `image:`. This standalone shape # is required for the single-file paste flows (Portainer web editor). The CI test # TestGHCRComposeParity fails the build if the two drift apart (finding H-11): # it used to silently miss the backup key, S3, SMTP, /backups and the proxy CIDRs. services: db: image: postgres:16-alpine@sha256:f4610795587492cd4fb887c2dc3de301b813278bb6f616992061141b5f15ac36 container_name: parkrr-db restart: unless-stopped environment: POSTGRES_USER: ${PARKRR_DB_USER:-parkrr} POSTGRES_PASSWORD: ${PARKRR_DB_PASSWORD:?PARKRR_DB_PASSWORD must be set} POSTGRES_DB: ${PARKRR_DB_NAME:-parkrr} volumes: - parkrr-db-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${PARKRR_DB_USER:-parkrr} -d ${PARKRR_DB_NAME:-parkrr}"] interval: 5s timeout: 5s retries: 10 networks: - parkrr-net app: image: ghcr.io/${PARKRR_IMAGE:-d0linger/parkrr}:${PARKRR_TAG:-latest} container_name: parkrr-app restart: unless-stopped depends_on: db: condition: service_healthy environment: PARKRR_LISTEN_ADDR: ":8080" # --- Database (bundled service) --- # Optional full URL for an EXTERNAL database; overrides the PARKRR_DB_* below. PARKRR_DATABASE_URL: ${PARKRR_DATABASE_URL:-} PARKRR_DB_HOST: db PARKRR_DB_PORT: "5432" PARKRR_DB_USER: ${PARKRR_DB_USER:-parkrr} PARKRR_DB_PASSWORD: ${PARKRR_DB_PASSWORD:?PARKRR_DB_PASSWORD must be set} PARKRR_DB_NAME: ${PARKRR_DB_NAME:-parkrr} PARKRR_DB_SSLMODE: ${PARKRR_DB_SSLMODE:-disable} # --- Admin bootstrap (ADMIN_PASSWORD required) --- PARKRR_ADMIN_USERNAME: ${PARKRR_ADMIN_USERNAME:-admin} PARKRR_ADMIN_EMAIL: ${PARKRR_ADMIN_EMAIL:-admin@example.com} PARKRR_ADMIN_PASSWORD: ${PARKRR_ADMIN_PASSWORD:?PARKRR_ADMIN_PASSWORD must be set} # --- Security (SESSION_SECRET required, min. 32 chars) --- PARKRR_SESSION_SECRET: ${PARKRR_SESSION_SECRET:?PARKRR_SESSION_SECRET must be set} PARKRR_SESSION_MAX_AGE: ${PARKRR_SESSION_MAX_AGE:-604800} PARKRR_SESSION_SLIDING: ${PARKRR_SESSION_SLIDING:-false} PARKRR_SESSION_ABSOLUTE_MAX_AGE: ${PARKRR_SESSION_ABSOLUTE_MAX_AGE:-7776000} PARKRR_SECURE_COOKIES: ${PARKRR_SECURE_COOKIES:-true} PARKRR_TRUSTED_PROXY: ${PARKRR_TRUSTED_PROXY:-false} # Required when PARKRR_TRUSTED_PROXY=true: the reverse-proxy IP range(s) whose # forwarded headers are trusted. Without it the app refuses to start (H-06). PARKRR_TRUSTED_PROXY_CIDRS: ${PARKRR_TRUSTED_PROXY_CIDRS:-} PARKRR_CHECK_BREACHED_PASSWORDS: ${PARKRR_CHECK_BREACHED_PASSWORDS:-true} PARKRR_CHECK_BREACHED_BOOTSTRAP_PASSWORDS: ${PARKRR_CHECK_BREACHED_BOOTSTRAP_PASSWORDS:-false} # --- Passkeys (WebAuthn): set RP_ID + ORIGINS to enable --- PARKRR_WEBAUTHN_RP_ID: ${PARKRR_WEBAUTHN_RP_ID:-} PARKRR_WEBAUTHN_RP_NAME: ${PARKRR_WEBAUTHN_RP_NAME:-Parkrr} PARKRR_WEBAUTHN_ORIGINS: ${PARKRR_WEBAUTHN_ORIGINS:-} # --- Zweiter Faktor erzwingen (Opt-in, Standard aus) --- PARKRR_REQUIRE_2FA: ${PARKRR_REQUIRE_2FA:-false} PARKRR_PASSKEY_ONLY: ${PARKRR_PASSKEY_ONLY:-false} # --- Ops --- # Geschaeftszeitzone: bestimmt, welcher Kalendertag gemeint ist. Leer = Zone # des Containers (meist UTC). PARKRR_TIMEZONE: ${PARKRR_TIMEZONE:-} # Automatischer Rechnungslauf als 5-Feld-Cron. LEER = AUS. PARKRR_AUTO_INVOICE_CRON: ${PARKRR_AUTO_INVOICE_CRON:-} # Steuerbereich: lesend pruefen; Schreibzugriffe nur nach expliziter Aktivierung. PARKRR_TAX_WRITES_ENABLED: ${PARKRR_TAX_WRITES_ENABLED:-false} PARKRR_TAX_EXPORT_MAX_RECEIPT_MB: ${PARKRR_TAX_EXPORT_MAX_RECEIPT_MB:-24} # Empfaenger fuer Betriebsalarme (fehlgeschlagene Sicherungen). Braucht SMTP. PARKRR_ALERT_EMAIL: ${PARKRR_ALERT_EMAIL:-} PARKRR_RATE_LIMIT_PER_MIN: ${PARKRR_RATE_LIMIT_PER_MIN:-600} PARKRR_AUDIT_RETENTION_DAYS: ${PARKRR_AUDIT_RETENTION_DAYS:-2555} PARKRR_AUDIT_RETENTION_SHORT_DAYS: ${PARKRR_AUDIT_RETENTION_SHORT_DAYS:-365} # Encrypted backups. Set PARKRR_BACKUP_KEY to enable them (on-demand download # + scheduled). Scheduled backups default to the /backups volume below, which # lives next to the DB volume — convenient, but a copy beside the database it # protects is not an off-site backup: also configure S3 for 3-2-1. The # schedule (cron) and retention are edited in the Backup tab, not via env. # Large backup temp files (S3 upload/read-back, downloads, the decrypted dump # during a restore) also go to /.tmp; plan ~2x the # archive size of free space on this volume. PARKRR_BACKUP_KEY: ${PARKRR_BACKUP_KEY:-} PARKRR_BACKUP_DIR: ${PARKRR_BACKUP_DIR:-/backups} PARKRR_BROWSER_RESTORE: ${PARKRR_BROWSER_RESTORE:-false} # Optional off-site S3-compatible target (AWS S3 / Backblaze B2 / Wasabi / MinIO). PARKRR_S3_ENDPOINT: ${PARKRR_S3_ENDPOINT:-} PARKRR_S3_BUCKET: ${PARKRR_S3_BUCKET:-} PARKRR_S3_ACCESS_KEY: ${PARKRR_S3_ACCESS_KEY:-} PARKRR_S3_SECRET_KEY: ${PARKRR_S3_SECRET_KEY:-} PARKRR_S3_REGION: ${PARKRR_S3_REGION:-} PARKRR_S3_PREFIX: ${PARKRR_S3_PREFIX:-parkrr/} PARKRR_S3_USE_SSL: ${PARKRR_S3_USE_SSL:-true} PARKRR_METRICS_TOKEN: ${PARKRR_METRICS_TOKEN:-} # Compose defaults to true (fail closed): /metrics needs PARKRR_METRICS_TOKEN # and is disabled without one. Set false only to opt out of authentication. PARKRR_METRICS_REQUIRE_AUTH: ${PARKRR_METRICS_REQUIRE_AUTH:-true} # --- E-mail (SMTP): set PARKRR_SMTP_HOST to enable payment reminders. --- PARKRR_SMTP_HOST: ${PARKRR_SMTP_HOST:-} PARKRR_SMTP_PORT: ${PARKRR_SMTP_PORT:-587} PARKRR_SMTP_USERNAME: ${PARKRR_SMTP_USERNAME:-} PARKRR_SMTP_PASSWORD: ${PARKRR_SMTP_PASSWORD:-} PARKRR_SMTP_FROM: ${PARKRR_SMTP_FROM:-} PARKRR_SMTP_FROM_NAME: ${PARKRR_SMTP_FROM_NAME:-Parkrr} PARKRR_SMTP_TLS: ${PARKRR_SMTP_TLS:-starttls} # Externally reachable base URL, used for links inside e-mail (e.g. reminders). PARKRR_PUBLIC_BASE_URL: ${PARKRR_PUBLIC_BASE_URL:-} PARKRR_LOG_FORMAT: ${PARKRR_LOG_FORMAT:-json} PARKRR_LOG_LEVEL: ${PARKRR_LOG_LEVEL:-info} healthcheck: test: ["CMD", "/app/parkrr", "healthcheck"] interval: 30s timeout: 5s retries: 3 start_period: 20s ports: - "${PARKRR_HTTP_PORT:-8080}:8080" # Scheduled encrypted backups land here, in a named volume next to the DB's. volumes: - parkrr-backups:/backups networks: - parkrr-net volumes: parkrr-db-data: parkrr-backups: networks: parkrr-net: