Da
Developer Tools Azure

Dagu on Ubuntu 24.04 on Azure User Guide

| Product: Dagu on Ubuntu 24.04 LTS on Azure

Overview

Dagu is a self-contained workflow and cron orchestration engine. You describe your work as a DAG - a directed acyclic graph of steps - in a single, readable YAML file, and Dagu runs it on demand or on a schedule, resolving dependencies between steps and handling retries, timeouts, preconditions and lifecycle hooks. A built-in web UI lets you browse workflows, start and stop runs, watch each step of a run graph in real time and inspect per-run logs and execution history, while a REST API and a full command line interface drive the same engine from scripts. Because it needs no database and no message broker and keeps all of its state on the local filesystem, it starts instantly and is ideal for cron replacement, data pipelines, backups, batch jobs and edge automation on a single machine.

The cloudimg image installs the pinned Dagu 2.10.7 single Go binary running under systemd as dagu start-all (the HTTP server, scheduler and executor in one process), then locks it down for a marketplace appliance. Dagu binds to loopback 127.0.0.1:8080 so its UI and API are never exposed directly, and an nginx reverse proxy on port 80 adds a per-VM HTTP Basic Auth gate in front of it. Dagu's own web UI is unauthenticated by default, so this image closes that gap: nginx requires the admin credential (a unique password generated on the first boot of your VM) for the entire UI and API, while an unauthenticated /healthz endpoint is exposed for load balancer probes. An example workflow is bundled so the engine has something to run immediately. Backed by 24/7 cloudimg support.

What is included:

  • Dagu 2.10.7 installed as a single Go binary (/usr/local/bin/dagu) running as the dagu systemd service (dagu start-all)
  • The Dagu web UI and REST API on :80, fronted by nginx with the binary bound to loopback only
  • Per-VM HTTP Basic Auth (user admin) protecting the entire UI and API, with a unique password generated on first boot
  • Dagu bound to 127.0.0.1:8080 - nothing is exposed to the network directly
  • Dagu's own native basic auth also enabled as defence-in-depth on the loopback interface
  • An example workflow at /var/lib/dagu/dags/hello.yaml that runs on first boot to prove the engine
  • DAGU_HOME=/var/lib/dagu holding your workflow definitions (dags/), run logs and state
  • dagu.service + nginx.service as systemd units, enabled and active
  • An unauthenticated /healthz endpoint for Azure Load Balancer health probes
  • Ubuntu 24.04 LTS base, latest patches, unattended security upgrades enabled
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point; Dagu is light on resources. NSG inbound: allow 22/tcp from your management network, 80/tcp for the UI and API, and 443/tcp if you add TLS. Dagu serves plain HTTP on port 80; for production use, terminate TLS in front of it with your own domain and restrict access to trusted IP ranges (see Maintenance).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Dagu by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name dagu \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name dagu --port 80 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

systemctl is-active dagu.service nginx.service

Both report active. Dagu serves its web UI and REST API on the loopback address 127.0.0.1:8080; nginx fronts it on port 80 and adds the per-VM HTTP Basic Auth gate. Nothing binds a public application port directly - the only way in is through nginx.

The dagu and nginx services active, with dagu listening on loopback 127.0.0.1:8080 only and nginx on public port 80

Step 5 - Retrieve your web UI password

nginx protects the Dagu UI and API with HTTP Basic Auth. The username is admin and a unique password is generated on the first boot of your VM and written to a root-only file:

sudo cat /root/dagu-credentials.txt

This file contains DAGU_USERNAME, DAGU_PASSWORD and the DAGU_URL to open in a browser. The password is stored on disk only as a bcrypt hash in /etc/nginx/.dagu.htpasswd, so no plaintext password ships in the image. Store the password somewhere safe.

The per-VM credentials file with the password masked, dagu bound to loopback 127.0.0.1:8080 only, and the nginx HTTP Basic Auth round-trip returning 401 unauthenticated, 401 for a wrong password, 200 with the correct per-VM password, and 200 for the unauthenticated health probe

Step 6 - Confirm the health endpoint

nginx serves an unauthenticated health endpoint for load balancers and probes:

curl -s http://localhost/healthz

It returns ok. This endpoint never requires authentication, so it is safe for an Azure Load Balancer health probe.

Step 7 - Confirm the authentication gate

Because a password is set on first boot, an unauthenticated request to the UI returns HTTP 401, so nobody reaches Dagu without the password. The following reads the per-VM password from the credentials file and proves the round-trip - unauthenticated is rejected, a wrong password is rejected, and the correct password authenticates:

