Skip to main content

NGINX

NGINX WebDAV Module: Full File Sharing Server Setup

by ,


We have by far the largest RPM repository with NGINX module packages and VMODs for Varnish. If you want to install NGINX, Varnish, and lots of useful performance/security software with smooth yum upgrades for production use, this is the repository for you.
Active subscription is required.

NGINX includes a built-in DAV module that handles basic file operations like uploading and deleting files. However, this standard module only supports a subset of the WebDAV protocol. The NGINX WebDAV module (ngx_http_dav_ext_module) adds the missing PROPFIND, OPTIONS, LOCK, and UNLOCK methods that clients such as macOS Finder, Windows Explorer, and Cyberduck require for proper WebDAV access. Together with the standard module, the NGINX WebDAV module turns NGINX into a fully compliant WebDAV file server.

In this guide, you will learn how to install, configure, and secure a production-ready NGINX WebDAV server using both the standard DAV module and the NGINX WebDAV module together.

Why You Need the NGINX WebDAV Module

WebDAV (Web Distributed Authoring and Versioning) extends HTTP to allow clients to create, move, copy, and delete files on a remote server. It is widely used for file sharing, cloud storage, and collaborative editing. Applications that rely on WebDAV include macOS Finder’s “Connect to Server” feature, Windows mapped network drives, Cyberduck, and many mobile file manager apps.

NGINX’s standard ngx_http_dav_module supports only five write methods: PUT, DELETE, MKCOL, COPY, and MOVE. These handle file uploads and directory management, but they are not enough for a working WebDAV server. Most WebDAV clients need PROPFIND to list directory contents, OPTIONS to discover supported methods, and LOCK/UNLOCK for safe concurrent editing.

The following table shows what each module provides:

Method Standard DAV Module DAV Extensions Module
GET, HEAD NGINX core
PUT Yes
DELETE Yes
MKCOL Yes
COPY Yes
MOVE Yes
PROPFIND Yes
OPTIONS Yes
LOCK Yes
UNLOCK Yes

You need both modules working together to provide full WebDAV support in NGINX. The standard module handles file write operations, while the NGINX WebDAV module handles property queries, capability discovery, and resource locking.

Installing the NGINX WebDAV Module

RHEL, CentOS, AlmaLinux, Rocky Linux

Install the GetPageSpeed repository and the module package:

sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-dav-ext

Load the module by adding the following directive at the top of /etc/nginx/nginx.conf, before any http block:

load_module modules/ngx_http_dav_ext_module.so;

The standard ngx_http_dav_module is already compiled into NGINX by default, so no additional load_module directive is needed for it.

Debian and Ubuntu

First, set up the GetPageSpeed APT repository, then install the module:

sudo apt-get update
sudo apt-get install nginx-module-dav-ext

On Debian/Ubuntu, the package handles module loading automatically. No load_module directive is needed.

You can find detailed package information on the RPM module page or the APT module page.

Configuration Directives

The NGINX WebDAV module provides three directives. All directive names and their parameters are verified against the module source code.

dav_ext_methods

Enables support for the specified WebDAV methods in the current scope.

Syntax:  dav_ext_methods [PROPFIND] [OPTIONS] [LOCK] [UNLOCK] | off
Default: off
Context: http, server, location

You can enable any combination of the four methods. The off value explicitly disables all extended methods and is the default behavior. If you only need directory listing without locking, enable just PROPFIND and OPTIONS. If you need full WebDAV support with concurrent editing, enable all four methods.

dav_ext_lock_zone

Defines a shared memory zone for storing WebDAV locks and sets the lock expiration timeout.

Syntax:  dav_ext_lock_zone zone=NAME:SIZE [timeout=TIMEOUT]
Default: —
Context: http

Parameters:

  • zone=NAME:SIZE — The name and size of the shared memory zone used to store active locks. For example, zone=davlock:10m allocates 10 MB of shared memory. Each lock entry is small, so 10 MB can hold thousands of simultaneous locks.
  • timeout=TIMEOUT — The time after which a lock automatically expires if not refreshed. The default value is 60 seconds. WebDAV clients typically refresh locks before they expire, but a longer timeout (e.g., timeout=300 for 5 minutes) reduces the frequency of refresh requests.

This directive must be placed in the http context because the shared memory zone is global across all server blocks.

dav_ext_lock

Enables WebDAV locking in the specified scope and links it to a shared memory zone.

Syntax:  dav_ext_lock zone=NAME
Default: —
Context: http, server, location

