Can't login through webdav on nginx

EDIT
Nextcloud builds its own Webdav implementation, Sabredav.

Could it be the following nginx modules be interfering? --with-http_dav_module --add-module=/var/tmp/nginx-dav-ext-module

Someone knows how should I compile them dynamically? So i’m able to load/unload on runtime per virtual host config?

Thx :slight_smile:
EDIT END

I’m running Ubuntu server 20.04 on a personal server where I deployed a manual install of Nextcloud which is up and running properly except for webdav.

The whole thing is running under nginx 1.19.3, php-8.0 and FPM.

Trying to mount nextcloud private directory through davfs:

# mount -t davfs https://drive.example.com/remote.php/dav/files/myuser/ /mnt
Please enter the username to authenticate with server
https://drive.example.com/remote.php/dav/files/myuser/ or hit enter for none.
  Username: myuser
Please enter the password to authenticate user myuser with server
https://drive.example.com/remote.php/dav/files/myuser/ or hit enter for none.
  Password:
/sbin/mount.davfs: Mounting failed.
Could not authenticate to server: rejected Basic challenge

Nextcloud logs related to the previous mount command:

# cat /home/nginx/Tools/nextcloud_data/nextcloud.log
{"reqId":"gf8ZgEQVDV7AoHp667YG","level":2,"time":"2022-04-05T17:50:58+00:00","remoteAddr":"x.y.z.w","user":"--","app":"core","method":"OPTIONS","url":"/remote.php/dav/files/myuser/","message":"Login failed: 'myuser' (Remote IP: 'x.y.z.w')","userAgent":"davfs2/1.5.5 neon/0.30.2","version":"23.0.3.2"}

Nginx logs related to the previous mount command:

# cat /var/log/nginx/nextcloud.log
x.y.z.w drive.example.com - [05/Apr/2022:13:53:31 -0400] "OPTIONS /remote.php/dav/files/myuser/ HTTP/1.1" 401 569 "-" "davfs2/1.5.5 neon/0.30.2" "-" "-"
x.y.z.w drive.example.com myuser [05/Apr/2022:13:53:57 -0400] "OPTIONS /remote.php/dav/files/myuser/ HTTP/1.1" 401 427 "-" "davfs2/1.5.5 neon/0.30.2" "-" "Basic CRYPTED_PASSWORD"

Some irrelevant Ubuntu info:

# lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.4 LTS
Release:	20.04
Codename:	focal

# uname -a
Linux host.example.com 5.4.0-107-generic #121-Ubuntu SMP Thu Mar 24 16:04:27 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Nginx has been downloaded and compiled from source form nginx official repo and through apt:

# apt source nginx
# cd nginx-0.8.54
# edit debian/rules
# dpkg-buildpackage -b nginx

Nginx version, features and compilation parameters:

# nginx -vV
nginx version: nginx/1.19.3
built by gcc 9.3.0 (Ubuntu 9.3.0-10ubuntu2)
built with OpenSSL 1.1.1g  21 Apr 2020
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fdebug-prefix-map=/var/tmp/nginx-1.19.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' --add-dynamic-module=/var/tmp/ngx_http_geoip2_module --with-http_geoip_module --with-http_dav_module --add-module=/var/tmp/nginx-dav-ext-module --without-mail_imap_module --without-mail_pop3_module --without-mail_smtp_module --without-http_limit_conn_module --add-module=/var/tmp/incubator-pagespeed-ngx-1.13.35.2-stable/ --add-module=/home/nginx/Tools/openproject/.rbenv/versions/2.6.1//lib/ruby/gems/2.6.0//gems/passenger-6.0.6/src/nginx_module/

PHP info:

# php8.0 --version
PHP 8.0.15 (cli) (built: Jan 29 2022 07:24:52) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.15, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.15, Copyright (c), by Zend Technologies


# php8.0 -m
[PHP Modules]
apcu
bcmath
bz2
calendar
Core
ctype
curl
date
dom
exif
FFI
fileinfo
filter
ftp
gd
gettext
gmp
hash
iconv
igbinary
imagick
intl
json
libxml
mbstring
memcache
mongodb
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
pspell
readline
redis
Reflection
session
shmop
SimpleXML
soap
sockets
sodium
SPL
sqlite3
standard
sysvmsg
sysvsem
sysvshm
tokenizer
xml
xmlreader
xmlrpc
xmlwriter
xsl
Zend OPcache
zip
zlib

[Zend Modules]
Zend OPcache

Nextcloud info:

# sudo -u nginx php8.0 /home/nginx/Tools/nextcloud/occ status
  - installed: true
  - version: 23.0.3.2
  - versionstring: 23.0.3
  - edition:
  - maintenance: false
  - needsDbUpgrade: false
  - productname: Nextcloud
  - extendedSupport: false

Nginx virtual host file:

# cat /etc/nginx/sites-enabled/nextcloud.conf

cat /etc/nginx/sites-enabled/nextcloud.conf
upstream php-handler {
    server unix:/var/run/php/php8.0-fpm.sock;
}

# Set the `immutable` cache control options only for assets with a cache busting `v` argument
map $arg_v $asset_immutable {
    "" "";
    default "immutable";
}

