90192cd284
Event pep stack with SFTPGo inbox, sequential worker, FastAPI gallery/remix, and Traefik-ready compose. Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
3.3 KiB
YAML
99 lines
3.3 KiB
YAML
# live.f12.rocks — event photo pipeline: SFTP inbox -> gmic/rembg -> web.
|
|
#
|
|
# All three services share one host directory (default ./data, see
|
|
# .env.example DATA_HOST_DIR) at different mount points:
|
|
# sftpgo -> /srv/sftpgo/data (SFTP user home = /srv/sftpgo/data/inbox)
|
|
# worker -> /data (watches /data/inbox, writes /data/jobs)
|
|
# web -> /data (reads jobs, writes remix variants)
|
|
#
|
|
# Copy .env.example to .env and fill in real SFTP credentials before
|
|
# running this. Never commit .env.
|
|
|
|
services:
|
|
sftpgo:
|
|
image: drakkan/sftpgo:v2
|
|
restart: unless-stopped
|
|
# The image defaults to a fixed uid 1000 user. worker/web run as root
|
|
# (see Dockerfile), and Docker itself creates first-run bind-mount
|
|
# directories (./data/inbox, ./data/jobs, ...) as root:root — running
|
|
# sftpgo as root too avoids a uid mismatch on the shared ./data tree.
|
|
user: root
|
|
entrypoint: ["/bin/sh", "/entrypoint.sh"]
|
|
environment:
|
|
SFTP_USER: ${SFTP_USER:-livef12}
|
|
SFTP_PASSWORD: ${SFTP_PASSWORD:-changeme}
|
|
volumes:
|
|
- ${DATA_HOST_DIR:-./data}:/srv/sftpgo/data
|
|
- sftpgo_state:/var/lib/sftpgo
|
|
- ./sftpgo/entrypoint.sh:/entrypoint.sh:ro
|
|
ports:
|
|
# SFTP only. The SFTPGo web admin (container port 8080) is
|
|
# intentionally NOT published here and NOT attached to the
|
|
# `traefik` network — it stays unreachable from outside docker.
|
|
#
|
|
# Host SFTP port. Spec asked for 121212 which exceeds TCP max
|
|
# (65535); production default is 12121.
|
|
- "${SFTP_HOST_PORT:-12121}:2022"
|
|
networks:
|
|
- internal
|
|
|
|
worker:
|
|
build: .
|
|
restart: unless-stopped
|
|
command: ["python3", "-m", "app.worker"]
|
|
depends_on:
|
|
- sftpgo
|
|
environment:
|
|
DATA_DIR: /data
|
|
OUTPUT_COUNT: ${OUTPUT_COUNT:-3}
|
|
BLEND_OPACITY: ${BLEND_OPACITY:-30%}
|
|
FILTER_TIMEOUT: ${FILTER_TIMEOUT:-120}
|
|
MAX_FILTER_ATTEMPTS: ${MAX_FILTER_ATTEMPTS:-8}
|
|
NICE_LEVEL: ${NICE_LEVEL:-18}
|
|
volumes:
|
|
- ${DATA_HOST_DIR:-./data}:/data
|
|
- ./assets:/data/assets:ro
|
|
- rembg_cache:/app/.home
|
|
# Sequential-only by design (no threads/async in worker.py); these
|
|
# limits just make sure gmic/rembg can't starve the host too.
|
|
cpus: "1.0"
|
|
mem_limit: 2g
|
|
networks:
|
|
- internal
|
|
|
|
web:
|
|
build: .
|
|
restart: unless-stopped
|
|
command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
depends_on:
|
|
- worker
|
|
environment:
|
|
DATA_DIR: /data
|
|
OUTPUT_COUNT: ${OUTPUT_COUNT:-3}
|
|
BLEND_OPACITY: ${BLEND_OPACITY:-30%}
|
|
FILTER_TIMEOUT: ${FILTER_TIMEOUT:-120}
|
|
MAX_FILTER_ATTEMPTS: ${MAX_FILTER_ATTEMPTS:-8}
|
|
NICE_LEVEL: ${NICE_LEVEL:-18}
|
|
SITE_TITLE: live.f12.rocks
|
|
volumes:
|
|
- ${DATA_HOST_DIR:-./data}:/data
|
|
- ./assets:/data/assets:ro
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.livef12rocks.rule=Host(`live.f12.rocks`)"
|
|
- "traefik.http.routers.livef12rocks.entrypoints=websecure"
|
|
- "traefik.http.routers.livef12rocks.tls.certresolver=myresolver"
|
|
- "traefik.http.services.livef12rocks.loadbalancer.server.port=8000"
|
|
networks:
|
|
- internal
|
|
- traefik
|
|
|
|
networks:
|
|
internal: {}
|
|
traefik:
|
|
external: true
|
|
|
|
volumes:
|
|
sftpgo_state:
|
|
rembg_cache:
|