From 48f7dad599381e704ea0557841290bc5dd68e698 Mon Sep 17 00:00:00 2001 From: David Schroeder Date: Tue, 28 Jul 2026 18:01:29 -0500 Subject: [PATCH] fix clean deployment nginx configuration --- deploy/nginx/templates/http.conf.template | 1 - deploy/nginx/templates/tls.conf.template | 1 - docs/deployment.md | 7 +++ install.sh | 9 ++++ manage.sh | 52 ++++++++++++++++++++++- tests/test-deployment-scripts.sh | 35 +++++++++++++++ 6 files changed, 102 insertions(+), 3 deletions(-) diff --git a/deploy/nginx/templates/http.conf.template b/deploy/nginx/templates/http.conf.template index 6479dea..24be857 100644 --- a/deploy/nginx/templates/http.conf.template +++ b/deploy/nginx/templates/http.conf.template @@ -3,7 +3,6 @@ server_tokens off; reset_timedout_connection on; client_header_timeout 15s; client_body_timeout 60s; -keepalive_timeout 30s; send_timeout 60s; limit_conn_zone $binary_remote_addr zone=per_address_connections:10m; diff --git a/deploy/nginx/templates/tls.conf.template b/deploy/nginx/templates/tls.conf.template index 162b966..8209d15 100644 --- a/deploy/nginx/templates/tls.conf.template +++ b/deploy/nginx/templates/tls.conf.template @@ -4,7 +4,6 @@ server_tokens off; reset_timedout_connection on; client_header_timeout 15s; client_body_timeout 60s; -keepalive_timeout 30s; send_timeout 60s; limit_conn_zone $binary_remote_addr zone=per_address_connections:10m; diff --git a/docs/deployment.md b/docs/deployment.md index bf750be..e1d8381 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -119,6 +119,13 @@ The broker is deliberately not started during the first bootstrap. Blank OAuth/package values are valid for Gitea-only setup, while `start` refuses to launch the broker until all required credentials are present. +For troubleshooting, use `./manage.sh diagnostics`. Do not share unredacted +`docker compose config` output: Compose resolves the broker's `.env` file and +can print cookie, OAuth, and package secrets. If configuration output is +accidentally disclosed, rotate the cookie secret with +`./manage.sh rotate-cookie-secret` and replace any configured Gitea tokens or +OAuth secret that appeared. + ## 4. Enable TLS when forwarding is ready After public DNS resolves and the datacenter edge forwards public TCP 80 and diff --git a/install.sh b/install.sh index be3ca58..89ae5e1 100755 --- a/install.sh +++ b/install.sh @@ -32,6 +32,15 @@ valid_port() { [[ $# -eq 0 ]] || fail "usage: ./install.sh" [[ ! -e .env ]] || fail ".env already exists; use ./manage.sh instead of overwriting this deployment" +for required_file in \ + compose.yaml \ + compose.http.yaml \ + compose.tls.yaml \ + deploy/nginx/templates/http.conf.template \ + deploy/nginx/templates/tls.conf.template; do + [[ -f "$required_file" ]] || + fail "repository file is missing or not a regular file: ${required_file}" +done for command_name in docker openssl; do command -v "$command_name" >/dev/null 2>&1 || diff --git a/manage.sh b/manage.sh index c6dc30a..eb22159 100755 --- a/manage.sh +++ b/manage.sh @@ -65,6 +65,29 @@ compose_stack() { docker compose "${COMPOSE_FILES[@]}" "$@" } +require_regular_file() { + local path="$1" + + if [[ -f "$path" ]]; then + return 0 + fi + if [[ -d "$path" ]]; then + fail "${path} is a directory; remove it and restore the missing repository file" + fi + fail "required deployment file is missing: ${path}" +} + +require_stack_files() { + require_regular_file compose.yaml + if [[ "$SSL_MODE" == "none" ]]; then + require_regular_file compose.http.yaml + require_regular_file deploy/nginx/templates/http.conf.template + else + require_regular_file compose.tls.yaml + require_regular_file deploy/nginx/templates/tls.conf.template + fi +} + broker_config_ready() { local key local value @@ -157,6 +180,7 @@ require_env() { esac export GITEA_PUBLIC_URL SSL_CERTIFICATE_DIR SSL_CERTIFICATE_FILE SSL_CERTIFICATE_KEY_FILE select_compose_stack + require_stack_files } prepare() { @@ -284,6 +308,18 @@ configure-broker) printf 'Broker credentials saved to .env with mode 0600.\n' printf 'Start the complete stack with ./manage.sh start\n' ;; +rotate-cookie-secret) + require_env + command -v openssl >/dev/null 2>&1 || + fail "openssl is required to generate the cookie secret" + set_env_setting TAPM_COOKIE_SECRET "$(openssl rand -base64 48)" + printf 'TAPM_COOKIE_SECRET was rotated in .env.\n' + if compose_stack ps -q broker | grep -q .; then + printf 'Recreating the broker to apply it...\n' + compose_stack up -d --force-recreate broker + printf 'Existing technician browser sessions are now invalid.\n' + fi + ;; set-ssl) require_env target_mode="${2:-}" @@ -349,6 +385,20 @@ status) require_env compose_stack ps ;; +diagnostics) + require_env + printf '%s\n' 'Compose services:' + compose_stack config --services + printf '\n%s\n' 'Container status:' + compose_stack ps + printf '\n%s\n' 'Recent Nginx logs:' + compose_stack logs --tail=100 nginx + printf '\n%s\n' 'Published Nginx ports:' + compose_stack port nginx 80 || true + if [[ "$SSL_MODE" != "none" ]]; then + compose_stack port nginx 443 || true + fi + ;; broker-container-id) require_env compose_stack ps -q broker @@ -358,7 +408,7 @@ broker-logs) compose_stack logs --tail=100 broker ;; *) - printf 'Usage: %s {prepare|bootstrap|configure-broker|set-ssl|start|start-direct|create-admin|renew|backup|status}\n' "$0" + printf 'Usage: %s {prepare|bootstrap|configure-broker|rotate-cookie-secret|set-ssl|start|start-direct|create-admin|renew|backup|status|diagnostics}\n' "$0" exit 2 ;; esac diff --git a/tests/test-deployment-scripts.sh b/tests/test-deployment-scripts.sh index 8231881..7d30e14 100755 --- a/tests/test-deployment-scripts.sh +++ b/tests/test-deployment-scripts.sh @@ -18,6 +18,26 @@ cp -R \ "${TEST_ROOT}/deploy" \ "$deployment/" +mv "${deployment}/deploy/nginx/templates/http.conf.template" \ + "${deployment}/deploy/nginx/templates/http.conf.template.saved" +mkdir "${deployment}/deploy/nginx/templates/http.conf.template" +if ( + cd "$deployment" + printf '%s\n' \ + 'broker.test' \ + 'git.test' \ + '8780' \ + '8743' \ + '' | + ./install.sh >/dev/null 2>&1 +); then + printf 'FAIL: installer accepted a template path that was a directory\n' >&2 + exit 1 +fi +rmdir "${deployment}/deploy/nginx/templates/http.conf.template" +mv "${deployment}/deploy/nginx/templates/http.conf.template.saved" \ + "${deployment}/deploy/nginx/templates/http.conf.template" + cat >"${mock_bin}/docker" <<'MOCK' #!/usr/bin/env bash printf '%s\n' "$*" >>"$MOCK_DOCKER_LOG" @@ -32,6 +52,12 @@ chmod +x "${mock_bin}/docker" export MOCK_DOCKER_LOG="${test_dir}/docker.log" export PATH="${mock_bin}:${PATH}" +if grep -R '^[[:space:]]*keepalive_timeout[[:space:]]' \ + "${TEST_ROOT}/deploy/nginx/templates/"*.template >/dev/null; then + printf 'FAIL: conf.d template duplicates nginx.conf keepalive_timeout\n' >&2 + exit 1 +fi + printf '%s\n' \ 'broker.test' \ 'git.test' \ @@ -82,4 +108,13 @@ assert_env 'GITEA_PUBLIC_URL=https://git.test/' assert_env 'SSL_MODE=none' assert_env 'TAPM_PUBLIC_URL=http://broker.test:8780' +"${deployment}/manage.sh" rotate-cookie-secret >/dev/null +rotated_secret="$( + sed -n 's/^TAPM_COOKIE_SECRET=//p' "${deployment}/.env" +)" +(( ${#rotated_secret} >= 32 )) || { + printf 'FAIL: cookie secret rotation produced a short value\n' >&2 + exit 1 +} + printf 'PASS: guided HTTP deployment and TLS transition\n'