Ctrl K
ComunidadGuías…

docker-compose.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Every service refuses privilege escalation, and the services that run as an unprivileged
# user on a high port also drop every Linux capability. Caddy binds 80 and 443 as root, and
# PostgreSQL, migrate, backup, and restore run one-off root commands, so those keep theirs.
services:
  caddy:
    security_opt: ["no-new-privileges:true"]
    image: caddy:2.10.2-alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    environment:
      REMENTUM_DOMAIN: ${REMENTUM_DOMAIN:-localhost}
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      api:
        condition: service_healthy
      web:
        condition: service_healthy
      docs:
        condition: service_healthy

  web:
    security_opt: ["no-new-privileges:true"]
    cap_drop: ["ALL"]
    build:
      context: .
      dockerfile: apps/web/Dockerfile
      args:
        NEXT_PUBLIC_REMENTUM_API_URL: ${REMENTUM_PUBLIC_URL:-http://localhost}
    restart: unless-stopped
    environment:
      REMENTUM_API_INTERNAL_URL: http://api:8787
      NEXT_PUBLIC_REMENTUM_API_URL: ${REMENTUM_PUBLIC_URL:-http://localhost}
    depends_on:
      api:
        condition: service_healthy
    healthcheck:
      test:
        [
          "CMD",
          "node",
          "-e",
          "fetch('http://127.0.0.1:3000').then((response) => { if (!response.ok) process.exit(1) }).catch(() => process.exit(1))",
        ]
      interval: 10s
      timeout: 5s
      retries: 10

  docs:
    security_opt: ["no-new-privileges:true"]
    cap_drop: ["ALL"]
    build:
      context: .
      dockerfile: deploy/docs/Dockerfile
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/docs/"]
      interval: 10s
      timeout: 5s
      retries: 10

  migrate:
    security_opt: ["no-new-privileges:true"]
    build:
      context: .
      dockerfile: apps/api/Dockerfile
    restart: "no"
    env_file: .env
    command: ["node", "packages/db/dist/migrate.js"]
    environment:
      REMENTUM_DATABASE_ADMIN_URL: postgres://postgres:${REMENTUM_POSTGRES_SUPER_PASSWORD:?set REMENTUM_POSTGRES_SUPER_PASSWORD in .env}@postgres:5432/owl
    depends_on:
      postgres:
        condition: service_healthy

  # Only migrate, backup, and restore need the PostgreSQL superuser. The shared .env carries
  # it for them, so the long-running services blank it (and the secrets they never read):
  # a superuser connection string inside the API would bypass row-level security for
  # anyone who found a way to read that process's environment.
  api:
    security_opt: ["no-new-privileges:true"]
    cap_drop: ["ALL"]
    build:
      context: .
      dockerfile: apps/api/Dockerfile
    restart: unless-stopped
    env_file: .env
    environment:
      REMENTUM_DATABASE_ADMIN_URL: ""
      REMENTUM_POSTGRES_SUPER_PASSWORD: ""
      REMENTUM_DATABASE_URL: postgres://owl_app:${REMENTUM_POSTGRES_PASSWORD:?set REMENTUM_POSTGRES_PASSWORD in .env}@postgres:5432/owl
      REMENTUM_EMBEDDINGS_URL: http://embeddings:8790
      REMENTUM_BLOB_DIR: /data/blobs
      REMENTUM_EXPORT_DIR: /data/exports
    volumes:
      - owl_data:/data
    depends_on:
      embeddings:
        condition: service_healthy
      migrate:
        condition: service_completed_successfully
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8787/healthz"]
      interval: 10s
      timeout: 5s
      retries: 10

  worker:
    security_opt: ["no-new-privileges:true"]
    cap_drop: ["ALL"]
    build:
      context: .
      dockerfile: apps/worker/Dockerfile
    restart: unless-stopped
    env_file: .env
    environment:
      REMENTUM_DATABASE_ADMIN_URL: ""
      REMENTUM_POSTGRES_SUPER_PASSWORD: ""
      REMENTUM_COOKIE_KEYS: ""
      REMENTUM_JWT_JWKS: ""
      REMENTUM_RESEND_API_KEY: ""
      REMENTUM_MAIL_FROM: ""
      REMENTUM_TURNSTILE_SITE_KEY: ""
      REMENTUM_TURNSTILE_SECRET_KEY: ""
      REMENTUM_DATABASE_URL: postgres://owl_app:${REMENTUM_POSTGRES_PASSWORD:?set REMENTUM_POSTGRES_PASSWORD in .env}@postgres:5432/owl
      REMENTUM_EMBEDDINGS_URL: http://embeddings:8790
      REMENTUM_BLOB_DIR: /data/blobs
      REMENTUM_EXPORT_DIR: /data/exports
    volumes:
      - owl_data:/data
    depends_on:
      embeddings:
        condition: service_healthy
      migrate:
        condition: service_completed_successfully

  embeddings:
    security_opt: ["no-new-privileges:true"]
    cap_drop: ["ALL"]
    build:
      context: .
      dockerfile: apps/embeddings/Dockerfile
    restart: unless-stopped
    environment:
      REMENTUM_EMBEDDING_MODEL: ${REMENTUM_EMBEDDING_MODEL:-onnx-community/granite-embedding-97m-multilingual-r2-ONNX}
      # Optional overrides for models the service does not recognize; empty means unset.
      REMENTUM_EMBEDDING_DTYPE: ${REMENTUM_EMBEDDING_DTYPE:-}
      REMENTUM_EMBEDDING_POOLING: ${REMENTUM_EMBEDDING_POOLING:-}
      REMENTUM_EMBEDDING_QUERY_PREFIX: ${REMENTUM_EMBEDDING_QUERY_PREFIX:-}
      REMENTUM_EMBEDDING_PASSAGE_PREFIX: ${REMENTUM_EMBEDDING_PASSAGE_PREFIX:-}
      REMENTUM_MODEL_CACHE: /models
    volumes:
      - model_cache:/models
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8790/healthz"]
      interval: 10s
      timeout: 5s
      # The first probe pulls the model, a few hundred megabytes, so probes are expected to fail
      # until that finishes. The grace period covers a slow link; a cache the container cannot
      # write is caught at startup instead, so this budget only has to outlast a download.
      start_period: 600s
      retries: 30

  postgres:
    security_opt: ["no-new-privileges:true"]
    image: pgvector/pgvector:pg17
    restart: unless-stopped
    environment:
      POSTGRES_DB: owl
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${REMENTUM_POSTGRES_SUPER_PASSWORD:?set REMENTUM_POSTGRES_SUPER_PASSWORD in .env}
      REMENTUM_POSTGRES_PASSWORD: ${REMENTUM_POSTGRES_PASSWORD:?set REMENTUM_POSTGRES_PASSWORD in .env}
    ports:
      - "127.0.0.1:${REMENTUM_POSTGRES_PORT:-55432}:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./deploy/postgres/00-app-role.sh:/docker-entrypoint-initdb.d/00-app-role.sh:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d owl"]
      interval: 5s
      timeout: 5s
      retries: 20

  backup:
    security_opt: ["no-new-privileges:true"]
    profiles: ["backup"]
    build:
      context: .
      dockerfile: deploy/backup/Dockerfile
    env_file: .env
    environment:
      REMENTUM_MASTER_KEY: ""
      REMENTUM_COOKIE_KEYS: ""
      REMENTUM_JWT_JWKS: ""
      REMENTUM_RESEND_API_KEY: ""
      REMENTUM_TURNSTILE_SECRET_KEY: ""
      REMENTUM_DATABASE_ADMIN_URL: postgres://postgres:${REMENTUM_POSTGRES_SUPER_PASSWORD:?set REMENTUM_POSTGRES_SUPER_PASSWORD in .env}@postgres:5432/owl
      REMENTUM_BLOB_DIR: /data/blobs
      REMENTUM_BACKUP_DIR: /backups
    volumes:
      - owl_data:/data:ro
      - ${REMENTUM_BACKUP_HOST_DIR:-./backups}:/backups
    depends_on:
      postgres:
        condition: service_healthy

  restore:
    security_opt: ["no-new-privileges:true"]
    profiles: ["restore"]
    build:
      context: .
      dockerfile: deploy/backup/Dockerfile
    env_file: .env
    entrypoint: ["/usr/local/bin/rementum-restore"]
    environment:
      REMENTUM_MASTER_KEY: ""
      REMENTUM_COOKIE_KEYS: ""
      REMENTUM_JWT_JWKS: ""
      REMENTUM_RESEND_API_KEY: ""
      REMENTUM_TURNSTILE_SECRET_KEY: ""
      REMENTUM_DATABASE_ADMIN_URL: postgres://postgres:${REMENTUM_POSTGRES_SUPER_PASSWORD:?set REMENTUM_POSTGRES_SUPER_PASSWORD in .env}@postgres:5432/owl
      REMENTUM_BLOB_DIR: /data/blobs
      REMENTUM_BACKUP_AGE_IDENTITY_FILE: /run/secrets/age-identity
    volumes:
      - owl_data:/data
      - ${REMENTUM_BACKUP_HOST_DIR:-./backups}:/backups:ro
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  caddy_data:
  caddy_config:
  postgres_data:
  owl_data:
  model_cache: