How to Set Up Nginx with WebDAV

How to Set Up Nginx with WebDAV

How to Set Up Nginx with WebDAV

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:

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

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:

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:

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

location / {
    allow 10.0.0.0/8;
    allow 203.0.113.50;
    deny all;
    ...
}

Performance Tips

client_body_buffer_size 1M;
sendfile on;
tcp_nopush on;

Real-World Use Cases

Best Practices Recap

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.

Exit mobile version