# Standalone famapp deployment template. # Copy this to compose.yaml (or reference with -f), fill in .env from # .env.production.example, then: docker compose up -d # # Caddy (or any reverse proxy) should sit in front — see Caddyfile.snippet. # If Caddy runs in a separate compose stack, add famapp to that stack's # external network instead of exposing ports directly. name: famapp networks: famapp_net: volumes: famapp_db_data: authentik_db_data: authentik_redis_data: garden_uploads: backups: services: famapp: image: ${FAMAPP_IMAGE:-ghcr.io/ginnoir/famapp:latest} pull_policy: ${FAMAPP_PULL_POLICY:-always} restart: unless-stopped environment: NODE_ENV: production AUTH_URL: ${AUTH_URL} DATABASE_URL: postgres://${FAMAPP_DB_USER}:${FAMAPP_DB_PASSWORD}@famapp-db:5432/${FAMAPP_DB_NAME} AUTH_SECRET: ${AUTH_SECRET} AUTH_OIDC_ISSUER: ${AUTH_OIDC_ISSUER} AUTH_OIDC_CLIENT_ID: ${AUTH_OIDC_CLIENT_ID} AUTH_OIDC_CLIENT_SECRET: ${AUTH_OIDC_CLIENT_SECRET} VAPID_PUBLIC_KEY: ${VAPID_PUBLIC_KEY} VAPID_PRIVATE_KEY: ${VAPID_PRIVATE_KEY} VAPID_SUBJECT: ${VAPID_SUBJECT} NTFY_URL: ${NTFY_URL:-} NTFY_TOPIC: ${NTFY_TOPIC:-} LOG_LEVEL: ${LOG_LEVEL:-info} RUN_MIGRATIONS: ${RUN_MIGRATIONS:-true} MINIO_ENDPOINT: http://famapp-minio:9000 MINIO_ROOT_USER: ${famapp_MINIO_ROOT_USER} MINIO_ROOT_PASSWORD: ${famapp_MINIO_ROOT_PASSWORD} MINIO_BUCKET: ${famapp_MINIO_BUCKET:-garden} OPENPLANTBOOK_CLIENT_ID: ${famapp_OPENPLANTBOOK_CLIENT_ID:-} OPENPLANTBOOK_CLIENT_SECRET: ${famapp_OPENPLANTBOOK_CLIENT_SECRET:-} ports: - "${FAMAPP_PORT:-3000}:3000" depends_on: famapp-db: condition: service_healthy famapp-minio: condition: service_healthy networks: - famapp_net famapp-db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_USER: ${FAMAPP_DB_USER} POSTGRES_PASSWORD: ${FAMAPP_DB_PASSWORD} POSTGRES_DB: ${FAMAPP_DB_NAME} volumes: - famapp_db_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${FAMAPP_DB_USER} -d ${FAMAPP_DB_NAME}"] interval: 10s timeout: 5s retries: 5 networks: - famapp_net famapp-minio: image: minio/minio:latest command: server /data --console-address ":9001" restart: unless-stopped environment: MINIO_ROOT_USER: ${famapp_MINIO_ROOT_USER} MINIO_ROOT_PASSWORD: ${famapp_MINIO_ROOT_PASSWORD} volumes: - garden_uploads:/data ports: - "9000:9000" - "9001:9001" healthcheck: test: ["CMD-SHELL", "curl -sf http://localhost:9000/minio/health/live || exit 1"] interval: 30s timeout: 20s retries: 3 start_period: 30s networks: - famapp_net famapp-backup: image: alpine:3.20 restart: unless-stopped environment: FAMAPP_DB_HOST: famapp-db FAMAPP_DB_PORT: "5432" FAMAPP_DB_USER: ${FAMAPP_DB_USER} FAMAPP_DB_PASSWORD: ${FAMAPP_DB_PASSWORD} FAMAPP_DB_NAME: ${FAMAPP_DB_NAME} AUTHENTIK_DB_HOST: authentik-db AUTHENTIK_DB_PORT: "5432" AUTHENTIK_DB_USER: ${AUTHENTIK_DB_USER:-authentik} AUTHENTIK_DB_PASSWORD: ${AUTHENTIK_DB_PASSWORD} AUTHENTIK_DB_NAME: ${AUTHENTIK_DB_NAME:-authentik} volumes: - backups:/backups - ./backups:/scripts:ro depends_on: famapp-db: condition: service_healthy authentik-db: condition: service_healthy networks: - famapp_net entrypoint: ["sh", "/scripts/entrypoint.sh"] authentik-server: image: ghcr.io/goauthentik/server:${AUTHENTIK_IMAGE_TAG:-2024.12.3} restart: unless-stopped command: server environment: AUTHENTIK_REDIS__HOST: authentik-redis AUTHENTIK_POSTGRESQL__HOST: authentik-db AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER:-authentik} AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD} AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME:-authentik} AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY} AUTHENTIK_ERROR_REPORTING__ENABLED: "false" ports: - "9200:9000" depends_on: authentik-db: condition: service_healthy authentik-redis: condition: service_healthy networks: - famapp_net authentik-worker: image: ghcr.io/goauthentik/server:${AUTHENTIK_IMAGE_TAG:-2024.12.3} restart: unless-stopped command: worker environment: AUTHENTIK_REDIS__HOST: authentik-redis AUTHENTIK_POSTGRESQL__HOST: authentik-db AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_DB_USER:-authentik} AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD} AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_DB_NAME:-authentik} AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY} AUTHENTIK_ERROR_REPORTING__ENABLED: "false" depends_on: authentik-db: condition: service_healthy authentik-redis: condition: service_healthy networks: - famapp_net authentik-db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_USER: ${AUTHENTIK_DB_USER:-authentik} POSTGRES_PASSWORD: ${AUTHENTIK_DB_PASSWORD} POSTGRES_DB: ${AUTHENTIK_DB_NAME:-authentik} volumes: - authentik_db_data:/var/lib/postgresql/data healthcheck: test: [ "CMD-SHELL", "pg_isready -U ${AUTHENTIK_DB_USER:-authentik} -d ${AUTHENTIK_DB_NAME:-authentik}", ] interval: 10s timeout: 5s retries: 5 networks: - famapp_net authentik-redis: image: redis:7-alpine restart: unless-stopped command: --save 60 1 --loglevel warning volumes: - authentik_redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - famapp_net