Photograph from Mojtaba Roozegar’s original personal gallery
Personal gallery photograph used as an editorial illustration, not evidence of a business partnership.
Article

Reliable Website Deployment: GitHub Actions, VPS Relays and Rollback

An expert deployment playbook for immutable artifacts, pinned SSH identities, zero-downtime strategies, safe database migrations and automatic rollback.

Treat deployment as a reversible change to production state
A release is not complete when Git reports a successful merge; it is complete when the intended application behavior is verified on the real endpoint without damaging unrelated services. Define exactly which repository, application directory, routes, templates, databases and static assets the release may change. Everything else is out of scope. Save a manifest of old and new file hashes, commit SHA, deployment identifier and backup location. Refuse unexpected paths or symlink targets. These guards are particularly important on shared hosts where several sites occupy one account.

Build once and promote an identifiable artifact
Ideally, CI creates a tested immutable package or container from a known commit and deployment promotes that exact build rather than rebuilding source differently on the server. Record dependency lockfiles, runtime version, migration revision and asset manifest. A build that passes tests but depends on mutable unpinned packages can change between staging and production. Separate configuration and secrets from the artifact; never print private keys in logs. Require protected branch policies and an audit trail of who or what requested release.

Secure an SSH relay without broadening exposure
When a private hosting account is reachable only through a VPS, use a restricted SSH jump with pinned host-key fingerprints and minimal privileges. Verify both hop identities before transferring code and enforce strict host key checking. Avoid opening administrative ports to the public internet merely to satisfy automation. Keep SSH keys ephemeral on runners and clean them after every outcome. Assign the deploy identity access only to an allowlisted path and commands where infrastructure permits. A successful TCP connection is not proof of application health or correct target selection.

Preflight before writing any production file
Check that expected source content and prior markers exist, target files are regular files rather than symlinks, and a complete backup can be created. Parse templates in the actual Django environment and verify installed dependencies. Validate proposed database migrations against the current schema. Dry-run critical routes with DEBUG disabled and confirm that staticfiles manifest paths are resolvable. Preflight should fail closed if the site's structure differs from the tested assumptions; guessing which file to replace can destroy customized content.

Understand true zero downtime and consistency
Blue-green deployment uses two independently runnable versions and switches traffic once the new version is healthy. A constrained cPanel application may not support that architecture; a carefully controlled atomic file replacement plus application restart is a narrower strategy, not a promise of zero downtime. For larger systems, coordinate application versions with compatible schema migrations. A destructive migration can make code rollback impossible unless schema changes follow expand-contract principles. Preserve write availability and transaction integrity.

Automate observable post-deployment checks
Check representative pages, deep links, authentication, admin, static assets and any high-risk purchase or publishing routes. HTTP 200 alone is insufficient: confirm expected content markers and that older content is still present. For a journal release, verify the actual article body, canonical URL, description and author metadata. For images, inspect count and source paths rather than only whether an img tag exists. Capture concise evidence in CI logs with no secrets. Trigger rollback for failures within the declared safety boundary and report the outcome accurately.

Design rollback with both files and data in mind
Keep a protected copy of each replaced file and a signed or hashed release manifest. A database rollback should delete only records created by this deployment and only if their current content still matches the manifest, so it cannot erase later user edits. Do not blindly reverse a migration that may contain live new data. If a partial rollback cannot safely proceed, stop and raise a clear manual intervention flag instead of claiming success. Version the recovery procedure itself and test it in staging. References: https://docs.github.com/en/actions and https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ .

Editorial disclosure: Original advanced educational content by Mojtaba Roozegar. Examples are illustrative, not an audit of a particular production deployment or a guarantee of outcomes. Relevant external technical references are linked within each article.

← Back to Articles