From 44ef585ee3ce0ae3b8576776f77bae6ff40c470b Mon Sep 17 00:00:00 2001 From: lingkai5wu Date: Thu, 20 Aug 2026 23:08:06 +0800 Subject: [PATCH] fix: harden nginx template reload and remove stale generated configs --- nginx/reload.sh | 99 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/nginx/reload.sh b/nginx/reload.sh index abb095a..c1c461f 100755 --- a/nginx/reload.sh +++ b/nginx/reload.sh @@ -1,11 +1,102 @@ #!/usr/bin/env bash -set -euo pipefail +set -Eeuo pipefail cd -- "$(dirname -- "${BASH_SOURCE[0]}")" -docker compose exec -T nginx /docker-entrypoint.d/20-envsubst-on-templates.sh -docker compose exec -T nginx nginx -t -docker compose exec -T nginx nginx -s reload +readonly SERVICE="nginx" + +if ! docker compose exec -T "$SERVICE" true >/dev/null 2>&1; then + echo "Error: nginx container is not running." >&2 + exit 1 +fi + +docker compose exec -T "$SERVICE" sh <<'EOF' +set -eu + +TEMPLATE_DIR="/etc/nginx/templates" +OUTPUT_DIR="/etc/nginx" +ENVSUBST_SCRIPT="/docker-entrypoint.d/20-envsubst-on-templates.sh" +MANAGED_DIRS="conf.d snippets" + +if [ ! -d "$TEMPLATE_DIR" ]; then + echo "Error: template directory does not exist: $TEMPLATE_DIR" >&2 + exit 1 +fi + +if [ ! -x "$ENVSUBST_SCRIPT" ]; then + echo "Error: envsubst script is not executable: $ENVSUBST_SCRIPT" >&2 + exit 1 +fi + +# Only allow templates in directories managed by this script. +find "$TEMPLATE_DIR" -type f -name '*.template' -print | while IFS= read -r template; do + relative="${template#"$TEMPLATE_DIR"/}" + + case "$relative" in + conf.d/* | snippets/*) + ;; + *) + echo "Error: unmanaged template path: $relative" >&2 + exit 1 + ;; + esac +done + +backup_dir="$(mktemp -d /tmp/nginx-reload.XXXXXX)" +committed=0 + +rollback() { + status=$? + + if [ "$committed" -eq 0 ]; then + echo "Reload failed. Restoring previous generated configuration." >&2 + + for dir in $MANAGED_DIRS; do + rm -rf "$OUTPUT_DIR/$dir" + + if [ -d "$backup_dir/$dir" ]; then + cp -a "$backup_dir/$dir" "$OUTPUT_DIR/$dir" + fi + done + fi + + rm -rf "$backup_dir" + exit "$status" +} + +trap rollback EXIT HUP INT TERM + +for dir in $MANAGED_DIRS; do + if [ -d "$OUTPUT_DIR/$dir" ]; then + cp -a "$OUTPUT_DIR/$dir" "$backup_dir/$dir" + fi +done + +for dir in $MANAGED_DIRS; do + if [ -d "$OUTPUT_DIR/$dir" ]; then + find "$OUTPUT_DIR/$dir" -type f -print | while IFS= read -r output; do + relative="${output#"$OUTPUT_DIR"/}" + + if [ ! -f "$TEMPLATE_DIR/$relative.template" ]; then + echo "Removing stale generated file: $relative" + fi + done + fi + + rm -rf "$OUTPUT_DIR/$dir" + mkdir -p "$OUTPUT_DIR/$dir" +done + +"$ENVSUBST_SCRIPT" + +nginx -t + +committed=1 +trap - EXIT HUP INT TERM +rm -rf "$backup_dir" +EOF + +docker compose exec -T "$SERVICE" nginx -s reload echo "Nginx configuration reloaded successfully."