I've been using Seafile as my self-hosted file sync solution for a while now, and it's been fantastic. But I was using nextcloud before that and while I moved to seafile, I kept nextcloud for one reason: The webdav support. I'm using webdav as zotero attachment storage instead of using their expensive paid storage. I knew that there was a support for webdav in seafile, but I never got around to setting it up.

The documentation exists, but it's written with a traditional installation in mind. When we're running Seafile in Docker with Nginx Proxy Manager handling all our reverse proxy needs, things get a bit more nuanced. After spending sometime figuring out the right configuration, I wanted to document the process, both for future me and anyone else running a similar setup.

My selfhosted infrastructure runs mostly in Docker containers. Seafile lives in its own container with MariaDB and Redis, while Nginx Proxy Manager handles all incoming traffic and SSL certificates. The official Seafile documentation assumes we're either running a bare-metal installation or manually configuring Nginx, neither of which applied to my setup.

The challenge was that I needed to enable WebDAV inside the containerized Seafile instance, configure the correct networking between containers, and set up Nginx Proxy Manager to route WebDAV traffic properly.

Let's walk through each step.

Prerequisites

Before starting, make sure we have:

If we're starting fresh, we should get Seafile running and accessible through our domain first. This guide assumes we already have that foundation in place.

The first step is creating the WebDAV configuration file. In a containerized Seafile setup, configuration files live in /shared/seafile/conf/ inside the container. This maps to wherever we've mounted our Seafile data volume on the host.

Create the seafdav.conf file. We can do this directly inside the container 1:

docker exec seafile bash -c 'cat > /shared/seafile/conf/seafdav.conf << EOF
[WEBDAV]
enabled = true
port = 8080
debug = true
share_name = /seafdav
workers = 5
timeout = 1200
EOF'

Or if we prefer working on the host filesystem:

cat > /path/to/our/seafile_data/seafile/conf/seafdav.conf << 'EOF'
[WEBDAV]
enabled = true
port = 8080
debug = true
share_name = /seafdav
workers = 5
timeout = 1200
EOF

This needs to be adjusted to the location of your Seafile data mount on the host or the docker volume name if we're using one.

Let me break down what each option does:

Now we need to worry about the networking. This is where Docker setups differ from traditional installations. Our Seafile container needs to be on the same Docker network as Nginx Proxy Manager. In my docker-compose setup, it looks something like this:

services:
  seafile:
    image: seafileltd/seafile-mc:latest
    environment:
      - SEAFILE_ENABLE_WEBDAV: true
    # Other config stuff...
    networks:
      - seafile-internal  # Private network for database/redis
      - proxy-network     # Shared with Nginx Proxy Manager

networks:
  seafile-internal:
    driver: bridge
  proxy-network:
    external: true

The key insight: Seafile needs/should have two networks. One internal network for database and Redis communication, and one shared network with our reverse proxy. This allows Nginx Proxy Manager to route traffic to Seafile using the container name as a hostname. The only thing related to WebDAV we should include in our docker-compose file is the environment variable SEAFILE_ENABLE_WEBDAV: true. The rest of the configuration is handled by the seafdav.conf file.

We don't need to expose port 8080 to the host. In fact, we shouldn't. Let Nginx Proxy Manager handle all external access. The containers communicate internally over their shared Docker network. Also since it is external docker network, we have to make sure it is created before running the container. To do that we need to run the following command:

docker network create proxy-network

With the configuration in place, restart the Seafile container:

docker compose restart seafile

Give it a few seconds, then verify WebDAV is actually running:

docker exec seafile netstat -tlnp | grep 8080

We should see something indicating port 8080 is listening. We can also check the process directly:

docker exec seafile ps aux | grep seafdav

Look for wsgidav.server.server_cli in the output. If we see it, WebDAV is running. If not, check the logs:

docker exec seafile tail -f /shared/logs/seafdav.log

Now comes the interesting part. Nginx Proxy Manager's UI makes proxy configuration easy, but WebDAV requires some specific settings that aren't immediately obvious.

We open our NPM admin interface and edit the proxy host for our Seafile domain. We're going to add three locations.

Location 1: The Redirect

First, we need a redirect to ensure URLs with and without trailing slashes work correctly. WebDAV is particular about this.

Click "Add location" and configure:

In the "Custom config" section, add:

return 301 $scheme://$host/seafdav/;

This redirects /seafdav to /seafdav/ (note the trailing slash). It seems trivial, but WebDAV clients expect this behavior.

Save and test that our main Seafile instance still works. Add one location at a time – if something breaks, we'll know exactly which configuration caused it.

Location 2: The Main WebDAV Handler

This is where the actual WebDAV traffic gets routed. Add another location:

The ^~ prefix is important, it's a regex modifier that tells Nginx to stop searching for other location matches once this one is found. This ensures WebDAV requests don't accidentally get caught by other location blocks.

In "Custom config":

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1200s;
client_max_body_size 0;

These headers are crucial. They tell the backend Seafile service about the original request, the real client IP, the protocol (https), and the hostname. Without these, Seafile won't generate correct URLs for WebDAV operations.

The timeout matches what we set in seafdav.conf (1200 seconds), and client_max_body_size 0 removes any upload size limits imposed by Nginx.

Location 3: Directory Browser (Optional)

Seafile includes a web-based directory browser for WebDAV. If we want this functionality:

No custom config needed here. I honestly haven't used this feature, but it's nice to have.

At this point, we should be able to access WebDAV at:

https://ourdomain.com/seafdav

We try it in a browser first. We will see basic authentication prompt. We cannot use our normal login credentials. We need go to https://ourdomain.com/profile/#update-webdav-passwd and reset webdav password. It will also give us the WebDAV username which will be also same as our seafile username.

Now we should have a working WebDAV setup. A few things worth mentioning about security:

We should always use HTTPS. WebDAV transmits credentials, and we don't want those going over the wire in plaintext. Nginx Proxy Manager makes this easy. We Also should not expose port 8080 directly to the internet. Let Nginx Proxy Manager be our single entry point. And always use strong passwords for our Seafile accounts. Since WebDAV uses HTTP basic authentication, our password is essentially our only protection.

Or better yet, consider limiting WebDAV access to your local network or VPN if possible. I run everything through Tailscale, so my Seafile instance is only accessible on my private network.

1

Then we don't have to worry about where did we mount or which docker volume is mapped to /shared/seafile/conf/