--- version: "3.8" services: app: image: git.autonomic.zone/recipe-maintainers/caption-ninja-web:2026.09.07-dfcee8f networks: - proxy configs: - source: nginx_conf target: /etc/nginx/conf.d/default.conf healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1/"] interval: 30s timeout: 10s retries: 3 start_period: 10s deploy: update_config: failure_action: rollback order: start-first labels: - "traefik.enable=true" - "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`)" - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=80" - "coop-cloud.${STACK_NAME}.version=0.1.0+v2026.09.07" relay: image: git.autonomic.zone/recipe-maintainers/caption-ninja-relay:0.2.0-dfcee8f networks: - proxy environment: - DOMAIN - STT_DOMAIN - RELAY_EXTRA_ORIGINS - RELAY_PER_IP secrets: - src_read - src_write - out_read - out_write configs: - source: relay_entrypoint target: /relay-entrypoint.sh mode: 0555 entrypoint: /relay-entrypoint.sh healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:8787/health').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"] interval: 30s timeout: 10s retries: 3 start_period: 10s deploy: update_config: failure_action: rollback order: start-first labels: - "traefik.enable=true" - "traefik.http.routers.${STACK_NAME}_relay.rule=Host(`${DOMAIN}`) && Path(`/relay`)" - "traefik.http.routers.${STACK_NAME}_relay.entrypoints=web-secure" - "traefik.http.routers.${STACK_NAME}_relay.tls.certresolver=${LETS_ENCRYPT_ENV}" - "traefik.http.routers.${STACK_NAME}_relay.service=${STACK_NAME}_relay" - "traefik.http.routers.${STACK_NAME}_relay.middlewares=${STACK_NAME}_relay_strip" - "traefik.http.middlewares.${STACK_NAME}_relay_strip.stripprefix.prefixes=/relay" - "traefik.http.services.${STACK_NAME}_relay.loadbalancer.server.port=8787" stt: image: git.autonomic.zone/recipe-maintainers/caption-ninja-stt:1.1.0-7d759fe networks: - proxy environment: - DOMAIN - STT_DOMAIN - STT_EXTRA_ORIGINS - CAPTION_MODEL=${CAPTION_MODEL:-small} - CAPTION_BEAM_SIZE=${CAPTION_BEAM_SIZE:-5} - CAPTION_WORKERS=${CAPTION_WORKERS:-1} - CAPTION_THREADS=${CAPTION_THREADS:-4} - CAPTION_MAX_STREAMS=${CAPTION_MAX_STREAMS:-12} - CAPTION_COMPUTE_TYPE=${CAPTION_COMPUTE_TYPE:-auto} - CAPTION_DEVICE=cpu - CAPTION_OFFLINE=${CAPTION_OFFLINE:-0} - CAPTION_LOG_REQUESTS=${CAPTION_LOG_REQUESTS:-0} secrets: - stt_api_key configs: - source: stt_entrypoint target: /stt-entrypoint.sh mode: 0555 entrypoint: /stt-entrypoint.sh volumes: - models:/models healthcheck: # The image's own healthcheck reads CAPTION_API_KEY from the environment, # which only the entrypoint process has; feed it the secret here. test: ["CMD", "sh", "-c", "CAPTION_API_KEY=$$(cat /run/secrets/stt_api_key) python healthcheck.py"] interval: 30s timeout: 10s retries: 3 # First start downloads the Whisper model into the volume. start_period: 600s stop_grace_period: 100s deploy: update_config: failure_action: rollback order: stop-first labels: - "traefik.enable=true" - "traefik.http.routers.${STACK_NAME}_stt.rule=Host(`${STT_DOMAIN}`)" - "traefik.http.routers.${STACK_NAME}_stt.entrypoints=web-secure" - "traefik.http.routers.${STACK_NAME}_stt.tls.certresolver=${LETS_ENCRYPT_ENV}" - "traefik.http.routers.${STACK_NAME}_stt.service=${STACK_NAME}_stt" # Caption Local only accepts Host: localhost (upstream expects an SSH tunnel) - "traefik.http.routers.${STACK_NAME}_stt.middlewares=${STACK_NAME}_stt_host" - "traefik.http.middlewares.${STACK_NAME}_stt_host.headers.customrequestheaders.Host=localhost" - "traefik.http.services.${STACK_NAME}_stt.loadbalancer.server.port=8765" secrets: src_read: name: ${STACK_NAME}_src_read_${SECRET_SRC_READ_VERSION} external: true src_write: name: ${STACK_NAME}_src_write_${SECRET_SRC_WRITE_VERSION} external: true out_read: name: ${STACK_NAME}_out_read_${SECRET_OUT_READ_VERSION} external: true out_write: name: ${STACK_NAME}_out_write_${SECRET_OUT_WRITE_VERSION} external: true stt_api_key: name: ${STACK_NAME}_stt_api_key_${SECRET_STT_API_KEY_VERSION} external: true configs: nginx_conf: name: ${STACK_NAME}_nginx_conf_${NGINX_CONF_VERSION} file: nginx.conf relay_entrypoint: name: ${STACK_NAME}_relay_entrypoint_${RELAY_ENTRYPOINT_VERSION} file: relay-entrypoint.sh stt_entrypoint: name: ${STACK_NAME}_stt_entrypoint_${STT_ENTRYPOINT_VERSION} file: stt-entrypoint.sh networks: proxy: external: true volumes: models: