Files
archy/docker/dojobay/entrypoint.sh
T

81 lines
3.8 KiB
Bash
Executable File

#!/bin/sh
# Dojo Bay container entrypoint: seeds first-run data, points the backend at
# Archipelago's Tor SOCKS proxy, runs the 10-minute prober on a loop (in place
# of the systemd timer the standalone deploy used), and supervises all three
# processes (node backend, prober loop, nginx) so a SIGTERM from tini/podman
# stops them all cleanly rather than leaving orphans for the hard-kill timeout.
set -eu
# ---- first-run data seeding -------------------------------------------------
# /app/data is a bind-mounted, host-persistent volume: empty on first install,
# and shadows whatever was baked into the image at that path. Populate it from
# the clean templates exactly once; a real seed.json/operator.json (once the
# claim wizard or "Manage my Dojo" writes one) is never overwritten.
for f in seed.json dojos.json history.json history-daily.json paynym-codes.json version.json; do
if [ ! -f "/app/data/$f" ]; then
cp "/app/data-template/$f" "/app/data/$f"
fi
done
# ---- outbound Tor -----------------------------------------------------------
# The manifest generates /app/data/tor-proxy.conf with the archy-net bridge
# gateway's SOCKS address (Archipelago's Tor binds a second SocksPort there
# specifically for containers) — see docs/app-developer-guide.md's
# {{NETWORK_GATEWAY}} placeholder. probe.mjs already reads TOR_SOCKS_HOST/PORT
# (used for PayNym lookups, DNS-over-HTTPS domain checks, and probing every
# listed Dojo), so no code change is needed, only wiring the env vars here.
if [ -f /app/data/tor-proxy.conf ]; then
TOR_PROXY_ADDR="$(cat /app/data/tor-proxy.conf)"
export TOR_SOCKS_HOST="${TOR_PROXY_ADDR%:*}"
export TOR_SOCKS_PORT="${TOR_PROXY_ADDR##*:}"
fi
# ---- the backend -------------------------------------------------------------
cd /app/server
node index.mjs &
NODE_PID=$!
# ---- the 10-minute prober ----------------------------------------------------
# Replaces dojobay-update.timer: the same script, invoked on a loop instead of
# by systemd. update.mjs itself is unchanged from upstream. Runs once shortly
# after start (dojobay-update.timer's OnBootSec=2min counterpart — a fresh
# install should not sit on an empty/stale list for a full ten minutes), then
# every 10 minutes; a few seconds of random jitter on each wait, same reasoning
# as the timer's RandomizedDelaySec (a fleet of instances should not all probe
# the same nodes on the same wall-clock tick).
(
sleep "$((25 + RANDOM % 30))"
while true; do
node /app/scripts/update.mjs || echo "[update] cycle failed, will retry in 10 minutes" >&2
sleep "$((570 + RANDOM % 60))"
done
) &
UPDATE_LOOP_PID=$!
# ---- the web server -----------------------------------------------------------
# Backgrounded rather than exec'd: this script stays the live PID tini
# supervises, so the trap below can actually run when SIGTERM arrives and
# forward it to all three children. (exec'ing nginx here would replace this
# script's process image, and a trap registered by a process that no longer
# exists never fires — the other two would then only die on the container's
# hard-kill timeout instead of shutting down cleanly.)
# -e /dev/stderr: nginx's master process logs its very first startup lines
# (before it has even parsed nginx.conf's own error_log directive) to a
# compiled-in default path under /var/lib/nginx/logs — a symlink to
# /var/log/nginx, which is not one of the paths this app asks Archipelago to
# make writable under security.readonly_root. Overriding it here means
# nothing ever depends on /var/log/nginx existing or being writable at all,
# on this image or any other readonly-root host.
nginx -e /dev/stderr -g "daemon off;" &
NGINX_PID=$!
cleanup() {
kill -TERM "$NGINX_PID" "$NODE_PID" "$UPDATE_LOOP_PID" 2>/dev/null || true
wait "$NGINX_PID" 2>/dev/null || true
exit 0
}
trap cleanup TERM INT
wait "$NGINX_PID"
kill "$NODE_PID" "$UPDATE_LOOP_PID" 2>/dev/null || true