redirectRegex not working as expected

Hey there, I want to use the nextcloud webdav, I have setup consisting of a raspberry pi 4 with nextcloud on a docker container and traefik as a reverse proxy in between.

I already converted the configuration given in the nextcloud documentation for usage in traefik 2.0.4, but it is not working.

The configcheck under settings/admin/overview is still giving me a warning that "/.well-known/caldav" and "/.well-known/carddav" can not be resolved.
If I call the url "raspberrypi.mydomain.example.com/nc/.well-known/caldav" I get redirected to "https://raspberrypi.mydomain.example.com/remote.php/dav/" and see a 404.

If however I call "https://raspberrypi.mydomain.example.com/nc/remote.php/dav/", I get prompted "This is the WebDAV interface. It can only be accessed by WebDAV clients such as the Nextcloud desktop sync client.".

So there seems to be something wrong with either the regex, or is the "removeServiceSelector" middleware removing the "/nc" from the redirection path? Or something else?

But there seems to be some problem with the regex either way, because when I call "raspberrypi.mydomain.example.com/nc/.well-known/carddav" I get redirected to "https://$1/remote.php/dav/" and not to the url above.

I checked the regex with the suggested https://regex101.com/r/58sIgx/2 but it seems to be fine?

Any Ideas?

The configuration files are:

docker-compose.yml for traefik container

version: "3.1"

networks:
  web:
    external: true

services:

  traefik:
    image: traefik:v2.0.4
    container_name: traefik
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    environment:
      - TZ=Europe/Berlin
      - EXEC_PATH=/etc/traefik/domain_dns
      - DOMAIN_TOKEN=d42d9cd98f00b204e9345998ecf8427e
      - DOMAIN_NAME=mydomain.example.com
    volumes:
      - ./traefik.yml:/etc/traefik/traefik.yml
      - ./dynamic_conf.yml:/etc/traefik/dynamic_conf.yml
      - ./acme.json:/acme.json
      - ./domain_dns:/etc/traefik/domain_dns
    networks:
      - web

docker-compose.yml for service containers

version: "3.1"

networks:
  web:
    external: true
  internal:
    external: false

services:  

  nextcloud:
    image: nextcloud:stable-apache
    volumes:
      - "./nc/data:/var/www/html/data"
      - "./nc/custom_apps:/var/www/html/custom_apps"
      - "./nc/config:/var/www/html/config"
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=somepassword
    networks:
      - internal
      - web

  db:
    image: linuxserver/mariadb:arm32v7-110.4.10mariabionic-ls42
    restart: always
    volumes:
      - "./db:/config"
    env_file:
      - "db.env"
    networks:
      - internal

  adminer:
    image: adminer:4.7.4-standalone
    restart: always
    networks:
      - internal
      - web

traefik.yml

level: DEBUG

serversTransport:
  insecureSkipVerify: true

entryPoints:
  web:
    address: ":80"

  web-secure:
    address: ":443"

api:
  insecure: true
  dashboard: true

providers:
  file:
    filename: "/etc/traefik/dynamic_conf.yml"
    watch: true

certificatesResolvers:
  sample:
    acme:
      email: admin@mydomain.example.com
      storage: acme.json
      dnsChallenge:
        provider: exec
        delayBeforeCheck: 0

dynamic_conf.yml

