I have HAProxy handling my SSL termination and then for a subset of hostnames I pass traffic to Traefik to handle some dynamic routing to containers that are in our development environment and change as code moves through our development pipeline. Many of the services are built on top of an Nginx service which to simplify handling of IP addresses we enabled PROXY Protocol. But since adding Traefik to our request flow, I haven't been able to figure out the best way to handle routing via hostname on port 80 (HTTP) to a service using PROXY Protocol. I have successfully enabled listening on my HTTP port 80 entrypoint but when I try to enable it on my http service I get the following error:
traefik-1 | 2024-10-01T07:12:21Z ERR error="field not found, node: proxyprotocol" container=frontend-m108review-a533831e894319bc5cb82f03ef4461823dbc6bd69ae13605749e11b9840d9164 providerName=docker
I found that this is likely due to the proxyProtocol setting only being available to tcp type services but changing my configuration to tcp, I run into issues with my Host(m108review.dev.software.com
) rule as that rule is not supported.
invalid rule: "Host(m108review.dev.software.com
)" , unsupported function: Host
Can someone help me figure out what I am missing? Thank you ahead of time
Share your full Traefik static and dynamic config, and docker-compose.yml
if used.
Use 3 backticks before and after code/config to make it more readable and keep spacing.
ProxyProtocol only works with TCP, headers like X-Forwarded-For
and X-Real-Ip
are used with http.
The following is the current state of my Traefik/downstream Nginx service. I have temporarily disabled proxy protocol on the nginx service and it works. But I want to enable it again so that I am matching the same header handling as our production environment. I attempted to add the label "traefik.http.services.${CI_COMMIT_REF_SLUG}_backend.loadbalancer.proxyprotocol=true" but that led to the "field not found" error from my original post. I understand that Proxy Protocol is a TCP thing but there has to be a way to route based on hostname as in almost all implementations of the protocol I have seen, it is for HTTP(s) traffic. Both Nginx and HAProxy which I have used both have mechanisms for this and I have a hard time believing that this wasn't a use case to consider when proxy protocol was put into Traefik in the first place (at least in context of downstream services)...
docker-compose.yml
traefik:
image: traefik:3
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.http.address=:80"
- "--entrypoints.http.proxyprotocol=true"
- "--entrypoints.http.proxyprotocol.trustedips=172.17.0.0/11"
expose:
- "8080"
- "80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- frontend
- backend
downstream service (Nginx expecting proxy protocol)
docker run -d --name frontend-${CI_COMMIT_REF_SLUG} --env-file ./.dev-env --label "traefik.enable=true" --label "traefik.http.routers.${CI_COMMIT_REF_SLUG}.rule=Host(\`${CI_COMMIT_REF_SLUG}.dev.software.com\`)" --label "traefik.http.services.${CI_COMMIT_REF_SLUG}_backend.loadbalancer.server.port=3000" --expose 3000 --network backend_default mynginximage:latest
Check reference for proxyprotocol
.
For receiving: it can be placed under entrypoint
(doc).
For proxying/forwarding: it can only be placed under tcp
router (doc).
I understand this, but when changing my labels to the following I get an error that the Host rule cannot be used as mention in my original post...
--label "traefik.enable=true"
--label "traefik.tcp.routers.${CI_COMMIT_REF_SLUG}.rule=Host(\`${CI_COMMIT_REF_SLUG}.dev.software.com\`)"
--label "traefik.tcp.services.${CI_COMMIT_REF_SLUG}_backend.loadbalancer.server.port=3000"
--label "traefik.tcp.services.${CI_COMMIT_REF_SLUG}_backend.loadbalancer.proxyprotocol=true"
That is correct. Host()
is used with the Host
header of the http protocol. So it only works with http.
For a TCP router, you can only use HostSNI()
- if TLS is used for the TCP connection.