Ctrl K
ComunidadGuías…

selfhost/compose.yaml

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

Archivo original ↗Preguntar a KiBot
# Personal local/LAN converter stack.
# Do not publish the converter engine port to the host.
name: ekko-selfhost

services:
  shared-init:
    image: busybox:1.37
    command:
      - sh
      - -c
      - mkdir -p /data && chown 10001:10001 /data && chmod 700 /data
    volumes:
      - profiles_data:/data
    restart: "no"

  subconverter:
    build:
      context: ./subconverter
      args:
        # The engine carries the rules, so it carries their version too: the
        # gateway asks it at runtime rather than guessing from its own build.
        EKKO_RULES_VERSION: ${EKKO_RULES_VERSION:-local}
        EKKO_RULES_BUILT: ${EKKO_RULES_BUILT:-}
    image: ekko-rules-selfhost-subconverter:local
    restart: unless-stopped
    networks:
      - internal
    # Intentionally no host ports. Gateway reaches it only on the Docker network.
    expose:
      - "25500"
    read_only: true
    tmpfs:
      - /tmp:size=64m,mode=1777
      - /base/cache:size=64m,mode=0700,uid=10001,gid=10001
    security_opt:
      - no-new-privileges:true
    mem_limit: 512m
    cpus: 1.0

  web:
    build:
      context: ./app
      args:
        EKKO_SITE_VERSION: ${EKKO_SITE_VERSION:-local}
        SUBCONVERTER_VERSION: ${SUBCONVERTER_VERSION:-v1.3.0}
    image: ekko-rules-selfhost-web:local
    restart: unless-stopped
    depends_on:
      shared-init:
        condition: service_completed_successfully
      subconverter:
        condition: service_started
    ports:
      - "${WEB_BIND_HOST:-0.0.0.0}:${WEB_PORT:-8787}:3000"
    environment:
      NODE_ENV: production
      HOSTNAME: 0.0.0.0
      PORT: "3000"
      WEB_BIND_HOST: ${WEB_BIND_HOST:-0.0.0.0}
      WEB_PORT: ${WEB_PORT:-8787}
      LAN_BASE_URL: ${LAN_BASE_URL:-}
      # lan (default) = personal stored addresses; public = open, stores nothing.
      SELFHOST_MODE: ${SELFHOST_MODE:-lan}
      PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-}
      TRUST_PROXY_HEADERS: ${TRUST_PROXY_HEADERS:-}
      RATE_LIMIT_MANAGE_PER_MINUTE: ${RATE_LIMIT_MANAGE_PER_MINUTE:-}
      RATE_LIMIT_SUBSCRIBE_PER_MINUTE: ${RATE_LIMIT_SUBSCRIBE_PER_MINUTE:-}
      REMOTE_CONFIGS: ${REMOTE_CONFIGS:-}
      THIRD_PARTY_REMOTE_CONFIGS: ${THIRD_PARTY_REMOTE_CONFIGS:-}
      ALLOW_CUSTOM_REMOTE_CONFIG: ${ALLOW_CUSTOM_REMOTE_CONFIG:-}
      SITE_LINKS: ${SITE_LINKS:-}
      HOST_NETWORK_INFO_PATH: /host-runtime/lan-address.json
      SUBCONVERTER_BASE_URL: http://subconverter:25500
      # EKKO_SITE_VERSION is deliberately absent: the build above bakes it
      # into the image, so an image always reports the version it was built
      # from. Setting it here would let a stale value in .env outrank the
      # image and make a published release report someone else's number. The
      # rules version is not here either — the engine reports its own.
      SUBCONVERTER_VERSION: ${SUBCONVERTER_VERSION:-v1.3.0}
      CONVERT_TIMEOUT_MS: ${CONVERT_TIMEOUT_MS:-30000}
      MAX_SUBSCRIPTION_BYTES: ${MAX_SUBSCRIPTION_BYTES:-5242880}
      ACCESS_PASSWORD: ${ACCESS_PASSWORD:-}
      CONVERT_SHARED_DIR: /shared
      CONVERT_SHARED_URL_PREFIX: http://web:3000/api/internal/input
      PROFILE_DATA_DIR: /data
      CONVERT_ALLOW_HOSTNAMES: ${CONVERT_ALLOW_HOSTNAMES:-}
    volumes:
      - profiles_data:/data:rw
      - ./.runtime:/host-runtime:ro
    networks:
      - internal
    healthcheck:
      test:
        - CMD
        - node
        - -e
        - "fetch('http://127.0.0.1:3000/api/health').then((r) => r.json()).then((j) => process.exit(j.subconverter_reachable ? 0 : 1)).catch(() => process.exit(1))"
      interval: 30s
      timeout: 5s
      start_period: 20s
      retries: 3
    read_only: true
    tmpfs:
      - /tmp:size=64m,mode=1777
      - /shared:size=32m,mode=0700,uid=10001,gid=10001
    security_opt:
      - no-new-privileges:true
    mem_limit: 512m
    cpus: 1.0

  # Ephemeral fixture server used only by local end-to-end validation.
  fixture:
    image: python:3.12-alpine
    profiles: ["e2e"]
    working_dir: /srv
    command: ["python", "/srv/server.py"]
    volumes:
      - ./fixtures:/srv:ro
    networks:
      - internal

volumes:
  profiles_data:

networks:
  internal:
    driver: bridge
    internal: false