Too many redirect - Caddy with vaultwarden

1. The problem I’m having:

I’m trying to run a Docker instance of vaultwarden on a Hertzner server together with caddy (also through Docker) to manage HTTPS.

I have setup a domain name with sub-domain on OVH and created a redirection (A entry): vault.spdgzlz.ovh pointing to 94.130.168.115 (IP of the Hertzner server).

Both docker containers are running on the server:

CONTAINER ID   IMAGE                       COMMAND                  CREATED       STATUS                 PORTS                                                                                         NAMES
ad8e056c5352   caddy:2                     "caddy run --config …"   2 hours ago   Up 2 hours             0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 443/udp, 2019/tcp   caddy
8039840fdad9   vaultwarden/server:latest   "/start.sh"              2 hours ago   Up 2 hours (healthy)   127.0.0.1:3012->3012/tcp, 127.0.0.1:8080->80/tcp                                              vaultwarden

2. Error messages and/or full log output:

After having been through the setup process I’m unable to access vaultwarden’s login page and get a ERR_TOO_MANY_REDIRECTS error.

Also here’s the output of curl -v vault.spdgzlz.ovh:

*   Trying 94.130.168.115:80...
* Connected to vault.spdgzlz.ovh (94.130.168.115) port 80 (#0)
> GET / HTTP/1.1
> Host: vault.spdgzlz.ovh
> User-Agent: curl/7.86.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://vault.spdgzlz.ovh/
< Server: Caddy
< Date: Wed, 22 Mar 2023 17:18:37 GMT
< Content-Length: 0
<
* Closing connection 0

3. Caddy version:

v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=

4. How I installed and ran Caddy:

a. System environment:

Both vaultwarden and caddy are running in docker containers. The server is running Ubuntu 22.04.2 LTS on Hertzner cloud.

b. Command:

sudo docker run -d --name vaultwarden -v /srv/vaultwarden:/data -e WEBSOCKET_ENABLED=true -p 127.0.0.1:8080:80 -p 127.0.0.1:3012:3012 --restart on-failure vaultwarden/server:latest
sudo docker run -d -p 80:80 -p 443:443 --name caddy -v /etc/Caddyfile:/etc/caddy/Caddyfile -v /etc/caddy:/root/.local/share/caddy --restart on-failure caddy:2

d. My complete Caddy config:

vault.spdgzlz.ovh {
  encode gzip

  # The negotiation endpoint is also proxied to Rocket
  reverse_proxy /notifications/hub/negotiate 0.0.0.0:80

  # Notifications redirected to the websockets server
  reverse_proxy /notifications/hub 0.0.0.0:3012

  # Send all other traffic to the regular Vaultwarden endpoint
  reverse_proxy 0.0.0.0:80
}

e. Caddy logs

{"level":"info","ts":1679497296.4633143,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
{"level":"warn","ts":1679497296.4667418,"msg":"Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
{"level":"info","ts":1679497296.468553,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1679497296.4698992,"logger":"http","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
{"level":"info","ts":1679497296.4701233,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1679497296.469991,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00035f2d0"}
{"level":"info","ts":1679497296.47118,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1679497296.4712176,"logger":"tls","msg":"cleaning storage unit","description":"FileStorage:/data/caddy"}
{"level":"info","ts":1679497296.471649,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1679497296.4720025,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details."}
{"level":"info","ts":1679497296.4724207,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"info","ts":1679497296.4728177,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1679497296.472991,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["vault.spdgzlz.ovh"]}
{"level":"info","ts":1679497296.4740372,"logger":"tls.obtain","msg":"acquiring lock","identifier":"vault.spdgzlz.ovh"}
{"level":"info","ts":1679497296.4747412,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1679497296.4749641,"msg":"serving initial configuration"}
{"level":"info","ts":1679497296.4764059,"logger":"tls.obtain","msg":"lock acquired","identifier":"vault.spdgzlz.ovh"}
{"level":"info","ts":1679497296.4771523,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"vault.spdgzlz.ovh"}
{"level":"info","ts":1679497297.3143046,"logger":"http","msg":"waiting on internal rate limiter","identifiers":["vault.spdgzlz.ovh"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
{"level":"info","ts":1679497297.3143587,"logger":"http","msg":"done waiting on internal rate limiter","identifiers":["vault.spdgzlz.ovh"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
{"level":"info","ts":1679497297.6557417,"logger":"http.acme_client","msg":"trying to solve challenge","identifier":"vault.spdgzlz.ovh","challenge_type":"tls-alpn-01","ca":"https://acme-v02.api.letsencrypt.org/directory"}
{"level":"info","ts":1679497298.2448506,"logger":"tls","msg":"served key authentication certificate","server_name":"vault.spdgzlz.ovh","challenge":"tls-alpn-01","remote":"3.14.146.74:40540","distributed":false}
{"level":"info","ts":1679497298.3088036,"logger":"tls","msg":"served key authentication certificate","server_name":"vault.spdgzlz.ovh","challenge":"tls-alpn-01","remote":"34.214.208.130:14818","distributed":false}
{"level":"info","ts":1679497298.6522026,"logger":"tls","msg":"served key authentication certificate","server_name":"vault.spdgzlz.ovh","challenge":"tls-alpn-01","remote":"23.178.112.103:45846","distributed":false}
{"level":"info","ts":1679497299.0487876,"logger":"http.acme_client","msg":"authorization finalized","identifier":"vault.spdgzlz.ovh","authz_status":"valid"}
{"level":"info","ts":1679497299.0488214,"logger":"http.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-v02.api.letsencrypt.org/acme/order/1021861857/171630481907"}
{"level":"info","ts":1679497299.7781713,"logger":"http.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-v02.api.letsencrypt.org/acme/cert/032baec67408c44962fb6f3af7add10e188f"}
{"level":"info","ts":1679497299.7797542,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"vault.spdgzlz.ovh"}
{"level":"info","ts":1679497299.7802706,"logger":"tls.obtain","msg":"releasing lock","identifier":"vault.spdgzlz.ovh"}

5. Links to relevant resources:

I mostly followed the instructions of this guide How to Self-Host the vaultwarden Password Manager | Linode

Thanks a lot for your help! I’ve been helpless for the past few days trying to understand what’s going on.

That’s making an HTTP request. Try with curl -v https://vault.spdgzlz.ovh instead.

Inside of Docker, 0.0.0.0 (which is the same as localhost) means this container. So you’re telling Caddy to proxy to itself, which causes an infinite loop of redirects.

You should use the container/service name instead, as the address. Use vaultwarden:80.

Hi @francislavoie , thanks for your reply.

I’ve made the change you suggested and reloaded the caddy config by running caddy reload from within the caddy container.

I now get a 502 error when trying to access https://vault.spdgzlz.ovh/ with my browser.

Here’s the new Caddyfile:

vault.spdgzlz.ovh {
  encode gzip

  # The negotiation endpoint is also proxied to Rocket
  reverse_proxy /notifications/hub/negotiate 0.0.0.0:80

  # Notifications redirected to the websockets server
  reverse_proxy /notifications/hub 0.0.0.0:3012

  # Send all other traffic to the regular Vaultwarden endpoint
  reverse_proxy vaultwarden:80
}

And here’s the output of curl -v https://vault.spdgzlz.ovh

*   Trying 94.130.168.115:443...
* Connected to vault.spdgzlz.ovh (94.130.168.115) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=vault.spdgzlz.ovh
*  start date: Mar 22 14:01:39 2023 GMT
*  expire date: Jun 20 14:01:38 2023 GMT
*  subjectAltName: host "vault.spdgzlz.ovh" matched cert's "vault.spdgzlz.ovh"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: GET]
* h2h3 [:path: /]
* h2h3 [:scheme: https]
* h2h3 [:authority: vault.spdgzlz.ovh]
* h2h3 [user-agent: curl/7.86.0]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x150810a00)
> GET / HTTP/2
> Host: vault.spdgzlz.ovh
> user-agent: curl/7.86.0
> accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 502
< alt-svc: h3=":443"; ma=2592000
< server: Caddy
< content-length: 0
< date: Thu, 23 Mar 2023 08:16:47 GMT
<
* Connection #0 to host vault.spdgzlz.ovh left intact

Finally the last item in the output of sudo docker logs caddy

{"level":"error","ts":1679559718.402219,"logger":"http.log.error","msg":"dial tcp: lookup vaultwarden on 185.12.64.2:53: no such host","request":{"remote_ip":"82.66.225.219","remote_port":"59079","proto":"HTTP/2.0","method":"GET","host":"vault.spdgzlz.ovh","uri":"/","headers":{"Sec-Fetch-Dest":["document"],"Cache-Control":["max-age=0"],"User-Agent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"],"Sec-Fetch-User":["?1"],"Upgrade-Insecure-Requests":["1"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"],"Sec-Fetch-Site":["none"],"Sec-Fetch-Mode":["navigate"],"Accept-Encoding":["gzip, deflate, br"],"Sec-Ch-Ua":["\"Google Chrome\";v=\"111\", \"Not(A:Brand\";v=\"8\", \"Chromium\";v=\"111\""],"Sec-Ch-Ua-Mobile":["?0"],"Sec-Ch-Ua-Platform":["\"macOS\""],"Accept-Language":["en-GB,en-US;q=0.9,en;q=0.8,fr;q=0.7"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"vault.spdgzlz.ovh"}},"duration":0.002105755,"status":502,"err_id":"4v8ezd5dp","err_trace":"reverseproxy.statusError (reverseproxy.go:1299)"}

Is there anything else I should change in my setup?

Thanks a lot for your help!

Are both your containers in the same Docker network? They need to share a network to be able to communicate with eachother.

I’d strongly recommend using Docker Compose, it’ll make this easier:

You’ll need to update these as well, for the same reason.

Hi @francislavoie ,

Thanks for your inputs. I managed to make it work by inspecting the bridge docker network, finding the local IP of the vaultwarden service 172.17.0.2 and using this IP in the Caddyfile.

Here’s the new Caddyfile

vault.spdgzlz.ovh {
  encode gzip

  # The negotiation endpoint is also proxied to Rocket
  reverse_proxy /notifications/hub/negotiate 172.17.0.2:80

  # Notifications redirected to the websockets server
  reverse_proxy /notifications/hub 172.17.0.2:3012

  # Send all other traffic to the regular Vaultwarden endpoint
  reverse_proxy 172.17.0.2:80
}

Thanks for helping me making it work. Really appreciate you took the time.

If you use Docker Compose, then you wouldn’t need to worry about using a raw IP. The bridge network might go away or change IP, so using the container or service name is more reliable.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.