skip to content
Wünsch Consulting

Setting up WebDAV on NixOS

/ 3 min read

Setting up WebDAV on NixOS

Introduction

For my personal cloud storage I wanted to set up a WebDAV server on my NixOS machine, so I could easily share static files with friends or over the phone.

I want to be able to upload files on the go and share them with others without having them to sign up to anything. Therefore needed some of the endpoints to be password protected with upload functionality and others to be public read-only.

There is a Nginx module for WebDAV, but it seemed to not be able to handle permissions for users in a way that would allow me to achieve what I wanted.

I decided to use rclone to serve the files via WebDAV.

I seperated the routes into one for upload and one for public files.

Terminal window
/ # the public files are served from here
/private # here the files are uploaded
/public # here the public files are served
/example-file.txt # the file can be edited here
/example-file.txt # the file can be read from here

Setting up rclone

Here we setup an systemd service that starts the public WebDAV server on port 8080 with the user user and password pass. The files are served from /srv/data/public.

Before we can start the service we need to create a password file for the user user with the password pass.

Terminal window
# htpasswd is available from the apacheHttpd package
$ htpasswd -c passwords user

Then import the following configuration to your configuration.nix file. Add the htpasswdFile and htpasswdFileContent to the configuration. This will create the password file on the system and an systemd service that starts the WebDAV server.

I served the webdav server on port 8080, the public files on port 8081 and the upload endpoint on port 8082.

webdav.nix
{ config, pkgs, ... }:
let
port = 8080;
addr = "example.com"; # the address to bind to
serveDirectory = "/srv/data";
publicDirectory = "${serveDirectory}/public";
htpasswdFile = "/etc/nixos/webdav/httpasswd";
in
{
systemd.services.webdavPrivate = {
description = "Rclone WebDAV server";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''
${pkgs.rclone}/bin/rclone serve webdav --baseurl /private --addr :${toString port+2} --htpasswd ${htpasswdFile} ${serveDirectory}"
'';
Restart = "always";
};
};
}

Furthermore we need to add the public Part of the served Files. For this I used the static-web-server package.

services.static-web-server = {
enable = true;
listen = "localhost:${toString (port+1)}";
directory = publicDirectory;
configuration = { general = { "directory-listing" = true; }; };
};

Finally we proxy all of this with Nginx to serve the files from the same domain.

services.nginx = {
enable = true;
virtualHosts = {
"dav" = {
forceSSL = false;
enableACME = false;
locations = {
"/" = {
proxyPass = "http://localhost:${toString port + 1}";
};
"/private" = {
proxyPass = "http://localhost:${toString port + 2}/private";
};
};
listen = [{
port = port;
ssl = false;
addr = addr;
}];
};
};
};

Conclusion

This setup allows me to easily share files with friends and family. The setup is easy to maintain and can be easily extended with more features.