[v2] BasicAuth not working with docker image or custom build

1. Caddy version (caddy version):

2.0.0 docker builder with webdav plugin

2. How I run Caddy:

Running using docker/docker-compose, from a Caddy builder image.

a. System environment:

Debian 10, Docker 19.03.12, Docker-Compose 1.26.0

b. Command:

To build docker image: docker build --tag caddy:2.0.0-custom .
To run docker-compose: docker-compose up -d caddy

c. Service/unit/compose file:

Dockerfile to build image:

FROM caddy:2.0.0-builder AS builder

RUN caddy-builder \
    github.com/mholt/caddy-webdav

FROM caddy:2.0.0

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

docker-compose.yml:

version: '3.4'

services:
# Caddy web server, doing reverse proxy
  caddy:
    image: "caddy:2.0.0-custom"
    container_name: "caddy"
    ports:
     - "80:80"
     - "443:443"
    volumes:
     - /srv/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
     - /srv/caddy/www:/usr/share/caddy:rw
     - /srv/caddy/data:/data:rw
    restart: always

d. My complete Caddyfile or JSON config:

The basicauth password is hiccup, I copied it from the documentation for testing.

{
    order webdav last
}

(global) {
  encode gzip zstd
  log {
    output file /data/logs/caddy_access.log
  }
  handle_errors /data/logs/caddy_errors.log
  php_fastcgi phpfpm:9000
}

