services: app: build: context: . dockerfile: Dockerfile image: taxhacker:local ports: - "127.0.0.1:7331:7331" environment: - NODE_ENV=production - SELF_HOSTED_MODE=true - UPLOAD_PATH=/app/data/uploads - DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-taxhacker} - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-} volumes: - ./data:/app/data restart: unless-stopped security_opt: - no-new-privileges:true logging: driver: "local" options: max-size: "100M" max-file: "3" cron: image: taxhacker:local environment: - NODE_ENV=production - SELF_HOSTED_MODE=true - UPLOAD_PATH=/app/data/uploads - DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-taxhacker} # Optional override. When unset, both containers use the same persisted secret from ./data. - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-} volumes: - ./data:/app/data - ./etc/crontab:/mnt/crontab:ro restart: unless-stopped depends_on: - postgres - app security_opt: - no-new-privileges:true command: ["docker-cron-entrypoint.sh"] logging: driver: "local" options: max-size: "100M" max-file: "3" postgres: image: postgres:17-alpine container_name: taxhacker-postgres environment: - POSTGRES_USER=${POSTGRES_USER:-postgres} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in your .env file} - POSTGRES_DB=${POSTGRES_DB:-taxhacker} volumes: - ./pgdata:/var/lib/postgresql/data restart: unless-stopped ports: - "127.0.0.1:5432:5432" security_opt: - no-new-privileges:true logging: driver: "local" options: max-size: "100M" max-file: "3"