The zone=NAME parameter must reference a zone previously defined by dav_ext_lock_zone. You must also enable the LOCK and UNLOCK methods in dav_ext_methods for locking to function.

When locking is enabled, the module responds with DAV: 2 in the OPTIONS response, indicating DAV class 2 compliance (locking support). Without locking, the module reports DAV: 1.

Important: The module supports only exclusive write locks, which is the only lock type defined in the WebDAV specification (RFC 4918). All active locks are stored in a linked list, so lock checking requires O(n) operations. A very large number of simultaneous locks may degrade performance. Therefore, avoid setting an excessively long lock timeout.

Configuration Examples

Basic WebDAV Server (No Locking)

This minimal configuration provides file upload, download, directory listing, and file management without locking support:

server {
    listen 80;
    server_name files.example.com;

    location /webdav/ {
        alias /srv/webdav/;

        # Standard DAV methods for file operations
        dav_methods PUT DELETE MKCOL COPY MOVE;

        # Extended DAV methods for directory listing
        dav_ext_methods PROPFIND OPTIONS;

        # Auto-create intermediate directories on upload
        create_full_put_path on;

        # Set file permissions for uploaded files
        dav_access user:rw group:r all:r;

        # Allow large file uploads (adjust as needed)
        client_max_body_size 1g;
    }
}

With this configuration, clients can list files via PROPFIND, upload files via PUT, create directories via MKCOL, and manage files via COPY, MOVE, and DELETE. However, concurrent editing is not protected by locks, so simultaneous writes to the same file may conflict.

WebDAV Server with Locking

This configuration adds lock support for safe concurrent access. It is the recommended setup for shared file servers where multiple users edit files simultaneously:

http {
    dav_ext_lock_zone zone=davlock:10m;

    server {
        listen 80;
        server_name files.example.com;

        location /webdav/ {
            alias /srv/webdav/;

            dav_methods PUT DELETE MKCOL COPY MOVE;
            dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
            dav_ext_lock zone=davlock;

            create_full_put_path on;
            dav_access user:rw group:r all:r;

            client_max_body_size 1g;
        }
    }
}

With locking enabled, a client can lock a file before editing it. Other clients that attempt to modify the locked file receive a 423 Locked response until the lock is released or expires. The default lock timeout is 60 seconds.

macOS Finder Compatibility

macOS Finder sends MKCOL requests without a trailing slash when creating directories. NGINX’s standard DAV module requires the trailing slash for MKCOL, so you need a rewrite rule to add it. This configuration handles the macOS Finder quirk:

http {
    dav_ext_lock_zone zone=davlock:10m;

    server {
        listen 80;
        server_name files.example.com;

        location /webdav/ {
            alias /srv/webdav/;

            # Fix macOS Finder MKCOL without trailing slash
            set $x $uri$request_method;
            if ($x ~ [^/]MKCOL$) {
                rewrite ^(.*)$ $1/;
            }

            dav_methods PUT DELETE MKCOL COPY MOVE;
            dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
            dav_ext_lock zone=davlock;

            create_full_put_path on;
            dav_access user:rw group:r all:r;

            client_max_body_size 10g;
        }
    }
}

The rewrite rule detects MKCOL requests to URIs without a trailing slash and appends one. This allows macOS Finder to create directories without errors.

Testing Your WebDAV Server

After applying the configuration, verify the syntax and restart NGINX:

nginx -t && sudo systemctl restart nginx

Preparing the WebDAV Directory

Create the storage directory and set proper ownership:

sudo mkdir -p /srv/webdav
sudo chown nginx:nginx /srv/webdav

Verifying the Module Is Loaded

The most reliable way to confirm the NGINX WebDAV module is loaded is to add module-specific directives and test the configuration:

nginx -t

If nginx -t passes with dav_ext_methods directives present, the module is loaded and functioning. If you see unknown directive "dav_ext_methods", the module is not loaded — check that the load_module line is present and correct.

Testing OPTIONS

The OPTIONS method reveals which WebDAV methods are available:

curl -s -X OPTIONS http://localhost/webdav/ -D - -o /dev/null

Expected output with locking enabled:

HTTP/1.1 200 OK
DAV: 2
Allow: GET,HEAD,PUT,DELETE,MKCOL,COPY,MOVE,PROPFIND,OPTIONS,LOCK,UNLOCK

The DAV: 2 header confirms that locking is active. Without locking, this would show DAV: 1.

Testing PROPFIND

PROPFIND lists directory contents and file properties. Use Depth: 1 to list the immediate children:

curl -s -X PROPFIND http://localhost/webdav/ -H "Depth: 1"

The response is an XML document listing each file and directory with its properties:

