# plMail on the published image: web, worker and Postgres. # Secrets are generated on first start; see docs/install/docker.md. x-app-image: &app-image ghcr.io/karatektus/pl_mail:latest x-app-env: &app-env APP_ENV: prod APP_SECRET: ${APP_SECRET:-} APP_ENCRYPTION_KEY: ${APP_ENCRYPTION_KEY:-} DATABASE_URL: ${DATABASE_URL:-} POSTGRES_USER: ${POSTGRES_USER:-app} POSTGRES_DB: ${POSTGRES_DB:-app} POSTGRES_VERSION: ${POSTGRES_VERSION:-18} MESSENGER_TRANSPORT_DSN: ${MESSENGER_TRANSPORT_DSN:-doctrine://default?auto_setup=0} MERCURE_URL: ${MERCURE_URL:-http://mercure/.well-known/mercure} MERCURE_PUBLIC_URL: ${MERCURE_PUBLIC_URL:-https://localhost/.well-known/mercure} MERCURE_COOKIE_NAME: ${MERCURE_COOKIE_NAME:-} OIDC_ISSUER: ${OIDC_ISSUER:-} OIDC_CLIENT_ID: ${OIDC_CLIENT_ID:-} OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-} OIDC_BUTTON_LABEL: ${OIDC_BUTTON_LABEL:-} OIDC_SCOPES: ${OIDC_SCOPES:-openid email profile} OIDC_AUTO_CREATE: ${OIDC_AUTO_CREATE:-false} OIDC_REQUIRE_VERIFIED_EMAIL: ${OIDC_REQUIRE_VERIFIED_EMAIL:-true} OIDC_DISABLE_PASSWORD_LOGIN: ${OIDC_DISABLE_PASSWORD_LOGIN:-false} x-app-storage: &app-storage - app_secrets:/app/var/secrets - app_attachments:/app/var/attachments - app_raw:/app/var/raw - app_uploads:/app/var/uploads services: secrets-init: image: *app-image restart: "no" entrypoint: ["generate-secrets"] environment: APP_SECRET: ${APP_SECRET:-} APP_ENCRYPTION_KEY: ${APP_ENCRYPTION_KEY:-} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-} MERCURE_JWT_SECRET: ${MERCURE_JWT_SECRET:-} volumes: - app_secrets:/app/var/secrets php: image: *app-image restart: unless-stopped environment: <<: *app-env SERVER_NAME: ${SERVER_NAME:-localhost, :443}, php:80 MAILER_DSN: ${MAILER_DSN:-null://null} APP_CONTAINER_NAME: web volumes: - caddy_data:/data - caddy_config:/config - app_secrets:/app/var/secrets - app_attachments:/app/var/attachments - app_raw:/app/var/raw - app_uploads:/app/var/uploads ports: - target: 80 published: ${HTTP_PORT:-80} protocol: tcp - target: 443 published: ${HTTPS_PORT:-443} protocol: tcp - target: 443 published: ${HTTP3_PORT:-443} protocol: udp depends_on: secrets-init: condition: service_completed_successfully database: condition: service_healthy worker: image: *app-image restart: unless-stopped command: php bin/console app:work init: true stop_grace_period: 30s environment: <<: *app-env APP_CONTAINER_NAME: worker networks: default: aliases: [mercure] volumes: - mercure_data:/data - mercure_config:/config - app_secrets:/app/var/secrets - app_attachments:/app/var/attachments - app_raw:/app/var/raw - app_uploads:/app/var/uploads healthcheck: disable: true depends_on: secrets-init: condition: service_completed_successfully database: condition: service_healthy database: image: postgres:${POSTGRES_VERSION:-18}-alpine environment: POSTGRES_DB: ${POSTGRES_DB:-app} POSTGRES_USER: ${POSTGRES_USER:-app} POSTGRES_PASSWORD_FILE: /run/plmail/postgres_password depends_on: secrets-init: condition: service_completed_successfully healthcheck: test: ["CMD", "pg_isready", "-d", "${POSTGRES_DB:-app}", "-U", "${POSTGRES_USER:-app}"] interval: 5s timeout: 5s retries: 30 start_period: 60s volumes: - database_data:/var/lib/postgresql - app_secrets:/run/plmail:ro command: - "postgres" - "-c" - "shared_preload_libraries=pg_stat_statements" - "-c" - "pg_stat_statements.track=top" ntfy: image: binwiederhier/ntfy profiles: [push] restart: unless-stopped command: serve environment: NTFY_BASE_URL: ${NTFY_BASE_URL:-http://${SERVER_NAME:-localhost}:${NTFY_PORT:-8090}} NTFY_LISTEN_HTTP: ':80' NTFY_CACHE_FILE: /var/lib/ntfy/cache.db NTFY_AUTH_FILE: /var/lib/ntfy/auth.db NTFY_AUTH_DEFAULT_ACCESS: ${NTFY_AUTH_DEFAULT_ACCESS:-read-write} NTFY_VISITOR_REQUEST_LIMIT_BURST: '60' NTFY_VISITOR_REQUEST_LIMIT_REPLENISH: '5s' ports: - "${NTFY_PORT:-8090}:80" volumes: - ntfy_data:/var/lib/ntfy healthcheck: test: ["CMD", "wget", "-qO-", "http://localhost/v1/health"] timeout: 5s retries: 5 start_period: 20s volumes: app_secrets: app_attachments: app_raw: app_uploads: caddy_data: caddy_config: database_data: mercure_data: mercure_config: ntfy_data: