-
-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: Feedback on listener_wrappers
(mostly around proxy_protocol
)
#373
Comments
listener_wrappers
(_mostly around proxy_protocol
_)listener_wrappers
(mostly around proxy_protocol
)
Can you share your full config? You only showed global options, but the actual site blocks affect the result of It sounds to me like a logic error that you use PROXY protocol and are sending both HTTP and HTTPS to the same port. That implies you have a proxy in front of Caddy, so that proxy should be configured to never do that. The point of
That's because it used to only be available as a plugin before 2.7.0, but we've since bundled it with Caddy because we wanted to add PROXY protocol support to
Good point, updated. But anyway, the documents aren't materially different, looks like there was just a tiny fix regarding the byte format but that's not relevant to users, only relevant to library authors.
I assume you're using v2.7.6, right? We're using an older PROXY protocol implementation in that version, and we've merged a change in caddyserver/caddy#5915 to use a different library, which will release with v2.8.0 Do you mind trying a build from |
The Caddyfile was rather simple, beyond the global config (and using # Technically when http:// was active it was a separate site block with different respond text to avoid any confusion
#http://example.test {
example.test {
log
respond "hello world!"
}
Curl commands:
I can provide a proper
With the bug described above (no separate
I understand, and the docs could probably convey that intent better. Presently they imply the feature redirects in a manner that's contradicting if it's I understand that I would need to specify two separate Whereas a TLS / HTTPS connection worked fine with the PROXY protocol header. Plain HTTP works too when the implicit redirect feature isn't there, so that seems like a bug?
I understand. It may change if there is an update sometime in the future and the 1.8 docs aren't refreshed with that update though 🤷♂️ I figure the github source is more appropriate 👍 I'm not a library author but I didn't know anything about it until a week ago, there had been various issues from users with setting up PROXY protocol correctly with Traefik and other maintainers not knowing what the support status was with software we needed to use it with (neither documented v2 support IIRC, while our own prior community contributed docs had mixed versioning). I still found the spec useful :)
Yes 2.7.6. I can do a build tomorrow and get back to you 👍 |
So the thing is, the Basically if you're using the
I'm not sure I follow, but it's definitely wrong to enable the Similarly, it doesn't really make sense to enable PROXY protocol on the |
I don't actually want the
We'll see if the 2.8 build tomorrow is any different there. Regarding the ACME example and the quote,
It wasn't about if it made sense. Just identifying inconsistent in behaviour with connections when PROXY protocol is enabled or not. It should not break the default implicit redirect functionality. example.test {
respond "test"
} That should redirect http to https when PROXY protocol is enabled, it doesn't. |
I think I'd rather just document that they shouldn't be used together. There's not really any situation where it makes sense to have both.
Moreso, it shouldn't be configured on
So you're saying that |
Built Caddy 2.8 as shown in config below.
I'll trim the below example to bare minimal for demonstrating the bug in Caddy 2.8 and open an issue with that if you'd like? Full reproduction config# compose.yaml
# Usage:
# - Bring up services: docker compose up -d --force-recreate
# - Run curl tests: docker compose run --rm client
services:
reverse-proxy:
image: docker.io/traefik:3.0 #2.10
hostname: traefik.internal.test
networks:
default:
ipv4_address: 172.16.42.10
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --providers.docker.network=dms-test-network
- --entrypoints.web.address=:80
# Equivalent to Caddy trusted_proxies (insecure trusts everyone):
# An entrypoint is roughly equivalent to a caddy server config.
# NOTE: TCP routers will not discard any HTTP headers added by curl
# Nor will any `X-Forwarded-*` headers be added by Traefik.
#- --entryPoints.web.forwardedHeaders.insecure=true
# Equivalent to Caddy implicit redirects (HTTP/80 => HTTPS/443) functionality:
#- --entrypoints.web.http.redirections.entryPoint.to=websecure
#- --entrypoints.web.http.redirections.entryPoint.scheme=https
- --entryPoints.websecure.address=:443
#- --log.level=debug
# CAUTION: Production usage should configure socket access better (see Traefik docs)
volumes:
- /var/run/docker.sock:/var/run/docker.sock
web:
# Test Caddy 2.7 via image by uncommenting, should have priority over the build field.
# image: caddy:2.7
hostname: caddy.internal.test
networks:
default:
ipv4_address: 172.16.42.20
# Caddy 2.8 makes PROXY protocol header optional on
# the receiving port, just like Traefik.
# Build master branch for unreleased Caddy 2.8:
build:
dockerfile_inline: |
FROM caddy:2.7-builder AS builder
RUN xcaddy build master
FROM caddy:2.7
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
labels:
- traefik.enable=true
# Only TCP services can enable PROXY Protocol:
- traefik.tcp.routers.web.rule=HostSNI(`*`)
- traefik.tcp.routers.web.entrypoints=web
- traefik.tcp.routers.web.service=web
- traefik.tcp.services.web.loadbalancer.server.port=80
# Comment the below line to properly toggle off PROXY protocol for HTTP traffic:
- traefik.tcp.services.web.loadbalancer.proxyProtocol.version=2
# TLS passthrough delegates TLS termination to Caddy instead:
- traefik.tcp.routers.websecure.rule=HostSNI(`*`)
- traefik.tcp.routers.websecure.tls.passthrough=true
- traefik.tcp.routers.websecure.entrypoints=websecure
- traefik.tcp.routers.websecure.service=websecure
- traefik.tcp.services.websecure.loadbalancer.server.port=443
- traefik.tcp.services.websecure.loadbalancer.proxyProtocol.version=2
# As TCP routers can only match host by SNI (which requires TLS), the best they can do is
# use a wildcard catch-all via HOSTSNI(`*`).
# - However since TCP routers rules have precedence over HTTP routers,
# this prevents a more specific HTTP router rule from being matched:
# https://doc.traefik.io/traefik/routing/routers/#general_1
# - For HTTP routers with TLS (HTTPS) the precedence is flipped:
# https://github.com/traefik/traefik/issues/10186#issuecomment-1781200577
# https://github.com/traefik/traefik/pull/9024
# - Thus while the service below will work for https://http-only.test,
# the router itself will never match when the TCP non-TLS router is present above.
# - All non-TLS traffic incoming to Traefik is via the TCP router,
# only https://no-proxy-header.test tests without PROXY protocol as a result.
# NOTE: A rule like "PathPrefix(`/`)" should match any host if needed instead.
- traefik.http.routers.web.rule=Host(`http-only.test`) || Host(`no-proxy-header.test`)
- traefik.http.routers.web.entrypoints=web
- traefik.http.routers.web.service=web
- traefik.http.services.web.loadbalancer.server.port=80
# Uncomment this and traffic routed through this service to Caddy (eg: https://http-only.test)
# would always result in a HTTP redirect response as the host header is stripped away:
# https://doc.traefik.io/traefik/routing/services/#pass-host-header
#- traefik.http.services.web.loadbalancer.passHostHeader=false
# While this could have been a HTTP router with TLS, it instead demonstrates TCP TLS router
# behaviour when PROXY protocol is not enabled:
# Only matches requests to the explicit servername (SNI):
- traefik.tcp.routers.no-proxy-header.rule=HostSNI(`no-proxy-header.test`)
- traefik.tcp.routers.no-proxy-header.tls.passthrough=true
- traefik.tcp.routers.no-proxy-header.entrypoints=websecure
- traefik.tcp.routers.no-proxy-header.service=no-proxy-header
- traefik.tcp.services.no-proxy-header.loadbalancer.server.port=443
# Handle https://http-only.test differently than other HTTPS requests.
# Traefik will terminate TLS instead of delegating to Caddy (no passthrough).
# Thus the Traefik cert is presented instead, and TLS HTTP router uses the same
# HTTP/80 service defined above (`web`) to send decrypted traffic to Caddy.
- traefik.http.routers.http-only.rule=Host(`http-only.test`)
- traefik.http.routers.http-only.tls=true
- traefik.http.routers.http-only.entrypoints=websecure
- traefik.http.routers.http-only.service=web
configs:
- source: caddyfile
target: /etc/caddy/Caddyfile
# Only intended for running via `docker compose run --rm -it client`
client:
hostname: client.internal.test
# An easy to recognize IP in the logs:
networks:
default:
ipv4_address: 172.16.42.42
# Prevent starting this service by default with `docker compose up`:
profiles:
- testing
build:
dockerfile_inline: |
FROM alpine
RUN apk add curl
command: ash /tmp/run.sh
configs:
- source: curl-cmds
target: /tmp/run.sh
networks:
default:
name: dms-test-network
ipam:
config:
- subnet: "172.16.42.0/24"
configs:
curl-cmds:
content: |
#!/bin/sh
# Curl options:
# - `--location` (`-L`) to follow redirect for HTTP => HTTPS (used for direct Caddy example.test)
# - `-w '\n'` for ensuring a final LF which is not part of the Caddy respond directive
# - `--connect-to` routes traffic to the Traefik reverse proxy:
# https://curl.se/docs/manpage.html#--connect-to
echo 'HTTP should respond without redirect (when http:// site address is enabled):'
# This fails with `404 Bad Request` by default since the site address is disabled in Caddyfile
# When enabled, the next two tests will no longer fail and instead respond with a redirect.
echo -e '\n- Client => Traefik (PROXY protocol) => Caddy (http://http-only.test)'
curl --connect-to ::traefik.internal.test http://http-only.test -w '\n'
# HTTP without redirect
# Client IP: 172.16.42.42, Remote Host IP: 172.16.42.42
echo -e '\n------\nHTTP should redirect:'
# PROXY protocol fails to get redirect response unless Caddyfile has `http:// {}` or similar:
echo -e '\n- Client => Traefik (PROXY protocol) => Caddy (http://example.test)'
curl --verbose --connect-to ::traefik.internal.test http://example.test 2>&1 \
| grep -E '^< HTTP/1.1 (308 Permanent Redirect|400 Bad Request)'
# < HTTP/1.1 400 Bad Request
# < HTTP/1.1 308 Permanent Redirect
# This is inaccurate, Traefik router precedence prevents HTTP non-TLS being accessible
# when TCP non-TLS router is active.. Only the https://no-proxy-header.test is relevant.
echo -e '\n- Client => Traefik (no PROXY protocol) => Caddy (http://no-proxy-header.test) | **Unreliable**'
curl --verbose --connect-to ::traefik.internal.test http://no-proxy-header.test 2>&1 \
| grep -E '^< HTTP/1.1 (308 Permanent Redirect|400 Bad Request)'
# < HTTP/1.1 400 Bad Request
# < HTTP/1.1 308 Permanent Redirect
# Direct connections, always a redirect response:
echo -e '\n- Client => Caddy (http://example.test)'
curl --verbose --connect-to ::caddy.internal.test http://example.test 2>&1 | grep '308 Permanent Redirect'
# < HTTP/1.1 308 Permanent Redirect
echo -e '\n- Client => Caddy (http://no-proxy-header.test)'
curl --verbose --connect-to ::caddy.internal.test http://no-proxy-header.test 2>&1 | grep '308 Permanent Redirect'
# < HTTP/1.1 308 Permanent Redirect
echo -e '\n------\nHTTPS should respond successfully:'
echo -e '\n- Client => Traefik (PROXY protocol) => Caddy (https://example.test)'
curl --insecure --connect-to ::traefik.internal.test https://example.test -w '\n'
# Hello HTTP => HTTPS
# Client IP: 172.16.42.42, Remote Host IP: 172.16.42.42
echo -e '\n- Client => Traefik (no PROXY protocol) => Caddy 443 (https://no-proxy-header.test)'
curl --insecure --connect-to ::traefik.internal.test https://no-proxy-header.test -w '\n'
# Caddy 2.7 will reject connections from allowed PROXY protocol hosts when the PROXY header is missing. Caddy 2.8 is flexible!
# Client IP: 172.16.42.10, Remote Host IP: 172.16.42.10
#
# Curl output with Caddy 2.7:
# curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to no-proxy-header.test:443
echo -e '\n- Client => Traefik (no PROXY protocol, TLS termination) => Caddy 80 (https://http-only.test)'
curl --insecure --connect-to ::traefik.internal.test https://http-only.test -w '\n'
# HTTP without redirect
# Client IP: 172.16.42.42, Remote Host IP: 172.16.42.42
# X-Forwarded-* headers are present
#
# Curl output with Caddy 2.7:
# 400 Bad Request
echo -e '\n- Client => Caddy (https://example.test)'
curl --location --insecure --connect-to ::caddy.internal.test http://example.test -w '\n'
# Hello HTTP => HTTPS
# Client IP: 172.16.42.42, Remote Host IP: 172.16.42.42
# NOTE: This check is redundant but included for consistency:
echo -e '\n- Client => Caddy (https://no-proxy-header.test)'
curl --insecure --connect-to ::caddy.internal.test https://no-proxy-header.test -w '\n'
# Caddy 2.7 will reject connections from allowed PROXY protocol hosts when the PROXY header is missing. Caddy 2.8 is flexible!
# Client IP: 172.16.42.42, Remote Host IP: 172.16.42.42
caddyfile:
content: |
# Global options:
{
local_certs
#log default {
# level DEBUG
#}
# Enable ProxyProtocol for incoming Traefik connections
# https://caddyserver.com/docs/caddyfile/options#listener-wrappers
servers {
log_credentials
trusted_proxies static 172.16.42.0/24
listener_wrappers {
# Only trust PROXY protocol connections from Traefik:
proxy_protocol {
allow 172.16.42.10/32
}
# Technically neither of the below rules should be used for
# servers.listener_wrappers on :80, if needing PROXY protocol
# on HTTP as well, you should have separate server configs per port.
# Must come after proxy_protocol but before tls:
#http_redirect
tls
}
}
}
# https://caddyserver.com/docs/caddyfile/options#client-ip-headers
# > Pairing with trusted_proxies, allows configuring which headers to use to determine the client's IP address.
# > By default, only X-Forwarded-For is considered.
# https://caddyserver.com/docs/caddyfile/matchers#client-ip
# > Only requests from trusted proxies will have their client IP parsed at the start of the request;
# > untrusted requests will use the remote IP address of the immediate peer.
# https://caddyserver.com/docs/caddyfile/matchers#remote-ip
# > the first IP in the X-Forwarded-For request header, if present, will be preferred as the reference IP,
# > rather than the immediate peer's IP, which is the default.
(respond_with) {
log
respond <<EOF
{args[0]}
Caddy Received:
Client IP (ideally the real client): {client_ip}
Remote Host IP (connected to Caddy): {remote_host} (requests.remote_ip)
Request To (Host header): {host}
---
NOTE: Traefik only provides these headers for connections using HTTP router/services not TCP:
X-Forwarded-Server (aka Remote Host): {header.X-Forwarded-Server}
X-Forwarded-For (aka Client IP): {header.X-Forwarded-For}
X-Forwarded-Host (aka Host header): {header.X-Forwarded-Host}
X-Real-Ip (aka Client IP): {header.X-Real-Ip}
EOF
}
# Test default implicit redirect for HTTP/80 => HTTPS/443
# Fails when PROXY protocol header is present!
example.test {
import respond_with "Hello HTTP => HTTPS"
}
# This works from Traefik with Caddy 2.8, but not 2.7:
no-proxy-header.test {
import respond_with "Caddy 2.7 will reject connections from allowed PROXY protocol hosts when the PROXY header is missing. Caddy 2.8 is flexible!"
}
# Confirms bug with implicit HTTP -> HTTPS redirect on above site addresses:
# - Even with a PROXY header received, http:// connection responds without failure.
# - An `http_redirect` added after `proxy_protocol` in `servers.listener_wrappers` will also
# trigger this to handle HTTP => HTTPS, which demonstrates that an explicit redirect works.
#http://http-only.test {
# import respond_with "HTTP without redirect"
#}
# The http:// site block enables HTTP => HTTPS redirect for any inbound address on port 80 (no matching site address required)
# `http:// {}` is sufficient to trigger that. Observations from above reproductionCaddy 2.7 only, with
Caddy 2.7 and 2.8, when an
Third line is present when {"level":"info","logger":"http.auto_https","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","logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"warn","logger":"http.auto_https","msg":"server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server","server_name":"srv1","http_port":80} |
Yes. # Start the Traefik and Caddy containers:
$ docker compose up -d --force-recreate
# Get a shell into the client container for manual commands:
$ docker compose run --rm client ash
# Route to Caddy through Traefik TCP router with PROXY protocol:
$ curl --verbose --connect-to ::traefik.internal.test http://example.test
* Connecting to hostname: traefik.internal.test
* Host traefik.internal.test:80 was resolved.
* IPv6: (none)
* IPv4: 172.16.42.10
* Trying 172.16.42.10:80...
* Connected to traefik.internal.test (172.16.42.10) port 80
> GET / HTTP/1.1
> Host: example.test
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Content-Type: text/plain; charset=utf-8
< Connection: close
<
* Closing connection
400 Bad Request
# Direct to Caddy:
$ curl --verbose --connect-to ::caddy.internal.test http://example.test
* Connecting to hostname: caddy.internal.test
* Host caddy.internal.test:80 was resolved.
* IPv6: (none)
* IPv4: 172.16.42.20
* Trying 172.16.42.20:80...
* Connected to caddy.internal.test (172.16.42.20) port 80
> GET / HTTP/1.1
> Host: example.test
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://example.test/
< Server: Caddy
< Date: Tue, 13 Feb 2024 08:22:02 GMT
< Content-Length: 0
<
* Closing connection In the previous comment, comment out this TCP non-TLS service to disable PROXY protocol usage: - traefik.tcp.services.web.loadbalancer.proxyProtocol.version=2 Run the same curl command again: $ curl --verbose --connect-to ::traefik.internal.test http://example.test
* Connecting to hostname: traefik.internal.test
* Host traefik.internal.test:80 was resolved.
* IPv6: (none)
* IPv4: 172.16.42.10
* Trying 172.16.42.10:80...
* Connected to traefik.internal.test (172.16.42.10) port 80
> GET / HTTP/1.1
> Host: example.test
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://example.test/
< Server: Caddy
< Date: Tue, 13 Feb 2024 08:23:30 GMT
< Content-Length: 0
<
* Closing connection Issue is related to PROXY protocol header. Alternatively, enable PROXY protocol again for the TCP non-TLS service; Then uncomment the Caddyfile entry for http://http-only.test {
import respond_with "HTTP without redirect"
} Ignore that site address, just try connect to $ curl --verbose --connect-to ::traefik.internal.test http://example.test
* Connecting to hostname: traefik.internal.test
* Host traefik.internal.test:80 was resolved.
* IPv6: (none)
* IPv4: 172.16.42.10
* Trying 172.16.42.10:80...
* Connected to traefik.internal.test (172.16.42.10) port 80
> GET / HTTP/1.1
> Host: example.test
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://example.test/
< Server: Caddy
< Date: Tue, 13 Feb 2024 08:29:19 GMT
< Content-Length: 0
<
* Closing connection You can see that it works too.
Something to do with that change and/or PROXY protocol header interaction with the default implicit HTTP => HTTPS redirect? |
Okay so you're saying that you're sending PROXY protocol to port 80, while having only configured an HTTPS site? Yes, it's expected that this would fail as-is. As noted in the docs (e.g. https://caddyserver.com/docs/caddyfile/options#name), the HTTP server is only created after the fact by Automatic HTTPS. There's no way for it to guess that it should have enabled PROXY protocol. A user could just as easily only be using PROXY protocol for port 443 and not port 80, so assuming that and copying over the listener wrapper automatically or whatever, would be a flaky assumption I think. So I think there's no bug here, seems to be working as intended. |
Then why doesn't it fail when I connect to port 80 without PROXY protocol? 😕
Okay, I think that docs could be explained better. I read through it several times and still wasn't quite sure how to grok the admonition as it uses Thought process to making sense of itI was under the assumption that
When I add an
Note that:
The above image from the
So rather the docs linked are trying to communicate that the feature is unaware of the Caddyfile with generic Those docs could better explain:
I didn't care about the server name, nor was that immediately apparent in logic for me to grok that I'd probably have missed what it was explaining. That information should probably be pulled out to the main
No, my understanding was that if I define If I only wanted it on one port, I would be explicit with At least now I know that the implicit
Agreed not a bug, but still a docs issue. Not exactly specific to I had figured it was related to the That needs a disclaimer not hidden under
|
Why would it? You're just making a simple HTTP request to a simple HTTP server. If you send PROXY protocol to a simple HTTP server, then it won't be happy because it didn't see HTTP, it saw the PROXY preamble.
It's a really difficult concept to explain. It requires a grasp of all these things:
You might say "but if But anyway, yes this note shouldn't be only in the But still... it's so much to explain, and we don't want the docs to exhaust readers, so it needs to be presented in a sensible way, and I'm having trouble resolving those competing requirements. To be clear - the docs will change, I'm working on it. But it'll take time to find the right approach. |
Sorry, I forgot to go backwards and edit that away. I was asking that on the assumption that I had That's now understood that my
Warning
Could do with some revision but that already conveys the issue more clearly to the reader, without being hidden under Doesn't need to explain the technical details regarding adapting the Caddyfile to JSON, just that expectation/requirement of
While I'm sure you're correct about that, it does work regardless with Someone interested in
While it's not ideal, when I have this issue for the docs I maintain, niche concerns with a lot of technical details usually get placed in collapsed admonitions, or I link to a Github issue comment/thread for more info/insights. Here is an example for IPv6 docker config: That's already quite a bit on it's own, but neatly organizes alternative config via tabs and collapses more niche info. Above that part is an example of where I link to a Github comment for more info: For reference, recently revised PROXY protocol docs page (unreleased, so this link may eventually become broken for future readers). Quite a lot there is hidden away with the primary focus on the Traefik and related config to use PROXY protocol to preserve the client IP where needed.
No worries, I understand 👍 Writing/improving docs is a time consuming effort for me too 😓 I just wanted to raise awareness and clear up some confusion, which you've been extremely helpful with! ❤️ |
Hmm yeah, I guess so. I'll play with that, thanks.
Oh right 🤦♂️ I keep forgetting that the
The issue is our docs right now are pure markdown (with some sprinkled in jquery for targeted augmentations), so we don't have the infra for collapsibles right now. I did set up a tab box with AlpineJS for this one section https://caddyserver.com/docs/running#local-https-with-docker but I haven't gotten around to using this in more places yet (we will though). I'll need to set up the stuff for collapsibles with AlpineJS too eventually.
🫶 |
The docs I reference are generated from markdown as well ( You should be able to use HTML usually, and can add I really love the feature your docs have though with config snippets that are interactable (clicking a setting name goes to that part of the docs, or hover reveals some extra information). |
FYI #374, I'm working on a big docs update, this feedback is incorporated. |
Feedback on the docs on Global Caddyfile
listener_wrappers
setting, hope it's somewhat helpful!Sorry about the verbosity, low on time 😭
Summary:
auto_https
implicit redirects seem broken with PROXY protocol support (see Traefik logs shared below)http_redirect
may have a bug or would benefit from clearer communication of caveat.http_redirect
should document placement order afterproxy_protocol
, similar to need for beforetls
.proxy_protocol
could better clarifyallow
expectations (suggestion provided below), possibly improve implementation.proxy_protocol
, could be better clarified in JSON docs.http_redirect
http_redirect
describes itself as important for redirecting HTTP to HTTPS when the request is arriving on an HTTPS port to avoid responding with "Client sent an HTTP request to an HTTPS server.".proxy_protocol
to work correctly (at least for those connections matchingallow
).http://
site addresses: Following the docs example (instead of configuring separate servers per port) will make these routes inaccessible as the redirection is forced (like implicit redirects fromautohttps
).http://
scheme and HTTP port. Should be no-op on the server using HTTP port?proxy_protocol
https://caddyserver.com/docs/json/apps/http/servers/listener_wrappers/proxy_protocol/#allow
/32
CIDR notation) or IP ranges are configured, anything else is not trusted for PROXY protocol connections, while the allowed IPs are required to provide the PROXY protocol header?This is fine, just comparing to other software it might be helpful to clarify expectations?:
"Allow is an optional list of trusted CIDR ranges expected to provide PROXY headers. Untrusted IPs using PROXY protocol will be rejected, but may otherwise connect normally without PROXY protocol."
Reference - Comparison to other implementations
Here's what I've noticed from least flexible to most flexible:
I think Traefik has it right there, by enforcing communicating trust by default (a list of trusted IPs or toggle insecure) while allowing regular connections through that aren't using PROXY protocol? (other software is a bit inconvenient by requiring separate ports for internal clients)
Caddy can manage to handle this distinction well enough when the specific trusted IPs are known, but
allow
couldn't use a wider private range subnet liketrusted_proxies
due to trusted IPs enforcing the requirement for PROXY header (I'm having trouble understanding why that needs to be enforced, other than preventing misconfiguration from hosts that are expected to always send the PROXY header?).Observation - Bugs?
When connecting to an HTTPS site address via curl and the following config:
From the client IP
172.16.42.42
and Traefik (172.16.42.10
):tls
.The Caddy docs are rather clear about
proxy_protocol
needing to come beforetls
, so I assume the error is from the PROXY header being present via Traefik and thetls
being implicitly before it 👍That all makes sense, but if
tls
is uncommented, while HTTPS works correctly, HTTP fails with400 Bad Request
, Traefik wasn't able to connect to Caddy on port 80:http://
site address block. TCP router with PROXY protocol can be used then.I know that by default the
auto_https
feature would have enabled the implicit redirects, and thathttp://
site block explicitly opts-out of that feature. I guess something there is not compatible the PROXY protocol support? 🤷♂️I can also add
http_redirect
afterproxy_protocol
to restore that redirect behaviour for PROXY protocol connections to Caddy, it must be afterproxy_protocol
though to work. Alternatively in this scenario, Traefik could also handle HTTP => HTTPS, but Traefik isn't relevant here, only used to test support introduced in Caddy 2.7.I don't have any need for PROXY protocol with HTTP/HTTPS myself, I have used it for TCP traffic for mail servers but was curious about the Caddy 2.7 support and how it compared to the equivalent support in Traefik. Not sure how it compares to the Caddy L4 app, I haven't tried that yet due to current JSON only support.
Misc
Not sure why, but
proxy_protocol
has two entries listed (JSON docs forlistener_wrappers
) with one marked asnon-standard
:Seems to be better communicated here:
The PROXY protocol links point to docs location from HAProxy
1.8
release (that seems to have been updated since) but should probably reference a more direct source?: https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txtThe text was updated successfully, but these errors were encountered: