solution for automatically updating Docker Swarm services and Docker Compose containers when new images are available. It can be done periodically or triggered by a webhook.
To enable auto-updates for your services, just add this label:
services:
your-app:
image: your-app:latest
labels:
- "docker_autoupdater.enable=true"
# ... rest of your service configurationThis project uses a two-container architecture that separates responsibilities for enhanced security. If you do not need webhooks, you can also run the updater service as a standalone container and update images periodically.
┌─────────────────────────────────────────────────────────────┐
│ External Network │
│ │
│ ┌─────────────┐ HTTP Webhook ┌─────────────────────┐ │
│ │ GitHub │ ─────────────────► │ Trigger Service │ │
│ │ Registry │ /webhook │ (Port 8080) │ │
│ │ CI/CD │ │ • Node.js App │ │
│ └─────────────┘ │ • Non-root user │ │
│ │ • No Docker access │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────┬───────────────┘
│
┌─────────▼──────────┐
│ Shared Volume │
│ /shared/trigger │
└─────────┬──────────┘
│
┌─────────────────────────────────────────────┼───────────────┐
│ Internal Network │ │
│ ┌────────▼───────────┐ │
│ │ Updater Service │ │
│ │ • Root user │ │
│ │ • Docker socket │ │
│ │ • No network │ │
│ │ • Monitors file │ │
│ └─────────┬──────────┘ │
│ │ │
│ ┌─────────────────────────────────────────┐ │ │
│ │ Docker Socket │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │ │
│ │ │ Service │ │ Service │ │ ┘ Updates │
│ │ │ app-web │ │ app-api │ ... │ Containers │
│ │ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Security through separation of concerns:
-
Trigger Container (
woolfg/docker-container-autoupdater-trigger)- Handles HTTP webhooks from external sources
- Is connted to the outside world
- Runs as non-root user
- No Docker socket access - can't control containers
- Only writes trigger files to shared volume
-
Updater Container (
woolfg/docker-container-autoupdater-updater)- Monitors for trigger files
- Runs scheduled updates every 15 minutes
- No network access - can't be reached from outside
- Has Docker socket access for container management
This architecture ensures that even if the public-facing trigger service is compromised, attackers cannot directly access Docker or your containers. In case you do not need webhooks, you can run the updater service as a standalone container and update images periodically.
services:
# Updater service - runs as root with Docker socket access (isolated)
updater:
image: woolfg/docker-container-autoupdater-updater:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- trigger-volume:/shared
environment:
CHECK_INTERVAL: 5 # Check for triggers every 5 seconds
UPDATE_INTERVAL: 900 # Auto-update every 15 minutes
TRIGGER_FILE: /shared/update-trigger
restart: unless-stopped
network_mode: "none" # No network access for security
deploy:
placement:
constraints:
- node.role == manager # Must run on manager node
# Trigger service - public facing, no privileged access
trigger:
image: woolfg/docker-container-autoupdater-trigger:latest
ports:
- "8080:3000"
volumes:
- trigger-volume:/shared
environment:
PORT: 3000
HOOK: /update-YOUR_SECRET_WEBHOOK_PATH_HERE
TRIGGER_FILE: /shared/update-trigger
restart: unless-stopped
deploy:
placement:
constraints:
- node.role == manager # Must run on the same node as updater to be able to share the volume
volumes:
trigger-volume:version: '3.8'
services:
updater:
image: woolfg/docker-container-autoupdater-updater:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- trigger-volume:/shared
environment:
TRIGGER_FILE: /shared/update-trigger
restart: unless-stopped
trigger:
image: woolfg/docker-container-autoupdater-trigger:latest
ports:
- "8080:3000"
volumes:
- trigger-volume:/shared
environment:
HOOK: /update-YOUR_SECRET_WEBHOOK_PATH_HERE
TRIGGER_FILE: /shared/update-trigger
restart: unless-stopped
volumes:
trigger-volume:If you only want scheduled updates without webhooks:
services:
updater:
image: woolfg/docker-container-autoupdater-updater:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
UPDATE_INTERVAL: 300 # Check every 5 minutes
restart: unless-stoppedOnce deployed, trigger updates by calling your webhook:
# Trigger an update
curl -X GET http://your-server:8080/update-YOUR_SECRET_WEBHOOK_PATH_HERE
# Response
{
"message": "Update trigger created",
"timestamp": "2025-08-27T10:24:42.266Z",
"triggerFile": "/shared/update-trigger"
}| Variable | Default | Description |
|---|---|---|
CHECK_INTERVAL |
5 |
How often to check for trigger file (seconds) |
UPDATE_INTERVAL |
900 |
Scheduled update interval (seconds) |
TRIGGER_FILE |
/shared/update-trigger |
Path to trigger file |
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
HTTP server port |
HOOK |
/hook123456789 |
Webhook endpoint path |
TRIGGER_FILE |
/shared/update-trigger |
Path to trigger file |
Thanks to @mre for the input and code reviews.
MIT License - see LICENSE file for details.