diff --git a/infra/build-server/provision.sh b/infra/build-server/provision.sh index f74e00178..893ac37b9 100755 --- a/infra/build-server/provision.sh +++ b/infra/build-server/provision.sh @@ -32,6 +32,7 @@ # chain) listens on the same 26611 (infra/cloud-devnet/config.sh P2P_PORT=26611). RPC ports # (26610, 28610, 26790 and the 268xx set) stay on loopback as on every seed, so they are not opened. # BOX_HOSTNAME igneum-build-1 +# WORKERS_HOST build.igneum.network Caddy serves /srv/workers/{workers,headline}.json there (read-only, all else 404) # SSH_PUBKEY (unset) a public key line for the build user when root has no authorized_keys (installimage installs it) # # Mirrors: the Mac pushes to them (never a clone from GitHub; the fork vendor/igneum-node exists only on the Mac): @@ -54,6 +55,7 @@ WORKTREES="${WORKTREES:-}" SLOTS="${SLOTS:-1}" P2P_PORTS="${P2P_PORTS:-26611 26811}" BOX_HOSTNAME="${BOX_HOSTNAME:-igneum-build-1}" +WORKERS_HOST="${WORKERS_HOST:-build.igneum.network}" # the dashboard feed's HTTPS name (A record in deSEC, 6 Oct 2026) SSH_PUBKEY="${SSH_PUBKEY:-}" BUILD_USER=build BUILD_HOME=/home/$BUILD_USER @@ -122,7 +124,7 @@ step_os_check() { APT_PACKAGES=( build-essential clang lld llvm libclang-dev pkg-config libssl-dev cmake protobuf-compiler gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-x86-64-dev mingw-w64-tools - git tmux curl ca-certificates xz-utils zstd unzip rsync jq python3 ufw htop file + git tmux curl ca-certificates xz-utils zstd unzip rsync jq python3 ufw htop file caddy ) step_apt() { local need=() p @@ -337,17 +339,49 @@ EOF changed sshd "key-only, root prohibit-password" } +# the worker dashboard's feed (asked for on 6 October 2026, approved by main): Caddy serves exactly two files of /srv/workers +# over HTTPS at build.igneum.network (A record in deSEC, set by main), read-only, no directory listing, every other path 404, +# CORS for dl.igneum.network, no caching. Nothing under /srv/workers is a secret (workers.json and headline.json are written +# by the dashboard collector and remote-run.sh); the Caddyfile refuses every other file name anyway. Issuer pinned to Let's +# Encrypt: Ubuntu's Caddy 2.6.2 fails the ZeroSSL fallback (HTTP 422 caddy_legacy_user_removed, 6 Oct 2026) and would retry it for ever. +step_caddy() { + local f=/etc/caddy/Caddyfile tmp + command -v caddy >/dev/null 2>&1 || die "caddy is not installed (apt)" + install -d -m 755 -o "$BUILD_USER" -g "$BUILD_USER" /srv/workers + tmp=$(mktemp) + cat > "$tmp" </dev/null 2>&1 || { rm -f "$tmp"; die "caddy validate rejected the Caddyfile"; } + install -m 644 "$tmp" "$f"; rm -f "$tmp" + systemctl enable --quiet caddy 2>/dev/null || true + systemctl reload caddy 2>/dev/null || systemctl restart caddy + changed caddy "$WORKERS_HOST serving /srv/workers/{workers,headline}.json" +} + step_ufw() { local p want=() any=0 status status=$(ufw status verbose 2>/dev/null || true) grep -q 'Default: deny (incoming), allow (outgoing)' <<<"$status" || { ufw --force default deny incoming >/dev/null; ufw --force default allow outgoing >/dev/null; any=1; } - want=(22) + want=(22 80 443) for p in $P2P_PORTS; do want+=("$p"); done for p in "${want[@]}"; do grep -qE "^$p/tcp +ALLOW IN +Anywhere *$" <<<"$status" || { ufw allow "$p/tcp" >/dev/null; any=1; } done grep -q '^Status: active' <<<"$status" || { ufw --force enable >/dev/null; any=1; } - [ "$any" = 1 ] && changed ufw "22 and ${P2P_PORTS} open, everything else denied" || ok ufw "22 and ${P2P_PORTS}" + [ "$any" = 1 ] && changed ufw "22, 80, 443 and ${P2P_PORTS} open, everything else denied" || ok ufw "22, 80, 443 and ${P2P_PORTS}" } step_summary() { @@ -364,6 +398,7 @@ step_summary() { printf 'mirrors: /srv/igneum.git (%s) /srv/igneum-node.git (%s)\n' "$(as_build 'git -C /srv/igneum.git branch --list | wc -l') branches" "$(as_build 'git -C /srv/igneum-node.git branch --list | wc -l') branches" printf 'builds: %s worktree dirs under /srv/builds, %s slot(s)\n' "$(worktree_count)" "$(cat /srv/builds/_locks/slots)" printf 'ufw: %s\n' "$(ufw status | grep -E 'ALLOW' | awk '{ print $1 }' | tr '\n' ' ')" + printf 'caddy: %s, %s\n' "$(caddy version 2>/dev/null | cut -d' ' -f1)" "$(systemctl is-active caddy 2>/dev/null) at https://$WORKERS_HOST/headline.json" printf 'ssh line: ssh -i ~/.ssh/igneum_ed25519 build@%s\n' "$(hostname -I 2>/dev/null | awk '{ print $1 }')" } | sed 's/^/ /' } @@ -385,6 +420,7 @@ do_provision() { step_profile step_node step_sshd + step_caddy step_ufw step_summary log "done" diff --git a/infra/build-server/remote-run.sh b/infra/build-server/remote-run.sh index 6493e05bb..2ef2bdbd8 100755 --- a/infra/build-server/remote-run.sh +++ b/infra/build-server/remote-run.sh @@ -81,12 +81,19 @@ for k in $(seq 0 $((slots - 1))); do done if [ -z "$got" ]; then echo "build-remote: all $slots slot(s) busy, waiting (up to 2 h) for build-0: $(head -c 160 "$IGNEUM_BUILD_SLOTS_DIR/build-0" 2>/dev/null)" >&2 + # the queue is visible while it waits (the worker dashboard reads wait-* files; asked for on 6 October 2026): the same line + # format as a slot file, removed the moment the slot is taken or the wait is given up + waitfile="$IGNEUM_BUILD_SLOTS_DIR/wait-$BR_PID" + printf 'pid %s since %sZ waited 0 s: %s\n' "$BR_PID" "$(date -u +%H:%M:%S)" "$BR_LABEL" > "$waitfile" + trap 'rm -f "$waitfile"' EXIT exec {fd}>"$IGNEUM_BUILD_SLOTS_DIR/build-0" if ! flock -w 7200 "$fd"; then echo "build-remote: gave up waiting for a slot after 2 h" >&2 jsonlog 75 0 $(( $(date +%s) - BR_T0 )) "" "$(date +%s)" "" "" "" "" "" "" + rm -f "$waitfile" exit 75 fi + rm -f "$waitfile"; trap - EXIT got=0 fi waited=$(( $(date +%s) - BR_T0 ))