Nextcloud behind caddy reverse proxy: too many redirects

1. Caddy version (caddy version):


2. How I run Caddy:

I have a couple of raspberry pis, one running nextcloud in a snap and one running a Joplin server in a docker container. CAddy is running on the one also running the joplin server. For the moment, I am just trying to get the reverse proxy to Nextcloud working, and I can’t.

a. System environment:

This is 64bit Raspberry OS; caddy is running plain, ie not in any sort of container

Nextcloud is in a snap installation, with apache, which works when contacted directly

b. Command:

caddy run / reload

c. Service/unit/compose file:

paste full file contents here

d. My complete Caddyfile or JSON config:

My caddyfile is

localhost {
    respond "Hello, World. I don't believe this but it works"
} {
    route {
        reverse_proxy /nextcloud/* {
            header_down Strict-Transport-Security "max-age=15552000;"
            header_down X-Real-IP {http.request.remote}
            header_down X-Forwarded-For {http.request.remote}
        reverse_proxy /joplin/* localhost:22300
        respond "Yes, I do have a certificate, thank you: now go away."
} {
    reverse_proxy localhost:22300
} {
     reverse_proxy {
        header_down Strict-Transport-Security "max-age=15552000;"
        header_down X-Real-IP {http.request.remote}
        header_down X-Forwarded-For {http.request.remote}
        log {
         output file /var/log/caddy.log
         format console

# to run "caddy reload" after every change

The two unproxied responses work.
The proxy to nextcloud does not.
Neither does the one to joplin, but that has to be a variant of the same problem

3. The problem I’m having:

When I enter into my browser, I get

This page isn’t redirected you too many times.
Try clearing your cookies.

4. Error messages and/or full log output:

output of tail /var/log/caddy.log

1.6157531438012261e+09  info    http.log.access.log0    handled request {"request": {"remote_addr": "", "proto": "HTTP/1.1", "method": "GET", "host": "", "uri": "/status.php", "headers": {"Accept": ["*/*"], "X-Request-Id": ["0b569c5d-011f-4bbb-acbf-d7241f708318"], "Connection": ["Keep-Alive"], "Accept-Encoding": ["gzip, deflate"], "Accept-Language": ["en-GB,*"], "User-Agent": ["Mozilla/5.0 (Windows) mirall/3.1.3stable-Win64 (build 20210218) (Nextcloud)"], "Authorization": ["Basic XXXXXXXXXX
"]}, "tls": {"resumed": false, "version": 772, "cipher_suite": 4867, "proto": "", "proto_mutual": true, "server_name": ""}}, "common_log": " - - [14/Mar/2021:20:19:03 +0000] \"GET /status.php HTTP/1.1\" 301 256", "duration": 0.001007843, "size": 256, "status": 301, "resp_headers": {"Date": ["Sun, 14 Mar 2021 20:19:03 GMT"], "Location": [""], "Content-Length": ["256"], "Content-Type": ["text/html; charset=iso-8859-1"], "Strict-Transport-Security": ["max-age=15552000;"], "X-Forwarded-For": [""], "X-Real-Ip": [""], "Server": ["Caddy", "Apache"]}}
╭─pi@Quinn ~

5. What I already tried:

Endless googling for possible answers; adding the header lines you see into the configuration; running nextcloud on different ports; trying with http and without.

I’m sure I’m missing something obvious and stupid but I don’t know what.

6. Links to relevant resources:

There’s a couple things to talk about here.

First, I think you should use the header directive rather than header_down for the Strict-Transport-Security header. That’s more of a domain-level header, and isn’t specific to a particular proxy.

Second, it doesn’t really make sense to use header_down for X-Real-IP and X-Forwarded-For, because those headers are meant for telling the upstream app the originating IP address of the request. header_down writes those headers to the response, i.e. you’re telling the client/browser “hey, by the way this is your IP”, which isn’t useful.

What you’d actually want is header_up, but in this case, you can just remove those two lines altogether because Caddy’s reverse_proxy already adds the X-Forwarded-For header to the proxied request anyways (and X-Real-IP is redundant since X-Forwarded-For will already have that information set, and I know Nextcloud already handles that fine).

As for the issue with redirects, I don’t see a problem with your domain that would case this. Are you sure Nextcloud is properly configured?

Try making a request with curl -v and see what’s in the response headers.

Just FYI, proxying over HTTPS might require a bit more work, you may need to configure Caddy to trust the certificate served by Nextcloud. But it’s probably easier to just use HTTP since those services should only be directly accessible privately.

First, thank you for your help.

I had copied and pasted (of course) the header stuff from someone who seemed to have this working.

When I try curl -v I get

* Connected to ( port 80 (#0)
> GET / HTTP/1.1
> Host:
> User-Agent: curl/7.64.0
> Accept: */*
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location:
< Server: Caddy
< Date: Mon, 15 Mar 2021 07:42:08 GMT
< Content-Length: 0

Which suggests a misconfiguration in the nextcloud snap. Oh, God. I really don’t know how to fiddle with apache at all, (I used to use nginx) let alone inside a snap. Should I perhaps disable the apache that’s running in the nextcloud snap and put a second instance of Caddy on that pi?

ON investigation, the httpd,conf inside the snap is read only, so I am completely stuck.

That redirect is expected; Caddy serves HTTP->HTTPS redirects. You made an HTTP request with curl there. Try with this command (exactly):

curl -v

Ah. Now I get something I really don’t understand :slight_smile:

*   Trying
* Expire in 149984 ms for 3 (transfer 0x5597284c30)
* Expire in 200 ms for 4 (transfer 0x5597284c30)
* Connected to ( port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_CHACHA20_POLY1305_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject:
*  start date: Mar 10 17:45:43 2021 GMT
*  expire date: Jun  8 17:45:43 2021 GMT
*  subjectAltName: host "" matched cert's ""
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x5597284c30)
> GET / HTTP/2
> Host:
> User-Agent: curl/7.64.0
> Accept: */*
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 502
< server: Caddy
< content-length: 0
< date: Mon, 15 Mar 2021 12:38:55 GMT
* Connection #0 to host left intact

The error that seems to matter is the HTTP/2 502, but where should I be looking for clues about that?

A 502 means Caddy couldn’t communicate with the upstream proxy. Your logs will confirm this. Are you sure Caddy can reach that service on that IP address and port?

No: it can’t. It seems that nothing can, including curl from the machine that nextcloud is running from. I will investigate the nextcloud server and come back. But thank you for your help and patience.

1 Like

Thrashing around in confusion I had somehow managed to set nextcloud listening to port 80 and caddy proxying to port 81. Working now, though. There were also errors in the nextcloud config.php, but these weren’t being logged. Only by trying the 'Nextcloud.occ" commands did I see debuggable feedback – a tip I leave in case anyone else has similar problems after hand editing the config.php in a snap.

I only have one further question: where should the header Strict-Transport-Security line go? For the moment it is commented out, for when I put it outside a location block the caddyfile is rejected.

And in any case, I’d just like to say again thank you for your help and patience. So many help forums are full of snark and idiocy and my experience here has been entirely different. Any idiocy in this thread I bought to it myself!

What do you mean by “location block”? What did you actually try, i.e. what did your Caddyfile look like?

I was saying that you should use the header directive:


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