WebDAV doesn’t get talked about much these days, overshadowed by dedicated file-sync services and cloud storage APIs, but it’s still a genuinely useful protocol when you need something simple: a folder on a server that behaves like a network drive, mountable from Windows, macOS, Linux, or edited directly by tools like Transmit, Cyberduck, or even Microsoft Office (which can open and save files directly to a WebDAV share). I’ve used it for small team file shares, backup destinations, and as a lightweight upload target for automated scripts — no need for a full object storage service when a WebDAV folder does the job.
Nginx has built-in WebDAV support through its ngx_http_dav_module, along with a widely used third-party module (nginx-dav-ext-module) that adds the extra WebDAV methods most real clients expect. I’ll cover both, since the built-in module alone is genuinely too limited for most practical use.
What WebDAV Actually Adds to HTTP
Plain HTTP gives you GET (read) and not much else for file manipulation. WebDAV extends the HTTP method set with:
PUT— upload/overwrite a fileDELETE— remove a fileMKCOL— create a directoryCOPY— copy a file/directoryMOVE— move or rename a file/directoryPROPFIND— list directory contents and file metadata (this is what makes a WebDAV share “browsable” like a folder)LOCK/UNLOCK— advisory locking, so two clients don’t stomp on each other’s edits at the same time
Nginx’s built-in dav module supports PUT, DELETE, MKCOL, COPY, and MOVE — but not PROPFIND or locking. That means without the extension module, most GUI WebDAV clients (Finder, Windows Explorer, etc.) simply won’t be able to browse the share, even though scripted curl uploads would work fine. This is the single most common source of confusion I see when people set up “WebDAV in Nginx” using only the built-in module and then can’t figure out why their file manager won’t connect.
Requirements
- Ubuntu 22.04/24.04 with sudo access
- Nginx (we’ll need to check if
dav_extis compiled in, or install a build that has it) - A directory to serve as the WebDAV root
- Basic auth credentials (WebDAV over the open internet without authentication is asking for trouble)
Step 1: Check for Module Support
nginx -V 2>&1 | grep -o 'http_dav_module'
The built-in http_dav_module ships in most standard Nginx builds. The extension module, dav_ext, is a separate dynamic module and usually needs to be installed explicitly. On Debian/Ubuntu, the package-based route is easiest:
sudo apt update
sudo apt install nginx-extras -y
nginx-extras bundles a wide set of optional modules, including dav_ext, without requiring a manual compile. Confirm it’s available:
nginx -V 2>&1 | grep -o 'dav_ext_module'
ls /usr/lib/nginx/modules/ | grep dav_ext
If you see ngx_http_dav_ext_module.so listed, you’re set.
Step 2: Load the Dynamic Module
If it’s not already loaded by default, add this near the top of /etc/nginx/nginx.conf (outside any http/server block, at the very top):
load_module modules/ngx_http_dav_ext_module.so;
Step 3: Create the WebDAV Directory
sudo mkdir -p /var/www/webdav
sudo chown -R www-data:www-data /var/www/webdav
sudo chmod -R 750 /var/www/webdav
www-data is Nginx’s default worker user on Debian/Ubuntu — the WebDAV directory needs to be writable by this user since Nginx itself performs the file operations on the client’s behalf.
Step 4: Set Up Basic Authentication
Never expose a writable WebDAV share without at least basic auth in front of it.
sudo apt install apache2-utils -y
sudo htpasswd -c /etc/nginx/.htpasswd davuser
You’ll be prompted to set a password. Use -c only the first time (it creates the file); drop it when adding subsequent users, or it’ll overwrite the file:
sudo htpasswd /etc/nginx/.htpasswd anotheruser
Step 5: Configure the Nginx Server Block
sudo nano /etc/nginx/sites-available/webdav
server {
listen 443 ssl;
server_name webdav.example.com;
ssl_certificate /etc/letsencrypt/live/webdav.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/webdav.example.com/privkey.pem;
client_max_body_size 500M;
client_body_temp_path /var/www/webdav_tmp;
location / {
root /var/www/webdav;
auth_basic "Restricted WebDAV Area";
auth_basic_user_file /etc/nginx/.htpasswd;
# Core WebDAV methods
dav_methods PUT DELETE MKCOL COPY MOVE;
# Extended methods: PROPFIND, OPTIONS, LOCK/UNLOCK support
dav_ext_methods PROPFIND OPTIONS;
dav_access user:rw group:rw all:r;
create_full_put_path on;
autoindex on;
}
}
server {
listen 80;
server_name webdav.example.com;
return 301 https://$host$request_uri;
}
A few notes on what each directive is doing:
client_max_body_size 500M;— WebDAV is often used for uploading large files, so raise this well above Nginx’s tiny 1MB default. Adjust to whatever your realistic max file size is.client_body_temp_path— Nginx buffers uploaded request bodies to disk temporarily during processing; pointing this somewhere with adequate space avoids issues with large uploads on servers with a small root partition.dav_methods— enables the core built-in WebDAV verbs.dav_ext_methods PROPFIND OPTIONS;— this is what makes the share actually browsable by real WebDAV clients. Without it,PROPFINDrequests (which is how Finder/Explorer ask “what’s in this folder?”) get rejected.dav_access— controls the file permission bits Nginx applies to newly created files/directories, analogous to a umask specifically for WebDAV-created content.create_full_put_path on;— allows clients toPUTa file into a directory path that doesn’t exist yet, auto-creating intermediate directories. Handy for scripted uploads; you may want this off if you’d rather enforce that directories are created explicitly viaMKCOLfirst.
Note that true WebDAV locking (LOCK/UNLOCK) isn’t fully implemented by dav_ext_module — it acknowledges lock requests enough to satisfy picky clients like Windows Explorer and macOS Finder, but doesn’t enforce real distributed locking. For genuinely concurrent multi-writer scenarios, that’s worth keeping in mind; it’s not a replacement for a proper version-controlled or lock-aware file system.
Enable the site:
sudo ln -s /etc/nginx/sites-available/webdav /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 6: Add HTTPS
WebDAV credentials are sent as HTTP Basic Auth, which is base64-encoded, not encrypted — running this over plain HTTP is essentially sending your password in plaintext. Get a certificate:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d webdav.example.com
Testing Your Setup
Test basic connectivity and auth with curl:
# List directory contents
curl -u davuser -X PROPFIND https://webdav.example.com/ -H "Depth: 1"
# Upload a file
curl -u davuser -T localfile.txt https://webdav.example.com/localfile.txt
# Download it back
curl -u davuser https://webdav.example.com/localfile.txt -o downloaded.txt
# Delete it
curl -u davuser -X DELETE https://webdav.example.com/localfile.txt
For a real client test:
- macOS Finder —
Go > Connect to Server, enterhttps://webdav.example.com/ - Windows —
Map Network Drive, choose “Connect to a website,” enter the URL - Linux (GNOME Files/Nautilus) —
Other Locations > Connect to Server, usedavs://webdav.example.com/ - Cross-platform GUI apps — Cyberduck, Transmit, and WinSCP all support WebDAV explicitly
If PROPFIND-based browsing fails specifically in GUI clients but curl uploads work, that’s the telltale sign the dav_ext module isn’t loaded or dav_ext_methods isn’t set — go back and confirm Step 1/2.
Troubleshooting Common Issues
403 Forbidden on PUT/DELETE — Check that www-data (or whichever user Nginx runs as) actually owns and can write to the target directory. dav_access controls permissions on newly created files, but the parent directory permissions still need to allow Nginx to write there in the first place.
Windows Explorer refuses to connect — Windows’ native WebDAV client (the “WebClient” service) has historically been picky and, notably, refuses non-HTTPS WebDAV connections unless you explicitly change a registry setting (BasicAuthLevel). Using HTTPS from the start avoids this entirely.
Uploads fail for large files — Check client_max_body_size and also your reverse proxy/load balancer in front of Nginx, if any, since it may impose its own smaller limit.
“507 Insufficient Storage” — Actually means Nginx couldn’t write to client_body_temp_path — check disk space and permissions on that directory, not necessarily the final destination.
Files upload but directory listing seems stale in Finder/Explorer — These clients cache directory listings aggressively; a manual refresh (or reconnecting) usually resolves it. This is a client behavior, not an Nginx issue.
Security Considerations
- Always run WebDAV over HTTPS. Basic Auth credentials are trivially recoverable from plaintext traffic.
- Use strong, unique passwords in
.htpasswd— this file supports bcrypt hashing (htpasswd -B), which is preferable to the older MD5-based hash for anything internet-facing. - Restrict by IP where possible, especially for internal-only shares:
location / {
allow 10.0.0.0/8;
allow 203.0.113.50;
deny all;
...
}
- Disable directory listing (
autoindex off;) if you don’t want unauthenticated (or even authenticated but unintended) browsing of the full file tree — some setups only want programmatic PUT/GET access, not browsability. - Consider read-only shares for distribution use cases — just omit
PUT,DELETE,MKCOL,COPY,MOVEfromdav_methodsand leave GET/PROPFIND only. - Scan uploaded files if this share is exposed to less-trusted users — Nginx itself won’t do virus scanning; that’s a job for something like ClamAV triggered via a cron job or upload hook.
Performance Tips
- Keep the WebDAV directory off the same disk as your OS if you expect heavy upload traffic, to avoid I/O contention with system processes.
- Tune
client_body_buffer_sizefor typical file sizes — if most uploads are small, a larger in-memory buffer avoids unnecessary temp-file writes to disk:
client_body_buffer_size 1M;
- Enable
sendfileandtcp_nopushfor efficient large file downloads (usually already on by default in modern Nginx configs):
sendfile on;
tcp_nopush on;
- Monitor disk space actively. WebDAV shares tend to grow unpredictably since anyone with write access can fill the disk; a simple cron-based disk usage alert saves you from a 3am “server is down” page caused by a full partition.
Real-World Use Cases
- A small design team’s shared asset folder — mounted as a network drive on both Mac and Windows machines, letting designers drag-and-drop files without needing a dedicated cloud storage subscription.
- An automated backup destination for a handful of Linux servers, where a nightly cron job used
curl -Tto push encrypted backup archives to a WebDAV endpoint secured with IP allowlisting and a dedicated backup-only user. - A CMS media upload target, where the WebDAV share sat behind the same Nginx instance serving the CMS itself, letting non-technical editors drag files directly into a mapped drive instead of using a clunky browser upload widget.
Best Practices Recap
- Install
dav_ext_module(vianginx-extrasor a custom build) — the built-indavmodule alone isn’t enough for real-world GUI clients. - Always pair WebDAV with HTTPS and strong Basic Auth credentials.
- Set
client_max_body_sizeandclient_body_temp_pathdeliberately based on expected file sizes. - Lock down access by IP where the use case allows it.
- Decide deliberately between read-only and read-write shares — don’t enable
DELETE/MOVEmethods you don’t actually need. - Monitor disk usage on the WebDAV root; it’s an easy thing to forget until it’s a 2am problem.
WebDAV isn’t flashy, but it’s a dependable, well-understood protocol that basically every OS already knows how to speak. With Nginx handling it, you get a file share that’s secure, fast, and doesn’t require anyone to install a proprietary sync client just to drag a file onto a server.