Deployment runbook: Production V1¶
This is the authoritative Production V1 application-deployment runbook. Production V1 runs as
the isolated vayzomart-production Docker Compose project on the shared VPS. Its canonical files
are docker-compose.production.yml and scripts/deploy-production-vps.sh.
Documentation is not deployment authorization
Reading, building, validating, or publishing this page never authorizes or performs a production deployment. An operator must have explicit deployment authorization tied to the exact release SHA and immutable image digests before running the canonical deployment runner.
Application deployment is not public cutover
scripts/deploy-production-vps.sh deliberately does not edit or reload Host Nginx and does
not switch public traffic. Public routing requires a later, separate CUTOVER AUTHORIZATION
under Production Host Nginx cutover.
Authoritative V1 model¶
| Concern | Production V1 contract |
|---|---|
| Runtime | Shared VPS; Docker Compose project vayzomart-production |
| Application definition | docker-compose.production.yml |
| Deployment and application rollback | scripts/deploy-production-vps.sh |
| Frontend binding | 127.0.0.1:3300 |
| API binding | 127.0.0.1:3301 |
| Database and cache | Dedicated production MySQL, Redis, network, and named volumes; no host-published data ports |
| Runtime images | Backend and frontend pinned to immutable OCI sha256: digests and an exact release SHA |
| Payment launch state | PayU-only launch using PayU LIVE; Razorpay is disabled and is not a V1 fallback |
| Data Protection | Production-only vayzomart_production_data_protection_keys named volume |
| Public routing | Separately authorized Host Nginx cutover after localhost and business certification |
The earlier cluster-oriented deployment design is on hold and is not an operational Production V1 path. It is intentionally absent from this authoritative runbook.
Preconditions¶
All items below must be evidenced before deployment authorization. Never place secret values in an issue, pull request, command transcript, screenshot, or deployment evidence file.
- The exact release SHA passed staging, and the production candidate uses the same certified application artifacts rather than a rebuild.
- The backend and frontend repository coordinates and immutable OCI digests have been resolved;
latest, blank digests, and mutable tag-only identity are prohibited. - The production Compose environment is prepared out of band using
.env.production.exampleas the variable-name/template contract. The host copy is permission-restricted and uncommitted. - Production MySQL and Redis identities, network, containers, and named volumes are isolated from staging. Production uses loopback application ports 3300/3301; staging retains 3200/3201.
- Production R2 public/private media buckets and the dedicated encrypted-backup bucket are configured and isolated from staging. Backup credentials are scoped separately from media credentials, and bucket-lock evidence is recorded out of band.
- Production JWT signing and MFA encryption secrets are present and independent. Production tax identity key material is valid, independently generated, versioned, and distinct from both.
- CA/business-approved settlement and tax values are supplied; legal and policy gates are closed for the authorized launch scope.
- PayU KYC/onboarding and settlement-bank-account verification are complete. The LIVE merchant key and salt are supplied only through the protected production environment and are never logged or committed.
- Production V1 is PayU only: Razorpay credentials are not a launch prerequisite, Razorpay webhook ingress and refund execution remain disabled, and Razorpay is not a fallback.
PRODUCTION_PAYU_REFUND_EXECUTION_ENABLED=falseremains enforced unless refund execution has its own explicit authorization and certification. Reconciliation remains enabled as approved.- The production Data Protection named volume exists through the Compose contract, is writable by the API identity, persists across container replacement, and is never shared with staging.
- The encrypted off-host backup path, public
agerecipient, authenticated backup-bucket access, bucket-lock evidence, database backup, and restore rehearsal are ready. - The production Host Nginx candidate has passed repository isolation tests and disposable syntax validation. This is readiness evidence only; it is not permission to install it.
- Explicit application DEPLOYMENT AUTHORIZATION is recorded. Public CUTOVER AUTHORIZATION is a later and independent decision.
Release and image identity¶
Record the exact release SHA, backend digest, frontend digest, human-readable immutable image tag,
and authorization reference. Before any deployment action, prove the release is the staged release
and each digest has the form sha256: followed by 64 lowercase hexadecimal characters.
The deployment runner receives RELEASE_SHA, BACKEND_IMAGE_DIGEST, and
FRONTEND_IMAGE_DIGEST as operator-controlled inputs. Candidate .env.next content cannot
silently replace those inputs. The runner pulls each image by digest and verifies its identity
before migration or serving-container startup.
Production configuration preflight¶
Prepare /opt/vayzomart/production/.env.next for a candidate update, or the protected active
.env for first-time provisioning, from .env.production.example. Do not source it into a
shared interactive shell and do not print it. The canonical runner validates:
- required secret presence without echoing values;
- release SHA and immutable image digest formats;
- production database/user and 3300/3301 port isolation;
- R2 media and backup separation;
- JWT, MFA, tax-identity, and settlement configuration;
- PayU LIVE readiness/preflight requirements, with PayU refund execution off;
- Razorpay webhook and refund execution disabled;
- Compose rendering before database migration.
Backup and restore gate¶
Backup and restore proof is mandatory, not a best-effort checkpoint.
- Existing production upgrade: the runner creates a pre-migration database dump, manifest, and
structural fingerprint; restores it into a verification database; compares the restored
structure; encrypts the backup with the approved public
agerecipient; uploads it to the dedicated off-host R2 bucket; and reads it back to verify integrity before migration. - First-time provisioning: after migration, the runner creates and restore-rehearses a baseline backup and completes the same encrypted off-host proof before declaring success.
- A missing tool, inaccessible bucket, invalid recipient, failed restore, failed structure check, failed upload/readback, or absent bucket-lock evidence is a deployment failure.
Authoritative deployment and launch sequence¶
- Prove the exact release SHA passed staging and record the immutable backend/frontend OCI digests for those same artifacts.
- Complete the protected production configuration and secret-presence preflight.
- Confirm the production backup, restore-rehearsal, encryption, and off-host-readback gates.
- With explicit deployment authorization, use
scripts/deploy-production-vps.shto deploy the isolated application on 3300/3301 and run migration through its canonical migration entrypoint. - Certify the API and frontend locally on
127.0.0.1:3301and127.0.0.1:3300. - Verify production Data Protection keys persist across an authorized API container replacement and remain on the dedicated production named volume.
- Complete PayU LIVE readiness / preflight as defined below. This is not inbound external callback, browser-return, or webhook E2E certification. Razorpay remains disabled.
- Confirm legal, CA, tax, policy, security, and business gates are closed.
- Render and host-validate the production Host Nginx candidate without switching traffic.
- Obtain explicit CUTOVER AUTHORIZATION tied to the exact release and candidate digest.
- Capture the active Host Nginx file, install the candidate, require
nginx -tto pass, and only then reload Nginx under the separate cutover runbook. - Run external TLS, frontend, API readiness, and upload-limit smoke checks.
- Run the controlled post-cutover PayU LIVE external certification defined below.
- Issue final launch confirmation only after steps 12 and 13 pass. Public cutover by itself is not final launch approval. If either fails, stop launch and follow the documented routing/application rollback decision.
The authorized application invocation has this shape; placeholders must be resolved through the approved deployment record, never copied literally and never replaced with secret values:
RELEASE_SHA=<EXACT_40_HEX_RELEASE_SHA> \
BACKEND_IMAGE_DIGEST=sha256:<EXACT_BACKEND_DIGEST> \
FRONTEND_IMAGE_DIGEST=sha256:<EXACT_FRONTEND_DIGEST> \
./scripts/deploy-production-vps.sh <APPROVED_IMMUTABLE_IMAGE_TAG>
Successful completion must still report Public Cutover Done : NO and that Host Nginx was not
modified. Any output claiming otherwise violates the deployment/cutover separation.
Localhost certification before cutover¶
Before public cutover authorization, retain evidence for all of the following without including secrets or customer data:
- frontend responds through
http://127.0.0.1:3300/; - API health responds through
http://127.0.0.1:3301/healthand the readiness contract; - production containers use the expected immutable image digests and release SHA;
- MySQL and Redis remain internal to the production network and staging remains healthy;
- Data Protection key persistence survives the authorized replacement check;
- Razorpay remains disabled and is not used as a fallback;
- PayU automated refund execution remains false unless separately authorized and certified.
PayU LIVE readiness / preflight before cutover¶
This gate establishes production configuration and provider reachability; it does not claim
that an inbound external browser return or webhook has reached the production API. Until Host
Nginx routes vayzomart.com/api/ to port 3301, that end-to-end claim cannot be made.
Require evidence that:
- PayU KYC/onboarding is complete and the settlement bank account is verified;
- LIVE Merchant Key/Salt are provisioned only through the protected out-of-band environment;
PayU__Environment=Liveand the production payment/verification endpoints are verified against the approved PayU LIVE onboarding contract;- browser success/failure callback URLs are configured as
https://vayzomart.com/api/webhooks/payu/successandhttps://vayzomart.com/api/webhooks/payu/failure, and the server webhook is configured asPOST https://vayzomart.com/api/webhooks/payu; - DNS and TLS prerequisites for
vayzomart.comare verified without claiming traffic is already routed to the production API; - Razorpay remains disabled and is not a fallback;
- PayU automated refund execution remains false unless separately authorized and certified;
- reconciliation is configured;
- local startup, request-hash, response/reverse-hash, validation, idempotency, and configuration tests pass; and
- outbound connectivity to PayU's authoritative verification service passes where it can be tested safely without creating an uncontrolled LIVE transaction.
Public Host Nginx cutover¶
Application certification and PayU LIVE readiness/preflight do not authorize public traffic. Follow
Production Host Nginx cutover only after the separate cutover
authorization is recorded. The candidate routes vayzomart.com and www.vayzomart.com to
3300/3301, preserves TLS and forwarded headers, and applies client_max_body_size 100m; only to
/api/.
scripts/deploy-production-vps.sh must continue to have no Host Nginx installation, reload,
certificate issuance, DNS mutation, or public-traffic switching behavior.
Successful Host Nginx reload is only a routing milestone. It is not final launch approval.
PayU LIVE external certification after cutover¶
After authorized cutover and successful external TLS/frontend/API smoke checks, run exactly one explicitly authorized controlled production smoke transaction. Before declaring launch complete, verify:
- PayU Hosted Checkout initiation;
- browser success or failure return reaches the production callback route;
- response/reverse-hash validation rejects tampering;
- the server webhook reaches
POST /api/webhooks/payu; verify_payment(or the repository's equivalent authoritative provider-verification operation) confirms the transaction server-side;- duplicate webhook delivery and callback/webhook races remain idempotent;
- the reconciliation path observes the controlled transaction;
- order/payment finalization occurs exactly once; and
- Razorpay remains disabled throughout certification.
Do not authorize or exercise automated refunds as part of this certification. If any payment certification step fails, stop launch, do not announce production as ready, and execute the documented routing/application rollback decision appropriate to the observed failure.
Rollback boundaries¶
Application rollback¶
Application rollback uses the canonical production runner and its retained, hash-bound previous Compose/environment/release metadata:
The runner validates the active database identity and previous release contract before stopping serving containers. It restores the appropriate verified database backup when required, loads the previous protected environment, restarts the prior digest-pinned images, and verifies health. Application rollback does not edit Host Nginx or change public routing.
Host Nginx routing rollback¶
Routing rollback restores the exact Host Nginx file captured immediately before cutover, validates the restored configuration, and reloads Nginx as described in the cutover runbook. It does not change application images, migrate the database, or substitute staging ports for production.
If both layers fail, restore routing first when necessary to protect public traffic, then execute the independently authorized application rollback. Record both actions separately.
Payment-provider boundary¶
Production V1 is PayU only. Razorpay remains disabled, is not a fallback for V1, and has no LIVE credential prerequisite. Any future Razorpay re-enable is a separate business decision requiring its own threat review, configuration change, staging and LIVE certification, deployment approval, and rollback plan. It must not be inferred from dormant optional configuration fields.
Monitoring and evidence¶
Retain the release SHA, immutable digests, authorization references, runner result, backup and restore-rehearsal evidence, localhost certification, Data Protection persistence result, PayU LIVE readiness/preflight, legal/business approvals, rendered Host Nginx digest, cutover authorization, external smoke result, controlled post-cutover PayU LIVE external certification result, final launch decision, and any rollback evidence. Never retain secret-bearing environment files, raw payment payloads, private keys, merchant salt, or customer data in release evidence.