diff --git a/deploy.sh b/deploy.sh index 0f74db3..49f8016 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1461,6 +1461,11 @@ echo "" # Step 14: Start the stack echo -e "${BLUE}[14/14] Starting the Matrix stack...${NC}" + +if [[ "${SKIP_START:-false}" == "true" ]]; then + print_info "Skipping stack start (SKIP_START=true)" +else + print_info "Using compose file: ${COMPOSE_FILE}" print_info "This may take a few minutes on first run..." echo "" @@ -1563,6 +1568,8 @@ if [[ "$DEPLOYMENT_MODE" == "local" ]]; then echo "" fi +fi # end SKIP_START + # ============================================================================ # PRODUCTION: Generate Caddy and Authelia configs for separate machines # ============================================================================ diff --git a/quickstart.sh b/quickstart.sh index 52a5275..0f746bb 100755 --- a/quickstart.sh +++ b/quickstart.sh @@ -270,6 +270,7 @@ if [[ ! -f "synapse/data/homeserver.yaml" ]]; then -e SYNAPSE_SERVER_NAME="${MATRIX_DOMAIN}" \ -e SYNAPSE_REPORT_STATS=no \ matrixdotorg/synapse:latest generate 2>/dev/null + sudo chown -R "$(id -u):$(id -g)" synapse/data/ ok "Synapse config generated" fi @@ -297,6 +298,9 @@ database: cp_max: 10 enable_registration: false +allow_guest_access: false +allow_public_rooms_without_auth: false +allow_public_rooms_over_federation: false matrix_authentication_service: enabled: true @@ -337,7 +341,7 @@ fi cat > caddy/Caddyfile << EOF { email ${LETSENCRYPT_EMAIL} - admin 0.0.0.0:2019 + admin localhost:2019 } ${MATRIX_DOMAIN} { @@ -370,6 +374,8 @@ ${MATRIX_DOMAIN} { handle @compat { header Access-Control-Allow-Origin "*" reverse_proxy mas:8080 { + header_up Host {http.request.host} + header_up X-Forwarded-Host {http.request.host} header_down -Access-Control-Allow-Origin } } @@ -382,6 +388,11 @@ ${MATRIX_DOMAIN} { } } + # Block public access to Synapse admin API + handle /_synapse/admin* { + respond "Forbidden" 403 + } + handle { reverse_proxy synapse:8008 } @@ -391,21 +402,33 @@ ${AUTH_DOMAIN} { @disco path /.well-known/openid-configuration handle @disco { header Access-Control-Allow-Origin "*" - reverse_proxy mas:8080 + reverse_proxy mas:8080 { + header_up Host {http.request.host} + header_up X-Forwarded-Host {http.request.host} + } } @oauth path /oauth2/* route @oauth { header Access-Control-Allow-Origin "*" - reverse_proxy mas:8080 + reverse_proxy mas:8080 { + header_up Host {http.request.host} + header_up X-Forwarded-Host {http.request.host} + } } - handle_path /account/* { - reverse_proxy mas:8080 + handle /account/* { + reverse_proxy mas:8080 { + header_up Host {http.request.host} + header_up X-Forwarded-Host {http.request.host} + } } handle { - reverse_proxy mas:8080 + reverse_proxy mas:8080 { + header_up Host {http.request.host} + header_up X-Forwarded-Host {http.request.host} + } } } @@ -451,6 +474,11 @@ echo "" # ── Start the stack ─────────────────────────────────────────────────────────── +if [[ "${SKIP_START:-false}" == "true" ]]; then + ok "Skipping stack start (SKIP_START=true)" + echo "" +else + info "Starting PostgreSQL..." sudo docker compose up -d postgres @@ -469,6 +497,8 @@ info "Starting all services..." sudo docker compose --profile single-machine up -d ${CORE_SERVICES} echo "" +fi + # ── Summary ─────────────────────────────────────────────────────────────────── ok "Stack is up." diff --git a/test_deploy.sh b/test_deploy.sh index eb36c03..1bfe919 100755 --- a/test_deploy.sh +++ b/test_deploy.sh @@ -385,6 +385,40 @@ assert_endpoints() { || fail "Element Web root (no Element content in response)" } +# ─── Quickstart config assertions ──────────────────────────────────────────── +assert_quickstart_configs() { + local domain="$1" + local matrix_domain="matrix.${domain}" + local auth_domain="auth.${domain}" + + header "Quickstart config assertions (domain=${domain})" + + assert_file ".env" ".env generated" + assert_contains ".env" "DOMAIN=${domain}" ".env → DOMAIN" + assert_contains ".env" "MATRIX_DOMAIN=${matrix_domain}" ".env → MATRIX_DOMAIN" + + assert_file "mas/config/config.yaml" "mas/config/config.yaml generated" + assert_contains "mas/config/config.yaml" "homeserver: '${matrix_domain}'" "MAS → homeserver" + assert_contains "mas/config/config.yaml" "name: adminapi" "MAS → adminapi listener" + assert_contains "mas/config/config.yaml" "public_base: 'https://${auth_domain}/'" "MAS → public_base" + assert_contains "mas/config/config.yaml" "issuer: 'https://${auth_domain}/'" "MAS → issuer" + + assert_file "element/config/config.json" "element/config/config.json generated" + + assert_file "synapse/data/homeserver.yaml" "synapse/data/homeserver.yaml generated" + assert_contains "synapse/data/homeserver.yaml" "enable_registration: false" "Synapse → registration disabled" + assert_contains "synapse/data/homeserver.yaml" "allow_guest_access: false" "Synapse → guest access disabled" + assert_contains "synapse/data/homeserver.yaml" "allow_public_rooms_without_auth: false" "Synapse → public rooms blocked" + assert_contains "synapse/data/homeserver.yaml" "allow_public_rooms_over_federation: false" "Synapse → public rooms over federation blocked" + + assert_file "caddy/Caddyfile" "caddy/Caddyfile generated" + assert_contains "caddy/Caddyfile" "admin localhost:2019" "Caddyfile → admin API localhost only" + assert_contains "caddy/Caddyfile" "/_synapse/admin" "Caddyfile → synapse admin block present" + assert_contains "caddy/Caddyfile" "header_up X-Forwarded-Host" "Caddyfile → MAS proxy forwards X-Forwarded-Host" + assert_contains "caddy/Caddyfile" "handle /account/" "Caddyfile → /account/ uses handle (preserves prefix)" + assert_not_contains "caddy/Caddyfile" "handle_path /account/" "Caddyfile → /account/ not handle_path" +} + # ─── Run one full scenario ──────────────────────────────────────────────────── run_scenario() { local name="$1" @@ -459,6 +493,52 @@ run_scenario \ "2" \ "matrix.example.test" +# Scenario P — production Caddyfile generation (config only, no Let's Encrypt) +section "P · Production Caddyfile (config only)" +teardown_stack +cleanup_configs +info "Running deploy.sh production mode (piped stdin, SKIP_START=true)" +# Stdin answers in prompt order: +# [1] Deployment type: 2 (production) +# [2] Include Authelia? n +# [3] Enable Element Call? n +# [4] Custom Docker registry prefix: (empty) +# [5] Use hardened images? n +# [6] Base domain: example.com +# [7] Matrix subdomain: (empty → matrix) +# [8] Element subdomain: (empty → element) +# [9] Admin subdomain: (empty → admin) +# [10] Auth subdomain: (empty → auth) +# [11] Authelia subdomain: (empty → authelia) +# [12] SERVER_NAME choice: 1 (TLD: @user:example.com) +# [13] Matrix server address: (empty → 10.0.1.10) +# [14] Authelia server address: (empty → 10.0.1.20) +# [15] Let's Encrypt email: (empty → admin@example.com) +printf '%s\n' "2" "n" "n" "" "n" "example.com" "" "" "" "" "" "1" "" "" "" \ + | SKIP_START=true bash deploy.sh + +header "Production Caddyfile assertions" +assert_file "caddy/Caddyfile.production" "caddy/Caddyfile.production generated" +assert_contains "caddy/Caddyfile.production" "admin localhost:2019" "Caddyfile.production → admin API localhost only" +assert_contains "caddy/Caddyfile.production" "/_synapse/admin" "Caddyfile.production → synapse admin block present" +assert_contains "caddy/Caddyfile.production" "header_up X-Forwarded-Host" "Caddyfile.production → MAS proxy forwards X-Forwarded-Host" +assert_contains "caddy/Caddyfile.production" "handle /account/" "Caddyfile.production → /account/ uses handle (preserves prefix)" +assert_not_contains "caddy/Caddyfile.production" "handle_path /account/" "Caddyfile.production → /account/ not handle_path" +assert_contains "caddy/Caddyfile.production" '"m.authentication"' "Caddyfile.production → well-known includes m.authentication" +assert_contains "caddy/Caddyfile.production" "Access-Control-Allow-Origin" "Caddyfile.production → well-known has CORS header" + +# Scenario Q — quickstart.sh config generation +section "Q · quickstart.sh (single-machine, config only)" +teardown_stack +cleanup_configs +info "Running quickstart.sh (piped stdin, SKIP_START=true)" +printf '%s\n' "example.test" "test@example.test" "n" \ + | SKIP_START=true bash quickstart.sh +assert_quickstart_configs "example.test" +if [[ "$SKIP_INTEGRATION" != "true" ]]; then + warn "Quickstart endpoint tests skipped (stack not started in SKIP_START mode)" +fi + trap - EXIT cleanup_on_exit print_summary