Deployment11 min read

Docker v29 on VPS: migrate without breaking your stacks

Docker Engine v29, released in March 2026, changes three foundations simultaneously: minimum API version, nftables network backend, and containerd image store. An unprepared VPS receiving this update breaks silently — docker-compose v1 standalone stops working, Dockge no longer starts, and the iptables rules your stacks relied on disappear. This guide helps you detect what is broken, migrate cleanly, and prevent the next `apt upgrade` from becoming a client incident at 2 a.m.

Why Docker v29 breaks existing stacks — and why now

An agency managing a fleet of client VPS is caught in a particular bind: the upstream update (Docker, Ubuntu, Debian) arrives from outside, regardless of who administers the server. When a client VPS receives apt upgrade without oversight, three breaking changes arrive simultaneously.

First break — minimum API version. Docker Engine v29 raises the minimum API version to 1.44. Clients still running the old docker-compose v1 standalone binary (/usr/local/bin/docker-compose) fail immediately: their client code is compiled for earlier API versions, and the daemon refuses the connection with an incompatibility message.

Second break — nftables network backend. Docker v29 enables nftables by default instead of iptables to manage Docker network firewall rules. Third-party scripts that inspect iptables chains directly (monitoring scripts, custom firewalls, certain UFW rules) no longer see Docker rules — not because they disappeared, but because they now live in nftables.

Third break — containerd image store. The image storage backend switches to the containerd store. Opt-in since v29, it will become the default in v30. On a migrated server, existing images remain accessible but the cache path changes, which can surprise scripts that inspect /var/lib/docker/image directly.

The classic objection — "our clients manage their own VPS" — provides no protection. The break comes from outside, and the agency is who the client calls when their site stops responding.

What this guide enables you to do

  • Detect the API version tension between your docker client and the VPS daemon, before the next command produces a cryptic error.
  • Identify in 30 seconds whether a VPS is still running docker-compose v1 standalone — the binary deprecated since Docker Desktop 3.6 and removed from official packages.
  • Migrate to the docker compose v2 plugin with the exact two commands, then verify your existing docker-compose.yml files work without syntax changes.
  • Understand the nftables impact on your stacks: what continues to work (Docker networks), what can break (your scripts reading iptables), and the diagnostic command that settles it.
  • Enable or defer the containerd store based on your migration timeline, with the exact configuration key and verification command.
  • Evaluate the compatibility of Dockge, Portainer, and CasaOS App Store with v29, so you do not discover incompatibility during a client incident.
  • Prepare your client VPS fleet so the next apt upgrade is a planned event, not a late-night emergency.

Prerequisites before starting

