Docker v29 Just Broke Your Setup — Here’s What Changed

Docker Engine v29, released in March 2026, makes three backward-incompatible changes that will trip up anyone running self-hosted services on a VPS or dedicated server. The minimum API version jumps to 1.44, the containerd image store becomes the default, and nftables support arrives as an opt-in replacement for iptables.

If you’re running Docker v24 or older, your containers won’t start after the upgrade. If you’ve written custom firewall rules with iptables, those rules may stop working. And if you rely on the legacy overlay2 storage driver behavior, image pulls could behave differently than you expect.

This guide walks through each breaking change, shows you how to check whether you’re affected, and gives you the exact commands to migrate safely. If you’re running Docker on a CWH Cloud VPS, this applies directly to you.

The Three Breaking Changes

Change What It Means Who’s Affected
Minimum API version raised to 1.44 Docker CLI and SDK clients must support API v1.44+. Older clients get rejected. Anyone running Docker v24 or older, or using pinned client versions
containerd image store is now default Images are stored and managed by containerd instead of Docker’s legacy store. Existing images may need re-pulling. Anyone upgrading from Docker v27 or earlier with existing images
Opt-in nftables support Docker can now use nftables instead of iptables for container networking rules. Not default yet, but iptables behavior has subtle changes. Anyone with custom iptables rules for Docker networking, port forwarding, or firewalling

Check If You’re Affected

Before upgrading, run these three checks on your server.

Check Your Current Docker Version

docker version --format '{{.Server.Version}}'

If the output is 24.x or lower, the API version change will break your setup. Versions 25.x through 28.x support API v1.44 and will upgrade cleanly, though you’ll still want to audit the other two changes.

Check Your Image Store Driver

docker info --format '{{.Driver}}'

If you see overlay2, you’re on the legacy store. Docker v29 switches the default to containerd’s image store. Your existing images will still work, but new pulls and builds use the new store unless you opt out.

Check Your Firewall Rules

sudo iptables -L DOCKER -n 2>/dev/null | head -20
sudo iptables -L DOCKER-USER -n 2>/dev/null | head -20

If you’ve added custom rules to the DOCKER-USER chain or written iptables scripts that reference Docker’s chains directly, the nftables transition will affect you. Even without opting into nftables, Docker v29 changes how it manages some iptables rules.

If you’re running an intrusion prevention system like Fail2ban or CrowdSec, check that their Docker integration still works after the upgrade.

Step 1: Upgrade Docker Engine Safely

Don’t run apt upgrade blindly. Take a snapshot first and do a controlled upgrade.

On Ubuntu/Debian

# Take a snapshot if your VPS provider supports it (do this first)

# Update the Docker repository
sudo apt-get update

# Check what version is available
apt-cache madison docker-ce | head -5

# Install Docker v29 specifically
sudo apt-get install docker-ce=5:29.0.0-1~ubuntu.22.04~jammy   docker-ce-cli=5:29.0.0-1~ubuntu.22.04~jammy   containerd.io

# Verify the upgrade
docker version

On AlmaLinux/Rocky/RHEL

# Check available versions
yum list docker-ce --showduplicates | tail -5

# Install Docker v29
sudo yum install docker-ce-29.0.0 docker-ce-cli-29.0.0 containerd.io

# Restart Docker
sudo systemctl restart docker

# Verify
docker version

If the upgrade fails because your current Docker is too old (v23 or below), you’ll need to step through intermediate versions first — jump to v25, then to v29.

Step 2: Handle the containerd Image Store

Docker v29 defaults to the containerd image store. This is generally faster and more reliable, but there are two things to watch for.

What Changes

Behavior Legacy Store (overlay2) containerd Store (v29 default)
Image listing docker images shows all docker images shows all (same)
Multi-platform images Pulls only current platform Can pull and store multi-arch manifests
Build cache Stored in Docker’s graph driver Stored in containerd’s content store
Image export format Docker-format tarball OCI-format tarball by default
Disk usage Deduplication via layers Better deduplication via content-addressable storage

If You Need to Stay on the Legacy Store

Edit /etc/docker/daemon.json:

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

Then restart Docker:

sudo systemctl restart docker

This keeps the legacy overlay2 behavior. Use this as a stopgap if your CI/CD pipeline or backup scripts depend on the old image export format. Plan to migrate to the containerd store within the next few months — Docker will eventually remove the legacy store entirely.

Step 3: Audit Your Firewall Rules

