Production Host Nginx cutover runbook¶
This runbook describes a candidate configuration and an operator-controlled cutover for
vayzomart.com. It does not authorize a deployment, edit the live host, obtain certificates, or
switch public traffic. scripts/deploy-production-vps.sh deliberately leaves Host Nginx unchanged.
Fixed routing contract¶
| Request | Loopback upstream |
|---|---|
https://vayzomart.com/ and https://www.vayzomart.com/ |
frontend 127.0.0.1:3300 |
https://vayzomart.com/api/ |
API 127.0.0.1:3301/api/ |
/api/health/ready and /health/live |
API 127.0.0.1:3301 |
Only the production /api/ location permits client_max_body_size 100m;. Unknown HTTP and HTTPS
Host headers are rejected. Staging remains independently routed to ports 3200/3201.
Mandatory sequence¶
- Provision the production stack without changing Host Nginx or public traffic.
- Certify the production frontend/API through loopback ports and verify Data Protection persistence.
- Complete PayU LIVE readiness / preflight: onboarding, settlement account, protected LIVE credentials, endpoint/callback/webhook configuration, DNS/TLS prerequisites, local hash and validation tests, reconciliation configuration, and safe outbound verification connectivity. This is not inbound external callback, browser-return, or webhook E2E certification. Razorpay remains disabled and is not a fallback for V1; PayU automated refunds remain disabled. Any future Razorpay re-enable is a separate business decision and certification exercise.
- Confirm every legal, CA, business, security, backup, and release gate.
- Render and validate a Host Nginx candidate without switching traffic.
- Obtain explicit CUTOVER AUTHORIZATION tied to the exact release and candidate digest.
- Back up the active Host Nginx file, install the candidate, and require
nginx -tto pass before reload. If it fails, follow the pre-reload restore procedure below and do not reload. - Reload only the validated configuration, then run external TLS, frontend, API-readiness, and upload-limit smoke checks.
- Run the controlled post-cutover PayU LIVE external certification below.
- Confirm final launch only after both external application smoke and payment certification pass. Cutover alone is not final launch approval.
Steps 7 through 10 are prohibited until step 6 is recorded. This repository does not automate them.
Render a candidate (non-deploying)¶
Run from a trusted checkout of the authorized release. Certificate files must already exist and must cover both production names; this runbook never runs Certbot.
export PRODUCTION_FRONTEND_HOST='vayzomart.com'
export PRODUCTION_FRONTEND_PORT='3300'
export PRODUCTION_API_PORT='3301'
export PRODUCTION_TLS_CERTIFICATE_PATH='/absolute/path/to/existing/fullchain.pem'
export PRODUCTION_TLS_CERTIFICATE_KEY_PATH='/absolute/path/to/existing/privkey.pem'
envsubst '${PRODUCTION_FRONTEND_HOST} ${PRODUCTION_FRONTEND_PORT} ${PRODUCTION_API_PORT} ${PRODUCTION_TLS_CERTIFICATE_PATH} ${PRODUCTION_TLS_CERTIFICATE_KEY_PATH}' \
< infra/nginx/nginx-vps-production.conf.template \
> /tmp/vayzomart-production.conf.candidate
Inspect the rendered file for unresolved ${...} tokens and verify its digest against the
cutover record. Do not print or copy private-key contents.
Local disposable syntax proof¶
The test generates a disposable certificate and runs nginx -t inside an isolated Docker
container with networking disabled. It does not access /etc/nginx, staging, or production.
Authorized host procedure (reference only)¶
After explicit cutover authorization, the operator must first verify both loopback upstreams, validate the candidate against the host's installed Nginx, and capture the active configuration. The exact active site path is host-specific and must be confirmed rather than assumed.
curl --fail --silent --show-error http://127.0.0.1:3300/
curl --fail --silent --show-error http://127.0.0.1:3301/health/ready
sudo nginx -t -c /etc/nginx/nginx.conf
# Replace these placeholders only after confirming the actual live paths.
sudo cp --preserve=all <ACTIVE_SITE_FILE> <TIMESTAMPED_BACKUP_FILE>
sudo install -o root -g root -m 0644 /tmp/vayzomart-production.conf.candidate <ACTIVE_SITE_FILE>
sudo nginx -t
sudo systemctl reload nginx
The reload command is permitted only when the immediately preceding nginx -t succeeds.
Candidate fails validation before reload¶
If the newly installed candidate fails nginx -t before reload:
- Do not reload Nginx.
- Immediately restore the captured pre-cutover Host Nginx file to the active path.
- Run
nginx -tagain against the restored configuration. - Leave the currently running routing unchanged; existing Nginx workers continue using the pre-cutover configuration because no reload occurred.
- Stop the cutover and investigate. If the restored file does not validate, do not reload and escalate for manual recovery.
This pre-reload restore is distinct from routing rollback after a successful reload followed by failed external verification.
Then verify HTTPS for both names, the two health routes, representative API behavior, and upload limits. Do not expose secrets in command output or logs. Passing these checks is not final launch approval; controlled PayU LIVE external certification is still required.
PayU LIVE external certification after cutover¶
Use only an explicitly authorized controlled production smoke transaction. Verify Hosted Checkout
initiation; browser success/failure return delivery; response/reverse-hash validation; delivery to
POST /api/webhooks/payu; authoritative verify_payment provider verification; duplicate-webhook
and callback/webhook-race idempotency; reconciliation; exactly-once order/payment finalization;
and that Razorpay remains disabled.
Do not authorize automated refunds. If certification fails, stop launch, do not announce production as ready, and choose the documented Host Nginx routing rollback and/or canonical application rollback based on the failure. Public cutover alone never constitutes final launch approval.
Routing rollback¶
If external post-reload verification or controlled payment certification fails and the decision is to reverse public routing, restore the exact timestamped Host Nginx backup, validate it, and reload. Do not improvise a new configuration during an incident.
sudo install -o root -g root -m 0644 <TIMESTAMPED_BACKUP_FILE> <ACTIVE_SITE_FILE>
sudo nginx -t
sudo systemctl reload nginx
Restoring Host Nginx reverses only the traffic switch. If the production application stack also needs rollback, follow its separately gated rollback procedure. Do not point production traffic at staging ports or reuse staging certificates/configuration.