Graham Eddy

nginx wevDAV Server

Install and configure wevDAV modules of nginx for a domain with virtual users. Multiple domains each have their own wevDAV server.

2022-08-06 Raspbian bullseye, Ubuntu 22.04 (not 20.04)


This provides a password-protected wevDAV file server with two kinds of user access:

Fundamental technical issues addressed in this configuration:


Installation

graham:~ sudo apt update graham:~ sudo apt install nginx-full libnginx-mod-http-cache-purge \ libnginx-mod-http-dav-ext libnginx-mod-http-fancyindex \ libnginx-mod-http-headers-more-filter libnginx-mod-nchan graham:~ cd /etc/nginx graham:/etc/nginx sudo vi snippets/webdav_server.conf
/etc/nginx/snippets/webdav_server.conf new file
#https://github.com/mcnewton/nginx_webdav/blob/master/snippets/webdav_server.conf
#
#  This file should be included in each http server{} section that
#  is going to do WebDav.
#
#  From https://gist.github.com/jirutka/5380770
#
location ~ \.(_.*|DS_Store|Spotlight-V100|TemporaryItems|Trashes|hidden)$ {
    access_log off;
    error_log off;

    if ($request_method = PUT) {
        return 403;
    }

    return 404;
}

location ~ \.metadata_never_index$ {
    return 200 "Don't index this drive, Finder!";
}
graham:/etc/nginx sudo vi snippets/webdav.conf
/etc/nginx/snippets/webdav.conf new file
#https://github.com/mcnewton/nginx_webdav/blob/master/snippets/webdav.conf
#
#  General settings for WebDAV config with fixups for different
#  broken clients
#
#  From what I can tell, all of the mainstream O/S based WebDav clients
#  are broken and don't follow the spec in subtly different ways.
#
#  This file should be included in a location{} block that needs
#  WebDav access.
#

#
#  MacOS Sends MKCOL without the trailing slash
#  MOVE with trailing slash on URI but no trailing slash on destination
#
#  Linux sends MKCOL with trailing slash
#  but MOVE with no trailing slash on URI or destination
#
#  Windows sends MOVE with no trailing slash on URI or destination
#

#
#  Add / to URI with MKCOL, if needed
#

if ($request_method = MKCOL) {
    rewrite ^(.*[^/])$ $1/;
}


#
#  Handle missing trailing slash with MOVE and DELETE
#
#  Can't do nested or complex if statements in nginx, so use $s
#  (source) and $t (target) to track the state.
#

set $s A;
set $t A;

#  Check if it's a MOVE or DELETE operation
if ($request_method = MOVE) {
    set $s B$s;
    set $t B$t;
}

if ($request_method = DELETE) {
    set $s B$s;
}


#  Update URI if trailing slash is missing for MOVE or DELETE
if (-d $request_filename) {
    set $s C$s;
}

if ($s = "CBA") {
    rewrite ^(.*[^/])$ $1/;
}


#  More checks for Destination - first make sure the source is a
#  directory...
if ($uri ~ ^.*/$) {
    set $t C$t;
}

#  ...and destination doesn't already end in slash...
if ($http_destination !~ ^.*/$) {
    set $t D$t;
}

#  ...then fix up the destination by adding a slash on the end. 
if ($t = "DCBA") {
    set $destination $http_destination;
    set $destination $destination/;
    more_set_input_headers "Destination: $destination";
}


#
#  Fix up for Windows, which sends PROPPATCH: return a fake "OK" to
#  keep it happy.
#
#  https://github.com/arut/nginx-dav-ext-module/issues/52
#  http://netlab.dhis.org/wiki/ru:software:nginx:webdav (Russian)
#

if ($request_method = PROPPATCH) {
    add_header          Content-Type 'text/xml';
    return              207 '<?xml version="1.0"?><a:multistatus xmlns:a="DAV:"><a:response><a:propstat><a:status>HTTP/1.1 200 OK</a:status></a:propstat></a:response></a:multistatus>';
}


#
#  General "enable WebDav" stuff
#
dav_methods             PUT DELETE MKCOL COPY MOVE;
dav_ext_methods         PROPFIND OPTIONS LOCK UNLOCK;

client_body_temp_path   /tmp/nginx;
client_max_body_size    0;
create_full_put_path    on;

#  Defined in conf.d/webdav.conf
dav_ext_lock            zone=xfer_webdav;
dav_access              user:rw group:rw;
graham:/etc/nginx sudo vi conf.d/webdav.conf
/etc/nginx/conf.d/webdav.conf new file
#https://github.com/mcnewton/nginx_webdav/blob/master/conf.d/webdav.conf
#
#  On Debian based systems this file will be included in
#  httpd.conf http{} section automatically. Otherwise that's where
#  this config needs to go...
#
#  See snippets/webdav.conf for where this is used.
#
dav_ext_lock_zone zone=xfer_webdav:10m;

