Skip to content

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.example as 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=false remains 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 age recipient, 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 age recipient; 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

  1. Prove the exact release SHA passed staging and record the immutable backend/frontend OCI digests for those same artifacts.
  2. Complete the protected production configuration and secret-presence preflight.
  3. Confirm the production backup, restore-rehearsal, encryption, and off-host-readback gates.
  4. With explicit deployment authorization, use scripts/deploy-production-vps.sh to deploy the isolated application on 3300/3301 and run migration through its canonical migration entrypoint.
  5. Certify the API and frontend locally on 127.0.0.1:3301 and 127.0.0.1:3300.
  6. Verify production Data Protection keys persist across an authorized API container replacement and remain on the dedicated production named volume.
  7. Complete PayU LIVE readiness / preflight as defined below. This is not inbound external callback, browser-return, or webhook E2E certification. Razorpay remains disabled.
  8. Confirm legal, CA, tax, policy, security, and business gates are closed.
  9. Render and host-validate the production Host Nginx candidate without switching traffic.
  10. Obtain explicit CUTOVER AUTHORIZATION tied to the exact release and candidate digest.
  11. Capture the active Host Nginx file, install the candidate, require nginx -t to pass, and only then reload Nginx under the separate cutover runbook.
  12. Run external TLS, frontend, API readiness, and upload-limit smoke checks.
  13. Run the controlled post-cutover PayU LIVE external certification defined below.
  14. 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/health and 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=Live and 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/success and https://vayzomart.com/api/webhooks/payu/failure, and the server webhook is configured as POST https://vayzomart.com/api/webhooks/payu;
  • DNS and TLS prerequisites for vayzomart.com are 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:

./scripts/deploy-production-vps.sh rollback

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.