#!/usr/bin/env sh # Scripted clean-machine install test for the self-hosting guide (issue #88): # proves that a fresh directory containing ONLY the published reference files # (docker-compose.yml, Caddyfile, .env.example) boots to a working first-run # wizard behind the caddy profile's TLS. Uses its own compose project name, # high ports, and DOMAIN=localhost (internal-CA certificate), then removes # everything — safe to run on a host with live stacks. # # Environment: # IMAGE_PREFIX (default gitea.101010.cloud/stwaidele/dorfteich) # TAG (default test; a release = its semver tag) # HTTPS_PORT (default 8443) HTTP_PORT (default 8480) set -eu IMAGE_PREFIX="${IMAGE_PREFIX:-gitea.101010.cloud/stwaidele/dorfteich}" TAG="${TAG:-test}" HTTPS_PORT="${HTTPS_PORT:-8443}" HTTP_PORT="${HTTP_PORT:-8480}" HERE=$(cd "$(dirname "$0")" && pwd) PROJECT="dorfteich-selfhost-verify-$(date +%s)" DIR=$(mktemp -d) log() { echo "self-hosting-verify: $*"; } fail() { echo "self-hosting-verify: FAILED — $*" >&2; exit 1; } cleanup() { log "tearing down $PROJECT" (cd "$DIR" && docker compose --profile caddy down -v --remove-orphans >/dev/null 2>&1) || true rm -rf "$DIR" } trap cleanup EXIT # --- the guide's install steps, scripted ------------------------------------- cp "$HERE/compose/docker-compose.yml" "$HERE/compose/Caddyfile" "$DIR/" cp "$HERE/compose/.env.example" "$DIR/.env" chmod 600 "$DIR/.env" edit() { sed -i.bak "s|^#*$1=.*|$1=$2|" "$DIR/.env" && rm "$DIR/.env.bak"; } edit POSTGRES_PASSWORD "verify-$(date +%s%N | tail -c 13)" edit COLLAB_TOKEN_SECRET "verify-secret-$(date +%s%N)" edit IMAGE_PREFIX "$IMAGE_PREFIX" edit TAG "$TAG" edit COMPOSE_PROJECT_NAME "$PROJECT" edit WEB_PORT 0 && edit API_PORT 0 && edit COLLAB_PORT 0 # ephemeral host ports edit APP_BASE_URL "https://localhost:$HTTPS_PORT" edit DOMAIN localhost edit CADDY_HTTP_PORT "$HTTP_PORT" edit CADDY_HTTPS_PORT "$HTTPS_PORT" # Mail stays unconfigured — exactly the guide's "skip SMTP for now" path. edit SMTP_HOST "" && edit SMTP_PORT "" && edit SMTP_SECURE "" edit SMTP_USER "" && edit SMTP_PASS "" && edit SMTP_FROM "" log "starting $PROJECT from $DIR (images $IMAGE_PREFIX-*:$TAG)" (cd "$DIR" && docker compose --profile caddy pull --quiet && docker compose --profile caddy up -d) # --- the guide's promise: the wizard answers over TLS ------------------------ SETUP="" for _ in $(seq 1 60); do SETUP=$(curl -sk "https://localhost:$HTTPS_PORT/api/v1/setup" || true) case "$SETUP" in *'"status":"required"'*) break ;; esac sleep 2 done case "$SETUP" in *'"status":"required"'*) log "wizard reachable over TLS: $SETUP" ;; *) (cd "$DIR" && docker compose logs api caddy | tail -40); fail "wizard never answered: $SETUP" ;; esac echo | openssl s_client -connect "localhost:$HTTPS_PORT" -servername localhost 2>/dev/null \ | grep -q 'Caddy Local Authority' || fail "TLS certificate is not Caddy-issued" log "TLS certificate issued by Caddy's internal CA (a real DOMAIN gets Let's Encrypt)" curl -sk "https://localhost:$HTTPS_PORT/" | grep -qi '
' \ || fail "web app shell not served through the ingress" log "SPA shell served through the ingress" log "OK — a clean install following only the guide reaches the working wizard"