Add a virtual server

Add virtual server docs.geddy.au.

graham:/etc/nginx sudo vi sites-available/docs.geddy.au
/etc/nginx/sites-available/docs.geddy.au new file
# docs.geddy.au - virtual server

server {
    listen 80;
    listen [::]:80;
    server_name docs.geddy.au;
    root /srv/http/docs.geddy.au/html;
    index index.html index.htm;

    include snippets/webdav_server.conf;

    fancyindex on;
    fancyindex_exact_size off;
    fancyindex_localtime on;
    fancyindex_css_href /.config/autoindex.css;
    fancyindex_time_format "%a %d/%m/%Y at %I:%M %p";

    location / {
        try_files $uri $uri/ =404;
    }

    # example share 'shared'
    #location ~ ^/shared(?:/(.*))?$ {
    #    include snippets/webdav.conf;
    #
    #    auth_basic "shared";
    #    auth_basic_user_file /srv/http/docs.geddy.au/realm/shared;
    #}
}
graham:/etc/nginx sudo mkdir -p /srv/http/docs.geddy.au graham:/etc/nginx cd /srv/http/docs.geddy.au graham:/srv/http/docs.geddy.au sudo mkdir html graham:/srv/http/docs.geddy.au sudo chown root:www-data html graham:/srv/http/docs.geddy.au sudo chmod 2755 html graham:/srv/http/docs.geddy.au sudo mkdir html/.config html/downloads graham:/srv/http/docs.geddy.au sudo vi html/.config/autoindex.css
/srv/http/docs.geddy.au/html/.config/autoindex.css new file
/* autoindex.css - style for nginx autoindex pages */
h1 {
  margin: 0 0 0.4em 0;
  padding: 0.4em;
  font-size: 1.2em;
  background: indigo;
  color: white;
}
h1::before {
  content: "docs.geddy.au: ";
  opacity: 0.75;
}
th { width: auto !important; }
td:nth-child(1) { }
td:nth-child(2) { width: 6em; }
td:nth-child(3) { width: 15em; }
graham:/srv/http/docs.geddy.au sudo mkdir realm graham:/srv/http/docs.geddy.au sudo chmod 755 realm graham:/srv/http/docs.geddy.au sudo ls -alR | grep -v '\.$' | grep -v '^$' | grep -v '^total ' .: drwxr-sr-x 5 root www-data 4096 Aug 17 17:39 html drwxr-xr-x 2 root www-data 4096 Aug 27 22:36 realm ./html: drwxr-sr-x 2 root www-data 4096 Aug 27 18:46 .config drwxr-sr-x 2 root www-data 4096 Aug 27 18:46 downloads ./html/.config: -rw-r--r-- 1 root www-data 338 Aug 27 18:46 autoindex.css ./html/downloads: ./realm: graham:/srv/http/docs.geddy.au cd /etc/nginx/sites-enabled graham:/etc/nginx/sites-enabled sudo ln -s ../sites-available/docs.geddy.au . # note the trailing dot! graham:/etc/nginx/sites-enabled sudo systemctl reload nginx graham:/etc/nginx/sites-enabled sudo systemctl status nginx graham:/etc/nginx/sites-enabled sudo certbot -d docs.geddy.au --nginx

Add a share to virtual server

Add share shared to virtual server docs.geddy.au. This is often referred to externally by some variation on syntax //docs.geddy.au/shared.

graham:/etc/nginx/sites-enabled sudo vi docs.geddy.au
/etc/nginx/sites-enabled/docs.geddy.au insert text block before final }
    # share 'shared'
    location ~ ^/shared(?:/(.*))?$ {
        include snippets/webdav.conf;
    
        auth_basic "shared";
        auth_basic_user_file /srv/http/docs.geddy.au/realm/shared;
    }
graham:~ cd /srv/http/docs.geddy.au graham:/srv/http/docs.geddy.au sudo mkdir html/shared graham:/srv/http/docs.geddy.au sudo chmod 2770 html/shared graham:/srv/http/docs.geddy.au sudo vi html/shared/README.txt
/srv/http/docs.geddy.au/html/shared/README.txt new file
This is a share: play nicely.
graham:/srv/http/docs.geddy.au sudo touch realm/shared # no users yet

Add a virtual user to share

Add virtual user fred.nerk to share //docs.geddy.au/shared.

This is done at per-share level (as opposed to per-domain level) to assign individual access rights to each share, at the cost of duplicating user/password declarations. The alternative is to have a single realm for all shares, or to symlink all realms to a master copy.

graham:~ echo "fred.nerk:$(openssl passwd -apr1)" | \ sudo tee -a /srv/http/docs.geddy.au/realm/shared Password: fred.nerk's password