Setup WebDAV Server with Nginx on Linux (2026 Guide)
Set up a secure WebDAV server with Nginx on Linux. Covers SSL, basic auth, file locking, davfs2 and rclone clients, Docker, and troubleshooting.
Updated Published 41 min read

While NFS works well for Linux-to-Linux file sharing and Samba handles cross-platform compatibility, sometimes you need web-based file access that works through firewalls and NAT. That’s where WebDAV (Web Distributed Authoring and Versioning) comes in.
I run WebDAV alongside NFS and Samba on my N100 mini PC to get secure remote access to files when I’m away from home. Unlike traditional file sharing protocols, WebDAV works over standard HTTP/HTTPS ports, so you can access your home server files from anywhere with a dedicated client app. This guide covers how to setup WebDAV server with Nginx on Linux, including SSL encryption, basic auth, file locking (DAV Level 2), rclone and davfs2 clients, Docker alternatives, and troubleshooting.
Understanding WebDAV
What is WebDAV?
WebDAV (Web Distributed Authoring and Versioning) is an extension of HTTP that allows clients to perform remote web content authoring operations. It enables users to collaboratively edit and manage files on remote web servers.
Key advantages of WebDAV
- Firewall friendly: Uses standard HTTP(S) ports (80/443), works through most firewalls
- Secure by default: Built-in SSL/TLS encryption support
- Client-rich access: Windows Explorer, macOS Finder, rclone, Cyberduck, mobile apps. No browser needed
- Cross-platform: Supported by Windows, macOS, Linux, and mobile platforms
- File locking: Exclusive write locks via dav-ext (no versioning; that’s what Nextcloud/Zotero add on top)
- Cloud-like experience: Provides Dropbox-style functionality on your own server
WebDAV vs NFS, Samba, and FTP
| Feature | WebDAV | NFS | Samba/SMB | FTP |
|---|---|---|---|---|
| Remote Access | Excellent | Poor | Poor | Good |
| Security | Excellent (HTTPS) | Moderate | Good | Poor |
| Firewall Compatibility | Excellent | Poor | Poor | Moderate |
| Web Browser Access | No (use a client app) | No | No | Limited |
| Mobile Support | Excellent | Poor | Good | Good |
| Performance (LAN) | Moderate | Excellent | Very Good | Good |
| Setup Complexity | Moderate | Simple | Moderate | Simple |
Prerequisites and planning
Before you start, make sure you have:
- Linux server (Ubuntu 22.04+, Debian 12+, RHEL 9+, or Alpine) with root or sudo access
- Domain name with a DNS A record pointing to the server
- Ports 80 and 443 open in your firewall
- (Optional) A VPS if you need remote access. Affordable VPS hosting like Hetzner or budget VPS options like Hostinger work well for this
VPS prices jumped across the board in 2026 — if you’re rethinking a rented box, see what changed and when a mini PC wins.
WebDAV architecture overview
Update Nginx first: CVE-2026-27654
Security: Update Nginx Before Proceeding
A buffer overflow in ngx_http_dav_module (CVE-2026-27654, CVSS 8.2-8.8) was disclosed on 2026-03-24. It affects configurations using alias with DAV COPY/MOVE, a pattern that appears in several examples below. A remote unauthenticated attacker can crash the nginx worker or manipulate filenames outside the document root.
Fixed in: nginx 1.28.3 / 1.29.7 (upstream), Ubuntu noble 1.24.0-2ubuntu7.7 (USN-8375-1), Debian bookworm security backports.
nginx -v
If your version is older than the fixed builds above, update now before proceeding.
Step 1: Install Nginx with the WebDAV module
Nginx’s base ngx_http_dav_module handles PUT, DELETE, MKCOL, COPY, and MOVE. For full WebDAV support (PROPFIND, OPTIONS, LOCK, UNLOCK), you also need the dav-ext third-party module.
Install the Nginx WebDAV module
Debian/Ubuntu
# Base nginx already includes ngx_http_dav_module. Add only the ext module
sudo apt update
sudo apt install nginx libnginx-mod-http-dav-ext apache2-utils -yRHEL/Alma/Rocky
# Enable EPEL, then install
sudo dnf install epel-release -y
sudo dnf install nginx nginx-mod-http-dav-ext httpd-tools -yAlpine
# Useful for container builds
apk add nginx nginx-mod-http-dav-extModule split explained
The base ngx_http_dav_module (compiled into standard nginx packages on Debian/Ubuntu) handles write methods: PUT, DELETE, MKCOL, COPY, MOVE. The dav-ext module adds the read/lock methods: PROPFIND, OPTIONS, LOCK, UNLOCK. You need both for a functional WebDAV server.
Verify the modules are loaded:
# Check base module
nginx -V 2>&1 | grep -o with-http_dav_module
# Check ext module (Debian/Ubuntu)
ls /usr/lib/nginx/modules/ | grep davIf the first command returns nothing, your nginx build lacks the base DAV module. If the second returns nothing, the ext module isn’t installed.
Create the WebDAV directory structure
# Create share directories
sudo mkdir -p /var/www/webdav/{documents,media,projects,shared}
# Create temp directory on the SAME filesystem (important, see note below)
sudo mkdir -p /var/www/webdav/.tmp
# Set ownership to www-data (Nginx user)
sudo chown -R www-data:www-data /var/www/webdav
# Set permissions
sudo chmod -R 755 /var/www/webdavSame filesystem for temp path
The client_body_temp_path directory must be on the same filesystem as your WebDAV root. If they’re on different filesystems, nginx copies the uploaded file instead of doing an atomic rename, which is slower and can fail on large uploads. The /var/www/webdav/.tmp path above keeps everything together.
Configure SSL with Certbot
# Install Certbot
sudo apt install certbot python3-certbot-nginx -y
# Obtain SSL certificate (replace with your domain)
sudo certbot --nginx -d webdav.yourdomain.com
# Verify certificate auto-renewal works
sudo certbot renew --dry-runDNS must point to this server
Make sure your domain’s A record resolves to this server’s IP before running Certbot. The HTTP-01 challenge needs to reach your server on port 80.
Step 2: Configure Nginx for WebDAV
This is the core config. It includes all the fixes: correct dav_ext_methods (no PROPPATCH), file locking for DAV Level 2, same-filesystem temp path, macOS Finder workaround, and modern TLS settings.
Enable WebDAV methods
Create the main config file:
sudo nano /etc/nginx/sites-available/webdavAdd this configuration:
# /etc/nginx/sites-available/webdav
#
# Requires dav_ext_lock_zone in http{} context. See "Enable File Locking" below.
# Make sure /var/www/webdav/.tmp exists on the same filesystem as /var/www/webdav.
server {
listen 80;
server_name webdav.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name webdav.yourdomain.com;
# SSL Configuration
ssl_certificate /etc/letsencrypt/live/webdav.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/webdav.yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Security Headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
# Authentication
auth_basic "WebDAV Access";
auth_basic_user_file /etc/nginx/.htpasswd;
# WebDAV root
location / {
root /var/www/webdav;
# Write methods (base module)
dav_methods PUT DELETE MKCOL COPY MOVE;
# Read/lock methods (dav-ext module)
# NOTE: PROPPATCH is NOT supported — do not add it here
dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
# Enable real LOCK/UNLOCK (requires dav_ext_lock_zone in http{})
dav_ext_lock zone=davlock;
dav_access user:rw group:rw all:r;
create_full_put_path on;
min_delete_depth 1;
# Temp path on same filesystem
client_body_temp_path /var/www/webdav/.tmp;
client_max_body_size 10G;
client_body_timeout 300s;
# Fix macOS Finder MKCOL-without-slash (creates dirs without trailing /)
set $x $uri$request_method;
if ($x ~ [^/]MKCOL$) { rewrite ^(.*)$ $1/; }
# Logging
access_log /var/log/nginx/webdav_access.log;
error_log /var/log/nginx/webdav_error.log;
}
# Block access to hidden files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}If nginx -t fails with 'unknown directive dav_ext_methods'
The dav-ext module isn’t loaded. Check with: ls /usr/lib/nginx/modules/ | grep dav. On Debian/Ubuntu, install libnginx-mod-http-dav-ext. On RHEL/Alpine, install nginx-mod-http-dav-ext.
Enable file locking for DAV Level 2
Without explicit lock configuration, the server advertises DAV: 1 (basic read/write only). macOS Finder requires DAV: 2 (working LOCK support) for read/write mounts. Windows Explorer also checks this header.
Add the lock zone to your main nginx config (/etc/nginx/nginx.conf) inside the http {} block:
http {
# ... existing config ...
# WebDAV lock zone — shared memory for tracking locks
# 10MB handles thousands of concurrent locks; 300s timeout
dav_ext_lock_zone zone=davlock:10m timeout=300;
}DAV Level 1 vs Level 2
Level 1 = basic read/write (PUT/DELETE/PROPFIND). Level 2 = adds LOCK/UNLOCK for concurrent editing. macOS Finder and Windows Explorer need Level 2 for full read/write access. Without the lock zone config above, the server only advertises DAV: 1.
Verify DAV Level 2 is working:
curl -i -X OPTIONS https://webdav.yourdomain.com/ -u webdavuser:passwordLook for DAV: 2 in the response headers. If you see DAV: 1 only, the lock zone isn’t configured.
Create WebDAV users
# Create password file with first user (use -B for bcrypt)
sudo htpasswd -cB /etc/nginx/.htpasswd webdavuser
# Add additional users (no -c flag after first user)
sudo htpasswd -B /etc/nginx/.htpasswd john
sudo htpasswd -B /etc/nginx/.htpasswd mary
# Secure the password file
sudo chmod 640 /etc/nginx/.htpasswd
sudo chown root:www-data /etc/nginx/.htpasswdUse bcrypt (-B)
The default htpasswd hash is MD5-crypt, which is weak against modern GPUs. Always use the -B flag for bcrypt. On RHEL-family, htpasswd comes from the httpd-tools package.
Advanced user management
For different access levels (admin, users, public read-only):
# Admin access — full WebDAV methods
location /admin {
alias /var/www/webdav/admin;
dav_methods PUT DELETE MKCOL COPY MOVE;
dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
dav_ext_lock zone=davlock;
dav_access user:rw group:rw all:r;
create_full_put_path on;
auth_basic "Admin WebDAV";
auth_basic_user_file /etc/nginx/.htpasswd-admin;
}
# User access — limited methods
location /users {
alias /var/www/webdav/users;
dav_methods PUT DELETE MKCOL;
dav_ext_methods PROPFIND OPTIONS;
dav_access user:rw group:rw all:r;
create_full_put_path on;
auth_basic "User WebDAV";
auth_basic_user_file /etc/nginx/.htpasswd-users;
}
# Public read-only access
location /public {
alias /var/www/webdav/public;
limit_except GET {
deny all;
}
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}alias + DAV is the CVE-2026-27654 pattern
The alias directive combined with DAV COPY/MOVE is the exact trigger for CVE-2026-27654. Make sure your nginx is patched before using these location blocks. See the CVE notice in Prerequisites.
Enable and test the configuration
# Test configuration syntax
sudo nginx -t
# Enable the site
sudo ln -s /etc/nginx/sites-available/webdav /etc/nginx/sites-enabled/
# Remove default site if it conflicts
sudo rm -f /etc/nginx/sites-enabled/default
# Restart and enable nginx
sudo systemctl restart nginx
sudo systemctl enable nginx
# Check status
sudo systemctl status nginxFull verification checklist:
# 1. Module loaded?
nginx -V 2>&1 | grep -o with-http_dav_module
# 2. Config valid?
sudo nginx -t
# 3. Methods advertised? (expect DAV: 2 + Allow list)
curl -i -X OPTIONS https://webdav.yourdomain.com/ -u webdavuser:password
# 4. Directory listing works?
curl -i -X PROPFIND https://webdav.yourdomain.com/ -u webdavuser:password -H "Depth: 1"
# 5. Upload works?
curl -i -T test.txt https://webdav.yourdomain.com/test.txt -u webdavuser:password
# 6. Move works?
curl -i -X MOVE https://webdav.yourdomain.com/test.txt \
-H "Destination: https://webdav.yourdomain.com/final.txt" \
-u webdavuser:passwordStep 3: Connect WebDAV clients on every platform
Windows: Map WebDAV as a network drive
# Map WebDAV as network drive
net use W: https://webdav.yourdomain.com /user:webdavuser
# Or via File Explorer:
# 1. Open File Explorer
# 2. Right-click "This PC" → "Map network drive"
# 3. Enter: https://webdav.yourdomain.com
# 4. Check "Connect using different credentials"
# 5. Enter username and passwordWindows WebDAV caveats
Windows native WebDAV is finicky. Common issues:
- Error 0x80070043 (“The network name cannot be found”) — usually means the WebClient service isn’t running or the URL is wrong
- Basic auth over HTTP blocked — modern Windows requires HTTPS for basic authentication by default
- WebClient service must be running:
net start WebClient
If native mapping fails, use a third-party client like RaiDrive, Cyberduck, or WinSCP.
Linux: Mount WebDAV with davfs2
# Install davfs2
sudo apt install davfs2 -y
# Create mount point
sudo mkdir /mnt/webdav
# Mount WebDAV share
sudo mount -t davfs https://webdav.yourdomain.com /mnt/webdav
# Verify
mount | grep webdavFor permanent mounting, add credentials and fstab entry:
# Add credentials (one line per share)
sudo nano /etc/davfs2/secrets
# Add: https://webdav.yourdomain.com webdavuser your_password
# Secure the secrets file
sudo chmod 600 /etc/davfs2/secrets
# Add to fstab for auto-mount on boot
sudo nano /etc/fstab
# Add: https://webdav.yourdomain.com /mnt/webdav davfs _netdev,user,uid=1000,gid=1000 0 0GUI file managers also work:
# Nautilus (GNOME): Other Locations → Connect to Server
# Enter: davs://webdav.yourdomain.com
# Dolphin (KDE): Network → Add Network Folder → WebDAVmacOS Finder and mount_webdav
- Open Finder
- Press
Cmd + K(Connect to Server) - Enter:
https://webdav.yourdomain.com - Enter credentials when prompted
Finder mounts read/write only if the server advertises DAV: 2 (working LOCK support). If you followed Step 2’s locking configuration, this works out of the box.
Command-line mount:
mkdir ~/webdav
mount_webdav https://webdav.yourdomain.com ~/webdav
# Unmount
umount ~/webdavMobile WebDAV apps (iOS/Android)
| App | Platform | Features | Price |
|---|---|---|---|
| Documents by Readdle | iOS | Document management + WebDAV | Free |
| FE File Explorer | iOS/Android | Multi-protocol support | Freemium |
| Solid Explorer | Android | Dual-pane file manager | Paid |
| Total Commander | Android | With WebDAV plugin | Free |
| FX File Explorer | Android | WebDAV support | Freemium |
Power users: Sync and mount with rclone
rclone is the Swiss-army-knife client for WebDAV. It handles sync, mount, and backup with a single binary.
# Install rclone
curl https://rclone.org/install.sh | sudo bash
# Configure a WebDAV remote
rclone config
# Choose: New remote → name: webdav-remote → type: webdav → vendor: other
# URL: https://webdav.yourdomain.com
# User: webdavuser / Password: your_password
# Sync a local directory to WebDAV
rclone sync /data/source webdav-remote:backup
# Mount WebDAV as a local directory (with caching)
rclone mount webdav-remote: ~/webdav --vfs-cache-mode full
# List files
rclone ls webdav-remote:rclone also works as a lightweight WebDAV server itself — useful for side projects where you don’t need nginx:
# Serve a local directory over WebDAV (single binary, TLS, user/pass)
rclone serve webdav /data/to/share --addr :8080 --user admin --pass secretStep 4: Advanced configuration and hardening
IP allow/deny and rate limiting
# Restrict access by IP range
location / {
allow 192.168.1.0/24;
allow 10.0.0.0/8;
deny all;
# ... rest of WebDAV configuration ...
}Rate limiting in the http {} block:
http {
limit_req_zone $binary_remote_addr zone=webdav:10m rate=30r/s;
location / {
limit_req zone=webdav burst=50 nodelay;
# ... WebDAV configuration ...
}
}Rate limiting caveat
WebDAV clients make many rapid requests — PROPFIND with Depth: 1 on large folders, rclone multi-file PUTs, etc. Set the rate generously or scope rate limits to authentication failures. Heavier throttling belongs in fail2ban, not nginx’s limit_req.
Two-factor auth with auth_request
For external authentication (SSO, TOTP, etc.), use the auth_request module — no Lua dependency needed:
# Internal auth endpoint
location /auth {
internal;
proxy_pass http://your-auth-service/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
# Apply to WebDAV location
location / {
auth_request /auth;
# ... WebDAV configuration ...
}Tuning Nginx for large file uploads
# In the WebDAV location block
client_max_body_size 50G;
client_body_buffer_size 256k;
client_body_timeout 600s;
client_header_timeout 300s;
keepalive_timeout 300s;
send_timeout 300s;
# Use sendfile for downloads
sendfile on;
sendfile_max_chunk 1m;
tcp_nopush on;
tcp_nodelay on;min_delete_depth
The min_delete_depth 1 directive (nginx ≥1.25.5) prevents DELETE requests from removing top-level files in the share root. It’s a useful safety knob — a client can’t accidentally delete the entire share with a single request.
Run WebDAV in Docker
The official nginx:alpine image includes the base DAV module but not the dav-ext module. Mounting a config with dav_ext_methods into nginx:alpine will fail with unknown directive "dav_ext_methods". Here are three working options:
hacdias/webdav (recommended)
A Go-based WebDAV server. 5.8k GitHub stars, actively maintained (v5.14.2), per-user permissions, bcrypt support.
# docker-compose.yml
services:
webdav:
image: hacdias/webdav:latest
restart: unless-stopped
ports:
- "127.0.0.1:6065:6065"
volumes:
- ./webdav-config.yml:/config.yml:ro
- /var/www/webdav:/data
command: -c /config.ymlConfig file (webdav-config.yml):
address: 0.0.0.0
port: 6065
scope: /data
modify: true
rules: []
users:
- username: webdavuser
password: "$2a$10$..." # bcrypt hash
scope: /datanginx-webdav-nononsense
An nginx-based image with dav-ext pre-installed. 500K+ Docker Hub pulls, works with macOS Finder and Windows 11 out of the box.
# docker-compose.yml
services:
webdav:
image: dgraziotin/nginx-webdav-nononsense:latest
restart: unless-stopped
ports:
- "443:443"
volumes:
- /var/www/webdav:/var/www/webdav
- ./htpasswd:/etc/nginx/.htpasswd:ro
environment:
- WEBDAV_USERNAME=webdavuser
- WEBDAV_PASSWORD=your_passwordnginx:alpine + dav-ext
For those who want pure nginx in a container. Requires installing the ext module inside the container.
# docker-compose.yml
services:
webdav:
image: nginx:alpine
restart: unless-stopped
ports:
- "443:443"
volumes:
- /var/www/webdav:/var/www/webdav
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro
entrypoint: >
sh -c "apk add --no-cache nginx-mod-http-dav-ext &&
nginx -g 'daemon off;'"Add to the mounted nginx.conf at the top level:
load_module modules/ngx_http_dav_ext_module.so;Avoid bytemark/webdav
The bytemark/webdav image hasn’t been updated in over 7 years. It’s based on an unmaintained Apache configuration. Use one of the options above instead.
For more Docker ideas, see Docker containers for your home server and a self-hosted web file manager like FileBrowser.
Integrate with NFS, Samba, and backups
Create a unified access point that combines your existing file shares:
# Symlink NFS and Samba shares into WebDAV
sudo ln -s /srv/samba/media /var/www/webdav/media
sudo ln -s /srv/nfs/documents /var/www/webdav/documents
# Set ownership on symlinks (note -h flag)
sudo chown -h www-data:www-data /var/www/webdav/media
sudo chown -h www-data:www-data /var/www/webdav/documentsCombine with your backup strategy — and test the restore, not just the backup:
#!/bin/bash
# webdav-backup.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/var/www/webdav/backups"
mkdir -p "$BACKUP_DIR/$DATE"
# Backup configs
cp /etc/nginx/sites-available/webdav "$BACKUP_DIR/$DATE/"
cp /etc/nginx/.htpasswd "$BACKUP_DIR/$DATE/"
# Backup content (use -l to preserve symlinks as-is)
rsync -av /var/www/webdav/documents/ "$BACKUP_DIR/$DATE/documents/"Step 5: Monitor and maintain your WebDAV server
Log analysis
# Monitor access in real time
sudo tail -f /var/log/nginx/webdav_access.log
# Check for errors
sudo tail -f /var/log/nginx/webdav_error.log
# Top IPs by request count
sudo awk '{print $1}' /var/log/nginx/webdav_access.log | sort | uniq -c | sort -nr | head -20
# Recent PUT/GET activity
sudo grep -E "(PUT|GET)" /var/log/nginx/webdav_access.log | tail -20For broader server health, see how to monitor your server’s CPU, memory and disk.
WebDAV monitoring script
#!/bin/bash
# webdav-monitor.sh
echo "=== WebDAV Server Monitor ==="
echo "Date: $(date)"
echo
echo "Nginx Status:"
sudo systemctl status nginx --no-pager -l
echo
echo "SSL Certificate Status:"
sudo certbot certificates
echo
echo "Active Connections:"
ss -tlnp | grep :443 | wc -l
echo
echo "Disk Usage:"
df -h /var/www/webdav
echo
echo "Recent Access (Last 10 entries):"
sudo tail -10 /var/log/nginx/webdav_access.logAutomated maintenance script
#!/bin/bash
# webdav-maintenance.sh
# Rotate logs
sudo logrotate /etc/logrotate.d/nginx
# Clean temp files older than 1 day
sudo find /var/www/webdav/.tmp -type f -mtime +1 -delete 2>/dev/null
# Check SSL certificate expiry
DAYS_LEFT=$(sudo certbot certificates 2>/dev/null | grep "VALID" | head -1 | grep -oP '\d+(?= days)')
if [ -n "$DAYS_LEFT" ] && [ "$DAYS_LEFT" -lt 30 ]; then
echo "WARNING: SSL certificate expires in $DAYS_LEFT days"
fi
# Fix permissions
sudo chown -R www-data:www-data /var/www/webdav
sudo find /var/www/webdav -type d -exec chmod 755 {} \;
sudo find /var/www/webdav -type f -exec chmod 644 {} \;WebDAV security best practices
Use HTTPS only and harden TLS
Never expose WebDAV over plain HTTP. The config above already redirects HTTP to HTTPS and sets TLS 1.2+1.3 only.
For custom cipher profiles, use the Mozilla SSL Configuration Generator to generate a config matching your nginx version. The defaults from Certbot are fine for most setups.
Block brute force with fail2ban or CrowdSec
# Install fail2ban
sudo apt install fail2ban -y
# Create WebDAV jail
sudo nano /etc/fail2ban/jail.local[webdav]
enabled = true
port = 443
filter = webdav
logpath = /var/log/nginx/webdav_access.log
maxretry = 5
bantime = 3600
findtime = 600fail2ban logpath fix
The 401 responses from failed authentication are logged in the access log, not the error log. Make sure logpath points to webdav_access.log, not webdav_error.log. The jail won’t match anything if it watches the wrong file.
Create the filter:
sudo nano /etc/fail2ban/filter.d/webdav.conf[Definition]
failregex = ^<HOST> -.*"(GET|POST|PUT|DELETE|PROPFIND|MKCOL|COPY|MOVE|LOCK|UNLOCK)" .* (401|403) .*$
ignoreregex =For a more modern approach, consider CrowdSec as a modern fail2ban alternative — it shares threat intelligence across a community network.
Backup and restore script
#!/bin/bash
# webdav-backup-config.sh
BACKUP_DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_ROOT="/backup/webdav-config"
mkdir -p "$BACKUP_ROOT/$BACKUP_DATE"
# Backup Nginx configuration
cp /etc/nginx/sites-available/webdav "$BACKUP_ROOT/$BACKUP_DATE/"
# Backup authentication files
cp /etc/nginx/.htpasswd* "$BACKUP_ROOT/$BACKUP_DATE/" 2>/dev/null
# Backup SSL certificates
cp -r /etc/letsencrypt "$BACKUP_ROOT/$BACKUP_DATE/"
# Create restoration script
cat > "$BACKUP_ROOT/$BACKUP_DATE/restore.sh" << 'EOF'
#!/bin/bash
set -e
sudo cp webdav /etc/nginx/sites-available/
sudo cp .htpasswd* /etc/nginx/
sudo cp -r letsencrypt /etc/
sudo nginx -t && sudo systemctl restart nginx
echo "WebDAV configuration restored"
EOF
chmod +x "$BACKUP_ROOT/$BACKUP_DATE/restore.sh"
echo "Backup completed: $BACKUP_ROOT/$BACKUP_DATE"Test the restore — run the restore script on a staging server or in a container before you need it in production.
Keep Nginx patched
Stay patched
CVE-2026-27654 is not the only nginx security fix in 2026. Check your version regularly:
nginx -vIf you’re on a distro package, security updates come through
apt upgrade / dnf update. If you use the nginx.org repo, watch their release announcements. Either way, don’t run an unpatched nginx exposed to the internet.Troubleshooting common WebDAV problems
405 Method Not Allowed
The WebDAV module isn’t loaded or the methods aren’t configured.
# Verify module
nginx -V 2>&1 | grep dav
# Check config syntax
sudo nginx -t
# Test methods
curl -X OPTIONS https://webdav.yourdomain.com/ -u webdavuser:password -vAuthentication failures
# Check password file exists and is readable
ls -la /etc/nginx/.htpasswd
# Test auth with curl
curl -X GET https://webdav.yourdomain.com/ -u webdavuser:password -v
# Reset a user's password
sudo htpasswd -B /etc/nginx/.htpasswd webdavuserSSL/TLS problems
# Test SSL handshake
openssl s_client -connect webdav.yourdomain.com:443 -servername webdav.yourdomain.com
# Check certificate validity
sudo certbot certificates
# Force renewal
sudo certbot renew --force-renewal -d webdav.yourdomain.comWindows-specific errors
- 0x80070043 “The network name cannot be found”: Start the WebClient service (
net start WebClient), verify the URL uses HTTPS, and check that the server responds to OPTIONS requests. - “The user has not been authenticated”: Windows blocks basic auth over HTTP by default. Use HTTPS.
- Still failing?: Use RaiDrive, Cyberduck, or WinSCP instead of Windows Explorer.
macOS Finder issues
- Read-only mount: The server isn’t advertising
DAV: 2. Add thedav_ext_lock_zoneanddav_ext_lockdirectives from Step 2. - MKCOL 409 errors: The macOS Finder MKCOL workaround is already in the main config above.
SELinux permission denied (RHEL/Fedora)
If PROPFIND returns 500 on RHEL-family systems, SELinux is likely blocking nginx from reading the WebDAV directory.
# Set the correct SELinux context
sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/webdav(/.*)?"
sudo restorecon -Rv /var/www/webdav
# Verify
ls -laZ /var/www/webdav/SELinux blocks PROPFIND
Check /var/log/audit/audit.log for avc: denied entries related to nginx. The old advice to use httpd_exec_t is wrong for data directories — use httpd_sys_rw_content_t instead.
Slow upload/download
# Increase buffer sizes
client_body_buffer_size 256k;
large_client_header_buffers 4 256k;
# Optimize workers
worker_processes auto;
worker_connections 1024;
# Enable HTTP/2 (use the directive, not the deprecated listen parameter)
http2 on;Use cases and integration examples
Remote work setup
Create a dedicated work location with its own credentials:
location /work {
alias /var/www/webdav/work;
dav_methods PUT DELETE MKCOL COPY MOVE;
dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
dav_ext_lock zone=davlock;
dav_access user:rw group:rw all:r;
create_full_put_path on;
auth_basic "Work Files";
auth_basic_user_file /etc/nginx/.htpasswd-work;
}For time-restricted access, use fail2ban rules or IP whitelisting rather than Lua-based hour checks — simpler, no extra module dependency.
Photo backup from mobile
location /photos {
alias /var/www/webdav/photos;
dav_methods PUT MKCOL;
dav_ext_methods PROPFIND OPTIONS;
dav_access user:rw group:rw all:r;
create_full_put_path on;
# Allow large image uploads
client_max_body_size 100M;
auth_basic "Photo Backup";
auth_basic_user_file /etc/nginx/.htpasswd-photos;
}Unified endpoint with NFS and Samba
Combine WebDAV with your existing home server file shares:
# Create unified access point
sudo mkdir -p /var/www/webdav/unified
sudo ln -s /srv/nfs/media /var/www/webdav/unified/media-nfs
sudo ln -s /srv/samba/documents /var/www/webdav/unified/docs-samba
sudo ln -s /var/lib/docker/volumes /var/www/webdav/unified/container-data
# Set permissions on symlinks
sudo chown -h www-data:www-data /var/www/webdav/unified/*This creates a single WebDAV endpoint that provides access to files from your NFS, Samba, and Docker container setups.
Conclusion
WebDAV with Nginx gives you secure remote file access that complements your existing file sharing infrastructure. Unlike NFS which works best on local networks, or Samba for cross-platform local sharing, WebDAV handles remote access through firewalls and NAT.
On my N100 mini PC, WebDAV serves as the bridge for accessing files remotely while keeping local protocols for internal network access. Running all three protocols covers everything from local media streaming to secure remote document access.
Start with basic functionality — get SSL and authentication working first, then add locking, fail2ban, and custom access controls as you need them. If you’re exposing WebDAV to the internet, keep nginx patched and consider CrowdSec for automated threat blocking. For personal access only, a VPN like self-hosting your own Tailscale control server is often the better choice — it removes the public attack surface entirely.
For more on building a complete home server, see my guides on server monitoring and best mini PCs for home servers.
Deploy Your WebDAV Server