server {
    listen 80;
    listen [::]:80;
    server_name drive.foobar.es drive.foobar.com cloud.foobar.es cloud.foobar.com cloud.example.es cloud.example.com cloud.example.net cloud.example.org cloud.example.info drive.example.es drive.example.com drive.example.org drive.example.net drive.example.info drive.example.cat cloud.example.cat;

    access_log	/var/log/nginx/nextcloud.access.log main;
    error_log	/var/log/nginx/nextcloud.error.log crit;

    return 301 https://$host$request_uri;
#    return 302 https://$host$request_uri;
}

server {
    listen		443 ssl http2;
    listen		[::]:443 ssl http2;
    server_name		drive.foobar.es drive.foobar.com cloud.foobar.es cloud.foobar.com cloud.example.es cloud.example.com cloud.example.net cloud.example.org cloud.example.info drive.example.es drive.example.com drive.example.org drive.example.net drive.example.info drive.example.cat cloud.example.cat;

    ssl_certificate		/etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key		/etc/letsencrypt/live/example.com/privkey.pem;
    include			/etc/nginx/conf.d-enabled/ssl-security.conf;
    ssl_trusted_certificate	/etc/letsencrypt/live/example.es/cert.pem;

    access_log			/var/log/nginx/nextcloud_ssl.access.log main;
    error_log			/var/log/nginx/nextcloud_ssl.error.log crit;

    # Codi per habilitar la renovació dels certificats Letsencrypt
    include /etc/nginx/snippets/letsencrypt-cert-renewal-dir.conf;

    if ($http_host != "drive.example.com" ) {
	rewrite ^ https://drive.example.com$request_uri permanent;
	break;
    }

    # HSTS settings
    # WARNING: Only add the preload option once you read about
    # the consequences in hstspreload.org. This option
    # will add the domain to a hardcoded list that is shipped
    # in all major browsers and getting removed from this list
    # could take several months.
    #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Make a regex exception for `/.well-known` so that clients can still
    # access it despite the existence of the regex rule
    # `location ~ /(\.|autotest|...)` which would otherwise handle requests
    # for `/.well-known`.
    location ^~ /.well-known {
        # The rules in this block are an adaptation of the rules
        # in `.htaccess` that concern `/.well-known`.

        location = /.well-known/carddav { return 301 /remote.php/dav/; }
        location = /.well-known/caldav  { return 301 /remote.php/dav/; }

        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
        location /.well-known/pki-validation    { try_files $uri $uri/ =404; }

        # Let Nextcloud's API for `/.well-known` URIs handle all other
        # requests by passing them to the front-end controller.
        return 301 /index.php$request_uri;
    }

#location ^~ / {
    # set max upload size and increase upload timeout:
    client_max_body_size 50G;
    client_body_timeout 300s;
    fastcgi_buffers 64 4K;

    client_body_temp_path /home/nginx/Tools/nextcloud_data/tmp/;
    fastcgi_param PHP_VALUE "upload_tmp_dir=/home/nginx/Tools/nextcloud_data/tmp/;";
    fastcgi_param PHP_VALUE "output_buffering=0;";
    add_header X-Accel-Buffering no;

    # Because php-fpm can’t read PHP settings in .htaccess these settings
    # must be set in the nextcloud/.user.ini
    # fastcgi_param PHP_VALUE "upload_max_filesize=5M;\n error_reporting=E_ALL;";
    fastcgi_param PHP_VALUE "upload_max_filesize=50G;";
    fastcgi_param PHP_VALUE "post_max_size=50G;";
    fastcgi_param PHP_VALUE "max_input_time=4600;";
    fastcgi_param PHP_VALUE "max_execution_time=3600;";
    fastcgi_param PHP_VALUE "request_terminate_timeout=3600;";
    fastcgi_read_timeout 3600;

    # Enable gzip but do not remove ETag headers
    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

    # Pagespeed is not supported by Nextcloud, so if your server is built
    # with the `ngx_pagespeed` module, uncomment this line to disable it.
    pagespeed off;

    # HTTP response headers borrowed from Nextcloud `.htaccess`
    add_header Referrer-Policy                      "no-referrer"   always;
    add_header X-Content-Type-Options               "nosniff"       always;
    add_header X-Download-Options                   "noopen"        always;
    add_header X-Frame-Options                      "SAMEORIGIN"    always;
    add_header X-Permitted-Cross-Domain-Policies    "none"          always;
    add_header X-Robots-Tag                         "none"          always;
    add_header X-XSS-Protection                     "1; mode=block" always;

    # Remove X-Powered-By, which is an information leak
    fastcgi_hide_header X-Powered-By;

    # Path to the root of your installation
    root /home/nginx/Tools/nextcloud/;

    # Specify how to handle directories -- specifying `/index.php$request_uri`
    # here as the fallback means that Nginx always exhibits the desired behaviour
    # when a client requests a path that corresponds to a directory that exists
    # on the server. In particular, if that directory contains an index.php file,
    # that file is correctly served; if it doesn't, then the request is passed to
    # the front-end controller. This consistent behaviour means that we don't need
    # to specify custom rules for certain paths (e.g. images and other assets,
    # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
    # `try_files $uri $uri/ /index.php$request_uri`
    # always provides the desired behaviour.
    index index.php index.html /index.php$request_uri;

    # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
    location = / {
        if ( $http_user_agent ~ ^DavClnt ) {
            return 302 /remote.php/webdav/$is_args$args;
        }
    }

    # Rules borrowed from `.htaccess` to hide certain paths from clients
    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; }

    # Ensure this block, which passes PHP files to the PHP process, is above the blocks
    # which handle static assets (as seen below). If this block is not declared first,
    # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
    # to the URI, resulting in a HTTP 500 error response.
    location ~ \.php(?:$|/) {
        # Required for legacy support
        rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;

        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        set $path_info $fastcgi_path_info;

        try_files $fastcgi_script_name =404;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_param HTTPS on;

        fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
        fastcgi_param front_controller_active true;     # Enable pretty urls
        fastcgi_pass php-handler;

        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;

        fastcgi_max_temp_file_size 0;
    }

   location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite|map)$ {
        try_files $uri /index.php$request_uri;
        add_header Cache-Control "public, max-age=15778463, $asset_immutable";
        access_log off;     # Optional: Don't log access to assets

        location ~ \.wasm$ {
            default_type application/wasm;
        }
    }

    location ~ \.woff2?$ {
        try_files $uri /index.php$request_uri;
        expires 7d;         # Cache-Control policy borrowed from `.htaccess`
        access_log off;     # Optional: Don't log access to assets
    }

    # Suppressing log messages
    # If you’re seeing meaningless messages in your logfile, for example client denied by server configuration: /var/www/data/htaccesstest.txt, add this section to your nginx configuration to suppress them:
    location = /data/htaccesstest.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Rule borrowed from `.htaccess`
    location /remote {
        return 301 /remote.php$request_uri;
    }

    location / {
        try_files $uri $uri/ /index.php$request_uri;
    }
