Sign inSign up

harlenalvarez/huddle-stack:latest

Manifest digest

sha256:50dc5b7c3d61d980e91d11140425a733f678a89f56dd3da53e84d0446615f2d7

Last pushed

2 days by harlenalvarez

Type

Compose

Manifest digest

sha256:50dc5b7c3d61d980e91d11140425a733f678a89f56dd3da53e84d0446615f2d7

Compose file content

name: huddle

services:
  postgres:
    image: docker.io/${DOCKER_HUB_NAMESPACE:-local}/huddle-postgres:${HUDDLE_IMAGE_TAG:-dev}
    environment:
      DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required}
      POSTGRES_ALLOWED_HOSTS: postgres
    volumes:
      - postgres_data:/var/lib/postgresql
    networks:
      - backend
    healthcheck:
      # Check the private listener without assuming a role from DATABASE_URL;
      # the custom entrypoint may initialize any configured username.
      test:
        [
          'CMD',
          'python3',
          '-c',
          "import socket; connection = socket.create_connection(('127.0.0.1', 5432), 3); connection.close()",
        ]
      interval: 5s
      timeout: 5s
      retries: 20
      start_period: 15s
    restart: unless-stopped

  redis:
    image: redis:8-alpine
    command: ['redis-server', '--appendonly', 'yes']
    volumes:
      - redis_data:/data
    networks:
      - backend
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 5s
      timeout: 3s
      retries: 20
    restart: unless-stopped

  nats:
    image: nats:2-alpine
    command: ['-js', '-sd', '/data', '-m', '8222']
    volumes:
      - nats_data:/data
    networks:
      - backend
    healthcheck:
      test: ['CMD', 'wget', '--quiet', '--spider', 'http://127.0.0.1:8222/healthz']
      interval: 5s
      timeout: 3s
      retries: 20
    restart: unless-stopped

  nats-tools:
    image: natsio/nats-box:latest
    profiles: ['tools']
    entrypoint: ['sleep', 'infinity']
    depends_on:
      nats:
        condition: service_healthy
    networks:
      - backend

  artifact-storage-init:
    image: docker.io/${DOCKER_HUB_NAMESPACE:-local}/huddle-api:${HUDDLE_IMAGE_TAG:-dev}
    user: '0:0'
    entrypoint: ['sh', '-c']
    command:
      - mkdir -p /var/lib/huddle/artifacts && chown -R 10001:10001 /var/lib/huddle/artifacts
    volumes:
      - artifact_data:/var/lib/huddle/artifacts
    restart: 'no'

  api:
    image: docker.io/${DOCKER_HUB_NAMESPACE:-local}/huddle-api:${HUDDLE_IMAGE_TAG:-dev}
    environment:
      DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required}
      DATABASE_STARTUP_TIMEOUT: ${DATABASE_STARTUP_TIMEOUT:-120}
      FERNET_KEY: ${FERNET_KEY:?FERNET_KEY is required}
      ARTIFACT_BLOB_ROOT: /var/lib/huddle/artifacts
      HTTP_TIMEOUT: ${HTTP_TIMEOUT:-300}
      HTTPX_MAX_CONNECTIONS: ${HTTPX_MAX_CONNECTIONS:-100}
      HTTP_MAX_KEEPALIVE: ${HTTP_MAX_KEEPALIVE:-20}
      ASR_WS_URL: ${ASR_WS_URL:-ws://spark-427e.local:8005/v1/audio/transcriptions/realtime}
      VLLM_API_KEY: ${VLLM_API_KEY:-EMPTY}
      CHAT_HEIC_MODE: ${CHAT_HEIC_MODE:-passthrough}
      EXA_API_KEY: ${EXA_API_KEY:-}
      REDIS_HOST: redis:6379
      REDIS_KEY_PREFIX: ${REDIS_KEY_PREFIX:-huddle:}
      REDIS_MAX_CONNECTIONS: ${REDIS_MAX_CONNECTIONS:-10}
      REDIS_SOCKET_CONNECT_TIMEOUT: ${REDIS_SOCKET_CONNECT_TIMEOUT:-10.0}
      REDIS_SOCKET_TIMEOUT: ${REDIS_SOCKET_TIMEOUT:-30.0}
      REDIS_SOCKET_KEEPALIVE: ${REDIS_SOCKET_KEEPALIVE:-true}
      REDIS_SSL_ENABLED: 'false'
      REDIS_IS_CLUSTER: 'false'
      NATS_URL: nats://nats:4222
      LOG_LEVEL: ${LOG_LEVEL:-INFO}
      WEB_PUSH_ENABLED: ${WEB_PUSH_ENABLED:-false}
      WEB_PUSH_VAPID_PUBLIC_KEY: ${WEB_PUSH_VAPID_PUBLIC_KEY:-}
      OAUTH_CLIENT_ID: ${OAUTH_CLIENT_ID:-}
      OAUTH_CLIENT_SECRET: ${OAUTH_CLIENT_SECRET:-}
      HUDDLE_PUBLIC_ORIGIN: ${HUDDLE_PUBLIC_ORIGIN:-https://localhost}
      EBAY_ENVIRONMENT: ${EBAY_ENVIRONMENT:-sandbox}
      EBAY_CLIENT_ID: ${EBAY_CLIENT_ID:-}
      EBAY_CLIENT_SECRET: ${EBAY_CLIENT_SECRET:-}
      EBAY_REDIRECT_URI: ${EBAY_REDIRECT_URI:-}
      EBAY_ALLOW_PRODUCTION: ${EBAY_ALLOW_PRODUCTION:-false}
      EBAY_ACCOUNT_DELETION_VERIFICATION_TOKEN: ${EBAY_ACCOUNT_DELETION_VERIFICATION_TOKEN:-}
      EBAY_ACCOUNT_DELETION_PUBLIC_ORIGIN: ${EBAY_ACCOUNT_DELETION_PUBLIC_ORIGIN:-}
      EBAY_SANDBOX_API_URL: ${EBAY_SANDBOX_API_URL:-https://api.sandbox.ebay.com}
      EBAY_PRODUCTION_API_URL: ${EBAY_PRODUCTION_API_URL:-https://api.ebay.com}
      EBAY_SANDBOX_INVENTORY_API_URL: ${EBAY_SANDBOX_INVENTORY_API_URL:-https://api.sandbox.ebay.com/sell/inventory/v1}
      EBAY_PRODUCTION_INVENTORY_API_URL: ${EBAY_PRODUCTION_INVENTORY_API_URL:-https://api.ebay.com/sell/inventory/v1}
    depends_on:
      artifact-storage-init:
        condition: service_completed_successfully
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
      nats:
        condition: service_healthy
    volumes:
      - artifact_data:/var/lib/huddle/artifacts
    networks:
      - backend
      - frontend
      - webhook_backend
    healthcheck:
      test:
        [
          'CMD',
          'python',
          '-c',
          "import urllib.request; urllib.request.urlopen('http://127.0.0.1:9000/api/health', timeout=3)",
        ]
      interval: 10s
      timeout: 5s
      retries: 12
      start_period: 30s
    restart: unless-stopped

  schedule-publisher:
    image: docker.io/${DOCKER_HUB_NAMESPACE:-local}/huddle-api:${HUDDLE_IMAGE_TAG:-dev}
    entrypoint: ['python', '-m', 'huddle_api.scheduled_worker', 'scheduler']
    environment:
      DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required}
      DATABASE_HOST_OVERRIDE: postgres
      DATABASE_PORT_OVERRIDE: '5432'
      FERNET_KEY: ${FERNET_KEY:?FERNET_KEY is required}
      NATS_URL: nats://nats:4222
      LOG_LEVEL: ${LOG_LEVEL:-INFO}
      WEB_PUSH_VAPID_PUBLIC_KEY: ${WEB_PUSH_VAPID_PUBLIC_KEY:-}
      WEB_PUSH_VAPID_PRIVATE_KEY: ${WEB_PUSH_VAPID_PRIVATE_KEY:-}
      WEB_PUSH_VAPID_SUBJECT: ${WEB_PUSH_VAPID_SUBJECT:-}
      WEB_PUSH_ENABLED: ${WEB_PUSH_ENABLED:-false}
      HUDDLE_PUBLIC_ORIGIN: ${HUDDLE_PUBLIC_ORIGIN:-https://localhost}
      REDIS_HOST: redis:6379
      REDIS_KEY_PREFIX: ${REDIS_KEY_PREFIX:-huddle:}
      VLLM_API_KEY: ${VLLM_API_KEY:-EMPTY}
      EXA_API_KEY: ${EXA_API_KEY:-}
    depends_on:
      postgres:
        condition: service_healthy
      nats:
        condition: service_healthy
      api:
        condition: service_healthy
    networks:
      - backend
      # Web Push must reach external browser push providers.
      - frontend
    restart: unless-stopped

  scheduled-task-worker:
    image: docker.io/${DOCKER_HUB_NAMESPACE:-local}/huddle-api:${HUDDLE_IMAGE_TAG:-dev}
    entrypoint: ['python', '-m', 'huddle_api.scheduled_worker', 'worker']
    environment:
      DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required}
      DATABASE_HOST_OVERRIDE: postgres
      DATABASE_PORT_OVERRIDE: '5432'
      FERNET_KEY: ${FERNET_KEY:?FERNET_KEY is required}
      ARTIFACT_BLOB_ROOT: /var/lib/huddle/artifacts
      NATS_URL: nats://nats:4222
      LOG_LEVEL: ${LOG_LEVEL:-INFO}
      OAUTH_CLIENT_ID: ${OAUTH_CLIENT_ID:-}
      OAUTH_CLIENT_SECRET: ${OAUTH_CLIENT_SECRET:-}
      HUDDLE_PUBLIC_ORIGIN: ${HUDDLE_PUBLIC_ORIGIN:-https://localhost}
      REDIS_HOST: redis:6379
      REDIS_KEY_PREFIX: ${REDIS_KEY_PREFIX:-huddle:}
      VLLM_API_KEY: ${VLLM_API_KEY:-EMPTY}
      HTTP_TIMEOUT: ${HTTP_TIMEOUT:-300}
      HTTPX_MAX_CONNECTIONS: ${HTTPX_MAX_CONNECTIONS:-100}
      HTTP_MAX_KEEPALIVE: ${HTTP_MAX_KEEPALIVE:-20}
      CHAT_HEIC_MODE: ${CHAT_HEIC_MODE:-passthrough}
      EXA_API_KEY: ${EXA_API_KEY:-}
      EBAY_ENVIRONMENT: ${EBAY_ENVIRONMENT:-sandbox}
      EBAY_CLIENT_ID: ${EBAY_CLIENT_ID:-}
      EBAY_CLIENT_SECRET: ${EBAY_CLIENT_SECRET:-}
      EBAY_REDIRECT_URI: ${EBAY_REDIRECT_URI:-}
      EBAY_ALLOW_PRODUCTION: ${EBAY_ALLOW_PRODUCTION:-false}
      EBAY_SANDBOX_API_URL: ${EBAY_SANDBOX_API_URL:-https://api.sandbox.ebay.com}
      EBAY_PRODUCTION_API_URL: ${EBAY_PRODUCTION_API_URL:-https://api.ebay.com}
      EBAY_SANDBOX_INVENTORY_API_URL: ${EBAY_SANDBOX_INVENTORY_API_URL:-https://api.sandbox.ebay.com/sell/inventory/v1}
      EBAY_PRODUCTION_INVENTORY_API_URL: ${EBAY_PRODUCTION_INVENTORY_API_URL:-https://api.ebay.com/sell/inventory/v1}
    depends_on:
      postgres:
        condition: service_healthy
      nats:
        condition: service_healthy
      api:
        condition: service_healthy
    volumes:
      - artifact_data:/var/lib/huddle/artifacts
    networks:
      - backend
      - frontend
      - webhook_backend
    restart: unless-stopped

  web:
    image: docker.io/${DOCKER_HUB_NAMESPACE:-local}/huddle-web:${HUDDLE_IMAGE_TAG:-dev}
    networks:
      - frontend
    healthcheck:
      test: ['CMD', 'wget', '--quiet', '--output-document=/dev/null', 'http://127.0.0.1/healthz']
      interval: 10s
      timeout: 5s
      retries: 12
    restart: unless-stopped

  caddy:
    image: caddy:2-alpine
    environment:
      HUDDLE_HOSTNAME: ${HUDDLE_HOSTNAME:-localhost}
    configs:
      - source: caddyfile
        target: /etc/caddy/Caddyfile
    ports:
      - name: http
        target: 80
        published: ${HUDDLE_HTTP_PORT:-80}
        protocol: tcp
      - name: https
        target: 443
        published: ${HUDDLE_HTTPS_PORT:-443}
        protocol: tcp
      - name: http3
        target: 443
        published: ${HUDDLE_HTTPS_PORT:-443}
        protocol: udp
    volumes:
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      api:
        condition: service_healthy
      web:
        condition: service_healthy
    networks:
      - frontend
    healthcheck:
      test:
        ['CMD', 'wget', '--quiet', '--output-document=/dev/null', 'http://127.0.0.1:2019/config/']
      interval: 10s
      timeout: 5s
      retries: 12
    restart: unless-stopped

  ebay-webhook-gateway:
    image: caddy:2-alpine
    configs:
      - source: ebay_webhook_caddyfile
        target: /etc/caddy/Caddyfile
    depends_on:
      api:
        condition: service_healthy
    networks:
      - webhook_edge
      - webhook_backend
    healthcheck:
      test:
        ['CMD', 'wget', '--quiet', '--output-document=/dev/null', 'http://127.0.0.1:2019/config/']
      interval: 10s
      timeout: 5s
      retries: 12
      start_period: 5s
    restart: unless-stopped

  cloudflared:
    image: cloudflare/cloudflared:latest
    command: ['tunnel', '--no-autoupdate', '--url', 'http://ebay-webhook-gateway:8080']
    depends_on:
      ebay-webhook-gateway:
        condition: service_healthy
    networks:
      - webhook_edge
    restart: unless-stopped

configs:
  caddyfile:
    file: ./Caddyfile
  ebay_webhook_caddyfile:
    file: ./ebay-webhook.Caddyfile

networks:
  frontend:
  webhook_edge:
  webhook_backend:
    internal: true
  backend:
    internal: true

volumes:
  postgres_data:
  redis_data:
  nats_data:
  caddy_data:
  caddy_config:
  artifact_data:
services:
  api:
    image: docker.io/harlenalvarez/huddle-api:2026.09.26-1@sha256:f38a9ece2787ed062035bc0bf6df9328700a6722681ca4af48fbcd0925c4c0df
  artifact-storage-init:
    image: docker.io/harlenalvarez/huddle-api:2026.09.26-1@sha256:f38a9ece2787ed062035bc0bf6df9328700a6722681ca4af48fbcd0925c4c0df
  caddy:
    image: docker.io/library/caddy:2-alpine@sha256:6aeddd44c3078b0f9a35206472a11420648a79c184603ef95957d0a20044cb2b
  cloudflared:
    image: docker.io/cloudflare/cloudflared:latest@sha256:072c067d25ccbe61d46e18f0d0723255f2bb5304f7317caa95b27031520ff92c
  ebay-webhook-gateway:
    image: docker.io/library/caddy:2-alpine@sha256:6aeddd44c3078b0f9a35206472a11420648a79c184603ef95957d0a20044cb2b
  nats:
    image: docker.io/library/nats:2-alpine@sha256:ac8f88a6494bffc2c2a5289a0ca61cb28a9145c11ba5677cf24265d07f46d8d4
  nats-tools:
    image: docker.io/natsio/nats-box:latest@sha256:d2f04223f40e016f77922a8115d34b0cd5fad2ec10b19b39316ae92d07f3d295
  postgres:
    image: docker.io/harlenalvarez/huddle-postgres:2026.09.26-1@sha256:739f6d73ad08fb2db2a556254baf7e8a3513cb3ad889e61732d11b3ce58c5d61
  redis:
    image: docker.io/library/redis:8-alpine@sha256:3811787313eba226a2ef38658c6ccb91cd5e110edc89c37767de373120a0e5a0
  schedule-publisher:
    image: docker.io/harlenalvarez/huddle-api:2026.09.26-1@sha256:f38a9ece2787ed062035bc0bf6df9328700a6722681ca4af48fbcd0925c4c0df
  scheduled-task-worker:
    image: docker.io/harlenalvarez/huddle-api:2026.09.26-1@sha256:f38a9ece2787ed062035bc0bf6df9328700a6722681ca4af48fbcd0925c4c0df
  web:
    image: docker.io/harlenalvarez/huddle-web:2026.09.26-1@sha256:e215e117a98eb19acf246f41d7436aa88c7b21f5222c0b4ad50ad2b33b7cf21e

Docker commands

docker compose -f oci://harlenalvarez/huddle-stack:latest up

Use the above command to pull and run the Compose file. Learn more⁠.

Images used

Image + 1 more

Redis is the world’s fastest data platform for caching, vector search, and NoSQL databases.


Pulls

1B+

Stars

13619

Last Updated

4 days

Image

Caddy 2 is a powerful, enterprise-ready, open source web server with automatic HTTPS written in Go.


Pulls

500M+

Stars

988

Last Updated

3 days

Image + 1 more

NATS is an open-source, high-performance, cloud native messaging system.


Pulls

100M+

Stars

522

Last Updated

11 days

Image

Client for Cloudflare Tunnel, a daemon that exposes private services through the Cloudflare edge.


Pulls

100M+

Stars

587

Last Updated

4 days

Image

Lightweight container with NATS and NATS Streaming utilities


Pulls

50M+

Stars

5

Last Updated

5 days

Image


Pulls

401

Stars

0

Last Updated

2 days

Image


Pulls

320

Stars

0

Last Updated

2 days

Image


Pulls

303

Stars

0

Last Updated

2 days