AIO behind Caddy & Cloudflare: App Password login fails with 401, but main password works

Support Info

  • Nextcloud Server version: 31.0.7.1
  • Operating system and version: Ubuntu 24.04
  • Web server and version: Apache (in AIO Docker container)
  • Reverse proxy and version: Caddy (in Docker container)
  • PHP version: Provided by AIO Docker image
  • Is this the first time you’ve seen this error?: Yes
  • Installation method: AIO (All-in-One) Docker
  • Are you using Cloudflare?: Yes

Hello everyone,

I’m trying to solve a persistent authentication issue with WebDAV clients (like FolderSync Pro on Android) connecting to my self-hosted Nextcloud AIO instance.

The Problem

When trying to connect via WebDAV, the server consistently returns the error: 401: PasswordLoginForbidden.

Key Findings from Diagnostics

After extensive testing using curl, I’ve narrowed down the issue significantly:

  1. ALL Password Logins Fail via WebDAV:

    • Using a newly generated App Password (with 2FA enabled) fails with 401 PasswordLoginForbidden.
    • Using my main user password (with 2FA temporarily disabled) also fails with the exact same 401 PasswordLoginForbidden error.
  2. Web UI Login Works Perfectly:
    I can log in to the Nextcloud web interface at https://cloud.mydomain.com using my main password and 2FA without any issues.

This proves that the problem is not specific to App Passwords but affects all password-based authentication attempts over the WebDAV endpoint.

My Setup

  • Server: Ubuntu 24.04 running the official Nextcloud All-in-One (AIO) in Docker.
  • Reverse Proxy: Caddy in Docker.
  • CDN: Cloudflare.

My Configurations

config.php:
My config.php includes the recommended trusted_proxies settings for both Cloudflare IP ranges and the internal Docker network CIDR. The overwritehost, overwriteprotocol, etc., are also set.

'trusted_proxies' =>
array (
  0 => '172.19.0.0/16', // Local Caddy proxy
  // ... plus all official Cloudflare IP ranges
),
'overwritehost' => 'cloud.mydomain.com',
'overwriteprotocol' => 'https',
// ...

Caddyfile: My Caddyfile is minimal and proxies traffic to the correct AIO container and port.

cloud.mydomain.com {
reverse_proxy nextcloud-aio-apache:11000
redir /.well-known/carddav /remote.php/dav/ 301
redir /.well-known/caldav /remote.php/dav/ 301
}

Cloudflare Settings:
I have confirmed that Bot Fight Mode is OFF. The WAF has no custom rules that should affect this.

My Question
Why would my server reject all password-based WebDAV authentication attempts with a PasswordLoginForbidden error, while the web UI login works perfectly? Given that the trusted_proxies configuration seems correct for a Cloudflare + Caddy setup, is there a known issue or a specific server-side configuration (in Nextcloud, AIO, or Caddy) that I am missing?

Thank you for any help you can provide.

Can you be more specific? Specifically:

  • Are you using an email address to login?
  • What WebDAV URL are you testing against?
  • Can you share the full curl command you’re using?
  • Are you using local accounts?

What appears in your Nextcloud log?

It would also be helpful if you shared your full parsed config (occ config:list system) and app list (occ app:list) as requested in the support template.

Do you have any warnings or errors under Admin settings->Overview?

Hello jtr,

Thank you very much for your follow-up questions. I have gathered all the requested information.

1. Are you using an email address for login?
No, I am using the username admin for login, not an email address.

2. What WebDAV URL are you testing against?
I am testing against the standard WebDAV endpoint for my user:
https://cloud.example.com/remote.php/dav/files/admin/

3. Can you share the full curl command you’re using?
Yes. After further testing, I discovered that both App Password and the main password fail with the same error.

Testing with an App Password (while 2FA is ON):

curl -u "admin:[APP_PASSWORD_HERE]" "https://cloud.example.com/remote.php/dav/files/admin/" -X PROPFIND -H "Depth: 1"
# Result: 401 PasswordLoginForbidden

Use code with caution.

Testing with my main password (with 2FA temporarily OFF):

Generated bash

curl -u "admin:[MY_MAIN_PASSWORD]" "https://cloud.example.com/remote.php/dav/files/admin/" -X PROPFIND -H "Depth: 1"
# Result: 401 PasswordLoginForbidden

This confirms the issue is not specific to App Passwords but affects all password-based WebDAV authentication.

4. Are you using local accounts?
Yes, this is a standard Nextcloud AIO installation with local user accounts. I am not using any external authentication backend like LDAP or SAML.

5. What appears in your Nextcloud log?
This is a key point. When I tailed the logs of the nextcloud-aio-apache container (sudo docker logs -f nextcloud-aio-apache), absolutely no new log entries appeared during the failed WebDAV attempts. The request does, however, appear in my Caddy logs with a 401 status code returned from the upstream (Nextcloud).