This is the change most likely to cause production incidents. Docker has historically created its own iptables chains (DOCKER, DOCKER-USER, DOCKER-ISOLATION-STAGE-1/2) to manage container networking. Docker v29 changes how these chains interact with the rest of your firewall.

The nftables Opt-In

Docker v29 adds an iptables-backend option in daemon.json:

{
  "iptables-backend": "nftables"
}

When enabled, Docker creates nftables rules instead of iptables rules. This fixes long-standing issues where Docker’s iptables rules conflicted with host firewall managers like ufw, firewalld, or manual nftables configurations.

What to Audit (Even Without Opting In)

Even if you stay on iptables, Docker v29 tightens how it manages the DOCKER-USER chain. Custom rules you’ve added may behave differently. Run this check:

# List all custom DOCKER-USER rules
sudo iptables -L DOCKER-USER -n --line-numbers

# Check for any rules that reference Docker bridge IPs directly
sudo iptables -S | grep -i docker

Common patterns that break:

Pattern Why It Breaks Fix
Hard-coded bridge subnet (172.17.0.0/16) Docker may assign different subnets Use interface-based rules (-i docker0)
iptables scripts that flush all chains Deletes Docker’s managed chains Exclude DOCKER chains from flush scripts
UFW rules assuming Docker respects INPUT chain Docker bypasses INPUT via FORWARD chain Use DOCKER-USER chain for access control
Port-based blocks in INPUT chain Container ports use FORWARD, not INPUT Block in DOCKER-USER or use nftables backend

If you’re running a reverse proxy like Caddy with auto-HTTPS, verify that your proxy container can still reach the upstream containers after the upgrade. The networking changes in v29 can silently break inter-container communication if you’re using custom Docker networks with specific subnet configurations.

The UFW Problem (Finally Fixed)

One of Docker’s most infamous issues has been that ufw deny rules don’t actually block access to container-published ports, because Docker’s iptables rules bypass the INPUT chain entirely. The nftables backend in v29 fixes this — when enabled, Docker respects the host firewall’s rules properly.

If you’ve been using the DOCKER-USER chain workaround, switching to the nftables backend lets you drop that complexity and use ufw or firewalld directly.

Docker Compose Compatibility

Docker Compose v2 (the docker compose plugin, not the legacy docker-compose Python binary) works fine with Docker v29. But if you’re still using the standalone docker-compose v1 binary, it will fail — it doesn’t support API v1.44.

# Check which Compose you're running
docker compose version    # v2 plugin (good)
docker-compose --version  # v1 standalone (must upgrade)

If you’re on v1, switch to the v2 plugin:

# Install Compose v2 plugin
sudo apt-get install docker-compose-plugin

# Verify
docker compose version

The syntax is almost identical. The main difference is docker compose (space) instead of docker-compose (hyphen). If you have scripts or cron jobs using the hyphenated command, update them.

Testing Your Migration

After upgrading, run through this checklist:

# 1. Verify Docker is running
sudo systemctl status docker

# 2. Check that all containers restarted
docker ps -a --format 'table {{.Names}}	{{.Status}}	{{.Ports}}'

# 3. Verify networking between containers
docker exec my-app ping -c 2 my-database

# 4. Check published ports are accessible
curl -s -o /dev/null -w '%{http_code}' http://localhost:8080

# 5. Verify firewall rules are intact
sudo iptables -L DOCKER-USER -n

# 6. Run a test image pull with the new store
docker pull hello-world && docker run --rm hello-world

# 7. Check disk usage
docker system df

If anything fails, check the Docker daemon logs:

sudo journalctl -u docker --since "1 hour ago" --no-pager

Set up a monitoring stack if you don’t already have one — you’ll want to know immediately if a container stops responding after the upgrade.

Wrapping Up

Docker v29’s changes are significant but manageable. The API version bump forces you to keep clients current, the containerd store is a genuine improvement worth adopting, and the nftables backend finally fixes Docker’s long-standing firewall bypass issues.

The migration path:

  1. Snapshot your server
  2. Check your current Docker and Compose versions
  3. Upgrade Docker Engine (step through v25 first if you’re on v23 or older)
  4. Audit your iptables rules and consider switching to nftables
  5. Update any docker-compose v1 scripts to docker compose v2
  6. Test container networking, published ports, and firewall rules

If you’re running Docker on a CWH Cloud VPS, snapshot support is built in — take one before you start. And if you’d rather not handle this yourself, CWH’s Managed Support team can run the migration for you.