<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>/webdav/</D:href>
<D:propstat>
<D:prop>
<D:displayname>webdav</D:displayname>
<D:getlastmodified>Tue, 03 Mar 2026 15:29:53 GMT</D:getlastmodified>
<D:resourcetype><D:collection/></D:resourcetype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>

The module returns six standard WebDAV properties for each resource: displayname, getcontentlength, getlastmodified, resourcetype, lockdiscovery, and supportedlock.

Testing File Operations

Upload a file, verify it exists, then clean up:

# Upload a file
echo "Hello WebDAV" | curl -s -T - http://localhost/webdav/test.txt -D - -o /dev/null

# Read it back
curl -s http://localhost/webdav/test.txt

# Create a directory
curl -s -X MKCOL http://localhost/webdav/documents/ -D - -o /dev/null

# Copy the file into the directory
curl -s -X COPY http://localhost/webdav/test.txt \
     -H "Destination: http://localhost/webdav/documents/test.txt" \
     -D - -o /dev/null

# Delete the original
curl -s -X DELETE http://localhost/webdav/test.txt -D - -o /dev/null

Testing Locking

Lock a file, attempt modification without the token, then use the token:

# Lock the file
curl -s -X LOCK http://localhost/webdav/documents/test.txt \
     -H "Content-Type: application/xml" \
     -d '<?xml version="1.0" encoding="utf-8" ?>
<D:lockinfo xmlns:D="DAV:">
  <D:lockscope><D:exclusive/></D:lockscope>
  <D:locktype><D:write/></D:locktype>
</D:lockinfo>'

The response includes a Lock-Token header (e.g., <urn:3b658999>) and an XML body confirming the lock details. Note the token value for subsequent requests.

# Attempt to modify without the token — returns 423 Locked
echo "Unauthorized write" | curl -s -T - http://localhost/webdav/documents/test.txt \
     -D - -o /dev/null

# Modify with the correct token — succeeds
echo "Authorized write" | curl -s -T - http://localhost/webdav/documents/test.txt \
     -H "If: (<urn:3b658999>)" -D - -o /dev/null

# Release the lock
curl -s -X UNLOCK http://localhost/webdav/documents/test.txt \
     -H "Lock-Token: <urn:3b658999>" -D - -o /dev/null

Security Best Practices

A WebDAV server exposes file management over HTTP, so it is critical to secure it properly before deploying to production.

Enable Authentication

Never expose a WebDAV server without authentication. Use HTTP Basic Auth at minimum:

# Install htpasswd utility
sudo dnf install httpd-tools    # RHEL-based
sudo apt-get install apache2-utils  # Debian/Ubuntu

# Create password file
sudo htpasswd -c /etc/nginx/.htpasswd webdav_user

Add the authentication directives to your location block:

location /webdav/ {
    auth_basic "WebDAV";
    auth_basic_user_file /etc/nginx/.htpasswd;

    # ... DAV directives ...
}

For stronger authentication, consider using the NGINX auth hash module for token-based URL authentication, or integrate with an external authentication provider using NGINX’s auth_request directive.

Use HTTPS

WebDAV transmits file contents and credentials over the network. Always use TLS in production:

server {
    listen 443 ssl;
    server_name files.example.com;

    ssl_certificate /etc/letsencrypt/live/files.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/files.example.com/privkey.pem;

    location /webdav/ {
        auth_basic "WebDAV";
        auth_basic_user_file /etc/nginx/.htpasswd;

        alias /srv/webdav/;
        dav_methods PUT DELETE MKCOL COPY MOVE;
        dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
        # ... remaining config ...
    }
}

You can enhance your TLS configuration with the NGINX security headers module, which automatically adds security-related response headers.

Restrict Access by IP

If your WebDAV server is only accessed from specific networks, combine authentication with IP restrictions:

location /webdav/ {
    allow 192.168.1.0/24;
    allow 10.0.0.0/8;
    deny all;

    auth_basic "WebDAV";
    auth_basic_user_file /etc/nginx/.htpasswd;

    # ... DAV directives ...
}

Limit Upload Sizes

Set client_max_body_size to a reasonable value for your use case. A file server might allow 1-10 GB uploads, while a document collaboration server might limit to 100 MB:

client_max_body_size 1g;

SELinux Configuration

On RHEL-based distributions with SELinux enabled (the default on Rocky Linux, AlmaLinux, and RHEL), NGINX is restricted from reading and writing arbitrary directories. You must configure the correct SELinux context for your WebDAV storage directory.

