External edge smoke

Prove the public edge is narrow before inviting testers.

This harness runs from outside the VPS against the final HTTPS origin. It checks that only shallow health/docs are public, private app surfaces stay gated, headers survive the proxy, and request body limits fail closed.

Command

Run from an external machine after HTTPS proxy attachment

scripts/external-edge-smoke.sh https://members.final-domain.example

# Or through make:
NOCTURNE_PUBLIC_ORIGIN=https://members.final-domain.example make external-edge-smoke

The script is intentionally dependency-light: bash, curl, and python3. It refuses local, placeholder, .test, .invalid, and non-HTTPS origins by default.

TLS rule: valid certificate verification is part of the smoke. NOCTURNE_EDGE_SMOKE_INSECURE=1 exists only for temporary private TLS debugging and should never be treated as launch-ready evidence.
Coverage

What the smoke proves

CheckExpected resultWhy it matters
/healthz200 with plain ok.Confirms the public proxy can reach the app while keeping health shallow.
Security headersHSTS, CSP, nosniff, referrer policy, and permissions policy are present.Confirms app/proxy header posture survived TLS termination.
/docs/200 with Nocturne docs marker.Confirms the public documentation surface works.
CLI-only diagnostics/doctor, /production-preflight, /backup-status, /local-smoke, and /metrics are 404 or 405.Confirms operational detail stays local/operator-only.
Member gatesUnauthenticated /library and media file routes return 401 or 403.Confirms private media is not exposed by the proxy.
Private media rootDirect /private_media/... path is not 200.Confirms the proxy does not serve the filesystem media root.
/report body capOversized 9 KB report post returns 413.Confirms the public intake cap is active at proxy or app.
Default form capOversized 17 KB join post returns 413.Confirms the global small-form posture is active at proxy or app.
Sequence

Recommended VPS validation order

  1. Replace all placeholders in .env.production and the selected proxy config.
  2. Run vps-bootstrap-plan --env-file .env.production, then production-preflight locally on the VPS with production env loaded.
  3. Validate the live proxy syntax on the VPS: caddy validate or nginx -t.
  4. Attach/reload the proxy and confirm public DNS/TLS resolves.
  5. Run scripts/external-edge-smoke.sh from outside the VPS network and record a deployment-evidence-record --stage external_edge_smoke entry with an artifact hash.
  6. Run smoke-member-provision --recovery-key-file ... on the VPS to create a disposable recovery-confirmed member for private external testing.
  7. Run external member smoke from outside the VPS network with that member ID and recovery-key file.
  8. Run smoke-member-cleanup --confirm-smoke-member-cleanup after the authenticated smoke window closes.
  9. Run production-preflight locally again after the public and member smokes pass, record sealed backup dump/media hashes with backup-manifest-record, record encrypted/offsite custody with backup-custody-record, run deployment-evidence-check for the final origin, then run private-vps-readiness before widening private testing.
  10. Record the date, origin, proxy type/version, smoke output, and any warnings in the deployment notes.
Failure interpretation

What to fix first

Limits

What this smoke does not prove