selfhost/compose.yaml
Rama main · réplica de lectura del repositorio original.
# 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