Deployment guide

WebDAV Server

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. It works as a drop-in remote file share, backup target or document store that you run and own inside your own Azure subscription.

This SecureAnyCloud 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. A webdav-firstboot.service oneshot creates the credentials on first boot.

WebDAV is a protocol, not a web application, so there is no web UI to sign in to. 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 you get:

  • WebDAV Server (verified at 5.14.0) as the official single static Go binary
  • webdav.service serving HTTPS on :443
  • Secure by default, with no default login. Upstream webdav can run with plaintext or no authentication, but this image never ships that. The server always runs over HTTPS with HTTP Basic Auth enforced, and the password is stored only as a bcrypt hash.
  • A per-VM self-signed TLS certificate generated on first boot
  • webdav-firstboot.service, a oneshot that generates a unique username and password and a TLS certificate on each VM's first boot. It stores the password only as a bcrypt hash in the server configuration, writes the plaintext credential to a root-only 0600 file, resolves the instance URL, refreshes the binary, and then disables itself. No two VMs share a credential, and none is baked into the image.
  • Fail-secure startup. A bootstrap gate (ConditionPathExists) clears only after first boot has written the per-VM credential and certificate, so the server cannot start until they exist. If first boot were interrupted, the server would not serve, rather than coming up open or unencrypted.
  • Always current. On first boot, the appliance downloads the newest webdav release binary and falls back to the baked version if the network is unavailable. Every launch runs current software rather than the version frozen at build time.
  • An Ubuntu 24.04 LTS base, patched at build time
  • 24/7 SecureAnyCloud support with a 24-hour response SLA

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet.

WebDAV is light on CPU. Performance is dominated by disk and network throughput. The recommended VM size is Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and small teams. For busy file shares, choose a larger size with a bigger data disk.

The served directory lives on the OS disk by default. Expand the disk, or attach a dedicated data disk (see the sizing section), before you store large amounts of data.

1

Deploy from the Azure Portal

Search the Marketplace for WebDAV Server on Ubuntu 24.04 and choose your VM size. Attach a network security group (NSG) that allows TCP 22 (SSH) from your management network and TCP 443 (HTTPS WebDAV) from the clients that will use the share.

Basic Auth and TLS are enforced, so the server is safe to expose to your clients. Still, restrict the source ranges to networks you control.

2

Deploy from the Azure CLI

RG="webdav-prod"; LOCATION="eastus"; VM_NAME="webdav-01" IMAGE_URN="sac1647283583153:webdav-server-ubuntu-24-04:default:latest" 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
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:webdav-server-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
  --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
3

Connect via SSH

ssh azureuser@<vm-ip>
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/)"

The output shows the service active, the listening socket on :443, and HTTP 401 from the unauthenticated call. The 401 confirms that authentication is enforced.

5

Read your per-VM credentials

The image generated a username and password on this VM's first boot and stored them in a root-only file. The server configuration keeps the password only as a bcrypt hash. Read the credentials and keep them secret. Then confirm that the per-VM credential authenticates and that 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. It is owned by root:root with mode 0600. The server returns 401 without the credential and 2xx with it. The per-VM TLS certificate at /etc/webdav/tls/cert.pem encrypts the transport.

6

Store and fetch a file (WebDAV round trip)

Upload a file with an authenticated PUT. Fetch it straight back and confirm that it matches byte for byte. Then list the directory with PROPFIND. A WebDAV client does exactly this 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, which is the directory listing. An unauthenticated GET of the same path returns 401, so content is never served without the credential.

7

Connect a WebDAV client

Use the username and password from Step 5 and the server address https://<vm-ip>/. The certificate is self-signed, so clients 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 prompts 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 (Command-K) and enter https://<vm-ip>/. 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>/
8

Trusting or replacing the certificate

The server ships with a per-VM self-signed certificate. It encrypts traffic, but clients do not trust it out of the box, so they 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, you need a public DNS name that points at the VM and TCP 80 reachable. Install certbot, obtain a certificate for <your-domain>, point the config at it, and restart the service:

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>/ without a certificate warning.

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 the service. 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 and mount it at /var/lib/webdav/data, preserving webdav ownership. 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, password and TLS certificate. It refreshes the webdav binary to the latest release and writes the fail-secure bootstrap marker. It then disables itself, so subsequent reboots are unaffected. The OS is patched at build time and ships 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 SecureAnyCloud deployment includes 24/7 support with a 24-hour response SLA. Contact sales@secureanycloud.com for help with deployment, configuration or scaling.

This is a repackaged open-source software product with additional charges for SecureAnyCloud support services. WebDAV Server (hacdias/webdav) is open source under the MIT license. 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.

Deploy on Azure

Launch WebDAV Server on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure