WebDAV Server on Ubuntu 24.04 on Azure User Guide
Overview
WebDAV Server delivers hacdias/webdav, a fast, simple, self hosted WebDAV server written as a single static Go binary. WebDAV lets you mount and manage a remote directory as if it were a local drive from Windows Explorer, macOS Finder, Linux file managers and any WebDAV client, so it works as a drop in remote file share, backup target or document store that you run and own inside your own Azure subscription.
The cloudimg image installs the official webdav binary at /usr/local/bin/webdav, running as the webdav service. It serves a directory at /var/lib/webdav/data on the OS disk over HTTPS on port 443, with configurable per user permissions for create, read, update and delete.
Secure by default, no default login: upstream webdav can be run with a plaintext or no authentication configuration; this image never ships that. The server always runs over HTTPS with HTTP Basic Auth enforced. A webdav-firstboot.service oneshot generates a unique username and password and a TLS certificate on each VM's first boot, stores the password only as a bcrypt hash in the server configuration, writes the plaintext credential to a root only file, resolves the instance URL, then disables itself. No two VMs share a credential and none is baked into the image.
Fail secure: the server carries a bootstrap gate (ConditionPathExists) that only clears after first boot has written the per VM credential and certificate, so the server cannot start at all until they exist. If first boot were interrupted the server simply would not serve, rather than coming up open or unencrypted.
Always current: on first boot the appliance downloads the newest webdav release binary (falling back to the baked version if the network is unavailable), so every launch runs current software rather than the version frozen at build time.
Note on the interface: WebDAV is a protocol, not a web application, so there is no web UI to log into. You drive it with any WebDAV client (Windows Explorer, macOS Finder, Linux davfs2, Cyberduck, WinSCP, or a mobile app) or with curl. This guide uses curl to demonstrate the server and shows how to connect the common desktop clients.
What is included:
- WebDAV Server (verified at 5.14.0) as the official single static Go binary
webdav.serviceserving HTTPS on:443- HTTP Basic Auth enforced, with the password stored only as a bcrypt hash
- A per VM self signed TLS certificate generated on first boot
webdav-firstboot.servicefor the first boot credential, certificate, binary refresh and info note- A unique per VM username and password generated on first boot, in a root only
0600file - A fail secure bootstrap gate so the server never starts without a credential and certificate
- Ubuntu 24.04 LTS base, fully patched
- 24/7 cloudimg support, 24h response SLA
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet with a subnet. WebDAV is CPU light; performance is dominated by disk and network throughput. Recommended VM size: Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and small teams, or a larger size with a bigger data disk for busy file shares. The served directory lives on the OS disk by default, so expand the disk (or attach a dedicated data disk, see the sizing section) before storing large amounts of data.
Step 1: Deploy from the Azure Portal
Search the Marketplace for WebDAV Server on Ubuntu 24.04, choose your VM size, and attach an NSG that allows TCP 22 (SSH) from your management network and TCP 443 (HTTPS WebDAV) from the clients that will use the share. Because Basic Auth and TLS are enforced, the server is safe to expose to your clients, but you should still restrict the source ranges to networks you control.
Step 2: Deploy from the Azure CLI
RG="webdav-prod"; LOCATION="eastus"; VM_NAME="webdav-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/webdav-server-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name wd-vnet --address-prefix 10.90.0.0/16 --subnet-name wd-subnet --subnet-prefix 10.90.1.0/24
az network nsg create -g "$RG" --name wd-nsg
az network nsg rule create -g "$RG" --nsg-name wd-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name wd-nsg --name allow-webdav --priority 110 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 443 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name wd-vnet --subnet wd-subnet --nsg wd-nsg --public-ip-sku Standard
Step 3: Connect via SSH
ssh azureuser@<vm-ip>
Step 4: Verify the service and listener
WebDAV Server serves HTTPS on :443. Every request requires authentication, so an unauthenticated call returns 401.
sudo systemctl start webdav 2>/dev/null || true
sudo systemctl is-active webdav
ss -tln | grep ':443'
echo "unauthenticated / -> HTTP $(curl -sk -o /dev/null -w '%{http_code}' https://127.0.0.1/)"
You should see the service active, the listening socket on :443, and HTTP 401 from the unauthenticated call, which confirms authentication is enforced.

Step 5: Read your per VM credentials
The username and password were generated on this VM's first boot and stored in a root only file, and the password is kept only as a bcrypt hash in the server configuration. Read the credentials, keep them secret, and confirm that the per VM credential authenticates while an unauthenticated request does not.
sudo cat /root/webdav-info.txt
U=$(sudo grep '^WEBDAV_USER=' /root/webdav-info.txt | cut -d= -f2-)
P=$(sudo grep '^WEBDAV_PASSWORD=' /root/webdav-info.txt | cut -d= -f2-)
echo "unauthenticated -> HTTP $(curl -sk -o /dev/null -w '%{http_code}' https://127.0.0.1/)"
echo "authenticated -> HTTP $(curl -sk -o /dev/null -w '%{http_code}' -u "$U:$P" https://127.0.0.1/)"
The info note holds WEBDAV_USER, WEBDAV_PASSWORD and the WebDAV URL, is owned root:root with mode 0600, and the server returns 401 without the credential and 2xx with it. The transport is encrypted with the per VM TLS certificate at /etc/webdav/tls/cert.pem.

