mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-07 07:18:18 +00:00
fix(zdeploy): verify Next.js deploys on the server instead of probing the public IP (stops the bogus security-group warning) (#41)
* fix(zdeploy): verify Next.js deploys on the server, not the public IP The nextjs handler verified by requesting http://<ec2-ip>:<prod-port>/. A compose stack behind the edge proxy normally publishes to 127.0.0.1 only, so that request can never be answered and every deploy ended with "is the port open in the security group?" — pointing at a firewall rule for an app that was already serving fine. No security-group change could have made that probe succeed, which is what made the warning actively harmful: it named the one fix guaranteed not to work, and opening the port would have exposed the app directly, bypassing the proxy and TLS. The nextjs handler now uses the precedence the python handler already used: verify.port (curl localhost on the server) -> domain (Host-header check through the edge proxy) -> an honest "NOT verified" instead of a misleading warning. Also follow redirects in the health check. An app whose "/" answers 307 (Next.js -> /login) returns a body of a few bytes that read as "not ready"; -L fetches the page that actually renders. No effect on projects that point verify.path at a plain 200 endpoint such as /health. The example config now documents the verify block on the nextjs project, and CHECKSUMS.txt is regenerated for the changed script. * fix(zdeploy): truncate the health-check body in the PASS line Pointing the nextjs handler at Test-DeployHealth means the body is now often an HTML page, not a line of JSON, so the PASS line dumped ~10 KB of markup into the deploy output and buried everything after it. Match on the full body as before, but print at most 200 characters plus the byte count. A /health endpoint still prints in full.
This commit is contained in:
parent
b84d24b3a2
commit
c8fcfee76c
@ -8,7 +8,7 @@ c336a61cb8563736bd6550671d7dc90b14702a43f25a97b1ac15ffd64605fbf6 zbackup_ec2.cm
|
|||||||
20e6282901a919aa32ea717c739ba2dc9657426dff860f0e5fce201edefd99da zchecksums.cmd
|
20e6282901a919aa32ea717c739ba2dc9657426dff860f0e5fce201edefd99da zchecksums.cmd
|
||||||
692b7b0ff9e51e5d9b880358b33c54d2db4f967297a5350e154df1ce6f06ebc6 zchecksums.ps1
|
692b7b0ff9e51e5d9b880358b33c54d2db4f967297a5350e154df1ce6f06ebc6 zchecksums.ps1
|
||||||
b56085112e7c573926a70a58872163b71416d58ce91ea7114b1f5de5fc96c982 zdeploy.cmd
|
b56085112e7c573926a70a58872163b71416d58ce91ea7114b1f5de5fc96c982 zdeploy.cmd
|
||||||
3352214fac08cd83242680c0e7f60025c8f132bafb510384d7c7a0fe9a4c5094 zdeploy.ps1
|
c4189cef72368487af4524a00603967d7c8dc03c58ace5d4dd1e264ce1d22bd9 zdeploy.ps1
|
||||||
fa817d3bd7bba98b03b411d3c5a82b210d3cca316ac0c9785afa5b4ac5fe0766 zec2.cmd
|
fa817d3bd7bba98b03b411d3c5a82b210d3cca316ac0c9785afa5b4ac5fe0766 zec2.cmd
|
||||||
5f70432af23df3459a98d9ad6a0da723783f2269dd5f5ab8ecdd6366ebc84942 zec2.ps1
|
5f70432af23df3459a98d9ad6a0da723783f2269dd5f5ab8ecdd6366ebc84942 zec2.ps1
|
||||||
4df94eda29b6f5b2cb6bfa63e0add4d90ea24d936305f36a69988e8dd5d69154 zec2_rotatekeys.cmd
|
4df94eda29b6f5b2cb6bfa63e0add4d90ea24d936305f36a69988e8dd5d69154 zec2_rotatekeys.cmd
|
||||||
|
|||||||
@ -79,6 +79,12 @@
|
|||||||
"path": "/home/YOUR_SSH_USER/stack/nextapp",
|
"path": "/home/YOUR_SSH_USER/stack/nextapp",
|
||||||
"appService": "web"
|
"appService": "web"
|
||||||
},
|
},
|
||||||
|
"verify": {
|
||||||
|
"_comment": "Optional: after deploy, curl this ON the server (localhost:port+path). Add it when compose publishes the app to 127.0.0.1 only, as it usually does behind the edge proxy — probing the public IP on that port can never answer. Redirects are followed, so a Next.js '/' that 307s to '/login' still verifies. Takes precedence over the domain check.",
|
||||||
|
"port": 3000,
|
||||||
|
"path": "/",
|
||||||
|
"expect": ""
|
||||||
|
},
|
||||||
"deploy": { "zipName": "NextAppDeploy.zip" }
|
"deploy": { "zipName": "NextAppDeploy.zip" }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
39
zdeploy.ps1
39
zdeploy.ps1
@ -25,12 +25,15 @@
|
|||||||
# python kind: app service "app", db service "db"
|
# python kind: app service "app", db service "db"
|
||||||
# nextjs kind: app service "web", db service "db"
|
# nextjs kind: app service "web", db service "db"
|
||||||
#
|
#
|
||||||
# Verification (python kind, when there is no scripts/build_version_tool.py):
|
# Verification (python kind when there is no scripts/build_version_tool.py, and
|
||||||
|
# nextjs kind):
|
||||||
# Projects with a "verify" block are checked ON the server via
|
# Projects with a "verify" block are checked ON the server via
|
||||||
# localhost:<port><path> — the only accurate way for stacks that are not
|
# localhost:<port><path> — the only accurate way for stacks that are not
|
||||||
# published through the edge proxy. Projects with only a "domain" fall back
|
# published through the edge proxy. Projects with only a "domain" fall back
|
||||||
# to a Host-header request. Projects with neither are reported as NOT
|
# to a Host-header request. Projects with neither are reported as NOT
|
||||||
# verified rather than passing on the proxy's default vhost.
|
# verified rather than passing on the proxy's default vhost.
|
||||||
|
# A compose stack usually publishes to 127.0.0.1 only, so probing the public
|
||||||
|
# IP on the app's port can never answer — give those a "verify" block.
|
||||||
#
|
#
|
||||||
param(
|
param(
|
||||||
[Parameter(Position = 0, ValueFromRemainingArguments = $true)]
|
[Parameter(Position = 0, ValueFromRemainingArguments = $true)]
|
||||||
@ -260,11 +263,18 @@ function Test-DeployHealth {
|
|||||||
Write-Host "`n--- [$Key] Health check (on server: localhost:$port$path) ---" -ForegroundColor Cyan
|
Write-Host "`n--- [$Key] Health check (on server: localhost:$port$path) ---" -ForegroundColor Cyan
|
||||||
$deadline = (Get-Date).AddSeconds($TimeoutSec)
|
$deadline = (Get-Date).AddSeconds($TimeoutSec)
|
||||||
while ((Get-Date) -lt $deadline) {
|
while ((Get-Date) -lt $deadline) {
|
||||||
$raw = ssh -o StrictHostKeyChecking=no -i $PEM_KEY $SSH_TARGET "curl -s -m 8 http://localhost:$port$path"
|
# -L: an app whose "/" redirects (e.g. Next.js "/" -> "/login") answers a
|
||||||
|
# 307 whose body is a few bytes or empty, which reads as "not ready".
|
||||||
|
# Follow to the page that actually renders before judging.
|
||||||
|
$raw = ssh -o StrictHostKeyChecking=no -i $PEM_KEY $SSH_TARGET "curl -sL -m 8 http://localhost:$port$path"
|
||||||
$body = ($raw | Out-String).Trim()
|
$body = ($raw | Out-String).Trim()
|
||||||
if ($LASTEXITCODE -eq 0 -and $body) {
|
if ($LASTEXITCODE -eq 0 -and $body) {
|
||||||
if (-not $expect -or $body.Contains($expect)) {
|
if (-not $expect -or $body.Contains($expect)) {
|
||||||
Write-Host " PASS - $body" -ForegroundColor Green
|
# A /health endpoint returns a line of JSON; an app page returns
|
||||||
|
# kilobytes of HTML. Match on the whole body, but only print
|
||||||
|
# enough to recognise it — the rest is unreadable in a log.
|
||||||
|
$shown = if ($body.Length -gt 200) { $body.Substring(0, 200) + "... ($($body.Length) bytes)" } else { $body }
|
||||||
|
Write-Host " PASS - $shown" -ForegroundColor Green
|
||||||
return $true
|
return $true
|
||||||
}
|
}
|
||||||
Write-Host " Responding but '$expect' not found - waiting..." -ForegroundColor DarkYellow
|
Write-Host " Responding but '$expect' not found - waiting..." -ForegroundColor DarkYellow
|
||||||
@ -539,16 +549,23 @@ function Invoke-NextDeploy {
|
|||||||
Invoke-Ec2Step "record deploy timestamp; remove remote zip" "date -u +'%Y-%m-%d %H:%M:%S UTC' | sudo tee $remotePath/.last_deploy_utc > /dev/null && rm -f $RemoteHome/$zipName"
|
Invoke-Ec2Step "record deploy timestamp; remove remote zip" "date -u +'%Y-%m-%d %H:%M:%S UTC' | sudo tee $remotePath/.last_deploy_utc > /dev/null && rm -f $RemoteHome/$zipName"
|
||||||
|
|
||||||
Write-Host "`n--- [5] Verifying deployment ---" -ForegroundColor Cyan
|
Write-Host "`n--- [5] Verifying deployment ---" -ForegroundColor Cyan
|
||||||
if ($Proj.ports -and $Proj.ports.prod) {
|
# Same precedence as the python handler. Do NOT probe http://<ec2-ip>:<prod-port>/
|
||||||
$directUrl = "http://${EC2_IP}:$([int]$Proj.ports.prod)/"
|
# here: a compose stack behind the edge proxy usually publishes to
|
||||||
|
# 127.0.0.1 only, so that probe can never answer and the old "is the port
|
||||||
|
# open in the security group?" warning sent you chasing a firewall rule
|
||||||
|
# for an app that was already up.
|
||||||
|
if ($Proj.verify -and $Proj.verify.port) {
|
||||||
|
Test-DeployHealth -Key $Key -Proj $Proj -TimeoutSec 60 | Out-Null
|
||||||
|
} elseif ($Proj.domain) {
|
||||||
|
$headers = @{ 'Host' = $Proj.domain }
|
||||||
$deadline = (Get-Date).AddSeconds(60)
|
$deadline = (Get-Date).AddSeconds(60)
|
||||||
$verified = $false
|
$verified = $false
|
||||||
while ((Get-Date) -lt $deadline) {
|
while ((Get-Date) -lt $deadline) {
|
||||||
Start-Sleep -Seconds 4
|
Start-Sleep -Seconds 4
|
||||||
try {
|
try {
|
||||||
$resp = Invoke-WebRequest -Uri $directUrl -TimeoutSec 8 -ErrorAction Stop -UseBasicParsing
|
$resp = Invoke-WebRequest -Uri "http://$EC2_IP/" -Headers $headers -TimeoutSec 8 -ErrorAction Stop -UseBasicParsing
|
||||||
if ($resp.StatusCode -eq 200) {
|
if ($resp.StatusCode -lt 500) {
|
||||||
Write-Host " PASS - app is responding at $directUrl" -ForegroundColor Green
|
Write-Host " PASS - app is responding at https://$($Proj.domain)/" -ForegroundColor Green
|
||||||
$verified = $true
|
$verified = $true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -557,8 +574,12 @@ function Invoke-NextDeploy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (-not $verified) {
|
if (-not $verified) {
|
||||||
Write-Host " WARNING: no response at $directUrl within 60s (is the port open in the security group?)." -ForegroundColor Yellow
|
Write-Host " WARNING: no response for https://$($Proj.domain)/ within 60s." -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host " Deploy finished - NOT verified." -ForegroundColor Yellow
|
||||||
|
Write-Host " No 'domain' and no 'verify' block in zconfig.json for '$Key'," -ForegroundColor Yellow
|
||||||
|
Write-Host ' Add to the project: "verify": { "port": <hostPort>, "path": "/health" }' -ForegroundColor Gray
|
||||||
}
|
}
|
||||||
if ($preZipBuild) {
|
if ($preZipBuild) {
|
||||||
# Committed stamp, not +1 — see the note in Wait-VerifyStaticBuild.
|
# Committed stamp, not +1 — see the note in Wait-VerifyStaticBuild.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user