#}
}

Nginx SSL config file included in nginx virtual host config file:

# cat /etc/nginx/conf.d-enabled/ssl-security.conf
  # enable session resumption to improve https performance
  # vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077.html
  ssl_session_cache shared:SSL:50m;
  ssl_session_timeout 1d;
  ssl_session_tickets off;

  # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
  #ssl_dhparam /etc/ssl/certs/dhparam.pem;
  # openssl dhparam -dsaparam -out /etc/ssl/private/dhparam.pem 4096
  ssl_dhparam /etc/ssl/certs/dhparam4096.pem;

  # enables server-side protection from BEAST attacks
  # blog.ivanristic.com/2013/09/is-beast-still-a-threat.html
  ssl_prefer_server_ciphers on;

  # disable SSLv3(enabled by default since nginx 0.8.19) since it's less secure then TLS en.wikipedia.org/wiki/Secure_Sockets_Layer#SSL_3.0
  # Disabled protocols: TLSv1 TLSv1.1
  ssl_protocols SSLv3 TLSv1.2 TLSv1.3;
#  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

  # ciphers chosen for forward secrecy and compatibility
  # blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html
  ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';

  # enable ocsp stapling (mechanism by which a site can convey certificate revocation information to visitors in a privacy-preserving, scalable manner)
  # blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox/
  resolver 8.8.8.8 8.8.4.4;
  ssl_stapling on;
  ssl_stapling_verify on;
#  ssl_trusted_certificate /etc/nginx/ssl/star_forgott_com.crt;

  # config to enable HSTS(HTTP Strict Transport Security) developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
  # to avoid ssl stripping en.wikipedia.org/wiki/SSL_stripping#SSL_stripping
  # also hstspreload.org/
  add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload";

# cat /etc/nginx/fastcgi
fastcgi.conf              fastcgi_params            fastcgi_params.dpkg-dist
root@we:~# cat /etc/nginx/fastcgi_params
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

### SET GEOIP Variables ###
fastcgi_param GEOIP_COUNTRY_CODE $geoip_country_code;
fastcgi_param GEOIP_COUNTRY_CODE3 $geoip_country_code3;
fastcgi_param GEOIP_COUNTRY_NAME $geoip_country_name;

fastcgi_param GEOIP_CITY_COUNTRY_CODE $geoip_city_country_code;
fastcgi_param GEOIP_CITY_COUNTRY_CODE3 $geoip_city_country_code3;
fastcgi_param GEOIP_CITY_COUNTRY_NAME $geoip_city_country_name;
fastcgi_param GEOIP_REGION $geoip_region;
fastcgi_param GEOIP_CITY $geoip_city;
fastcgi_param GEOIP_POSTAL_CODE $geoip_postal_code;
fastcgi_param GEOIP_CITY_CONTINENT_CODE $geoip_city_continent_code;
fastcgi_param GEOIP_LATITUDE $geoip_latitude;
fastcgi_param GEOIP_LONGITUDE $geoip_longitude;

Thanks you so much in advanced.

Hope someone can help :slight_smile:

Compiling nginx without ngx_http_dav_ext module fixed the issue. Also, compiling nginx with the module as a dynamic one, also worked.