From f31a45618801ffa1300fe2b1c72efeec3b5a9b28 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 26 May 2026 10:36:29 +0000 Subject: [PATCH 1/2] fix(nginx): harden error handling in bash and PowerShell installers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace || true on ACME .so staging copy with explicit Stop-Script so a missing libnginx_acme.so fails loudly instead of silently - Add error handling to cd in Install-Nginx (bash) to give a clear message instead of relying on set -e - Replace nginx -t && systemctl start nginx with explicit if/Stop-Script so config failures produce a readable log entry - Add lsof availability check with ss fallback in Test-RunningWebServers (both .sh and .ps1) — avoids silent skip on minimal containers - Fix ACME staging copy in PS1 to use ErrorAction Stop + catch instead of SilentlyContinue - Align pacman update failure in PS1 Update-SystemPackages to Write-Log WARN (matching bash behavior) instead of Stop-Script - Add Stop-Transcript to finally block in PS1 to ensure log is flushed https://claude.ai/code/session_01QuVvMsLEmrc5iLdMM5R3up --- nginx/nginx_installer.ps1 | 19 ++++++++++++++++--- nginx/nginx_installer.sh | 18 ++++++++++++++---- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/nginx/nginx_installer.ps1 b/nginx/nginx_installer.ps1 index 5354940..0535768 100644 --- a/nginx/nginx_installer.ps1 +++ b/nginx/nginx_installer.ps1 @@ -233,7 +233,7 @@ function Update-SystemPackages { } 'pacman' { & pacman -Syu --noconfirm 2>&1 | Out-Null - if ($LASTEXITCODE -ne 0) { Stop-Script 'pacman upgrade failed' } + if ($LASTEXITCODE -ne 0) { Write-Log 'WARN' 'pacman upgrade failed' } } default { Write-Log 'WARN' 'Unable to detect package manager' @@ -425,7 +425,11 @@ export LDFLAGS='-lzstd' } New-Item -ItemType Directory -Path "$Script:BUILD_DIR/nginx-acme/objs" -Force | Out-Null - Copy-Item 'target/release/libnginx_acme.so' -Destination "$Script:BUILD_DIR/nginx-acme/objs/ngx_http_acme_module.so" -Force -ErrorAction SilentlyContinue + try { + Copy-Item 'target/release/libnginx_acme.so' -Destination "$Script:BUILD_DIR/nginx-acme/objs/ngx_http_acme_module.so" -Force -ErrorAction Stop + } catch { + Stop-Script 'Failed to stage ACME module: target/release/libnginx_acme.so not found' + } Pop-Location # nginx-acme Pop-Location # nginx @@ -820,7 +824,15 @@ function Test-RunningWebServers { $portsInUse = [System.Collections.Generic.List[string]]::new() foreach ($port in @(80, 443)) { - $procId = (bash -c "lsof -ti :$port 2>/dev/null | head -n1" 2>$null)?.Trim() + $detectPid = @' +port=$1 +if command -v lsof >/dev/null 2>&1; then + lsof -ti ":$port" 2>/dev/null | head -n1 +else + ss -tlnp 2>/dev/null | awk -v p="$port" '$0 ~ ":"p"[[:space:]]" {match($0,/pid=([0-9]+)/,a); if(a[1]) {print a[1]; exit}}' +fi +'@ + $procId = (bash -c $detectPid 'detect-port' $port 2>$null)?.Trim() if ($procId) { $proc = (bash -c "ps -p $procId -o comm= 2>/dev/null || echo unknown").Trim() $portsInUse.Add("$port ($proc)") @@ -862,5 +874,6 @@ try { } } } finally { + Stop-Transcript -ErrorAction SilentlyContinue Remove-Item $Script:BUILD_DIR -Recurse -Force -ErrorAction SilentlyContinue } diff --git a/nginx/nginx_installer.sh b/nginx/nginx_installer.sh index 7dd4f39..4d5e739 100755 --- a/nginx/nginx_installer.sh +++ b/nginx/nginx_installer.sh @@ -349,7 +349,8 @@ Build-Nginx() { fi mkdir -p "$BUILD_DIR/nginx-acme/objs" - cp target/release/libnginx_acme.so "$BUILD_DIR/nginx-acme/objs/ngx_http_acme_module.so" || true + cp target/release/libnginx_acme.so "$BUILD_DIR/nginx-acme/objs/ngx_http_acme_module.so" \ + || Stop-Script "Failed to stage ACME module: target/release/libnginx_acme.so not found" Write-Log INFO "ACME module built successfully" Write-Log INFO "Build complete" @@ -553,7 +554,7 @@ Install-Nginx() { fi # Install binaries - cd "$BUILD_DIR/nginx" + cd "$BUILD_DIR/nginx" || Stop-Script "Cannot cd to $BUILD_DIR/nginx" local output if ! output=$(make install 2>&1); then Write-Log ERROR "Install output: $(echo "$output" | tail -10)" @@ -646,7 +647,10 @@ EOF systemctl daemon-reload systemctl enable nginx >/dev/null 2>&1 - nginx -t && systemctl start nginx + if ! nginx -t; then + Stop-Script "nginx configuration test failed — check the error above" + fi + systemctl start nginx || Stop-Script "Failed to start nginx service" local openssl_ver openssl_ver=$(openssl version 2>/dev/null | awk '{print $1" "$2}' || echo "OpenSSL unknown") @@ -716,7 +720,13 @@ Test-RunningWebServers() { for port in 80 443; do local pid - pid=$(lsof -ti :"$port" 2>/dev/null | head -n1 || true) + if command -v lsof >/dev/null 2>&1; then + pid=$(lsof -ti :"$port" 2>/dev/null | head -n1 || true) + else + pid=$(ss -tlnp 2>/dev/null \ + | awk -v p="${port}" '$0 ~ ":"p"[[:space:]]" {match($0,/pid=([0-9]+)/,a); if(a[1]) {print a[1]; exit}}' \ + || true) + fi if [[ -n "$pid" ]]; then local proc proc=$(ps -p "$pid" -o comm= 2>/dev/null || echo "unknown") From f3fde3dfea849a9398bbfa9fd93a06328b1d9e80 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 26 May 2026 10:44:06 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix(nginx):=20address=20Copilot=20review=20?= =?UTF-8?q?=E2=80=94=20improve=20ACME=20error=20messages,=20absolute=20ngi?= =?UTF-8?q?nx=20path,=20portable=20awk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Split ACME staging into an explicit existence check ([[ -f ]]/Test-Path) with a "not built" message, followed by a cp error that preserves the actual failure reason ($_.Exception.Message in PS1; generic disk/perms hint in bash) instead of always saying "not found" - Replace bare `nginx` calls with `/usr/sbin/nginx` throughout (Install-Nginx and Test-NginxInstallation in both scripts) so PATH stripping in non-interactive/root contexts cannot mask a missing binary - Rewrite ss PID extraction to use POSIX 2-arg match() + RSTART/RLENGTH instead of gawk-only 3-arg match(), making it compatible with mawk and busybox awk - Add pre-loop availability check for lsof/ss; emit a WARN and skip the port conflict check rather than silently producing an empty result when neither tool is present https://claude.ai/code/session_01QuVvMsLEmrc5iLdMM5R3up --- nginx/nginx_installer.ps1 | 31 ++++++++++++++++++++++--------- nginx/nginx_installer.sh | 27 ++++++++++++++++++++------- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/nginx/nginx_installer.ps1 b/nginx/nginx_installer.ps1 index 0535768..954e506 100644 --- a/nginx/nginx_installer.ps1 +++ b/nginx/nginx_installer.ps1 @@ -425,10 +425,14 @@ export LDFLAGS='-lzstd' } New-Item -ItemType Directory -Path "$Script:BUILD_DIR/nginx-acme/objs" -Force | Out-Null + $acmeSo = 'target/release/libnginx_acme.so' + if (-not (Test-Path $acmeSo)) { + Stop-Script "ACME module not built: $acmeSo missing (cargo build may have failed)" + } try { - Copy-Item 'target/release/libnginx_acme.so' -Destination "$Script:BUILD_DIR/nginx-acme/objs/ngx_http_acme_module.so" -Force -ErrorAction Stop + Copy-Item $acmeSo -Destination "$Script:BUILD_DIR/nginx-acme/objs/ngx_http_acme_module.so" -Force -ErrorAction Stop } catch { - Stop-Script 'Failed to stage ACME module: target/release/libnginx_acme.so not found' + Stop-Script "Failed to stage ACME module: $($_.Exception.Message)" } Pop-Location # nginx-acme @@ -746,7 +750,7 @@ WantedBy=multi-user.target bash -c 'systemctl daemon-reload' | Out-Null bash -c 'systemctl enable nginx' 2>&1 | Out-Null - bash -c 'nginx -t && systemctl start nginx' | Out-Null + bash -c '/usr/sbin/nginx -t && systemctl start nginx' | Out-Null if ($LASTEXITCODE -ne 0) { Stop-Script 'Failed to start nginx' } $opensslVer = (bash -c 'openssl version 2>/dev/null').Trim() @@ -754,7 +758,7 @@ WantedBy=multi-user.target Write-Log 'INFO' "Nginx $Script:NGINX_VERSION with $opensslVer (system) installed" Write-Log 'INFO' 'Access: https://localhost' Write-Log 'INFO' 'Manage nginx with: systemctl {start|stop|reload|restart|status} nginx' - bash -c 'nginx -V 2>&1 | head -n1' + bash -c '/usr/sbin/nginx -V 2>&1 | head -n1' $testResult = Test-NginxInstallation if (-not $testResult) { @@ -777,7 +781,7 @@ function Test-NginxInstallation { Write-Log 'INFO' 'ACME module present' } - $nginxTest = bash -c 'nginx -t 2>&1' + $nginxTest = bash -c '/usr/sbin/nginx -t 2>&1' if ($LASTEXITCODE -ne 0) { Write-Log 'ERROR' "nginx -t failed: $nginxTest" $ok = $false @@ -823,16 +827,25 @@ function Remove-Nginx { function Test-RunningWebServers { $portsInUse = [System.Collections.Generic.List[string]]::new() + $portTool = (bash -c '(command -v lsof >/dev/null 2>&1 && echo lsof) || (command -v ss >/dev/null 2>&1 && echo ss) || echo none').Trim() + if ($portTool -eq 'none') { + Write-Log 'WARN' 'Neither lsof nor ss available; skipping port conflict check' + return + } + foreach ($port in @(80, 443)) { $detectPid = @' -port=$1 -if command -v lsof >/dev/null 2>&1; then +tool=$1; port=$2 +if [ "$tool" = "lsof" ]; then lsof -ti ":$port" 2>/dev/null | head -n1 else - ss -tlnp 2>/dev/null | awk -v p="$port" '$0 ~ ":"p"[[:space:]]" {match($0,/pid=([0-9]+)/,a); if(a[1]) {print a[1]; exit}}' + ss -tlnp 2>/dev/null | awk -v p="$port" ' + $0 ~ ":"p"[[:space:]]" { + if (match($0, /pid=[0-9]+/)) { print substr($0, RSTART+4, RLENGTH-4); exit } + }' fi '@ - $procId = (bash -c $detectPid 'detect-port' $port 2>$null)?.Trim() + $procId = (bash -c $detectPid 'detect-port' $portTool $port 2>$null)?.Trim() if ($procId) { $proc = (bash -c "ps -p $procId -o comm= 2>/dev/null || echo unknown").Trim() $portsInUse.Add("$port ($proc)") diff --git a/nginx/nginx_installer.sh b/nginx/nginx_installer.sh index 4d5e739..d82d513 100755 --- a/nginx/nginx_installer.sh +++ b/nginx/nginx_installer.sh @@ -349,8 +349,10 @@ Build-Nginx() { fi mkdir -p "$BUILD_DIR/nginx-acme/objs" - cp target/release/libnginx_acme.so "$BUILD_DIR/nginx-acme/objs/ngx_http_acme_module.so" \ - || Stop-Script "Failed to stage ACME module: target/release/libnginx_acme.so not found" + local acme_so="target/release/libnginx_acme.so" + [[ -f "$acme_so" ]] || Stop-Script "ACME module not built: $acme_so missing (cargo build may have failed)" + cp "$acme_so" "$BUILD_DIR/nginx-acme/objs/ngx_http_acme_module.so" \ + || Stop-Script "Failed to stage ACME module: cp failed (check disk space or permissions)" Write-Log INFO "ACME module built successfully" Write-Log INFO "Build complete" @@ -647,7 +649,7 @@ EOF systemctl daemon-reload systemctl enable nginx >/dev/null 2>&1 - if ! nginx -t; then + if ! /usr/sbin/nginx -t; then Stop-Script "nginx configuration test failed — check the error above" fi systemctl start nginx || Stop-Script "Failed to start nginx service" @@ -657,7 +659,7 @@ EOF Write-Log INFO "Nginx ${NGINX_VERSION} with ${openssl_ver} (system) installed" Write-Log INFO "Access: https://localhost" Write-Log INFO "Manage nginx with: systemctl {start|stop|reload|restart|status} nginx" - nginx -V 2>&1 | head -n1 || true + /usr/sbin/nginx -V 2>&1 | head -n1 || true Test-NginxInstallation || Write-Log WARN "Post-install checks detected issues" } @@ -676,7 +678,7 @@ Test-NginxInstallation() { Write-Log INFO "ACME module present" fi - if ! nginx -t >/dev/null 2>&1; then + if ! /usr/sbin/nginx -t >/dev/null 2>&1; then Write-Log ERROR "nginx -t failed" return 1 fi @@ -717,14 +719,25 @@ Remove-Nginx() { Test-RunningWebServers() { local ports_in_use=() + local has_lsof=0 has_ss=0 + command -v lsof >/dev/null 2>&1 && has_lsof=1 + command -v ss >/dev/null 2>&1 && has_ss=1 + + if [[ $has_lsof -eq 0 && $has_ss -eq 0 ]]; then + Write-Log WARN "Neither lsof nor ss available; skipping port conflict check" + return 0 + fi for port in 80 443; do local pid - if command -v lsof >/dev/null 2>&1; then + if [[ $has_lsof -eq 1 ]]; then pid=$(lsof -ti :"$port" 2>/dev/null | head -n1 || true) else pid=$(ss -tlnp 2>/dev/null \ - | awk -v p="${port}" '$0 ~ ":"p"[[:space:]]" {match($0,/pid=([0-9]+)/,a); if(a[1]) {print a[1]; exit}}' \ + | awk -v p="${port}" ' + $0 ~ ":"p"[[:space:]]" { + if (match($0, /pid=[0-9]+/)) { print substr($0, RSTART+4, RLENGTH-4); exit } + }' \ || true) fi if [[ -n "$pid" ]]; then