fix(upgrade): keep Coolify running when Docker reports IPv6 gateways with a prefix

Docker Engine 27.0 to 28.0.0 reports an IPv6 network gateway with its
prefix length (fd00::1/64) until the daemon restarts (moby/moby#49520).
The Docker CLI 29 and Compose 5 in the helper image reject it, so
deployments failed and the upgrade left Coolify stopped.

- Stop the upgrade before it changes containers when the coolify network
  has such a gateway, and tell the user to restart or upgrade Docker.
- Create a new coolify network again without IPv6 when Docker reports
  its gateway with a prefix.
- Report an error, not "Upgrade complete", when the new Coolify
  containers do not start.
- Add the fix to deployment errors that contain this ParseAddr failure.

Fixes #11583
This commit is contained in:
Andras Bacsai
2026-10-16 21:19:35 +02:00
parent f1f7d5269e
commit 420692c020
7 changed files with 304 additions and 35 deletions
+52 -17
View File
@@ -38,6 +38,47 @@ write_status() {
echo "${step}|${message}|$(date -Iseconds)" > "$STATUS_FILE"
}
# Print the first gateway of a network that Docker reports with a prefix length (fd00::1/64).
# Docker Engine 27.0 to 28.0.0 does this for IPv6 until the daemon restarts (https://github.com/moby/moby/pull/49520).
# The Docker CLI and Compose in the helper image fail on such a network with a ParseAddr error.
network_gateway_with_prefix() {
docker network inspect "$1" --format '{{range .IPAM.Config}}{{.Gateway}} {{end}}' 2>&1 | grep -oE '[0-9A-Fa-f:.]+/[0-9]+' | head -n1
}
# Make sure the coolify network exists and the helper image can read it.
# It is created when starting Coolify with docker compose
ensure_coolify_network() {
log "Checking Docker network 'coolify'..."
if ! docker network inspect coolify >/dev/null 2>&1; then
log "Network 'coolify' does not exist, creating..."
if ! docker network create --attachable --ipv6 coolify 2>/dev/null; then
log "Failed to create network with IPv6, trying without IPv6..."
docker network create --attachable coolify 2>/dev/null
log "Network 'coolify' created without IPv6"
elif [ -n "$(network_gateway_with_prefix coolify)" ]; then
# No container uses the new network yet, so it is safe to recreate it.
log "Docker reports the IPv6 gateway of network 'coolify' with a prefix length, recreating it without IPv6..."
docker network rm coolify >/dev/null 2>&1
docker network create --attachable coolify 2>/dev/null
log "Network 'coolify' created without IPv6"
else
log "Network 'coolify' created with IPv6 support"
fi
return 0
fi
log "Network 'coolify' already exists"
local gateway
gateway=$(network_gateway_with_prefix coolify)
if [ -n "$gateway" ]; then
local message="Docker Engine $(docker version --format '{{.Server.Version}}' 2>/dev/null) reports the gateway of the 'coolify' network as ${gateway}, which Coolify cannot read (Docker Engine bug, fixed in 28.0.1). Run 'systemctl restart docker' (this restarts all containers) or upgrade Docker Engine, then upgrade Coolify again."
log "ERROR: ${message}"
write_status "error" "$message"
echo " ERROR: ${message}"
return 1
fi
}
# Pull an image. Retry with backoff, because the registry can rate limit many instances that pull at the same time.
pull_image() {
local image="$1"
@@ -177,21 +218,7 @@ fi
log "Environment variables check complete"
echo " Done."
# Make sure coolify network exists
# It is created when starting Coolify with docker compose
log "Checking Docker network 'coolify'..."
if ! docker network inspect coolify >/dev/null 2>&1; then
log "Network 'coolify' does not exist, creating..."
if ! docker network create --attachable --ipv6 coolify 2>/dev/null; then
log "Failed to create network with IPv6, trying without IPv6..."
docker network create --attachable coolify 2>/dev/null
log "Network 'coolify' created without IPv6"
else
log "Network 'coolify' created with IPv6 support"
fi
else
log "Network 'coolify' already exists"
fi
ensure_coolify_network || exit 1
mkdir -p /data/coolify/images/{avatars,project-icons}
chown -R 9999:root /data/coolify/images
@@ -316,8 +343,16 @@ nohup bash -c "
fi
log 'Running docker compose up...'
docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock \${DOCKER_CONFIG_MOUNT} --rm \${REGISTRY_URL:-docker.io}/coollabsio/coolify-helper:\${LATEST_HELPER_VERSION} bash -c \"LATEST_IMAGE=\${LATEST_IMAGE} docker compose --env-file /data/coolify/source/.env \${COMPOSE_FILES} up -d --remove-orphans --wait --wait-timeout 60\" >>\"\$LOGFILE\" 2>&1
log 'Docker compose up completed'
if docker run -v /data/coolify/source:/data/coolify/source -v /var/run/docker.sock:/var/run/docker.sock \${DOCKER_CONFIG_MOUNT} --rm \${REGISTRY_URL:-docker.io}/coollabsio/coolify-helper:\${LATEST_HELPER_VERSION} bash -c \"LATEST_IMAGE=\${LATEST_IMAGE} docker compose --env-file /data/coolify/source/.env \${COMPOSE_FILES} up -d --remove-orphans --wait --wait-timeout 60\" >>\"\$LOGFILE\" 2>&1; then
log 'Docker compose up completed'
elif [ \"\$(docker inspect --format '{{.State.Running}}' coolify 2>/dev/null)\" = 'true' ]; then
# A slow first start (for example long migrations) can pass the wait timeout. Coolify is still starting.
log 'Docker compose up did not finish waiting, but the coolify container is running'
else
log 'ERROR: Docker compose up failed and the coolify container is not running'
write_status 'error' \"Coolify did not start. Check the upgrade log: \$LOGFILE\"
exit 1
fi
# Final log entry
echo '' >>\"\$LOGFILE\"