Files
channel-exit/docker-compose.yml
T

40 lines
1.7 KiB
YAML
Raw Normal View History

2026-08-18 15:41:28 -04:00
# How this runs on the host. There is one service and no database: the relay
# keeps nothing, which is deliberate — an outbox of everyone's reminders is a
# liability, and the providers already have delivery logs.
#
# The two bind addresses below are the security boundary of this whole service.
# Neither is routable from outside the machine:
#
# 127.0.0.1 — for a human on the host, and for the health check.
# 172.17.0.1 — the docker bridge, so sibling containers can reach it by an
# address that exists for them. `127.0.0.1` inside a consumer's
# container is that container, so a consumer configured with a
# loopback gateway URL fails every delivery and looks fine.
#
# It must never be given a 0.0.0.0 binding or a cloudflared route. An
# authenticated relay on the public internet is an open spam relay the moment
# the token leaks, and that token is copied into every consumer's environment.
services:
channel-exit:
image: ${CHANNEL_EXIT_IMAGE:-channel-exit:local}
build: .
restart: unless-stopped
env_file: .env
ports:
- "127.0.0.1:${CHANNEL_EXIT_PORT:?allocate a port in the 5400-5999 range}:8080"
- "${DOCKER_BRIDGE_IP:-172.17.0.1}:${CHANNEL_EXIT_PORT:?}:8080"
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8080/healthz', timeout=4).status == 200 else 1)"]
interval: 15s
timeout: 5s
start_period: 10s
retries: 3
logging:
# Bounded, because this log names who was messaged and when. It should
# not accumulate on disk indefinitely.
driver: json-file
options:
max-size: "10m"
max-file: "3"