Dragonfly P2P Distribution on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and use of Dragonfly on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images.
Dragonfly is an open source, cloud native peer to peer (P2P) file and container image distribution system, and a graduated project of the Cloud Native Computing Foundation. It turns the machines that pull artifacts into a swarm that shares pieces with each other, so a large image, model file or dataset is fetched from the origin once and then spread P2P between peers. This cuts origin bandwidth, speeds up mass rollouts, and stops registries and object stores from being overwhelmed when thousands of hosts pull the same content at once.
This image is a complete single node cluster. Dragonfly normally scales out across many hosts; this appliance runs the smallest useful shape of the same software on one VM, managed by systemd:
- manager — the control plane and web console. It holds cluster configuration and users, and serves the REST and gRPC APIs. It is backed by a bundled MariaDB database and a Redis cache.
- scheduler — builds the P2P scheduling graph, deciding which peer fetches which piece from whom.
- dfdaemon (seed peer) — the peer agent running in seed peer mode. It fetches from the origin, seeds the swarm, and exposes an HTTP proxy and a
dfgetcommand line for pulling content through the P2P network.
Security by design. Dragonfly's manager ships a default console login of root / dragonfly. An appliance that shipped that unchanged would be wide open. This image inverts that:
- The published default login is never present on your VM. At first boot the manager console is brought up on the loopback interface only, its
rootpassword is rotated to a value unique to your VM, and only then is the console rebound to the network. There is no window in which the published default is reachable from off the box, and the image itself contains no console password. - Nothing is baked into the image. The captured image contains no console password, no database password, no Redis password and no API signing key. All of them are generated uniquely on your VM at first boot and written to a root only file.
- The database and cache are private. MariaDB and Redis listen on the loopback interface only and are never exposed to the network.
- Proven before it ships. Every image is verified by pulling a real file end to end through the seed peer and scheduler and checksum matching the delivered bytes before it is published.
What is included:
- Dragonfly server 2.5.1 (the
managerandschedulerGo binaries) from the pinned upstream release, under systemd asdragonfly-manager.serviceanddragonfly-scheduler.service - Dragonfly client 1.4.9 (the Rust
dfdaemonanddfgetbinaries) from the pinned upstream release, withdfdaemonrunning in seed peer mode asdragonfly-dfdaemon.service - MariaDB and Redis from the Ubuntu archive, preconfigured as the manager's backing store and tuned to run comfortably on a small VM
- A first boot service that rotates every secret and registers the cluster before anything accepts connections
Prerequisites
- An Azure subscription and the Azure CLI (
az) installed and logged in (az login), or access to the Azure Portal. - An SSH key pair for Linux VM access.
- A network security group that allows inbound TCP 22 (SSH) and 8080 (the manager web console) from your address, and, if you want other machines to pull through this node's proxy, 4001. Keep the manager console restricted to trusted addresses (see Security recommendations).
Deploy the virtual machine
Create a resource group and launch the image. Replace the image reference with the cloudimg Dragonfly offer from the Azure Marketplace.
az group create --name my-resource-group --location eastus
az vm create \
--resource-group my-resource-group \
--name dragonfly \
--image <cloudimg-dragonfly-marketplace-image> \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
# Open the console port to your address (and, optionally, the proxy port 4001):
az vm open-port --resource-group my-resource-group --name dragonfly --port 8080 --priority 1001
Note the public IP address that az vm create prints; this guide refers to it as <vm-ip>.
Confirm the services are healthy
SSH in:
ssh azureuser@<vm-ip>
Then check that all five services are active. The manager, scheduler and dfdaemon are exposed on the network; MariaDB and Redis are bound to the loopback interface only.
sudo systemctl is-active dragonfly-manager dragonfly-scheduler dragonfly-dfdaemon mariadb redis-server
All five report active, and the listening sockets show the manager on 8080 and 65003, the scheduler on 8002, the dfdaemon proxy and health ports on 4001 and 4003, and MariaDB and Redis on loopback only.

The manager exposes an unauthenticated liveness probe. It returns HTTP 200 and nothing sensitive, so an Azure Load Balancer or Application Gateway health probe can use it directly.
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/healthy
Retrieve your per VM credentials
The unique administrator password and every backing secret are written to a root only file at first boot. Read it over your SSH session:
sudo cat /root/dragonfly-oss-credentials.txt
You will see the manager console URL, the root administrator password unique to this VM, the proxy URL, and the database and Redis passwords. The values below are masked; yours are real and unique to your VM.

The health check answers 200, the per VM root password authenticates against the console API, and the published default root / dragonfly is rejected with HTTP 401:

Sign in to the Manager console
Open the manager web console in your browser at http://<vm-ip>:8080/. Sign in with the account root and the MANAGER_ADMIN_PASSWORD from your credentials file.

