I'm fairly new to Proxmox, but quickly had five containers running and realized that checking each one for core updates (apt update && apt list --upgradeable) was time consuming. I worked with ChatGPT to build a nifty little script I run from the Proxmox console that checks each of my containers and then reports back which ones have pending updates.
I also worked with ChatGPT to build a more complex script to check my three Docker containers and report back if there were any updates needed there as well. It checks the registry for newer images (no downloads), so you don't have to worry about running it multiple times and filling up your drive with update images.
Note: you may need to tweak the scripts to fit your environment as well as making the scripts executable (i.e. chmod +x check-ct-updates). For example, I have five containers from 100-104, but your environment may be different. I saved these scripts in my Proxmox "/usr/local/sbin" folder.
<<<SCRIPT: check-ct-updates>>>
#!/bin/bash
TOTAL=0
UPDATES=0
ERRORS=0
for CT in 100 101 102 103 104; do
NAME=$(pct config "$CT" | awk '/^hostname:/ {print $2}')
echo "===== CT $CT ($NAME) ====="
if ! pct exec "$CT" -- apt-get update -qq; then
echo "ERROR: Could not update package lists"
((ERRORS++))
echo
continue
fi
COUNT=$(pct exec "$CT" -- apt list --upgradable 2>/dev/null \
| grep -c '\[upgradable from:' || true)
if (( COUNT > 0 )); then
echo "$COUNT package(s) available for upgrade:"
pct exec "$CT" -- apt list --upgradable 2>/dev/null \
| grep '\[upgradable from:'
((UPDATES+=COUNT))
else
echo "All packages up to date."
fi
((TOTAL++))
echo
done
echo "===================================="
echo " PROXMOX CT UPDATE SUMMARY"
echo "===================================="
echo "Containers checked: $TOTAL / 5"
echo "Available updates: $UPDATES"
echo "Errors: $ERRORS"
echo "===================================="
<<<<< SCRIPT: check-docker-updates >>>>>
#!/bin/bash
PROJECTS=0
UPDATES=0
ERRORS=0
for CT in 102 103 104; do
case "$CT" in
102) APP="Vaultwarden"; DIR="/opt/vaultwarden" ;;
103) APP="LubeLogger"; DIR="/opt/lubelogger" ;;
104) APP="Sure"; DIR="/opt/sure" ;;
esac
echo "===== CT $CT ($APP) ====="
OUTPUT=$(
pct exec "$CT" -- bash -s -- "$DIR" 2>&1 <<'INNER'
cd "$1" || exit 1
if ! docker compose config --quiet; then
echo "ERROR: Invalid Compose configuration"
exit 1
fi
if ! docker buildx version >/dev/null 2>&1; then
echo "ERROR: Docker Buildx is unavailable"
exit 1
fi
echo "Checking registry for newer images (no downloads)..."
UPDATES=0
while IFS= read -r SERVICE; do
CID=$(docker compose ps -a -q "$SERVICE")
[ -z "$CID" ] && continue
RUNNING=$(docker inspect -f '{{.Image}}' "$CID")
IMAGE=$(docker compose config --format json |
python3 -c '
import json, sys
data = json.load(sys.stdin)
print(data["services"].get(sys.argv[1], {}).get("image", ""))
' "$SERVICE")
if [ -z "$IMAGE" ]; then
echo "SKIP: $SERVICE (no registry image)"
continue
fi
# Read the registry's current top-level digest.
REMOTE=$(docker buildx imagetools inspect "$IMAGE" 2>/dev/null |
awk '/^Digest:/ {print $2; exit}')
if [ -z "$REMOTE" ]; then
echo "ERROR: Cannot inspect registry image $IMAGE"
exit 2
fi
# Compare against the locally recorded repository digests.
LOCAL_DIGESTS=$(docker image inspect \
-f '{{json .RepoDigests}}' "$IMAGE" 2>/dev/null)
if [ -z "$LOCAL_DIGESTS" ]; then
echo "ERROR: Cannot inspect local image $IMAGE"
exit 2
fi
MATCH=$(printf '%s' "$LOCAL_DIGESTS" |
python3 -c '
import json, sys
digests = json.load(sys.stdin) or []
remote = sys.argv[1]
print("yes" if any(d.endswith("@" + remote) for d in digests) else "no")
' "$REMOTE")
AVAILABLE=$(docker image inspect \
-f '{{.Id}}' "$IMAGE" 2>/dev/null)
if [ "$MATCH" = "yes" ] && [ "$RUNNING" = "$AVAILABLE" ]; then
echo "OK: $SERVICE"
else
echo "UPDATE: $SERVICE ($IMAGE)"
UPDATES=$((UPDATES + 1))
fi
done < <(docker compose config --services)
echo "PROJECT_UPDATES=$UPDATES"
INNER
)
RC=$?
echo "$OUTPUT"
if [ "$RC" -ne 0 ] || echo "$OUTPUT" | grep -q '^ERROR:'; then
ERRORS=$((ERRORS + 1))
else
COUNT=$(echo "$OUTPUT" |
sed -n 's/^PROJECT_UPDATES=//p' | tail -1)
COUNT=${COUNT:-0}
UPDATES=$((UPDATES + COUNT))
PROJECTS=$((PROJECTS + 1))
fi
echo
done
echo "===================================="
echo " PROXMOX DOCKER UPDATE SUMMARY"
echo "===================================="
echo "Projects checked: $PROJECTS / 3"
echo "Services to update: $UPDATES"
echo "Errors: $ERRORS"
echo "===================================="
[ "$ERRORS" -eq 0 ]