This guide applies to any VPS running Ubuntu 22.04/24.04 or Debian 11/12 with Docker Engine installed from the official Docker Inc. repositories (not the distribution's docker.io package). You need SSH access as root or sudo. No service interruption is required for the diagnostic steps; migrating the compose plugin takes a few seconds during which docker compose commands are unavailable. Take a VPS snapshot before modifying /etc/docker/daemon.json if you enable the containerd store — restoring in case of issues takes less than five minutes with a VPS that offers on-demand snapshots.

Step 1 — Diagnose the API version

01

Check the client and daemon API versions

On each VPS to audit, run the following two commands:

docker version --format '{{.Client.APIVersion}}'
docker version --format '{{.Server.APIVersion}}'

If the client version is below 1.44 and the daemon is running v29, you will get an error on the next commands. The 1.44 threshold is the minimum accepted by Docker Engine v29: a client compiled for 1.43 or earlier fails with Error response from daemon: client version 1.43 is too old. Minimum supported API version is 1.44, please upgrade your client.

If both lines show 1.44 or higher, your client is compatible. Proceed to the next step.

02

Detect the presence of docker-compose v1 standalone

The docker-compose command with a hyphen and the docker compose command without a hyphen are not the same thing. v1 is a standalone Python binary, v2 is a Go plugin integrated into the Docker CLI.

which docker-compose && docker-compose --version

If the command returns a path in /usr/local/bin/ or /usr/bin/ with a version 1.x.x, you have the deprecated standalone binary. After the Docker v29 update, this binary returns docker-compose: command not found if the package was removed, or the API error described above if it is still present.

docker compose version

If this command returns Docker Compose version v2.x.x, the v2 plugin is already present. Both can coexist temporarily, but the goal is to use only the v2 plugin.

Step 2 — Migrate from docker-compose v1 to the v2 plugin

01

Remove the v1 binary and install the plugin

apt remove docker-compose
apt install docker-compose-plugin

On a Debian or Ubuntu VPS using the official Docker Inc. repositories (download.docker.com), the docker-compose-plugin package is available without additional configuration. If apt remove docker-compose responds Package not found, the binary was installed manually: locate it with which docker-compose and delete the file.

Post-migration verification:

docker compose version
# Docker Compose version v2.36.0
02

Verify syntax compatibility of your existing Compose files

The vast majority of docker-compose.yml files written for v1 work without modification with the v2 plugin. The only syntax breaks concern version: directives above "3.8" (ignored in v2, not blocking) and the --compatibility option (removed). Validate your existing files:

docker compose config

This command resolves environment variables, validates syntax, and displays the resolved configuration. An error-free output means your file is compatible.

If your team uses shell scripts with docker-compose (hyphen), add a compatibility alias in /etc/bash.bashrc on the VPS:

alias docker-compose='docker compose'

This alias does not fix scripts that call docker-compose in absolute in a cron or systemd service — audit those separately.

Step 3 — Understand and adapt to the nftables network backend change

01

Verify that Docker networks still work

The good news: docker network works correctly with nftables. Inter-container traffic, NAT, and port exposure continue to work. What changes is the underlying tool that writes the rules.

docker network ls

Your existing bridge networks are still listed. To verify that a container is receiving traffic on the expected port, test directly:

curl -s http://localhost:8080/health

If the response is correct, the Docker data plane works regardless of the backend.

02

Diagnose the impact on your iptables scripts

The problem arises when a third-party script (monitoring, Ansible, UFW rules) inspects iptables to verify Docker rules are present:

iptables -L DOCKER 2>&1

With the nftables backend, this chain is empty or absent. The script returns an error while Docker works perfectly. This is not a Docker failure — your audit tool is no longer looking in the right place.

To inspect the actual rules:

nft list ruleset | grep -A 20 'docker'

If your monitoring scripts or Ansible playbooks check for Docker-specific iptables rules, adapt them to query nftables instead of inferring a failure.

Step 4 — Evaluate and enable the containerd image store

01

Check the current storage driver

docker info | grep 'Storage Driver'

On a VPS updated to v29 without configuration changes, you typically get Storage Driver: overlay2. The containerd store is opt-in on v29 — it is not enabled automatically. It will become the default on v30.

02

Enable the containerd store (opt-in, recommended before v30)

To enable the containerd store on v29 and prepare the migration before it is imposed in v30, add the following key to /etc/docker/daemon.json:

{
  "features": {
    "containerd-snapshotter": true
  }
}

Restart the daemon:

systemctl restart docker

Verification:

docker info | grep 'Storage Driver'
# Storage Driver: overlayfs

Note: existing images pulled under overlay2 remain available, but new layers are written in containerd format. If you need to revert, remove the key and restart — images in the new format will no longer be accessible without the containerd backend. This is why a snapshot before this step is recommended.

Third-party tool compatibility with Docker Engine v29

Toolv29 compatibility statusRecommended action
**Dockge** (up to 1.4.1 included)Not compatible: the Dockge daemon calls API routes removed in v29. The panel no longer starts after the Docker update.Update Dockge to version 1.4.2 or higher, which targets API v1.44. Check Dockge release notes before `apt upgrade` on a VPS hosting it.
**Portainer** (Community Edition < 2.21)Partially compatible: the interface works, but standalone Docker environments may show errors on network views. Version 2.21 fixes the nftables calls.Update Portainer via `docker pull portainer/portainer-ce:latest` then `docker compose up -d` before upgrading Docker Engine.
**CasaOS App Store**Partial compatibility documented: deployed apps continue to work, but the app manager may report errors when inspecting images if the containerd store is enabled. No corrective version announced as of 2026-08.Keep the containerd store opted out (v29 default) on CasaOS VPS until a corrective version. Test on a copy environment before any update.

Test the migration on a snapshot before touching production

A VPS with root access and snapshots lets you validate each step of this migration without risk. Create a snapshot named before-docker-v29, perform the full migration, validate your stacks, then delete the snapshot. If something goes wrong mid-way, restoring brings the VPS back to its initial state in under five minutes. This is exactly the use case on-demand snapshots cover: testing a risky system update on an exact copy, not on a client's production server.

Troubleshooting — real errors and remedies

The following scenarios cover the majority of incidents observed during Docker v29 migrations on VPS fleets.

Common error scenarios

01

Error: `client version X.XX is too old. Minimum supported API version is 1.44`

Cause: the docker-compose v1 standalone binary is still present and attempts to communicate with the v29 daemon.

Remedy:

apt remove docker-compose
apt install docker-compose-plugin
docker compose version

If the binary was installed manually (outside apt), find it:

which docker-compose
rm /usr/local/bin/docker-compose
02

Error: `docker-compose: command not found` after `apt upgrade`

Cause: the docker-compose package (v1) was removed during the update, and the v2 plugin was not installed.

Remedy:

apt install docker-compose-plugin

Then verify that your scripts calling docker-compose (with hyphen) now use docker compose (without hyphen), or set the system alias.

03

Error: `iptables: No chain/target/match by that name` in a monitoring script

Cause: your script inspects the DOCKER chain in iptables, but Docker v29 with nftables no longer writes it there.

Remedy: replace the iptables check with an nftables check:

nft list ruleset | grep -c 'docker'

If the count is above zero, Docker rules are present in nftables. Or use docker network inspect bridge to verify the data plane state directly from Docker, without depending on the network backend.

04

Dockge no longer starts after the update

Cause: Dockge 1.4.1 and earlier call API routes absent from Docker Engine v29.

Remedy:

cd /opt/dockge
docker compose pull
docker compose up -d

If the latest tag of the Dockge image is already at 1.4.2 or higher, this command suffices. Otherwise, edit your Dockge docker-compose.yml to point to the corrective version tag before relaunching.

05

Containers no longer respond on their ports after daemon restart

Cause: on the first restart of dockerd in nftables mode, NAT rules are rewritten in the correct backend, but some distributions have a conflict between the iptables-legacy service and nftables that delays rule setup.

Remedy:

systemctl stop docker
systemctl disable iptables
systemctl start docker

Then verify containers are restarted (docker compose up -d) and ports are exposed (`docker ps --format 'table {{.Names}}\t{{.Ports}}').

Preparing your fleet to avoid the next incident

A well-managed Docker v29 migration is not a one-off event — it is an opportunity to put in place the reflexes that prevent the next late-night emergency.

Lock the Docker version in apt. On client VPS, prevent Docker from updating automatically during unsupervised apt upgrade runs:

apt-mark hold docker-ce docker-ce-cli containerd.io

Unlock (apt-mark unhold) only when you are ready to migrate, after testing on a snapshot.

Automate fleet auditing. An Ansible playbook that checks the Docker API version on each VPS takes under an hour to write and gives you a dashboard of your fleet's exposure before each major Docker release.

Integrate Docker migration into your patch routine. The procedure described here — snapshot, API check, compose migration, nftables test, stack validation — documents as a runbook and replays at each major release.

VPS ready for Docker v29 — with snapshots and root access

An agency managing multiple client VPS needs a homogeneous Docker infrastructure, versioned and prepared for upstream updates. ServOrbit provides VPS with root access, dedicated IPv4, and snapshots — so every migration is tested first on a copy environment, not on a client's production server.

Need help?

Browse our help center and FAQ, or write to our team — support in French, English and Arabic.