After signing in, the Cluster overview shows your live control plane: one cluster (the default), one active scheduler, and the cluster-1 default cluster card. This is the managed P2P fabric this appliance registered at first boot.

Open cluster-1 to see its detail: it is the default cluster, scheduler cluster ID 1, with its scopes and load limits. The Schedulers and Peers tabs list the fabric members.

Distribute a file through the P2P swarm
The point of Dragonfly is to move bytes peer to peer. dfget hands a download to the local dfdaemon, which asks the scheduler and pulls the content through the seed peer, fetching from the origin in pieces and caching them in the swarm.
The self test below serves a 6 MiB file from a local origin that speaks HTTP range requests, pulls it with dfget, and confirms the delivered bytes match the source checksum. It runs entirely on the VM and needs no internet access:
OD=$(mktemp -d); head -c 6291456 /dev/urandom > "$OD/model.bin"
SRC=$(sha256sum "$OD/model.bin" | awk '{print $1}')
cat > "$OD/range.py" <<'PY'
import http.server,os,sys,re
F=sys.argv[2]; SZ=os.path.getsize(F)
class H(http.server.BaseHTTPRequestHandler):
def log_message(self,*a): pass
def do_GET(self):
d=open(F,'rb').read(); r=self.headers.get('Range')
if r:
m=re.match(r'bytes=(\d+)-(\d*)',r); s=int(m.group(1)); e=int(m.group(2)) if m.group(2) else SZ-1
self.send_response(206); self.send_header('Content-Range',f'bytes {s}-{e}/{SZ}')
self.send_header('Content-Length',str(e-s+1)); self.end_headers(); self.wfile.write(d[s:e+1])
else:
self.send_response(200); self.send_header('Content-Length',str(SZ)); self.send_header('Accept-Ranges','bytes'); self.end_headers(); self.wfile.write(d)
http.server.ThreadingHTTPServer(('127.0.0.1',18085),H).serve_forever()
PY
python3 "$OD/range.py" 18085 "$OD/model.bin" >/dev/null 2>&1 & SRV=$!
sleep 2
dfget http://127.0.0.1:18085/model.bin -O "$OD/pulled.bin"
kill "$SRV" 2>/dev/null
echo "source sha256: $SRC"
echo "dfget sha256: $(sha256sum "$OD/pulled.bin" | awk '{print $1}')"
rm -rf "$OD"
The two checksums match: the file was pulled through the Dragonfly seed peer and scheduler, not fetched directly.

In production you point Dragonfly at your real origins: for HTTP downloads route them through the dfdaemon proxy on port 4001 (curl -x http://<vm-ip>:4001 <url>), and for container images configure your registry mirror or containerd to use the proxy so image layers are distributed P2P.
Preheat content across the swarm
Under Job → Preheat the console can preheat content: pre distribute an image or file across the swarm before your hosts need it, so a mass rollout is served from peers instead of hammering the origin. On a fresh appliance the list is empty until you create your first preheat job.

Network ports
| Port | Service | Exposure |
|---|---|---|
| 22 | SSH | Network |
| 8080 | Manager REST API + web console | Network (restrict to trusted addresses) |
| 65003 | Manager gRPC | Network |
| 8002 | Scheduler gRPC | Network |
| 4001 | dfdaemon HTTP/HTTPS proxy | Network |
| 4003 | dfdaemon health | Network |
| 3306 | MariaDB | Loopback only |
| 6379 | Redis | Loopback only |
Managing the services
sudo systemctl status dragonfly-manager
sudo systemctl restart dragonfly-scheduler
sudo journalctl -u dragonfly-dfdaemon -f
The manager, scheduler and dfdaemon are enabled and restart on failure, and the whole stack survives a reboot. Configuration lives under /etc/dragonfly/ (manager.yaml, scheduler.yaml, dfdaemon.yaml).
Security recommendations
- Restrict the manager console (port 8080). Limit it to trusted addresses with your network security group. Dragonfly's manager job API has a known advisory (CVE-2026-24124) in which preheat job endpoints are callable without authentication, so the console port should never be open to the whole internet.
- Keep the per VM administrator password safe. It is unique to your VM and lives in
/root/dragonfly-oss-credentials.txt(mode 0600). Rotate it in the console under your profile if needed. - The database and cache stay private. MariaDB and Redis are bound to loopback; do not expose them.
- Keep the OS patched. Unattended security updates are enabled by default.
Support
These images are maintained by cloudimg with security updates and documentation. For deployment help or questions, contact support through the cloudimg listing. Dragonfly itself is an open source CNCF project; upstream documentation is at https://d7y.io and https://github.com/dragonflyoss.