http:
  routers:
    redirectToHttps:
      entyPoints:
      - web
      service: NeededButNeverUsed
      rule: "HostRegexp(`{host:.+}`)"
      middlewares:
      - httpsredirect
    nextcloud:
      entryPoints:
      - web-secure
      service: nextcloud
      rule: "Host(`raspberrypi.mydomain.example.com`) && PathPrefix(`/nc`)"
      middlewares:
      - redirectDAV
      - removeServiceSelector
      - ncSecHeader
      tls:
        certResolver: sample
    adminer:
      entryPoints:
      - web-secure
      service: adminer
      rule: "Host(`raspberrypi.mydomain.example.com`)  && PathPrefix(`/ad`)"
      middlewares:
      - removeServiceSelector
      tls:
        certResolver: sample

  services:
    NeededButNeverUsed:
      loadBalancer:
        servers:
          - url: "http://192.1.2.3"
    nextcloud:
      loadBalancer:
        servers:
          - url: "http://nextcloud:80/"
    adminer:
      loadBalancer:
        servers:
          - url: "http://adminer:8080/"

  middlewares:
    httpsredirect:
      redirectScheme:
        scheme: https
    removeServiceSelector:
      stripPrefix:
        prefixes:
          - "/nc"
          - "/ad"
        forceSlash: false
    ncSecHeader:
      headers:
        forceSTSHeader: true
        stsPreload: true
        stsSeconds: 15552000
        contentTypeNosniff: true
        browserXssFilter: true
        sslHost: raspberrypi.mydomain.example.com
    redirectDAV:
      redirectRegex:
        regex: "^https://(.*)/.well-known/(card|cal)dav"
        replacement: "https://${1}/remote.php/dav/"
        permanent: true

nextcloud config.php

<?php
$CONFIG = array (
  'htaccess.RewriteBase' => '/',
  'memcache.local' => '\\OC\\Memcache\\APCu',
  'apps_paths' =>
  array (
    0 =>
    array (
      'path' => '/var/www/html/apps',
      'url' => '/apps',
      'writable' => false,
    ),
    1 =>
    array (
      'path' => '/var/www/html/custom_apps',
      'url' => '/custom_apps',
      'writable' => true,
    ),
  ),
  'instanceid' => 'asdfasdfadsf',
  'trusted_domains' =>
  array (
    0 => 'nextcloud:80',
    1 => 'raspberrypi.mydomain.example.com',
  ),
  'trusted_proxies' =>
  array (
    0 => 'traefik',
  ),
  'overwrite.cli.url' => 'https://raspberrypi.mydomain.example.com/nc',
  'overwritehost' => 'raspberrypi.mydomain.example.com',
  'overwritewebroot' => '/nc',
  'overwriteprotocol' => 'https',
  'passwordsalt' => 'asdfasdfasdfasdfasdfasdfasdfas',
  'secret' => 'asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf',
  'datadirectory' => '/var/www/html/data',
  'dbtype' => 'mysql',
  'version' => '16.0.5.1',
  'dbname' => 'nextcloud',
  'dbhost' => 'db',
  'dbport' => '',
  'dbtableprefix' => 'oc_',
  'dbuser' => 'nextcloud',
  'dbpassword' => 'asdfasdfasdf',
  'installed' => true,
  'maintenance' => false,
  'theme' => '',
  'loglevel' => 0,
  'mysql.utf8mb4' => true,
);

In yaml $ is a special character in strings used for variable substitution. You cannot use it as is.

Hey @zespri,
thank you for the reply.

But as I understand the configuration example in the traefik documentation the code under redirectDAV should match the calling domain part and then replace the request with the "replacement" url inserting the first match into the part where "${1}" is standing.

So if I would call raspberrypi.mydomain.example.com/nc/.well-known/caldav it would match on "raspberrypi.mydomain.example.com/nc" and return a request for https://raspberrypi.mydomain.example.com/nc/remote.php/dav/.

Am I wrong?

I noticed that only the “/nc” path is missing from the redirected url to the working https://raspberrypi.mydomain.example.com/nc/remote.php/dav/ my guess is that the removeServiceSelector middleware is removing the /nc part of the url before the redirectDAV middleware is abled to process the called url?

If that would be the case, what configuration would I need to prevent this from happening, but still keep the service selection by path?

Or is it something else?

ok, scratch that it is working… :grinning:

As I tried with a different browser (which had never called raspberrypi.mydomain.example.com/nc/.well-known/caldav before) I suddenly got redirected to the correct url https://raspberrypi.mydomain.example.com/nc/remote.php/dav/ .
I guess that my first tests with a non working redirection were cached in the other browser and never got refreshed/altered afterwards?