Step 6: Store and fetch a file (WebDAV round trip)
Upload a file with an authenticated PUT, fetch it straight back and confirm it matches byte for byte, then list the directory with PROPFIND. This is exactly what a WebDAV client does under the hood.
U=$(sudo grep '^WEBDAV_USER=' /root/webdav-info.txt | cut -d= -f2-)
P=$(sudo grep '^WEBDAV_PASSWORD=' /root/webdav-info.txt | cut -d= -f2-)
BLOB="hello from WebDAV Server at $(date -u +%FT%TZ)"
printf '%s' "$BLOB" | curl -sk -u "$U:$P" -T - "https://127.0.0.1/demo.txt" -o /dev/null -w 'PUT /demo.txt -> HTTP %{http_code}\n'
GOT=$(curl -sk -u "$U:$P" "https://127.0.0.1/demo.txt")
[ "$GOT" = "$BLOB" ] && echo "GET /demo.txt -> byte for byte match" || echo "GET /demo.txt -> MISMATCH"
echo "PROPFIND / -> HTTP $(curl -sk -o /dev/null -w '%{http_code}' -u "$U:$P" -X PROPFIND -H 'Depth: 1' https://127.0.0.1/)"
echo "unauthenticated GET /demo.txt -> HTTP $(curl -sk -o /dev/null -w '%{http_code}' https://127.0.0.1/demo.txt)"
curl -sk -u "$U:$P" -X DELETE "https://127.0.0.1/demo.txt" -o /dev/null
The PUT returns 201, the authenticated GET returns the identical file, PROPFIND returns 207 Multi-Status (the directory listing), and an unauthenticated GET of the same path returns 401, so content is never served without the credential.

Step 7: Connect a WebDAV client
Use the username and password from Step 5 and the server address https://<vm-ip>/. Because the certificate is self signed, clients will prompt you to trust it on first connect (see Step 8 to install a trusted certificate).
Windows (File Explorer): open File Explorer, right click This PC, choose Map network drive, and enter https://<vm-ip>/ as the folder. Windows will prompt for the username and password. You can also use the command line:
net use * https://<vm-ip>/ /user:<webdav-username> <webdav-password>
macOS (Finder): in Finder choose Go → Connect to Server (⌘K), enter https://<vm-ip>/, and supply the username and password when prompted.
Linux (davfs2): install davfs2 and mount the share:
sudo apt-get install -y davfs2
sudo mount -t davfs https://<vm-ip>/ /mnt/webdav
curl (any platform): upload, download and list from scripts:
curl -u <webdav-username>:<webdav-password> -T ./report.pdf https://<vm-ip>/report.pdf
curl -u <webdav-username>:<webdav-password> https://<vm-ip>/report.pdf -o report.pdf
curl -u <webdav-username>:<webdav-password> -X PROPFIND -H 'Depth: 1' https://<vm-ip>/
Step 8: Trusting or replacing the certificate
The server ships with a per VM self signed certificate, which encrypts traffic but is not trusted by clients out of the box, so clients prompt on first connect. For a smoother experience, either distribute the self signed certificate to your clients as a trusted root, or replace it with a certificate from a public CA.
To use a real certificate from Let's Encrypt (requires a public DNS name pointing at the VM and TCP 80 reachable), install certbot, obtain a certificate for <your-domain>, point the config at it, and restart:
sudo apt-get install -y certbot
sudo certbot certonly --standalone -d <your-domain> --agree-tos -m <your-email> -n
sudo sed -i "s#^cert:.*#cert: /etc/letsencrypt/live/<your-domain>/fullchain.pem#" /etc/webdav/config.yml
sudo sed -i "s#^key:.*#key: /etc/letsencrypt/live/<your-domain>/privkey.pem#" /etc/webdav/config.yml
sudo systemctl restart webdav
Clients then connect to https://<your-domain>/ with no certificate warning.
Step 9: Permissions, users and sizing
The server configuration lives at /etc/webdav/config.yml. It defines the listening address and port, the served directory, the TLS certificate, and the users with their permissions. Permissions combine the letters C (create), R (read), U (update) and D (delete); the per VM admin user is granted CRUD.
To add a read only user or a second full access user, generate a bcrypt hash and add a users entry, then restart. Never store a plaintext password in the config:
# generate a bcrypt hash for a new password (never store plaintext in the config)
htpasswd -nbBC 10 reader "<new-password>"
# add a users: entry to /etc/webdav/config.yml with permissions: R for read only, then:
sudo systemctl restart webdav
The served directory lives on the OS disk under /var/lib/webdav/data. Inspect it and its disk usage:
ls -ld /var/lib/webdav/data
du -sh /var/lib/webdav/data 2>/dev/null
df -h /var/lib/webdav
To grow capacity, attach a dedicated data disk, mount it at /var/lib/webdav/data (preserving webdav ownership), and the served content then lives on the larger volume.
Persistence, first boot and updates
The served directory lives on the OS disk under /var/lib/webdav/data. The first boot service generates the per VM username and password and TLS certificate, refreshes the webdav binary to the latest release, writes the fail secure bootstrap marker, then disables itself so subsequent reboots are unaffected. The OS ships fully patched with unattended security upgrades enabled.
sudo /usr/local/bin/webdav version 2>/dev/null | head -1
systemctl is-enabled webdav-firstboot.service webdav.service
ls -ld /var/lib/webdav/data
export DEBIAN_FRONTEND=noninteractive; sudo apt-get update -y >/dev/null 2>&1
echo "held packages: $(apt-mark showhold | tr '\n' ' ')[none]"

Support
Every cloudimg deployment includes 24/7 support with a 24 hour response SLA. Contact support@cloudimg.co.uk for help with deployment, configuration or scaling.
This is a repackaged open source software product with additional charges for cloudimg support services. WebDAV Server (hacdias/webdav) is open source under the MIT licence. All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.