http://dav.homelab.zt {
  import global

  basicauth /* {
    secureguy JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
  }

  webdav / {
    root /usr/share/caddy/webdav
  }

  header {
    Access-Control-Allow-Origin *
    Access-Control-Allow-Credentials true
    Access-Control-Allow-Methods GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK
    Access-Control-Allow-Headers Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite
    Access-Control-Expose-Headers ETag
    Access-Control-Max-Age 1728000
  }
}

http://static.homelab.zt {
  import global

  root * /usr/share/caddy/static
  file_server /* browse

  basicauth /* {
    secureguy JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
  }
}

3. The problem I’m having:

I ran a docker builder to add the webdav plugin, and while doing testing with converting my v1 config to v2 I ran across the issue that basicauth isn’t working. Firefox and Chrome headers show Www-Authenticate: Basic realm="restricted", but I’m not getting any credentials request. If I take the basicauth directive out of the my static.homelab.zt or dav.homelab.zt, I get the file browser from static and XML output from dav. Also, if I change the order webdav last to order webdav first, then I get XML output from dav and still no basicauth request (which makes sense since I am running webdav directive before the basicauth).

4. Error messages and/or full log output:

Access.log when I tried to access http://dav.homelab.zt from Firefox

{"level":"info","ts":1593117167.841527,"logger":"http.log.access.log0",
"msg":"handled request","request":{"method":"GET","uri":"/","proto":"HTTP/1.1",
"remote_addr":"172.25.163.57:41254","host":"dav.homelab.zt",
"headers":{"User-Agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0"],
"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"],
"Accept-Language":["en-US,en;q=0.5"],"Accept-Encoding":["gzip, deflate"],
"Connection":["keep-alive"],"Upgrade-Insecure-Requests":["1"]}},
"common_log":"172.25.163.57 - - [25/Jun/2020:20:32:47 +0000] \"GET / HTTP/1.1\" 0 0",
"duration":0.000083627,"size":0,"status":0,"resp_headers":{"Access-Control-Expose-Headers":["ETag"],
"Access-Control-Max-Age":["1728000"],"LOCK,":["UNLOCK"],
"Www-Authenticate":["Basic realm=\"restricted\""],"Server":["Caddy"],
"Access-Control-Allow-Credentials":["true"],
"Access-Control-Allow-Headers":["Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite"],
"Access-Control-Allow-Origin":["*"]}}

5. What I already tried:

If I remove the basicauth directive, I get an XML response from my WebDAV site and a file browser from the Static File_Server site.

If I add basicauth directive, I just get a white blank page. The log above is from basicauth being added.

I changed my docker-compose to use the Docker Hub caddy:2.0.0 instead of my custom build, and I adjusted my Caddyfile to remove the webdav site and order directive. My static site still will not work with the basicauth directive.

6. Links to relevant resources:

https://hub.docker.com/_/caddy


Path matching in Caddy v2 is exact-match. webdav / will only match requests to / and nothing else. Just remove the /. Also, /* is redundant, just remove those as well. Omitting the matcher will default to * anyways, which means “all requests”.

So I removed the matchers and reloaded caddy. It appears to have the same issue. Man, I hoped it was going to be that simple.

Caddyfile:

{
    order webdav last
}

(global) {
  encode gzip zstd
  log {
    output file /data/logs/caddy_access.log
  }
  handle_errors /data/logs/caddy_errors.log
  php_fastcgi phpfpm:9000
}

http://dav.homelab.zt {
  import global

  basicauth {
    secureguy JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
  }

  webdav {
    root /usr/share/caddy/webdav
  }

  header {
    Access-Control-Allow-Origin *
    Access-Control-Allow-Credentials true
    Access-Control-Allow-Methods GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK
    Access-Control-Allow-Headers Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite
    Access-Control-Expose-Headers ETag
    Access-Control-Max-Age 1728000
  }
}

http://kee.homelab.zt {
  import global
  root * /usr/share/caddy/html
  file_server /*
}

http://static.homelab.zt {
  import global

  root * /usr/share/caddy/static
  file_server /* browse

   basicauth {
     secureguy JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
   }
}

Log output formatted with jq:

{
  "level": "info",
  "ts": 1593179004.5176988,
  "logger": "http.log.access.log0",
  "msg": "handled request",
  "request": {
    "method": "GET",
    "uri": "/",
    "proto": "HTTP/1.1",
    "remote_addr": "172.25.163.57:2950",
    "host": "dav.homelab.zt",
    "headers": {
      "User-Agent": [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0"
      ],
      "Accept": [
        "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
      ],
      "Accept-Language": [
        "en-US,en;q=0.5"
      ],
      "Accept-Encoding": [
        "gzip, deflate"
      ],
      "Connection": [
        "keep-alive"
      ],
      "Upgrade-Insecure-Requests": [
        "1"
      ]
    }
  },
  "common_log": "172.25.163.57 - - [26/Jun/2020:13:43:24 +0000] \"GET / HTTP/1.1\" 0 0",
  "duration": 9.9787e-05,
  "size": 0,
  "status": 0,
  "resp_headers": {
    "Access-Control-Allow-Credentials": [
      "true"
    ],
    "Www-Authenticate": [
      "Basic realm=\"restricted\""
    ],
    "Server": [
      "Caddy"
    ],
    "Access-Control-Allow-Headers": [
      "Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite"
    ],
    "Access-Control-Allow-Origin": [
      "*"
    ],
    "Access-Control-Expose-Headers": [
      "ETag"
    ],
    "Access-Control-Max-Age": [
      "1728000"
    ],
    "LOCK,": [
      "UNLOCK"
    ]
  }
}
{
  "level": "info",
  "ts": 1593179005.0896335,
  "logger": "http.log.access.log0",
  "msg": "handled request",
  "request": {
    "method": "GET",
    "uri": "/favicon.ico",
    "proto": "HTTP/1.1",
    "remote_addr": "172.25.163.57:2950",
    "host": "dav.homelab.zt",
    "headers": {
      "Accept-Language": [
        "en-US,en;q=0.5"
      ],
      "Accept-Encoding": [
        "gzip, deflate"
      ],
      "Connection": [
        "keep-alive"
      ],
      "User-Agent": [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0"
      ],
      "Accept": [
        "image/webp,*/*"
      ]
    }
  },
  "common_log": "172.25.163.57 - - [26/Jun/2020:13:43:25 +0000] \"GET /favicon.ico HTTP/1.1\" 0 0",
  "duration": 9.9685e-05,
  "size": 0,
  "status": 0,
  "resp_headers": {
    "LOCK,": [
      "UNLOCK"
    ],
    "Www-Authenticate": [
      "Basic realm=\"restricted\""
    ],
    "Server": [
      "Caddy"
    ],
    "Access-Control-Allow-Credentials": [
      "true"
    ],
    "Access-Control-Allow-Headers": [
      "Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite"
    ],
    "Access-Control-Allow-Origin": [
      "*"
    ],
    "Access-Control-Expose-Headers": [
      "ETag"
    ],
    "Access-Control-Max-Age": [
      "1728000"
    ]
  }
}
{
  "level": "info",
  "ts": 1593179006.9676456,
  "logger": "http.log.access.log0",
  "msg": "handled request",
  "request": {
    "method": "GET",
    "uri": "/",
    "proto": "HTTP/1.1",
    "remote_addr": "172.25.163.57:2956",
    "host": "dav.homelab.zt",
    "headers": {
      "Accept-Language": [
        "en-US,en;q=0.5"
      ],
      "Accept-Encoding": [
        "gzip, deflate"
      ],
      "Connection": [
        "keep-alive"
      ],
      "Upgrade-Insecure-Requests": [
        "1"
      ],
      "Cache-Control": [
        "max-age=0"
      ],
      "User-Agent": [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0"
      ],
      "Accept": [
        "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
      ]
    }
  },
  "common_log": "172.25.163.57 - - [26/Jun/2020:13:43:26 +0000] \"GET / HTTP/1.1\" 0 0",
  "duration": 8.1097e-05,
  "size": 0,
  "status": 0,
  "resp_headers": {
    "Access-Control-Allow-Origin": [
      "*"
    ],
    "Access-Control-Expose-Headers": [
      "ETag"
    ],
    "Access-Control-Max-Age": [
      "1728000"
    ],
    "LOCK,": [
      "UNLOCK"
    ],
    "Access-Control-Allow-Credentials": [
      "true"
    ],
    "Www-Authenticate": [
      "Basic realm=\"restricted\""
    ],
    "Server": [
      "Caddy"
    ],
    "Access-Control-Allow-Headers": [
      "Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite"
    ]
  }
}
{
  "level": "info",
  "ts": 1593179007.5720232,
  "logger": "http.log.access.log0",
  "msg": "handled request",
  "request": {
    "method": "GET",
    "uri": "/",
    "proto": "HTTP/1.1",
    "remote_addr": "172.25.163.57:2956",
    "host": "dav.homelab.zt",
    "headers": {
      "Upgrade-Insecure-Requests": [
        "1"
      ],
      "Cache-Control": [
        "max-age=0"
      ],
      "User-Agent": [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:77.0) Gecko/20100101 Firefox/77.0"
      ],
      "Accept": [
        "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
      ],
      "Accept-Language": [
        "en-US,en;q=0.5"
      ],
      "Accept-Encoding": [
        "gzip, deflate"
      ],
      "Connection": [
        "keep-alive"
      ]
    }
  },
  "common_log": "172.25.163.57 - - [26/Jun/2020:13:43:27 +0000] \"GET / HTTP/1.1\" 0 0",
  "duration": 9.8153e-05,
  "size": 0,
  "status": 0,
  "resp_headers": {
    "Access-Control-Allow-Credentials": [
      "true"
    ],
    "Access-Control-Allow-Headers": [
      "Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite"
    ],
    "Access-Control-Allow-Origin": [
      "*"
    ],
    "Access-Control-Expose-Headers": [
      "ETag"
    ],
    "Access-Control-Max-Age": [
      "1728000"
    ],
    "Www-Authenticate": [
      "Basic realm=\"restricted\""
    ],
    "Server": [
      "Caddy"
    ],
    "LOCK,": [
      "UNLOCK"
    ]
  }
}