Set the httpd_sys_rw_content_t context to allow NGINX to read and write files:

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/srv/webdav(/.*)?"
sudo restorecon -Rv /srv/webdav/

If NGINX uses a custom client_body_temp_path, apply the same context to that directory:

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/tmp/nginx-dav(/.*)?"
sudo restorecon -Rv /tmp/nginx-dav/

Without the correct SELinux context, PROPFIND requests return 500 Internal Server Error and file uploads fail. The NGINX error log will show Permission denied errors even if the Unix file permissions are correct.

You can verify the current context with:

ls -laZ /srv/webdav/

The output should show httpd_sys_rw_content_t for the directory and its contents.

Performance Considerations

Shared Memory Zone Sizing

The dav_ext_lock_zone allocates shared memory for storing lock information. Each lock entry is small (a few hundred bytes), so 10 MB is sufficient for thousands of simultaneous locks. For most deployments, you will never need to increase this value.

Lock Timeout Tuning

The default lock timeout of 60 seconds works well for interactive editing where clients refresh locks frequently. However, for batch operations or slow connections, a longer timeout reduces the risk of lock expiration during file transfers:

dav_ext_lock_zone zone=davlock:10m timeout=300;

A 5-minute timeout is a reasonable balance between lock durability and resource cleanup. Avoid setting very long timeouts (e.g., hours) because active locks are checked linearly, and a large number of stale locks degrades PROPFIND performance.

Directory Listing Performance

PROPFIND with Depth: 1 lists all files in a directory. For directories containing thousands of files, this operation may become slow because NGINX reads each file’s metadata (size, modification time) from the filesystem. If you expect very large directories, consider organizing files into subdirectories.

Upload Buffering

When receiving large file uploads via PUT, NGINX buffers the request body in the client_body_temp_path directory before writing it to the final location. Ensure this directory has enough disk space and is on the same filesystem as the WebDAV root to allow atomic renames:

client_body_temp_path /srv/webdav/.tmp;
client_max_body_size 10g;

Using the same filesystem avoids a costly copy operation during the final file move.

Troubleshooting

“Unknown directive” Error

If nginx -t reports unknown directive "dav_ext_methods":

  1. Verify the module file exists: ls /usr/lib64/nginx/modules/ngx_http_dav_ext_module.so
  2. Ensure the load_module directive is at the top of nginx.conf, outside any block.
  3. Verify the module package version matches your NGINX version: rpm -q nginx-module-dav-ext

PROPFIND Returns 500 Internal Server Error

This is almost always a permissions issue. Check the NGINX error log:

tail -f /var/log/nginx/error.log

Common causes:

  • SELinux blocking access — The error log shows Permission denied even with correct Unix permissions. Apply the httpd_sys_rw_content_t context as described in the SELinux section above.
  • Directory not owned by nginx user — Run chown -R nginx:nginx /srv/webdav/.
  • Incorrect alias path — Ensure the alias directive path ends with a trailing slash and the directory actually exists.

Locked File Returns 423 but You Lost the Token

If a client crashes without unlocking a file, you must wait for the lock timeout to expire. The default timeout is 60 seconds. For development or testing, you can restart NGINX to clear all locks from shared memory:

sudo systemctl restart nginx

In production, the recommended approach is to set a reasonable timeout value in dav_ext_lock_zone rather than restarting NGINX.

macOS Finder Cannot Create Directories

macOS Finder sends MKCOL requests without a trailing slash. Add the rewrite rule from the macOS Finder Compatibility section. Without this fix, NGINX returns 409 Conflict when Finder tries to create a new folder.

Windows Explorer Shows Empty Folder

Windows Explorer may cache directory listings aggressively. Additionally, Windows requires DAV: 1 or DAV: 2 in the OPTIONS response to recognize a server as WebDAV-capable. Ensure that OPTIONS is listed in your dav_ext_methods directive.

Conclusion

The NGINX WebDAV module completes what the standard DAV module starts. Together, they provide full WebDAV support for file sharing, cloud storage, and collaborative editing directly from NGINX — without needing Apache, Nextcloud, or any additional application server.

For production deployments, always enable HTTPS and authentication, configure SELinux contexts on RHEL-based systems, and choose a lock timeout that matches your workflow. The module’s lightweight design means you can serve WebDAV alongside your existing NGINX configuration with minimal overhead.

The module source code is available on GitHub.

D

Danila Vershinin

Founder & Lead Engineer

NGINX configuration and optimizationLinux system administrationWeb performance engineering

10+ years NGINX experience • Maintainer of GetPageSpeed RPM repository • Contributor to open-source NGINX modules

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.