mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-22 23:09:49 +00:00
scripts: reduce comments in relay setup
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user