networks: proxy-net: external: true recipesage-internal: internal: true services: proxy: image: julianpoy/recipesage-selfhost-proxy:v4.0.0 container_name: recipesage_proxy restart: unless-stopped networks: - proxy-net - recipesage-internal depends_on: static: condition: service_started api: condition: service_started pushpin: condition: service_started labels: - "traefik.enable=true" - "traefik.docker.network=proxy-net" # --- 1. Authenticated Router (Priority 10) --- - "traefik.http.routers.recipesage.rule=Host(`${DOMAIN_NAME}`)" - "traefik.http.routers.recipesage.entrypoints=websecure" - "traefik.http.routers.recipesage.tls=true" - "traefik.http.routers.recipesage.tls.certresolver=cloudflare" # - "traefik.http.routers.recipesage.middlewares=authentik-auth@file" - "traefik.http.routers.recipesage.priority=10" - "traefik.http.routers.recipesage.service=recipesage-svc" # --- 2. Public Share Bypass Router (Priority 20) --- - "traefik.http.routers.recipesage-public.rule=Host(`${DOMAIN_NAME}`) && (PathPrefix(`/share`) || PathPrefix(`/p/`) || PathPrefix(`/api/v1/share`) || PathPrefix(`/assets/`))" - "traefik.http.routers.recipesage-public.entrypoints=websecure" - "traefik.http.routers.recipesage-public.tls=true" - "traefik.http.routers.recipesage-public.tls.certresolver=cloudflare" - "traefik.http.routers.recipesage-public.priority=20" - "traefik.http.routers.recipesage-public.service=recipesage-svc" # --- Service Target Port --- - "traefik.http.services.recipesage-svc.loadbalancer.server.port=80" api: image: julianpoy/recipesage-selfhost:api-v3.0.10 container_name: recipesage_api restart: unless-stopped networks: - recipesage-internal depends_on: postgres: condition: service_healthy typesense: condition: service_started pushpin: condition: service_started browserless: condition: service_started command: sh -c "npx prisma migrate deploy; npx nx seed prisma; npx ts-node --swc --project packages/backend/tsconfig.json packages/backend/src/bin/www" environment: - STORAGE_TYPE=filesystem - FILESYSTEM_STORAGE_PATH=/rs-media - NODE_ENV=selfhost - VERBOSE=false - VERSION=selfhost - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PORT=5432 - POSTGRES_HOST=postgres - POSTGRES_SSL=false - POSTGRES_LOGGING=false - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?schema=public - JWT_SECRET=${JWT_SECRET} - DISABLE_REGISTRATION=${DISABLE_REGISTRATION} - GRIP_URL=http://pushpin:5561/ - GRIP_KEY=changeme - SEARCH_PROVIDER=typesense - 'TYPESENSE_NODES=[{"host": "typesense", "port": 8108, "protocol": "http"}]' - TYPESENSE_API_KEY=${TYPESENSE_API_KEY} - BROWSERLESS_URL=http://browserless:3000 - PUSHPIN_URL=http://pushpin:7999 - OPENAI_API_KEY=${OPENAI_API_KEY:-} - OPENAI_API_BASE_URL=${OPENAI_API_BASE_URL:-} volumes: - /mnt/appdata/recipesage/data/uploads:/rs-media static: image: julianpoy/recipesage-selfhost:static-v3.0.10 container_name: recipesage_static restart: unless-stopped networks: - recipesage-internal typesense: image: typesense/typesense:26.0 container_name: recipesage_typesense restart: unless-stopped networks: - recipesage-internal environment: - TYPESENSE_API_KEY=${TYPESENSE_API_KEY} - TYPESENSE_DATA_DIR=/usr/share/typesense/data volumes: - /mnt/appdata/recipesage/data/typesense:/usr/share/typesense/data pushpin: image: fanout/pushpin:1.37.0 container_name: recipesage_pushpin restart: unless-stopped networks: - recipesage-internal browserless: image: ghcr.io/browserless/chromium:latest container_name: recipesage_browserless restart: unless-stopped networks: - recipesage-internal environment: - MAX_CONCURRENT_SESSIONS=5 postgres: image: postgres:15-alpine container_name: recipesage_postgres restart: unless-stopped networks: - recipesage-internal environment: - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} volumes: - /mnt/appdata/recipesage/data/postgres:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 5s timeout: 5s retries: 5