Okay you have a lot of stuff going on in your config. Let’s try to reduce the problem.

So you’re having issues with http://dav.homelab.zt right?

Let’s start fresh with that site.

http://dav.homelab.zt {
	basicauth {
		secureguy JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
	}
	respond "We're in." 200
}

Does this work? If so, let’s try this next:

{
	order webdav last
}

http://dav.homelab.zt {
	root * /usr/share/caddy/webdav

	basicauth {
		secureguy JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
	}

	webdav
}

Does this work? If so…

{
	order webdav last
}

http://dav.homelab.zt {
	root * /usr/share/caddy/webdav

	basicauth {
		secureguy JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
	}

	header {
		Access-Control-Allow-Origin *
		Access-Control-Allow-Credentials true
		Access-Control-Allow-Methods "GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK"
		Access-Control-Allow-Headers "Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite"
		Access-Control-Expose-Headers "ETag"
		Access-Control-Max-Age 1728000
	}

	webdav
}

Note I added some quotes around your header values to try and avoid some trouble with Caddy incorrectly parsing the tokens due to spaces. Not sure if it’ll have an effect.

If that worked…

{
	order webdav last
}

http://dav.homelab.zt {
	root * /usr/share/caddy/webdav

	log {
		output file /data/logs/caddy_access.log
	}

	basicauth {
		secureguy JDJhJDEwJEVCNmdaNEg2Ti5iejRMYkF3MFZhZ3VtV3E1SzBWZEZ5Q3VWc0tzOEJwZE9TaFlZdEVkZDhX
	}

	encode gzip zstd

	header {
		Access-Control-Allow-Origin *
		Access-Control-Allow-Credentials true
		Access-Control-Allow-Methods "GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK"
		Access-Control-Allow-Headers "Authorization,DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Accept-Charset,X-Accept,origin,accept,if-match,destination,overwrite"
		Access-Control-Expose-Headers "ETag"
		Access-Control-Max-Age 1728000
	}

	php_fastcgi phpfpm:9000

	webdav
}

FYI handle_errors is not a replacement for errors from Caddy v1, it has a completely different purpose. There’s no such thing as an errors directive in Caddy v2, the errors will always be spit out to stdout by default (configurable with JSON config, but not yet with Caddyfile).

Anyways, just keep adding pieces of your config back in bit-by-bit until you find out what exactly is causing things to break.

2 Likes