PW=$(sudo grep '^DAGU_PASSWORD=' /root/dagu-credentials.txt | cut -d= -f2-)
echo "unauth  : $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/)"
echo "wrongpw : $(curl -s -o /dev/null -w '%{http_code}' -u admin:wrong-pw http://127.0.0.1/)"
echo "authed  : $(curl -s -o /dev/null -w '%{http_code}' -u admin:$PW http://127.0.0.1/)"

It prints unauth : 401, wrongpw : 401, and authed : 200. The whole UI and API are only reachable with the per-VM password, because Dagu itself is bound to loopback and nginx is the only way in.

Step 8 - Run the bundled example workflow

A workflow in Dagu is just a YAML file describing a directed acyclic graph of steps. The image ships an example at /var/lib/dagu/dags/hello.yaml (two steps, greet then show_date, plus a */30 cron schedule). Run it from the command line and watch the engine execute each step to success:

sudo -u dagu env DAGU_HOME=/var/lib/dagu /usr/local/bin/dagu start /var/lib/dagu/dags/hello.yaml

The engine runs greet, then show_date (which depends on greet), and reports Result: Succeeded. Copy this file and edit it to build your own workflows, or create new ones under /var/lib/dagu/dags/.

The example hello.yaml workflow definition, and the dagu CLI running it so both the greet and show_date steps report succeeded with an overall Result of Succeeded

Step 9 - Sign in and open the dashboard

Browse to http://<vm-public-ip>/. Your browser prompts for a username and password: enter admin and the password from Step 5. Dagu opens on the Overview dashboard, which shows a timeline of recent DAG runs with an at-a-glance summary of how many succeeded, failed or were aborted.

The Dagu Overview dashboard showing the run timeline and a summary of recent runs with counts of ok, failed and aborted

Step 10 - Browse your workflows

Open the Workflows page from the left navigation. It lists every DAG under /var/lib/dagu/dags/ with its latest status, the time of its last run, and its schedule and next run time, plus action buttons to start, stop or reload a workflow. The bundled hello workflow appears here with its */30 cron schedule.

The Dagu Workflows page listing the hello workflow with a succeeded status, its last run time, its cron schedule and next run, and start, stop and reload actions

Step 11 - Inspect a workflow and its run graph

Click a workflow to open its detail view. The Status tab renders the DAG as a graph so you can see the dependencies between steps - here greet leads to show_date - with each node coloured by the outcome of the latest run. The Timeline, Outputs and Spec tabs show the run timeline, captured step outputs and the raw YAML definition.

The Dagu workflow detail view for hello showing the run graph with greet leading to show_date, both succeeded, and the Status, Timeline, Outputs and Spec tabs

Step 12 - Review execution history

Open the Executions page from the left navigation for a searchable, filterable history of every DAG run across your workflows. Each row shows the workflow name, the run ID, its status, what triggered it (a schedule, a manual start or a retry), the scheduled, queued and started times, the duration and the worker that executed it.

The Dagu Executions page listing recent runs of the hello workflow with run IDs, succeeded and failed statuses, the trigger type, timestamps and duration for each run

Step 13 - Review the installed components

Dagu ships as a single static Go binary with a small, predictable filesystem layout. DAGU_HOME=/var/lib/dagu holds your workflow definitions in dags/, run logs in logs/ and engine state in data/:

dagu version
ls /usr/local/bin/dagu /etc/dagu/dagu.env /var/lib/dagu/dags/hello.yaml

The dagu version, the single Go binary and its component paths, and the DAGU_HOME layout with the dags, logs and data directories

Maintenance

  • Password: the UI password is set on first boot and stored as a bcrypt entry in /etc/nginx/.dagu.htpasswd. To change it, run sudo htpasswd -B /etc/nginx/.dagu.htpasswd admin, set the same value in DAGU_AUTH_BASIC_PASSWORD in /etc/dagu/dagu.env, then sudo systemctl reload nginx and sudo systemctl restart dagu.
  • Create workflows: add your own *.yaml DAG files under /var/lib/dagu/dags/. Each file defines steps: with an id: and a run: command, optional depends: for ordering, and an optional schedule: cron expression. Dagu picks them up automatically and they appear on the Workflows page.
  • Restrict access: Dagu serves plain HTTP on port 80. For production, restrict access to trusted IP ranges in your Network Security Group, and front it with TLS (for example certbot with your own domain) terminating on :443.
  • Loopback binding: Dagu is bound to 127.0.0.1:8080 (DAGU_HOST/DAGU_PORT in /etc/dagu/dagu.env), so nginx is the only path in. Keep it that way - do not change the bind address to a public interface.
  • Scheduling: dagu start-all runs the scheduler, so any workflow with a schedule: cron expression runs automatically. Overlap policy, catch-up and retry behaviour are configured per workflow in its YAML.
  • Storage: all workflow definitions, run logs and engine state live under /var/lib/dagu; back up that directory to protect your workflows and run history.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.