Key takeaways
- Symptom: The target containers are running, but the database, certificate, or background jobs have not passed a real business test.
- Fastest fix: Do not cut traffic yet.
- Complete separate acceptance checks for containers and images, data volumes, environment variables, domains and certificates, scheduled work, and old-node rollback.
- This article is for you if you are moving an existing Docker application with OpenShip, replacing a production server, or switching an AI SaaS to a new node.
- Developers can use it to confirm that every service can be rebuilt.
Symptom: The target containers are running, but the database, certificate, or background jobs have not passed a real business test.
Fastest fix: Do not cut traffic yet. Complete separate acceptance checks for containers and images, data volumes, environment variables, domains and certificates, scheduled work, and old-node rollback.
This article is for you if you are moving an existing Docker application with OpenShip, replacing a production server, or switching an AI SaaS to a new node. Developers can use it to confirm that every service can be rebuilt. Operations teams can use it to control data and certificate risk. Technical leads can use it to define a clear “safe to cut over” standard.
Last updated August 3, 2026. Version details were checked against the official OpenShip v0.4.7 changelog, the current OpenShip documentation, the OpenShip repository, and the Docker volume migration guide. Recheck this process when OpenShip changes its migration logic, container adoption rules, or data volume and certificate workflow.
What v0.4.7 changes, and what it does not prove
The official changelog lists OpenShip v0.4.7 as released on July 28, 2026. It describes improvements to the self-hosted CLI flow and the SSH-to-Docker bridge used during remote Docker migrations. The release specifically addresses cases where a healthy remote Docker server could appear unreachable, hang during a reachability check, or fail while the forwarded channel was still usable. (OpenShip changelog)
That is useful, but it only proves that the migration path is more reliable at the transport and control-plane level. It does not prove that your application data is complete, your queue has no duplicate consumers, or your users can finish the most important workflow.
OpenShip’s public workflow also describes fresh containers, private networking, automatic TLS handling, persistent services, and rollback capability. Those are product capabilities. Your production acceptance still depends on what happened in your environment, including the exact source host, destination host, database state, credentials, DNS records, and application behavior. The OpenShip deployment workflow should therefore be treated as an implementation reference, not as proof that your migration has passed.
Use this rule: migration completion means the deployment process ended; production acceptance means the new node has passed evidence-based tests and the old node can still take traffic back.
The three hidden risks that cause most failed cutovers
A Docker migration can look successful while still carrying at least three separate risks:
- Runtime mismatch: The dashboard may show a service as running while the host is running a different container, an old image, or a duplicate container.
- State mismatch: The application starts, but a database table, uploaded asset, queue record, or data volume is incomplete.
- Control-plane mismatch: Secrets, repository credentials, DNS records, certificate files, or external API permissions still point to the old environment.
There is also a fourth risk for production AI SaaS: background work can be processed twice. If both old and new nodes run a scheduler or queue consumer during the migration window, users may receive duplicate emails, duplicate model jobs, repeated billing events, or conflicting database writes.
First, build the migration evidence pack
Before you test the new server, create one evidence folder or ticket for the migration. Do not rely on screenshots from the dashboard alone. Your record should contain:
- The exact OpenShip version running on the control plane.
- The source server identity and destination server identity.
- The list of projects, services, containers, images, databases, queues, object storage locations, domains, and scheduled jobs.
- The source image digest or image tag for every service.
- The current environment variable and secret inventory, without exposing secret values.
- The location and timestamp of the latest backup.
- The rollback entry point, including the old server address and the DNS records you can restore.
- The person responsible for approving cutover and the person responsible for rollback.
Compare the repository or Compose definition with the actual host inventory. This matters because a migration plan can include services that are not currently running. The OpenShip changelog states that the migration screen includes the full Compose service definition rather than only containers that happen to be up, including services such as an inactive Redis dependency.
Use the Docker Compose file reference to check whether the destination still contains every declared service, dependency, network, volume, health check, and restart policy. This prevents a common failure: the web container moves successfully, but the worker, cache, scheduled job, or internal database service is missing because it had no active container at the time of discovery.
Which runtime checks should pass before you test users?
Start with the runtime, but do not stop at a green status indicator.
1. Confirm the version and migration scope
Run a version check from the same control path used for the migration. Record the output and the timestamp. Then compare:
- Source Compose or project definition.
- Destination project definition.
- Source container list.
- Destination container list.
- Source image references.
- Destination image references.
- Service names and internal aliases.
- Published ports and private network attachments.
- Mounted paths and named volumes.
For every service, answer four questions:
- What is the expected service name?
- What container is actually running?
- What image or build source created it?
- What evidence proves that this is the intended container?
The acceptance standard is not “all cards are green.” The standard is that every planned service has one matching runtime identity and an explainable state.
Use the Docker container inspection reference to compare container IDs, labels, mounts, networks, restart policies, and image references on the live host. This is stronger evidence than a cached control-plane status because it tests the object that actually exists on the destination server.
2. Perform a controlled redeployment
A migration is not accepted until you test whether the destination can reproduce the workload.
Use a controlled redeployment with a known application revision. The test should include:
- At least one
build:service that must rebuild from source. - At least one
image:service that must pull the intended image. - A service that depends on the database.
- A service that depends on Redis, a queue, or another internal dependency.
- A health check or application-level readiness test.
The v0.4.7 changelog says the remote Docker bridge now handles forwarded channels more reliably, while the earlier migration work made migrated Compose projects behave like native repository projects: build services rebuild, image services pull, and the old running image is reused only at cutover.
Your failure action is clear:
- If a build service cannot rebuild, stop the cutover and restore the source definition.
- If an image service pulls a different digest than expected, pin the intended image before proceeding.
- If the application starts with a duplicate container, stop the duplicate and inspect service identity matching.
- If a service reports “stopped” while its endpoint responds, inspect live host state rather than trusting cached control-plane state.
Why can an old container show as stopped while the service still works? The dashboard may be matching the wrong container identity, especially after adoption or replacement. Check the live container name, labels, ID, network, and listening process on the destination host. OpenShip’s release notes describe fixes for service-state matching and duplicate-container behavior, but your acceptance record should still show the actual host-level match.
3. Reboot the destination and retest
A migration that works only before a reboot is not production-ready.
Restart the relevant services, then reboot the destination server during the planned test window. After the host returns, verify:
- The OpenShip control plane is reachable.
- The expected containers return automatically.
- Database and cache services start before dependent application services.
- Health checks recover without manual container creation.
- No second copy of a service appears.
- Scheduled jobs do not start unexpectedly before you approve them.
- Logs do not show repeated authentication, mount, or connection failures.
Record the reboot command, start time, recovery time, container list, and key application checks. The recovery result is more valuable than a screenshot taken immediately after deployment.
How do you prove that Docker migration did not lose data?
A Docker migration can preserve containers while losing the state attached to them. The risk is highest when your application uses named volumes, bind mounts, database files, object storage, or queue state.
Docker’s own volume backup and restore documentation distinguishes named volumes from anonymous volumes and provides separate backup and restore procedures. It also warns that volume behavior depends on the mount definition and the destination path.
4. Inventory every stateful component
Create a source-to-destination mapping for:
- Database volumes.
- Redis or queue persistence.
- User-uploaded files.
- Object storage buckets.
- Search indexes.
- Application-generated certificates.
- Local configuration directories.
- Scheduled job state.
- Audit logs.
- Any bind-mounted host directory.
Do not count volumes by name only. Compare the mount destination inside the container, ownership, permissions, and the service that consumes the mount.
Will an OpenShip Docker server migration lose data? It can if the migration copies the container definition but not the stateful storage, or if the destination mounts the copied data at the wrong path. A successful answer requires three tests: source and destination inventory comparison, business-level data sampling, and an isolated restore test. A backup task marked “successful” is not enough.
5. Test database integrity with business samples
For a relational database, verify more than whether the process accepts connections. Check:
- Database and schema names.
- Table count or migration version.
- Row counts for critical tables.
- Recent records near the migration boundary.
- User login and session behavior.
- One representative write.
- One representative read.
- One transaction that commits and one that rolls back.
- Application behavior after database restart.
For PostgreSQL-backed applications, compare your recovery procedure with the official PostgreSQL backup and restore documentation. The exact commands depend on your database version and deployment method, but the acceptance principle is the same: a backup is not proven until a separate restore can be opened and queried.
For an AI SaaS, sample records that represent the actual product: a user, an organization, an API key record, a prompt or job record, a usage event, a billing event, and a completed task.
Use application-level checks rather than relying only on SQL output. A table can exist while a missing index, wrong timezone, wrong extension, or stale migration prevents normal application behavior.
6. Test data volumes after restart
For every data volume, perform this sequence:
- Select a known file, object, or record before migration.
- Confirm it exists on the destination.
- Read it through the application.
- Create a new test value.
- Restart the consuming container.
- Read the value again.
- Remove the test value if it is not intended to remain.
For object storage, test upload, download, signed access, and deletion. For queues, enqueue one controlled job and confirm that exactly one worker consumes it.
The pass condition is persistence across a service restart, not merely visibility after the first deployment.
7. Prove backup recovery in isolation
Restore the latest backup into an isolated project, temporary database, or separate destination volume. Never restore directly over the only production copy as your first test.
Your evidence should include:
- Backup identifier.
- Backup creation time.
- Restore start and end time.
- Destination volume or database name.
- Integrity check result.
- Application read test.
- Any missing or incompatible records.
- Cleanup confirmation.
If the backup cannot be restored independently, treat it as unproven. This is one of the most important distinctions between “backup exists” and “rollback is possible.”
Which secrets, permissions, and external dependencies need review?
A new server often has the right containers but the wrong trust relationships.
8. Compare secret presence without copying secret values
Build a secret checklist containing variable names, expected scope, and rotation status. Check:
- Database credentials.
- Redis credentials.
- Session and encryption secrets.
- OAuth client credentials.
- Repository access tokens.
- Container registry credentials.
- External model API keys.
- Webhook signing secrets.
- Email credentials.
- DNS provider credentials.
- Backup destination credentials.
Do not paste secret values into the migration ticket. Record whether each value is present, valid, correctly scoped, and tested.
OpenShip’s permissions documentation describes organization roles, restricted access, resource grants, and scoped tokens. For migration work, use a limited deployment or recovery identity where possible rather than a permanent owner-level credential.
9. Test external dependencies from the destination
From the destination environment, verify:
- Outbound HTTPS to every required API.
- DNS resolution for service and provider hostnames.
- Repository access for rebuilds.
- Registry access for image pulls.
- Database connectivity.
- Email delivery or SMTP authentication.
- Webhook callback reachability.
- Object storage upload and download.
- Time synchronization.
Then inspect inbound exposure. The application should receive required traffic, but database, Redis, Docker, SSH, and control-plane administration ports must not become publicly reachable by accident.
Use the Docker network security guidance when reviewing published ports, bridge networks, and service reachability. A service that can communicate internally does not need to expose its administration port to the public internet.
Failure actions should be specific:
- Rotate credentials that were copied broadly.
- Restrict management access to the required source IPs or private network.
- Replace a token that cannot be scoped.
- Remove unused destination firewall rules.
- Delay cutover if external API permissions cannot be tested from the new node.
Domain, certificate, and long-connection checks
Domain migration is not complete when DNS records are edited. You must prove that the new edge serves the correct certificate, routes to the correct application, and supports the connection types your users need.
10. Test with a temporary hostname or local resolution
Before changing public DNS, use a test hostname or a controlled local hosts-file entry. Verify:
- HTTP response and redirect behavior.
- HTTPS certificate subject and chain.
- Correct application route.
- Correct proxy headers.
- WebSocket upgrade.
- Large request and upload behavior.
- Authentication cookies.
- Health-check path.
- Error page behavior.
- IPv4 and IPv6 behavior if both are advertised.
OpenShip documents automatic HTTPS and routing as part of its deployment workflow, but the acceptance question remains whether the certificate and route work for your exact hostname and proxy chain.
For certificate behavior, compare the destination configuration with the official ACME challenge documentation. The relevant challenge type, DNS access, HTTP routing, and renewal permissions must all remain valid after the move. A certificate that works once but cannot renew on the destination is not a passed migration.
How do you switch the domain and certificate during an OpenShip server move? First validate the hostname against the destination without changing the public record. Then confirm certificate issuance or reuse, renewal prerequisites, proxy headers, and WebSocket behavior. Only after those checks pass should you lower the operational risk of the DNS change by documenting the cutover window, the old-node service boundary, and the exact record values you can restore.
Do not shut down the old edge immediately. Keep it available for the agreed rollback window, but prevent it from processing new writes if the application cannot safely run in active-active mode.
11. Treat long connections as a separate test
HTTP success does not prove WebSocket success. AI SaaS products often stream responses, logs, or job status over long-lived connections. Test:
- Connection establishment.
- Authentication during upgrade.
- Idle timeout.
- Proxy forwarding.
- Reconnection after a container restart.
- Session behavior during DNS cutover.
Use the official WebSocket protocol reference to distinguish a normal HTTP request from an upgraded long-lived connection. If the application uses server-sent events or streaming responses, test those separately as well. A user may be able to open the page while the primary AI workflow still fails because the stream is terminated by the new proxy.
Cutover and rollback need an explicit ownership boundary
The most dangerous migration state is not “old server down.” It is “both servers are processing production work without an explicit ownership boundary.”
12. Freeze or coordinate background work
Before changing traffic, decide which node owns:
- Cron jobs.
- Queue consumers.
- Email sending.
- Webhook processing.
- Scheduled backups.
- Billing events.
- AI inference jobs.
- Cleanup tasks.
- Search indexing.
Pause the old consumers or configure an explicit leader boundary. Then confirm that the destination consumer is not active until you approve it.
For queues, record the queue depth before cutover, the consumer count after cutover, and a unique test job ID. For scheduled jobs, record the next run time and the node expected to execute it.
13. Execute a narrow traffic cutover
Use the smallest safe cutover step that proves the route:
- Enable the destination application and keep production writes controlled.
- Change the selected DNS or proxy route.
- Confirm the destination receives real requests.
- Run the highest-value user path.
- Check authentication and session continuity.
- Submit one controlled AI job.
- Confirm one queue consumer processes it.
- Check logs, metrics, and alert state.
- Compare error rates with the source baseline.
- Keep the old node available until the rollback decision is formally closed.
The old node should not be considered “retired” just because DNS has changed. It is still part of the recovery plan until the data boundary, rollback procedure, and retention period are documented.
14. Run the rollback drill before deleting anything
A rollback drill should answer:
- Can the old node start the expected containers?
- Can it reach the database or restored data copy?
- Can the old proxy serve the correct certificate?
- Can DNS or routing be restored quickly?
- Which writes occurred after the cutover?
- What data would be lost or duplicated if traffic returned?
- Which background jobs must be paused first?
Can you switch back to the old node if an OpenShip server migration fails? Yes, but only if the old node remains usable, its configuration is preserved, and you have defined the data boundary. A rollback is not simply changing DNS. If the new node accepted writes, you must know whether the old database is stale, whether queues have moved, and whether duplicate jobs could run after traffic returns.
OpenShip advertises previous versions and rollback support, but server migration rollback also includes infrastructure, storage, DNS, credentials, and background work. Treat the application rollback and the server rollback as separate operations.
Use this acceptance table before you close the old server
| Acceptance area | Test object | Evidence to save | Pass condition | Failure action |
|---|---|---|---|---|
| Version and scope | OpenShip version, projects, services, containers | Version output and inventory diff | Every planned service is accounted for | Reconcile Compose definition and host inventory |
| Images and containers | Build services, image services, live container IDs | Deploy log, image digest, host inspection | Correct image, one intended container, healthy state | Pin image, remove duplicate, inspect identity match |
| Database | Schema, critical tables, recent records | Query sample and application test | Reads and writes work after restart | Restore or repeat migration before cutover |
| Data volumes | Named volumes, bind mounts, object storage | Mount map, file sample, restart test | Data survives restart and matches source sample | Recopy volume and verify ownership and paths |
| Secrets and access | Environment names, API access, registry and repository credentials | Redacted checklist and connection tests | Required access works with limited permissions | Rotate, scope, or replace credentials |
| Domains and certificates | Test hostname, HTTPS, WebSocket, proxy headers | Certificate check and route logs | Correct hostname reaches destination securely | Fix DNS, certificate, proxy, or firewall |
| Background work | Cron, queue consumers, webhooks, AI jobs | Consumer count, job IDs, scheduler state | One clear owner processes each job | Pause duplicate workers and define ownership |
| Cutover and rollback | DNS, old node, data boundary | Change record and rollback drill | Old node can recover and data impact is known | Keep old node online and delay shutdown |
This table is also a useful procurement gate. If a server provider cannot let you retain the old environment long enough to run these checks, the infrastructure may be cheaper on paper but more expensive during a failed migration.
The current server versus a temporary Mac node
Your current server may be the right long-term home for stable production workloads, but it can make migration validation difficult when you cannot keep the old environment online, lack spare capacity for a parallel test, or need a clean isolated node for a short period. The usual weaknesses are limited rollback space, shared credentials, uncertain storage performance, and no safe place to rehearse recovery without touching production.
For a temporary migration lab, renting a dedicated Mac environment from kvmboot can be easier to control: you get a separate node for deployment rehearsal, data-restore testing, build validation, and rollback preparation without immediately dismantling the existing machine. It is not the best choice for every workload. Long-term heavy database service, hardware-specific peripherals, or permanent high-throughput production may justify buying or retaining a dedicated server. But when the decision is between cutting over blind and running a short dual-track validation, an independent temporary node gives you a safer acceptance boundary.
If your team needs to document the environment, access model, and support path before the migration window, review the kvmboot service overview and keep the support contact path available for the temporary-node decision.
Do not close the old server because OpenShip says the migration finished. Close it only after the new node passes the table, the rollback drill is recorded, and you can explain exactly which node owns data and background work.
Validate Your Migration on a Dedicated Cloud Mac
Deploy a remote Mac with kvmboot to test migrated containers, services, and workflows in a controlled environment.
OpenShip MCP deployment controls, approvals, and rollback responsibilities · Production Docker checks for images, bind mounts, caches, and disk headroom · Network cutover troubleshooting for MTU, routing, DNS, and remote access