6. Do you have any warnings or errors under Admin settings->Overview?
No, there are no warnings or errors displayed. Everything shows as “All checks passed”.

Here is the additional information you requested:

occ app:list output:

Enabled:
  - activity: 4.0.0
  - admin_audit: 1.21.0
  - bruteforcesettings: 4.0.0
  - calendar: 5.3.8
  - circles: 31.0.0
  - cloud_federation_api: 1.14.0
  - comments: 1.21.0
  - contacts: 7.2.3
  - contactsinteraction: 1.12.0
  - dashboard: 7.11.0
  - dav: 1.33.0
  - deck: 1.15.2
  - federatedfilesharing: 1.21.0
  - federation: 1.21.0
  - files: 2.3.1
  - files_downloadlimit: 4.0.0
  - files_fulltextsearch: 31.0.0
  - files_pdfviewer: 4.0.0
  - files_reminders: 1.4.0
  - files_sharing: 1.23.1
  - files_trashbin: 1.21.0
  - files_versions: 1.24.0
  - firstrunwizard: 4.0.0
  - fulltextsearch: 31.0.0
  - fulltextsearch_elasticsearch: 31.0.0
  - logreader: 4.0.0
  - lookup_server_connector: 1.19.0
  - nextcloud-aio: 0.8.0
  - nextcloud_announcements: 3.0.0
  - notes: 4.12.2
  - notifications: 4.0.0
  - notify_push: 1.1.0
  - oauth2: 1.19.1
  - password_policy: 3.0.0
  - photos: 4.0.0
  - privacy: 3.0.0
  - profile: 1.0.0
  - provisioning_api: 1.21.0
  - recommendations: 4.0.0
  - related_resources: 2.0.0
  - serverinfo: 3.0.0
  - settings: 1.14.0
  - sharebymail: 1.21.0
  - support: 3.0.0
  - survey_client: 3.0.0
  - systemtags: 1.21.1
  - tasks: 0.16.1
  - text: 5.0.0
  - theming: 2.6.1
  - twofactor_backupcodes: 1.20.0
  - twofactor_totp: 13.0.0-dev.0
  - updatenotification: 1.21.0
  - user_status: 1.11.0
  - viewer: 4.0.0
  - weather_status: 1.11.0
  - webhook_listeners: 1.2.0
  - workflowengine: 2.13.0
Disabled:
  - app_api: 5.0.2 (installed 5.0.2)
  - encryption: 2.19.0
  - files_external: 1.23.0
  - suspicious_login: 9.0.1
  - twofactor_nextcloud_notification: 5.0.0
  - user_ldap: 1.22.0

occ config:list system output:

{
    "system": {
        "one-click-instance": true,
        "one-click-instance.user-limit": 100,
        "memcache.local": "\\OC\\Memcache\\APCu",
        "apps_paths": [
            {
                "path": "/var/www/html/apps",
                "url": "/apps",
                "writable": false
            },
            {
                "path": "/var/www/html/custom_apps",
                "url": "/custom_apps",
                "writable": true
            }
        ],
        "check_data_directory_permissions": false,
        "memcache.distributed": "\\OC\\Memcache\\Redis",
        "memcache.locking": "\\OC\\Memcache\\Redis",
        "redis": {
            "host": "***REMOVED SENSITIVE VALUE***",
            "password": "***REMOVED SENSITIVE VALUE***",
            "port": 6379
        },
        "passwordsalt": "***REMOVED SENSITIVE VALUE***",
        "secret": "***REMOVED SENSITIVE VALUE***",
        "trusted_domains": [
            "localhost",
            "cloud.example.com"
        ],
        "datadirectory": "***REMOVED SENSITIVE VALUE***",
        "dbtype": "pgsql",
        "version": "31.0.7.1",
        "dbname": "***REMOVED SENSITIVE VALUE***",
        "dbhost": "***REMOVED SENSITIVE VALUE***",
        "dbport": "",
        "dbtableprefix": "oc_",
        "dbuser": "***REMOVED SENSITIVE VALUE***",
        "dbpassword": "***REMOVED SENSITIVE VALUE***",
        "installed": true,
        "instanceid": "***REMOVED SENSITIVE VALUE***",
        "maintenance": false,
        "updatedirectory": "/nc-updater",
        "loglevel": 2,
        "app_install_overwrite": [
            "nextcloud-aio"
        ],
        "log_type": "file",
        "logfile": "/var/www/html/data/nextcloud.log",
        "log_rotate_size": 10485760,
        "log.condition": {
            "apps": [
                "admin_audit"
            ]
        },
        "preview_max_x": 2048,
        "preview_max_y": 2048,
        "jpeg_quality": 60,
        "enabledPreviewProviders": {
            "1": "OC\\Preview\\Image",
            "2": "OC\\Preview\\MarkDown",
            "3": "OC\\Preview\\MP3",
            "4": "OC\\Preview\\TXT",
            "5": "OC\\Preview\\OpenDocument",
            "6": "OC\\Preview\\Movie",
            "7": "OC\\Preview\\Krita",
            "0": "OC\\Preview\\Imaginary",
            "23": "OC\\Preview\\ImaginaryPDF"
        },
        "enable_previews": true,
        "upgrade.disable-web": true,
        "mail_smtpmode": "smtp",
        "trashbin_retention_obligation": "auto, 30",
        "versions_retention_obligation": "auto, 30",
        "activity_expire_days": 30,
        "simpleSignUpLink.shown": false,
        "share_folder": "/Shared",
        "one-click-instance.link": "https://nextcloud.com/all-in-one/",
        "upgrade.cli-upgrade-link": "https://github.com/nextcloud/all-in-one/discussions/2726",
        "maintenance_window_start": 100,
        "allow_local_remote_servers": true,
        "davstorage.request_timeout": 3600,
        "documentation_url.server_logs": "https://github.com/nextcloud/all-in-one/discussions/5425",
        "htaccess.RewriteBase": "/",
        "dbpersistent": false,
        "auth.bruteforce.protection.enabled": true,
        "ratelimit.protection.enabled": true,
        "files_external_allow_create_new_local": false,
        "preview_imaginary_url": "***REMOVED SENSITIVE VALUE***",
        "preview_imaginary_key": "***REMOVED SENSITIVE VALUE***",
        "updatechecker": false,
        "trusted_proxies": "***REMOVED SENSITIVE VALUE***",
        "overwritehost": "cloud.example.com",
        "overwriteprotocol": "https",
        "overwritewebroot": "/",
        "overwrite.cli.url": "https://cloud.example.com/",
        "forwarded_for_headers": [
            "HTTP_X_FORWARDED_FOR",
            "HTTP_CF_CONNECTING_IP"
        ]
    }
}

