I'm looking to completely decommission my SMBA service and replace it with a WebDav service.

All the google searches so far have pointed me to using Apache / Webdav. This is close to what I need but as far as I read it requires Apache to have access to my user's files and worse; if it creates a file the new file will be owned by Apache (not the user). Note that having files with the correct Unix ownership and permissions is a requirement as some users have direct SSH access.

So I'm quite simply looking for a way to either make Apache / Webdav work "correctly" with multi-users (that is change unix user to the logged in user before attempting to serve the file) or find a complete alternative to Apache / Webdav.

So far searches haven't turned anything up.

  • As webdav is based on the HTTP protocol, I would say it's not existing except under the form of an HTTP server. And if you find product that offer webdav trhey will usually offer more than that – Kiwy Apr 3 '14 at 18:50
  • It looks like there may be something promising in the latest version of MPM ITK. mpm-itk.sesse.net I'll have a try with this and see if AssignUserIDExpr will accept the logged in user. It may not since AssignUserID appears to kick in before the user authenticates. – Philip Couling Apr 7 '14 at 11:09
  • There are standalone webdav servers like code.google.com/p/opendav or libraries like PyWebDAV that don't require apache. – Jan Aug 21 '14 at 7:58
  • @jan That may turn out to to be the best answer. Apache is running on the server already and webdav should be a subdirectory on the site but I can set that up as a proxy pass through and use Apache's SSL to provide the encryption. – Philip Couling Aug 25 '14 at 22:37
  • 1
    Should be moved to Software Recommendations.SE. – William Edwards Oct 18 '14 at 19:55

If you have the username and/or the uid, you can do this with nginx + lua + luarocks ljsyscall

On a debian system, configured as:

apt-get -y install nginx libnginx-mod-http-dav-ext libnginx-mod-http-lua luarocks
luarocks install ljsyscall

And nginx configured the following way:

user  root;
worker_processes  1;

load_module modules/ngx_http_dav_ext_module.so;
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_lua_module.so;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;

