.well-known seems to work but still a warning (using Traefik)

Maybe just my 50cents here, also nearly spent 2 days until I digged a bit deeper:

TL;DR;

traefik conifg for a nextcloud accessible in domainname root, e.g. https://mydomain.com/ (not in subpath)

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nextcloud.rule=Host(`$(DOMAINNAME)`)"
      - "traefik.http.routers.nextcloud.entrypoints=https"
      - "traefik.http.routers.nextcloud.tls.certresolver=myresolver"
      - "traefik.http.routers.nextcloud.middlewares=nextcloud-redirectregex1,nextcloud-redirectregex2"
      - "traefik.http.middlewares.nextcloud-redirectregex1.redirectregex.permanent=true"
      - "traefik.http.middlewares.nextcloud-redirectregex1.redirectregex.regex=https?://([^/]*)/.well-known/(card|cal)dav"
      - "traefik.http.middlewares.nextcloud-redirectregex1.redirectregex.replacement=https://$${1}/remote.php/dav/"
      - "traefik.http.middlewares.nextcloud-redirectregex2.redirectregex.permanent=true"
      - "traefik.http.middlewares.nextcloud-redirectregex2.redirectregex.regex=https?://([^/]*)(/.well-known[^#]*)"
      - "traefik.http.middlewares.nextcloud-redirectregex2.redirectregex.replacement=https://$${1}/index.php$${2}"

Why did the issue (maybe) suddenly disappeared, without any (obvious) change?

the requests to webfinger and nodeinfo get cached, so only if you wait until the cached time is over (and a real reload takes place) or if you disable the caching in F12 DevTools you get the real changes.
image

So the caching is maybe a hint here.

How to configure traefik?

For CalDav and CardDav the documentation tells a little bit on how to configure traefik here
Reverse proxy — Nextcloud latest Administration Manual latest documentation, which in labels is already mentioned here:

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nextcloud.rule=Host(`$(DOMAINNAME)`)"
      - "traefik.http.routers.nextcloud.entrypoints=https"
      - "traefik.http.routers.nextcloud.tls.certresolver=myresolver"
      - "traefik.http.routers.nextcloud.middlewares=nextcloud-redirectregex"
      - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.permanent=true"
      - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.regex=https?://(.*)/.well-known/(card|cal)dav"
      - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.replacement=https://$${1}/remote.php/dav/"

unfortunatley for webfinger and nodeinfo nothing is said.

I looked at an nginx example configuration here
https://github.com/nextcloud/docker/blob/211229f8dc1ddbede16f7bb67d4bcada75d6a047/.examples/docker-compose/with-nginx-proxy/mariadb/fpm/web/nginx.conf#L100-L117

this configures the nginx like that:

# 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;
}

the formerly seen traefik labels are for these two lines

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

result for traefik

      - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.permanent=true"
      - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.regex=https?://(.*)/.well-known/(card|cal)dav"
      - "traefik.http.middlewares.nextcloud-redirectregex.redirectregex.replacement=https://$${1}/remote.php/dav/"

but for this part

# 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;

nothing is provided. So in other words the webfinger request to e.g.https://mydomain.com/.well-known/webfinger should be redirected to https://mydomain.com/index.php/.well-known/webfinger

so I added a new middleware

      - "traefik.http.middlewares.nextcloud-redirectregex2.redirectregex.permanent=true"
      - "traefik.http.middlewares.nextcloud-redirectregex2.redirectregex.regex=https?://([^/]*)(/.well-known[^#]*)"
      - "traefik.http.middlewares.nextcloud-redirectregex2.redirectregex.replacement=https://$${1}/index.php$${2}"

The regex is a little bit special and it is essential to understand as otherwise it leads to issues and you get an endless redirect.
my nextcloud is available via https://mydomain.com/ so NO SUB PATH, for sub path the regex needs to be adapted.

What the regex right now does:
https?://([^/]*)(/.well-known[^#]*)

  • the first match group ([^/]*) only matches the host and port information (host [ “:” port ]) - up before the first occurrence of a /
  • the second group (/.well-known[^#]*) matches the full original request URI (with arguments) but without any fragment/comment/anchor, if it starts with /.well-known - this group content is comparable to the nginx.conf variable $request_uri

The second group then gets appended to the new location: https://$${1}/index.php$${2}

Why the first group is so important:
This redirect is different than the one for Cal/CardDav, it appends the magic string /.well-known again, to the new url: https://mydomain.com/index.php/.well-known/webfinger
so the regex needs to ensure that the redirected url is NOT matched again, otherwise you end in an endless redirection loop: https://mydomain.com/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/index.php/.well-known/webfinger

The regex can be tested e.g. here:
regex101: build, test, and debug regex
Sample Urls

  • https://mydomain.com/.well-known/webfinger
  • https://mydomain.com/.well-known/webfinger/longersample
  • https://mydomain.com/.well-known/webfinger#anchor_should_not_match

Full configuration:

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nextcloud.rule=Host(`$(DOMAINNAME)`)"
      - "traefik.http.routers.nextcloud.entrypoints=https"
      - "traefik.http.routers.nextcloud.tls.certresolver=myresolver"
      - "traefik.http.routers.nextcloud.middlewares=nextcloud-redirectregex1,nextcloud-redirectregex2"
      - "traefik.http.middlewares.nextcloud-redirectregex1.redirectregex.permanent=true"
      - "traefik.http.middlewares.nextcloud-redirectregex1.redirectregex.regex=https?://([^/]*)/.well-known/(card|cal)dav"
      - "traefik.http.middlewares.nextcloud-redirectregex1.redirectregex.replacement=https://$${1}/remote.php/dav/"
      - "traefik.http.middlewares.nextcloud-redirectregex2.redirectregex.permanent=true"
      - "traefik.http.middlewares.nextcloud-redirectregex2.redirectregex.regex=https?://([^/]*)(/.well-known[^#]*)"
      - "traefik.http.middlewares.nextcloud-redirectregex2.redirectregex.replacement=https://$${1}/index.php$${2}"

More Details

Uniform Resource Identifiers:
By RFC URIs have been known by many names: WWW addresses, Universal Document Identifiers, Universal Resource Identifiers, and finally the combination of Uniform Resource Locators (URL). As far as HTTP is concerned, Uniform Resource Identifiers are simply formatted strings which identify–via name, location, or any other characteristic–a resource.

Further Sources:
https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2
http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_uri

4 Likes