Please check the Nextcloud log (nextcloud.log) in the nextcloud-aio-nextcloud container (note: not the actual container log) and/or via Admin settings->Logging.

If possible I’d suggest bypassing Cloudflare to eliminate a variable too.

After extensive troubleshooting, I found and fixed the root cause of the WebDAV authentication issue.

The Problem:
WebDAV clients (like FolderSync Pro) were getting 401 PasswordLoginForbidden errors when trying to connect, even though the web UI worked perfectly with the same credentials.

Root Cause:
The issue was with trusted_proxies configuration. My setup has:

  • Caddy running in Docker network: proxy-network (172.18.0.0/16)
  • Nextcloud AIO running in Docker network: nextcloud-aio (172.19.0.0/16)

Nextcloud’s trusted_proxies only included its own network (172.19.0.0/16) but was missing the Caddy network (172.18.0.0/16). This broke the trust chain, causing Nextcloud to see
all requests as coming from an untrusted proxy IP.

The Solution:
Added the missing Caddy network to trusted_proxies:

docker exec --user www-data nextcloud-aio-nextcloud php occ config:system:set trusted_proxies 3 --value=“172.18.0.0/16”

Final trusted_proxies configuration:
127.0.0.1 # Loopback
::1 # IPv6 loopback
172.19.0.0/16 # Nextcloud AIO network
172.18.0.0/16 # Caddy proxy network ← ADDED THIS

Verification:

  • Before fix: curl returned PasswordLoginForbidden
  • After fix: curl returns normal 401 Basic realm=“Nextcloud” (correct behavior)
  • WebDAV clients: Now authenticate successfully with app passwords

Key Takeaway:
When using multiple Docker networks in a proxy chain, all intermediate proxy networks must be included in trusted_proxies, not just the application’s own network.

The fix was simple once identified - just one missing CIDR range in the trusted proxies configuration!

Thank you so much for your help and suggestions!

I’ve successfully resolved the issue. The problem was indeed related to the proxy chain as you suspected. It turned out to be a trusted_proxies configuration issue.

The root cause was that my Nextcloud AIO trusted_proxies included its own Docker network (172.19.0.0/16) but was missing the Caddy proxy network (172.18.0.0/16). This broke the
trust chain, causing Nextcloud to reject WebDAV authentication attempts.

The fix was simple - adding the missing Caddy network:
docker exec --user www-data nextcloud-aio-nextcloud php occ config:system:set trusted_proxies 3 --value=“172.18.0.0/16”

Your suggestion to check the Nextcloud logs and the observation about the 401 appearing in Caddy logs but not Apache logs really helped point me in the right direction. The issue
was happening at the Nextcloud application level before it even reached Apache logging.

WebDAV authentication now works perfectly with FolderSync Pro and app passwords!

Thanks again for taking the time to help troubleshoot this tricky issue. :+1: