caddyserver / caddy

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
https://caddyserver.com
Apache License 2.0
55.59k stars 3.91k forks source link

Automatic HTTPS redirects inconsistent in combination with bindings #5660

Open jorams opened 11 months ago

jorams commented 11 months ago

What I want to achieve: For Caddy to serve some public sites to the internet over HTTPS with an automatic redirect from HTTP, and some private sites to a Tailscale (Headscale) network over plain HTTP.

I first tried to set it up like the following. (I've simplified the configuration a lot for local testing, but the problem is the same.)

# Public site
test.example {
    bind 127.0.0.1
    tls internal
    respond "Hello"
}

# Private site
http://test2.example {
    bind 100.64.0.6
    respond "World"
}

The result is Caddy listening on port 80 on 100.64.0.6, and port 443 on 127.0.0.1. The listener on port 80 will redirect to https://test.example.

Expand for test commands ``` # Not listening to port 80 on 127.0.0.1 $ curl --insecure --include --connect-to test.example:80:127.0.0.1:80 http://test.example/ curl: (7) Failed to connect to 127.0.0.1 port 80 after 0 ms: Couldn't connect to server # Listening and redirecting on 100.64.0.6 $ curl --insecure --include --connect-to test.example:80:100.64.0.6:80 http://test.example/ HTTP/1.1 308 Permanent Redirect ... ```

This feels like a bug, but it can be explained based on the warning in the documentation for default_bind. The solution offered there (Also discussed in #5309) is to add an http:// site, like this:

# Public site
test.example {
    bind 127.0.0.1
    tls internal
    respond "Hello"
}

# Private site
http://test2.example {
    bind 100.64.0.6
    respond "World"
}

# Fix
http:// {
    bind 127.0.0.1
    respond "Fix"
}

Whether this solves the problem here is unpredictable every time Caddy gets restarted. The listener for the automatic redirects appears to be selected at random. (caddy adapt consistently returns the same JSON for this Caddyfile, so the inconsistency is not in the adaptation.)

Expand for test commands ``` # Start Caddy with the above Caddyfile # 200 OK on 127.0.0.1 $ curl --insecure --include --connect-to test.example:80:127.0.0.1:80 http://test.example/ HTTP/1.1 200 OK ... Fix # 308 Permanent Redirect on 100.64.0.6 $ curl --insecure --include --connect-to test.example:80:100.64.0.6:80 http://test.example/ HTTP/1.1 308 Permanent Redirect ... # Restart Caddy a few times without changing the Caddyfile # 308 Permanent Redirect on 127.0.0.1 $ curl --insecure --include --connect-to test.example:80:127.0.0.1:80 http://test.example/ HTTP/1.1 308 Permanent Redirect ... # 200 OK on 100.64.0.6 (but unrelated to the new catch-all http:// site) $ curl --insecure --include --connect-to test.example:80:100.64.0.6:80 http://test.example/ HTTP/1.1 200 OK ... ```

My first attempted configuration did not specify bind for the public sites. I thought the warning about inconsistent binding in the documentation for bind could apply, but as you can see above specifying a non-overlapping binding does not fix it.

mholt commented 11 months ago

Thanks; I wonder if we're using a map somewhere and we lose the ordering. Will have to look into that.

mholt commented 11 months ago

Thanks again for a thoroughly-researched issue. So my comment on the linked issue says:

This might suck, but maybe we should find all the addresses that use the HTTPS port and add the host portion of each of those addresses to the auto-redir server. i.e. a server configured to listen on "104.244.78.176:443", "127.0.0.1:443", "[2605:6400:30:f1ca::1]:443", "[::1]:443" would result in the auto-redir server listening on "104.244.78.176:80", "127.0.0.1:80", "[2605:6400:30:f1ca::1]:80", "[::1]:80".

We might need to do that :grimacing:

Is it OK if we don't slide this into 2.7? Maybe 2.7.1... unless someone wants to whip up a PR for it, but I'm not sure if this would be easy or not.

jorams commented 11 months ago

We might need to do that

That indeed seems like a good solution.

Is it OK if we don't slide this into 2.7?

Fine by me! I've worked around the issue with manual redirects.