services: broker: image: valkey/valkey:9-alpine restart: unless-stopped volumes: - redisdata:/data healthcheck: test: ["CMD-SHELL", "valkey-cli ping | grep -q PONG"] interval: 5s timeout: 3s retries: 10 db: image: postgres:18 restart: unless-stopped environment: POSTGRES_DB: paperless POSTGRES_USER: paperless POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - pgdata:/var/lib/postgresql healthcheck: # Over TCP: the server of the first start's initialisation listens on # the socket alone, and is not the one the app will reach. test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U paperless -d paperless"] interval: 5s timeout: 3s retries: 20 webserver: image: ghcr.io/paperless-ngx/paperless-ngx:3.3 restart: unless-stopped depends_on: db: condition: service_healthy broker: condition: service_healthy environment: PAPERLESS_REDIS: redis://broker:6379 PAPERLESS_DBENGINE: postgresql PAPERLESS_DBHOST: db PAPERLESS_DBPASS: ${POSTGRES_PASSWORD} PAPERLESS_URL: ${PAPERLESS_URL} PAPERLESS_SECRET_KEY: ${PAPERLESS_SECRET_KEY} # The first start makes this superuser, so no sign-up page is left open. PAPERLESS_ADMIN_USER: admin PAPERLESS_ADMIN_PASSWORD: ${ADMIN_PASSWORD} # TLS ends at the machine's proxy, which says so in X-Forwarded-Proto. PAPERLESS_PROXY_SSL_HEADER: '["HTTP_X_FORWARDED_PROTO", "https"]' volumes: - data:/usr/src/paperless/data - media:/usr/src/paperless/media - export:/usr/src/paperless/export - consume:/usr/src/paperless/consume healthcheck: # The image's own check, with time for the first start's migrations. test: ["CMD", "curl", "-fs", "-S", "-L", "--max-time", "2", "http://localhost:8000"] interval: 30s timeout: 10s retries: 5 start_period: 180s volumes: redisdata: pgdata: data: media: export: consume: