Docker Images
Dagu publishes multiple container images to GitHub Container Registry at ghcr.io/dagucloud/dagu. All images are multi-arch (linux/amd64, linux/arm64, linux/arm/v7) and ship with the same defaults: listen on 8080, run dagu start-all, and honor PUID/PGID/DAGU_* environment variables.
Image overview
| Tag(s) | Base | Package Manager | What's inside | Use when |
|---|---|---|---|---|
latest, <version> | Ubuntu 24.04 | apt | Core runtime + sudo, tzdata, jq | General deployments; closest to production defaults |
alpine, <version>-alpine | Alpine 3.22 | apk | Musl-based image with bash, sudo, jq, tzdata | Minimal footprint, Alpine-only environments |
dev, <version>-dev | Ubuntu 24.04 | apt | Adds build tools (git, curl/wget, zip/unzip, build-essential, python3/pip, openjdk-17, nodejs/npm, jq, tzdata) | Local development or workflows that need compilers/SDKs baked in |
Prefer pinning to a specific version tag (
ghcr.io/dagucloud/dagu:<version>) for reproducible deployments.
Entrypoint and Process Reaping
Official images start with Tini as PID 1:
/usr/local/bin/tini -g -- /entrypoint.sh dagu start-allKeep that entrypoint unless there is a specific reason to replace it. Tini reaps orphaned child processes and forwards stop signals to Dagu. Without an init process, a workflow step that starts a background subprocess can leave a zombie process in the container.
/entrypoint.sh prepares DAGU_HOME, applies PUID/PGID, runs optional init scripts, and then starts the requested Dagu command.
When changing how the container starts:
- Docker Compose: use
command: ["dagu", "..."]; do not useentrypoint: []orentrypoint: ["dagu", ...]. - Kubernetes: use
args: ["dagu", "..."]; do not usecommand:unless the replacement command keeps an init process. - Docker socket/root mode: if
/entrypoint.shmust be bypassed, keep Tini withentrypoint: ["/usr/local/bin/tini", "-g", "--"].
Examples
Standard image:
docker run -d -p 8525:8080 -v dagu-data:/var/lib/dagu ghcr.io/dagucloud/dagu:latestAlpine image:
docker run -d -p 8525:8080 -v dagu-data:/var/lib/dagu ghcr.io/dagucloud/dagu:alpineDev image with extra tooling:
docker run -d -p 8525:8080 -v dagu-data:/var/lib/dagu ghcr.io/dagucloud/dagu:devFor Docker-in-Docker workflows, mount the host socket and run as root:
docker run -d -p 8525:8080 -v dagu-data:/var/lib/dagu -v /var/run/docker.sock:/var/run/docker.sock --user 0:0 ghcr.io/dagucloud/dagu:latestThis setup should be treated as privileged host access. A workflow that can reach the Docker socket can usually control the host through containers, mounts, or image execution. Use it only when Docker executor support is required and the instance is otherwise tightly controlled.
Custom Images
If your workflows require additional tools (Python, Perl, Ruby, etc.) not included in the standard images, build a custom image based on Dagu:
FROM ghcr.io/dagucloud/dagu:latest
# Install additional packages
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
perl \
&& rm -rf /var/lib/apt/lists/*
# Install Python packages if needed
RUN pip3 install --break-system-packages requests pandasBuild and run:
docker build -t my-dagu .
docker run -d -p 8080:8080 -v dagu-data:/var/lib/dagu my-daguBuild Arguments
All Dockerfiles accept the following build arguments to customize the container user and data directory:
| Argument | Default | Description |
|---|---|---|
USER | dagu | Username for the in-container user |
USER_UID | 1000 | UID for the in-container user |
USER_GID | $USER_UID | GID for the in-container user |
DAGU_HOME | /var/lib/dagu | Data directory where Dagu stores its state |
Match the container UID/GID to your host user so that bind-mounted files have the correct ownership:
docker build \
--build-arg USER_UID="$(id -u)" \
--build-arg USER_GID="$(id -g)" \
-t my-dagu .