Production Operations on a Single Server · 7/10

Deploy on One Server with Health Checks and a Rollback Plan

What will this help you do?

Prepare and back up before release, start a candidate version, verify its health, switch traffic, observe the result, and keep a clear route back to the previous version.

Who is it for?

Readers working through this problem and checking each step.

Before you start

Check the scope of this guide, then prepare the environment and materials it actually calls for.

Updated

On this page

A rollback is more than “revert Git”

Time matters during a production incident. If rollback still requires finding a commit, reinstalling dependencies, and guessing whether the database is compatible, it is not a workable plan. Before release, keep the previous code or image, configuration, data protection point, and traffic-switching procedure ready.

One server cannot eliminate all downtime, but it can avoid unnecessary interruption. Start a candidate version on another local port, verify its health and essential routes, and only then point Caddy at it.

Define success and stop conditions before release

Write down the change, affected routes, database changes, expected window, and owner. Success is not an active service status; it is working health, homepage, essential API, and login or form behavior. Set concrete stop conditions such as repeated health failures, a sustained rise in 5xx responses, or a migration exceeding its planned window.

Freeze unrelated changes during release. Record the current version, configuration hash, and database backup. Do not combine an operating-system upgrade, database major upgrade, and application dependency update in one deployment; if it fails, you will not know which part caused it.

Start the candidate on a different port

The current version might listen on 127.0.0.1:3000 while the candidate uses 127.0.0.1:3002. Keep their release directories separate and read-only. Before both touch shared data, confirm that the old and new versions are compatible with the same database structure.

bash
curl -fsS http://127.0.0.1:3002/health
curl -fsS -H 'Host: www.example.com' http://127.0.0.1:3002/

The health endpoint should show that the process is ready for traffic; an essential-route check tests the page and its dependencies. A health endpoint that always returns 200 regardless of state is not useful. Conversely, making it depend on expensive outside calls can turn a brief wobble into a false failure.

Validate the proxy change and observe immediately afterward

Change the Caddy upstream from 3000 to 3002, run caddy validate, and reload only if validation passes. Preserve the previous configuration. After switching, inspect external HTTPS, Caddy logs, new-version logs, and remaining connections to the old process. Keep the old version available during a short observation window instead of deleting it immediately.

If the app supports multiple upstreams, you may briefly include a candidate and manage traffic, but both versions must be compatible with the shared database. Single-server blue-green deployment is a fast switching method, not independent infrastructure.

Database migrations set the limits of rollback

Dropping a column, renaming a field, or performing an irreversible transformation can prevent the previous version from running. A safer pattern is expand, migrate, contract: add backward-compatible fields, deploy code that tolerates both structures, move data and observe, then remove old fields in a later release.

Rehearse every data-writing migration on a recent backup copy and record its runtime and locking effects. Do not hide a long migration in the app's start command; a systemd restart or container replacement might run it again.

Follow the written rollback sequence

When a stop condition is met, switch Caddy back to the old upstream and reload. Confirm user traffic has recovered before stopping the candidate. If the database change was backward-compatible, do not restore the whole database automatically. If incorrect writes occurred, use a targeted recovery plan; overwriting production to repair one table may discard valid new data.

Keep candidate logs and the incident timeline. Restore service first, then investigate the cause—but do not erase the evidence of the failure.

Keep a short deployment record

Record the version, operator, backup location, start time, switch time, health results, problems, rollback decision, and finish time. After several releases, these records will show the real time and riskiest steps, which you can then automate.

You are ready when a candidate can be tested independently, switching does not restart the whole proxy, the old version can return within minutes, and the migration compatibility plan is clear. Next, set up monitoring and alerts to notice regressions promptly.

Sources

  1. Dockerfile HEALTHCHECKDocker Docs
  2. Caddy reverse_proxy directiveCaddy Documentation

Next steps

Continue with the next useful task; you do not need to read everything at once.

  1. Deploy Open WebUI with Docker and Persistent Storage →
  2. Install Ollama on Linux and Expose It Safely →
  3. Deploy Dify with Docker Compose: A Production-minded Guide →
RESOURCES I USE · REFERRAL

Two services to compare when you are ready to launch

This is not an automated ranking, and neither service is necessary for everyone. These are services I use, with the use case and limitations kept visible.

Cloud server · Used for early projects

RainYun

A practical candidate for a website or small service. Choose by user region, configuration and measured workload rather than the lowest headline price.

Referral disclosure: these links contain my referral information. I may receive a platform benefit if you sign up or order, at no additional charge from AIOOS. Check the order page for current pricing, availability, regions and terms. Read the full affiliate disclosure