services: ovumcy: image: ${OVUMCY_IMAGE:-ghcr.io/ovumcy/ovumcy-web:v1.9.2} pull_policy: always container_name: ovumcy env_file: - ./.env environment: - PORT=${PORT:-8080} - DEFAULT_LANGUAGE=${DEFAULT_LANGUAGE:-} - REGISTRATION_MODE=${REGISTRATION_MODE:-} - DB_DRIVER=${DB_DRIVER:-} - DB_PATH=/app/data/ovumcy.db - CALENDAR_FEED_FENCE_PATH=/app/fence/calendar-feed.fence - DATABASE_URL=${DATABASE_URL:-} - DATABASE_URL_FILE=${DATABASE_URL_FILE:-} - COOKIE_SECURE=${COOKIE_SECURE:-} - HSTS_ENABLED=${HSTS_ENABLED:-} - OIDC_ENABLED=${OIDC_ENABLED:-} - OIDC_ISSUER_URL=${OIDC_ISSUER_URL:-} - OIDC_CLIENT_ID=${OIDC_CLIENT_ID:-} - OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET:-} - OIDC_CLIENT_SECRET_FILE=${OIDC_CLIENT_SECRET_FILE:-} - OIDC_REDIRECT_URL=${OIDC_REDIRECT_URL:-} - OIDC_CA_FILE=${OIDC_CA_FILE:-} - OIDC_LOGIN_MODE=${OIDC_LOGIN_MODE:-} - OIDC_RESPONSE_MODE=${OIDC_RESPONSE_MODE:-} - OIDC_AUTO_PROVISION=${OIDC_AUTO_PROVISION:-} - OIDC_AUTO_PROVISION_ALLOWED_DOMAINS=${OIDC_AUTO_PROVISION_ALLOWED_DOMAINS:-} - OIDC_LOGOUT_MODE=${OIDC_LOGOUT_MODE:-} - OIDC_POST_LOGOUT_REDIRECT_URL=${OIDC_POST_LOGOUT_REDIRECT_URL:-} - RATE_LIMIT_LOGIN_MAX=${RATE_LIMIT_LOGIN_MAX:-} - RATE_LIMIT_LOGIN_WINDOW=${RATE_LIMIT_LOGIN_WINDOW:-} - RATE_LIMIT_REGISTER_MAX=${RATE_LIMIT_REGISTER_MAX:-} - RATE_LIMIT_REGISTER_WINDOW=${RATE_LIMIT_REGISTER_WINDOW:-} - RATE_LIMIT_FORGOT_PASSWORD_MAX=${RATE_LIMIT_FORGOT_PASSWORD_MAX:-} - RATE_LIMIT_FORGOT_PASSWORD_WINDOW=${RATE_LIMIT_FORGOT_PASSWORD_WINDOW:-} - RATE_LIMIT_TOTP_CHALLENGE_MAX=${RATE_LIMIT_TOTP_CHALLENGE_MAX:-} - RATE_LIMIT_TOTP_CHALLENGE_WINDOW=${RATE_LIMIT_TOTP_CHALLENGE_WINDOW:-} - RATE_LIMIT_PASSWORD_RESET_REDEEM_MAX=${RATE_LIMIT_PASSWORD_RESET_REDEEM_MAX:-} - RATE_LIMIT_PASSWORD_RESET_REDEEM_WINDOW=${RATE_LIMIT_PASSWORD_RESET_REDEEM_WINDOW:-} # Per-IP edge limiter, then the per-account identity-keyed budget. - RATE_LIMIT_LOGOUT_MAX=${RATE_LIMIT_LOGOUT_MAX:-} - RATE_LIMIT_LOGOUT_WINDOW=${RATE_LIMIT_LOGOUT_WINDOW:-} - RATE_LIMIT_LOGOUT_ACCOUNT_MAX=${RATE_LIMIT_LOGOUT_ACCOUNT_MAX:-} - RATE_LIMIT_LOGOUT_ACCOUNT_WINDOW=${RATE_LIMIT_LOGOUT_ACCOUNT_WINDOW:-} - RATE_LIMIT_API_MAX=${RATE_LIMIT_API_MAX:-} - RATE_LIMIT_API_WINDOW=${RATE_LIMIT_API_WINDOW:-} # Calendar feed: deliberately far below the API budget — it is the only cap on # a cookieless, unauthenticated polling surface, not on cheap authorized reads. - RATE_LIMIT_CALENDAR_FEED_MAX=${RATE_LIMIT_CALENDAR_FEED_MAX:-} - RATE_LIMIT_CALENDAR_FEED_WINDOW=${RATE_LIMIT_CALENDAR_FEED_WINDOW:-} - AUDIT_LOG_ENABLED=${AUDIT_LOG_ENABLED:-} - TRUST_PROXY_ENABLED=${TRUST_PROXY_ENABLED:-} - PROXY_HEADER=${PROXY_HEADER:-} - TRUSTED_PROXIES=${TRUSTED_PROXIES:-} # Webhook reminders: the built-in daily scheduler ships off, and delivery is # not restricted to public targets, so a LAN ntfy/Gotify endpoint works. - WEBHOOK_BLOCK_PRIVATE_ADDRESSES=${WEBHOOK_BLOCK_PRIVATE_ADDRESSES:-} - REMINDER_SCHEDULER_ENABLED=${REMINDER_SCHEDULER_ENABLED:-} - REMINDER_SCHEDULER_HOUR=${REMINDER_SCHEDULER_HOUR:-} init: true security_opt: - no-new-privileges:true cap_drop: - ALL read_only: true tmpfs: - /tmp volumes: - ovumcy_data:/app/data # The calendar-feed restore fence. Deliberately a SEPARATE volume from the # database: it is how the app tells a restored backup from the database it # replaced, so it only works while your backups leave it out. Do not archive # it, do not restore it, and do not point it at the data volume. Losing it # costs one round of re-generated subscribe URLs and nothing else. - ovumcy_fence:/app/fence # Optional: mount a file-backed app secret and set SECRET_KEY_FILE=/run/secrets/ovumcy_secret_key in .env # - ./secrets/ovumcy_secret_key:/run/secrets/ovumcy_secret_key:ro # Optional: mount a private OIDC CA bundle and set OIDC_CA_FILE=/run/certs/oidc-provider-ca.pem in .env # - ./certs/oidc-provider-ca.pem:/run/certs/oidc-provider-ca.pem:ro # DATABASE_URL_FILE and OIDC_CLIENT_SECRET_FILE support the same Docker # Swarm/Compose secrets pattern as SECRET_KEY_FILE above — mount a secret # file and point the *_FILE variable at its in-container path. healthcheck: test: ["CMD", "/app/ovumcy", "healthcheck"] interval: 30s timeout: 5s retries: 3 start_period: 20s ports: - "${HOST_BIND_ADDRESS:-127.0.0.1}:${PORT:-8080}:${PORT:-8080}" restart: unless-stopped volumes: ovumcy_data: name: ovumcy_data ovumcy_fence: name: ovumcy_fence