http {
    sendfile        on;
    keepalive_timeout  65;
    gzip  on;

    server {
        listen      80;
        listen [::]:80;

        location / {
            rewrite ^ http://$host$request_uri?; # permanent;

    server {
        listen      443           ssl http2;
        listen [::]:443           ssl http2;

        ssl                       on;    
        # [ SSL Sections Omitted ]

        # Set the maximum size of uploads
        client_max_body_size 200m;

        # Default is 60, May need to be increased for very large uploads
        client_body_timeout 120s; 

        # other configs
        location /webdav/ {
            autoindex              on;
            alias                  /data/www/;
            client_body_temp_path  /data/client_temp;

            dav_methods PUT DELETE MKCOL COPY MOVE;
            dav_ext_methods PROPFIND OPTIONS;

            create_full_put_path   on;
            # Not sure if you want to tweak this
            # dav_access             group:rw  all:r;

            # Let's assume you have an auth subrequest that can set X-UID
            auth_request  /auth
            auth_request_set $auth_status $upstream_status;
            auth_request_set $saved_remote_user $upstream_http_REMOTE_USER;
            auth_request_set $saved_remote_uid $upstream_http_X_UID;

            # Per-Request Impersonation
            access_by_lua_block {
                # Boilerplate because ljsyscall doesn't have setfsuid implemented directly
                local syscall_api = require 'syscall'
                local ffi = require "ffi"
                local nr = require("syscall.linux.nr")
                local sys = nr.SYS
                local uint = ffi.typeof("unsigned int")
                local syscall_long = ffi.C.syscall -- returns long
                local function syscall(...) return tonumber(syscall_long(...)) end 
                local function setfsuid(id) return syscall(sys.setfsuid, uint(id)) end
                -- If you only have ngx.var.saved_remote_user, install luaposix and do this ...
                -- local pwd = require 'posix.pwd'
                -- local new_uid = pwd.getpwnam(ngx.saved_remote_user).pw_uid
                local new_uid = tonumber(ngx.var.saved_remote_uid)
                ngx.log(ngx.NOTICE, "[Impersonating User #" .. new_uid .. "]")
                local previous = setfsuid(new_uid)
                local actual = setfsuid(new_uid)
                if actual ~= new_uid then
                    ngx.log(ngx.CRIT, "Unable to impersonate users")

        location = /auth {
            proxy_pass              http://localhost:8080/auth;
            proxy_pass_request_body off;
            proxy_set_header        Content-Length "";
            proxy_set_header        X-Original-URI $request_uri;
            proxy_set_header        X-Original-Method $request_method;

This will execute setfsuid on every request serviced by the nginx worker. Unfortunately, it seems you must be running nginx as root in order for this to work right currently. I believe it's possible for this to work with a different user provided the process started as root, dropped to a different user, with CAP_SETUID preserved (see documentation for capsh), and the user directive is absent in the nginx config file.

You may also need to set the group IDs, potentially.

See "Effect of user ID changes on capabilities" in http://man7.org/linux/man-pages/man7/capabilities.7.html

| improve this answer | |
  • That looks promising. I'll check it out. – Philip Couling Dec 19 '18 at 10:07

Having searched for a long time I just couldn't find one. There are many multi user servers but I couldn't find one which executed as the system user.

So I wrote one myself. This is only tested as far as I can test it myself. But for what its worth, the source code is here:


| improve this answer | |


I was looking for same thing and I finally gathered a solution using apache2. I tried node solution using npm webdav-server and found out not all worked as nicely then using the apache module. Then I tried a npm dav-server based on jsDAV that could do better and could be a solution, but as I had to deal with lousy 3g connection I preferred apache and found out about multiple instance scripts.

So here I share my experience.


I run an instance per webdav user... not very scalable, but to work in a small team it's good enough.

Replace myUser with your user.

On Ubuntu 14.04

sh /usr/share/doc/apache2/examples/setup-instance myUser

So I run a apache process as user myUser defined in /etc/apache2-myUser/envars

export APACHE_RUN_USER=myUser
export APACHE_RUN_GROUP=myUser

Edit ports.conf

# If you proxy with nginx as I did better to limit to local interface
listen localhost:8080
# listen 8080

I could not get PAM auth on ubuntu 14.04 to work so need to trick with basic auth as I then wrap it in https with nginx

htpasswd -c /etc/apache2/htpasswd myUser

Then /etc/apache2-myUser/sites-available/000-default.conf

<VirtualHost *:8080>

DocumentRoot /var/www/html

<Directory /home/${APACHE_RUN_USER}>
    Require all granted
    Options +Indexes

<Location /${APACHE_RUN_USER}>
      DAV On
      AuthType Basic
      AuthName "Restricted Area"
      AuthUserFile /etc/apache2/htpasswd
      Require valid-user

DavLockDB /home/${APACHE_RUN_USER}/.DavLock
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

then nginx proxy has a trick with header Destination passing icons folder lets webdav downgrade nicely on browsers

server {
listen 443 ssl http2;
server_name exemple.com;

location ~ ^/(myUser|icons)/ {

    proxy_pass http://dav-myUser;

#         auth_basic "Restricted Content";
#         auth_basic_user_file /etc/nginx/htpasswd;

#         proxy_set_header Authorization $http_authorization;

    proxy_pass_header  Authorization;
    proxy_pass_request_headers on;

    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;

    port_in_redirect off;

    # to avoid 502 Bad Gateway:
    # http://vanderwijk.info/Members/ivo/articles/ComplexSVNSetupFix
    set $destination $http_destination;

    if ($destination ~* ^https(.+)$) {
        set $destination http$1;

    proxy_set_header Destination $destination;

    proxy_read_timeout     300;
    proxy_connect_timeout  5;

    # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
    proxy_http_version 1.1;

    # Remove the Connection header if the client sends it,
    # it could be "close" to close a keepalive connection
    proxy_set_header Connection "";

ssl on;
ssl_certificate /etc/letsencrypt/live/exemple.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/exemple.com/privkey.pem;

include /etc/letsencrypt/options-ssl-nginx.conf;


There is no obligation to use nginx as proxy, apache could very well do the https, but as I bumped into the proxy Destination issue I felt it was worth mentioning it.

| improve this answer | |

This may be worth to read: Another input: multiple user folders and one shared folder http://hexeract.wordpress.com/2011/02/25/configure-a-webdav-enabled-webserver-for-multiple-user-folders-and-one-shared-folder/

| improve this answer | |
  • This has the same problem as your other answer. Some users have ssh access. The files MUST be given correct (their own, not the web server's) unix file permissions and ownership (both user and group). – Philip Couling Oct 20 '14 at 10:49

I used this one as guide to set up webdav: http://bernaerts.dyndns.org/linux/75-debian/62-debian-webdav-share

yes, Apache is the group (www-data under Debian) but you can add users to that group, so I added one user. Did not test why you may not add other users.... The webdav server using in principle this setup runs now for 3 yrs at my and my sons place (so 2 identical servers for the work of my son). Debian 6 is since some months the LTS version (till Feb-2016).

Compared to Bernaerts I adapted in the Apache file: /etc/apache2/sites-available/default this part of configuration.

Alias /webdav1 /data/webdav1

<Location /webdav1>
DAV on
Authtype Basic
Authname "webdav1"
AuthUserFile /var/www/web1/passwd1.dav
Require valid-user

So my files are no longer under www but in /data/webdav1 (through alias webdav1 to keep it short) For each hard disk I've created such a section and webdav1 becomes webdav2 for the 2nd hard disk in that section. We can build in max 10 hard disks in these servers, so 10 of these section in that config file. I added the user to www-data, davfs2 and davfs, so that the user can have access the webdav folder(s). So the user need to login and will be asked for the username and password. In fstab all the webdav data disks are listed so that mounting proceeds automaticallly. That part of fstab:

/dev/sda3 /data/webdav1 ext3, user,auto 0 0

| improve this answer | |
  • 2
    Sadly this doesn't solve the problem at all. The focus of this question was multi user. With this solution new files will be created as the apache user not the logged in user. In order to function apache all files must be www-data group with read / write permissions to that group. Since every user will have to be in that group every user will have to have access to read / write every other user's files. This solution simply doesn't wok for multiple users. – Philip Couling Oct 20 '14 at 10:45

Have you tried OwnCloud? Still just testing it myself, but it sounds like it fills your requirements: webdav works out-of-the-box.

| improve this answer | |
  • 2
    Yes I have an instance of Owncloud but thats not what I'm looking for because the owncloud user (apache) owns all the files. – Philip Couling May 31 '16 at 9:04

I'm also looking for a similar solution.

Solution 1: Your desktop environment (Gnome, KDE) might have widgets to expose a certain folder by WebDAV. This will run as long as your desktop environment is running and is not a daemon solution.

Solution 2: Nothing stops you from running Apache under your own user binding on unprivileged ports above 1024. Just write a configuration file or copy the ones bundled in your distribution to your $HOME/etc/httpd (just an example), add DAV-related config and run it as your own non-root user like:

$ httpd -f $HOME/etc/httpd

Running as your users ensures Apache will create files as you.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.