scripts: reduce comments in relay setup

This commit is contained in:
shum
2026-08-21 08:49:11 +00:00
parent 83dd97037f
commit 418f148f7a
4 changed files with 23 additions and 65 deletions
+3 -5
View File
@@ -1,16 +1,14 @@
# Copy to .env and edit per server (relay1 / relay2 / relay3).
# Copy to .env and edit.
# Relay identity.
RELAY_NAME="My Relay"
RELAY_WEB_DOMAIN=relay1.example.com
# PostgreSQL credentials (used by both the db service and the relay's DB_CONN).
POSTGRES_USER=simplex
POSTGRES_DB=simplex_chat_relay
POSTGRES_PASSWORD=change-me
# Source ref to build: tag, branch or commit.
# Ref to build: tag, branch or commit.
CHAT_REF=88df79d1e26921c7d1835fc8484fade596356fb6
# GHC runtime options for the relay. Uncomment to override the default.
# GHC runtime options, without the +RTS/-RTS markers.
#RELAY_RTS_OPTS="-N -F1.2 -A16m -I0.01 -Iw15"
+6 -14
View File
@@ -1,7 +1,4 @@
# syntax=docker/dockerfile:1
# Build simplex-chat in relay mode with PostgreSQL support, then ship it on a
# slim runtime with only the libraries the binary links against. A bare
# `scratch` image cannot run this dynamically-linked binary.
ARG CHAT_REF=88df79d1e26921c7d1835fc8484fade596356fb6
ARG GHC=9.6.3
@@ -15,14 +12,12 @@ ARG CABAL
ENV DEBIAN_FRONTEND=noninteractive \
PATH="/root/.cabal/bin:/root/.ghcup/bin:$PATH"
# Build toolchain and simplex-chat dependencies (libpq-dev for client_postgres).
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl git build-essential \
libpq-dev libgmp3-dev zlib1g-dev libnuma-dev libssl-dev \
llvm-12 llvm-12-dev \
&& rm -rf /var/lib/apt/lists/*
# GHC + cabal via ghcup, then fetch the package index into this layer.
RUN curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org \
| BOOTSTRAP_HASKELL_NONINTERACTIVE=1 \
BOOTSTRAP_HASKELL_GHC_VERSION="${GHC}" \
@@ -31,9 +26,8 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org \
&& ghcup set cabal "${CABAL}" \
&& cabal update
# CHAT_REF is declared here, after the toolchain layers, so changing the ref
# reuses everything above and rebuilds only the fetch + compile below. The
# fetch form accepts a commit hash as well as a tag or branch.
# Declared after the toolchain layers so that changing the ref does not rebuild
# them. Unlike `clone --branch`, this form also accepts a commit hash.
ARG CHAT_REF
WORKDIR /project
RUN git init -q . \
@@ -41,9 +35,7 @@ RUN git init -q . \
&& git fetch -q --depth 1 origin "${CHAT_REF}" \
&& git checkout -q FETCH_HEAD
# Compile the executable with PostgreSQL persistence and strip it. The cabal
# store (compiled dependencies) and dist-newstyle are cache mounts, so a
# different ref recompiles only changed code, not every dependency.
# The cache mounts keep compiled dependencies across ref changes.
RUN --mount=type=cache,target=/root/.cabal/store,sharing=locked \
--mount=type=cache,target=/project/dist-newstyle,sharing=locked \
cp scripts/cabal.project.local.linux cabal.project.local \
@@ -55,7 +47,7 @@ RUN --mount=type=cache,target=/root/.cabal/store,sharing=locked \
# ---- runtime --------------------------------------------------------------
FROM debian:stable-slim AS runtime
# python3 runs the entrypoint; the rest are the binary's shared libraries.
# The binary is dynamically linked, so it needs these libraries at runtime.
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates python3 \
libpq5 libgmp10 libssl3 zlib1g libnuma1 libffi8 \
@@ -65,9 +57,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
COPY --from=build /simplex-chat-relay /usr/local/bin/simplex-chat-relay
COPY entrypoint.py /usr/local/bin/entrypoint.py
# Run as non-root; host bind-mounts must be writable by this UID.
# Bind-mounted host directories must be writable by this UID.
USER relay
# The relay (GHC runtime) shuts down cleanly on SIGINT, not SIGTERM.
# The relay shuts down cleanly on SIGINT, not SIGTERM.
STOPSIGNAL SIGINT
ENTRYPOINT ["python3", "/usr/local/bin/entrypoint.py"]
+6 -15
View File
@@ -7,40 +7,32 @@ services:
args:
CHAT_REF: ${CHAT_REF:-88df79d1e26921c7d1835fc8484fade596356fb6}
image: chat-relay:latest # set your image/registry name
container_name: chat-relay # optional: rename
container_name: chat-relay
depends_on:
db:
condition: service_healthy
environment:
RELAY_NAME: ${RELAY_NAME}
RELAY_WEB_DOMAIN: ${RELAY_WEB_DOMAIN}
# Empty falls back to the entrypoint's default RTS options.
RELAY_RTS_OPTS: ${RELAY_RTS_OPTS:-}
# Password comes from PGPASSWORD (libpq reads it), so it stays out of the
# process argv and needs no URL-encoding.
RELAY_RTS_OPTS: ${RELAY_RTS_OPTS:-} # empty: entrypoint default
# Password is passed as PGPASSWORD to keep it out of argv.
DB_CONN: postgresql://${POSTGRES_USER}@db:5432/${POSTGRES_DB}
PGPASSWORD: ${POSTGRES_PASSWORD}
volumes:
# Channel previews + CORS config, served by the host's system Caddy.
- /var/www/relay-web-channels:/var/www/relay-web-channels
# Relay address is written here: `cat out/relay-address.txt`.
- ./out:/out
restart: unless-stopped
db:
image: postgres:18
container_name: chat-relay-db # optional: rename
container_name: chat-relay-db
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
# Parallel workers use POSIX shared memory; the default 64 MB /dev/shm can
# be too small and cause "could not resize shared memory segment" errors.
shm_size: 256mb
shm_size: 256mb # parallel workers need more than the 64 MB default
volumes:
# PG18+ uses a version-specific PGDATA (/var/lib/postgresql/18/docker) and
# a VOLUME at /var/lib/postgresql. Mount there so major-version upgrades
# can use pg_upgrade --link.
# PG18+ keeps PGDATA in a version-specific subdirectory of this volume.
- pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
@@ -48,7 +40,6 @@ services:
timeout: 5s
retries: 10
# Tuning for ~5 GB RAM / 4 cores. Match to the actual server.
# `--name=value` is postgres's equivalent of `-c name=value`.
command:
- postgres
- --max_connections=100
+8 -31
View File
@@ -1,15 +1,8 @@
#!/usr/bin/env python3
"""Record the relay address, then run the relay with no wrapper in the way.
"""Save the relay address on first start, then exec the relay.
On the first start (or whenever /out/relay-address.txt is missing) a short
one-shot invocation creates the profile and address if needed, prints the
address, and saves it. Then the real relay is exec'd, so it runs as PID 1 with
no Python left in the process tree. Steady-state starts skip straight to the
exec.
The address is not stored in the database as a ready-to-use string (it is a
binary conn-req blob plus short-link data, re-encoded on display), so the
relay's own output is the canonical source.
The address is printed only when it is created, and is not stored in the
database in its displayed form, so it is captured from the relay's output.
"""
import os
import shlex
@@ -19,10 +12,7 @@ import sys
BIN = "simplex-chat-relay"
WEB_ROOT = "/var/www/relay-web-channels"
ADDR_FILE = "/out/relay-address.txt"
CAPTURE_TIMEOUT = 180 # seconds; first address creation involves an SMP round-trip
# GHC runtime options for the relay, overridable with RELAY_RTS_OPTS. The binary
# is built with -rtsopts, so it accepts them on the command line.
CAPTURE_TIMEOUT = 180 # seconds
DEFAULT_RTS_OPTS = "-N -F1.2 -A16m -I0.01 -Iw15"
@@ -34,11 +24,7 @@ def require(name):
def rts_args():
"""Configured RTS options, wrapped in the +RTS/-RTS markers.
RELAY_RTS_OPTS holds bare options ("-N -A16m"); the markers are added here
and ignored if they are given anyway.
"""
"""RELAY_RTS_OPTS holds bare options; the +RTS/-RTS markers are added here."""
opts = [
o
for o in shlex.split(os.environ.get("RELAY_RTS_OPTS") or DEFAULT_RTS_OPTS)
@@ -55,13 +41,7 @@ def find_address(text):
def capture_address(oneshot):
"""One-shot: create the profile/address if needed, print it, and save it.
Runs before the real relay starts, so there is never a second agent
subscribing to the same queues. If it can't capture (e.g. SMP briefly
unreachable), the relay still creates and serves the address, and the next
start retries because the file is still missing.
"""
"""Create the address if needed and save it. Runs before the relay starts."""
cmd = oneshot + ["--create-schema", "-t", "0", "-e", "/sa"]
try:
out = subprocess.run(
@@ -74,7 +54,7 @@ def capture_address(oneshot):
).stdout
except subprocess.TimeoutExpired as exc:
out = exc.stdout or ""
sys.stdout.write(out) # keep it in the container logs
sys.stdout.write(out)
sys.stdout.flush()
address = find_address(out)
@@ -96,14 +76,11 @@ def main():
common = [BIN, "--relay", "--headless", "--user-display-name", name]
# First start (or the file was removed): bootstrap and capture the address,
# then the real relay reuses it. The avatar only applies at profile
# creation, so it goes on the one-shot, not the long-running relay.
# The image is applied only when the profile is created.
if not os.path.exists(ADDR_FILE):
oneshot = common + (["--user-image-file", image_file] if image_file else []) + ["-d", conn]
capture_address(oneshot)
# Replace this process with the relay: PID 1, native signals, no wrapper.
relay = common + [
"--relay-web-domain", domain,
"--relay-web-dir", f"{WEB_ROOT}/channel",