Caddy run behind web proxy, Unknown Host error when HTTPS_PROXY is set

1. The problem I’m having:

I run Caddy web server + FrankenPHP application in a docker container.

It runs behind a reverse proxy and has no direct access to the internet. This was OK.

Then my application needed to call external APIs , so I added HTTP_PROXY and HTTPS_PROXY env var defined to the http proxy URL of my organisation, in order to have access to internet.

But then Caddy respond an “Unknown Host” error

indeed a.domain.fr is not defined in DNS ,i try to add it in the docker extra_hosts param, but it has no effect, Caddy seems to really make a DNS resolution like dig would do.

I don’t understand why this DNS resolution is not done or don’t make error , when HTTP_PROXY is not set

2. Error messages and/or full log output:

Unknown Host


Description: Unable to locate the server named “a.domain.fr” — the server does not have a DNS entry. Perhaps there is a misspelling in the server name, or the server no longer exists. Double-check the name and try again.

3. Caddy version:

4. How I installed and ran Caddy:

a. System environment:

docker image based on dunglas/frankenphp:latest-alpine

b. Command:

c. Service/unit/compose file:

d. My complete Caddy config:

{
	{$CADDY_GLOBAL_OPTIONS}

	frankenphp {
		{$FRANKENPHP_CONFIG}
	}

	# https://caddyserver.com/docs/caddyfile/directives#sorting-algorithm
	order mercure after encode
	order vulcain after reverse_proxy
	order php_server before file_server
}

{$CADDY_EXTRA_CONFIG}

{$SERVER_NAME:localhost} {
	log {
		# Redact the authorization query parameter that can be set by Mercure
		format filter {
			wrap console
			fields {
				uri query {
					replace authorization REDACTED
				}
			}
		}
	}

	root * /app/public
	encode zstd gzip

	mercure {
		# Transport to use (default to Bolt)
		transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
		# Publisher JWT key
		publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
		# Subscriber JWT key
		subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
		# Allow anonymous subscribers (double-check that it's what you want)
		anonymous
		# Enable the subscription API (double-check that it's what you want)
		subscriptions
		# Extra directives
		{$MERCURE_EXTRA_DIRECTIVES}
	}

	vulcain

	# Add links to the API docs and to the Mercure Hub if not set explicitly (e.g. the PWA)
	header ?Link `</docs.jsonld>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation", </.well-known/mercure>; rel="mercure"`
	# Disable Topics tracking if not enabled explicitly: https://github.com/jkarlin/topics
	header ?Permissions-Policy "browsing-topics=()"

    # Matches requests for HTML documents, for static files and for Next.js files,
	# except for known API paths and paths with extensions handled by API Platform
	@frontend expression `
			!path(
				'/docs*', '/graphql*', '/bundles*', '/contexts*', '/_profiler*', '/_wdt*',
				'*.json*', '*.html', '*.csv', '*.yml', '*.yaml', '*.xml',
				'/api*', '/login*', '/logout*', '/forgot-password', '/print*'
			)
		|| path('/favicon.ico', '/manifest.json', '/robots.txt', '/_nuxt*', '/sitemap*', '/signatureProductionLibrary*')`


    # Comment the following line if you don't want frontend to catch requests for HTML documents.
	# In this case, they will be handled by the PHP app.
	reverse_proxy @frontend http://{$FRONTEND_UPSTREAM}

	php_server
}
$SERVER_NAME = http://b.domain.fr, http://a.domain.fr, http://localhost

5. Links to relevant resources:

Startup logs :

2024/03/05 13:32:12.487	INFO	using provided configuration	{"config_file": "/etc/caddy/Caddyfile", "config_adapter": ""}
2024/03/05 13:32:12.493	WARN	Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies	{"adapter": "caddyfile", "file": "/etc/caddy/Caddyfile", "line": 14}
2024/03/05 13:32:12.499	INFO	admin	admin endpoint started	{"address": "localhost:2019", "enforce_origin": false, "origins": ["//localhost:2019", "//[::1]:2019", "//127.0.0.1:2019"]}
2024/03/05 13:32:12.501	WARN	http.auto_https	server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server	{"server_name": "srv0", "http_port": 80}
2024/03/05 13:32:12.501	INFO	tls.cache.maintenance	started background certificate maintenance	{"cache": "0xc00063c080"}
2024/03/05 13:32:13.905	INFO	FrankenPHP started 🐘	{"php_version": "8.3.3"}
2024/03/05 13:32:13.905	INFO	http.log	server running	{"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2024/03/05 13:32:13.905	INFO	autosaved config (load with --resume flag)	{"file": "/config/caddy/autosave.json"}
2024/03/05 13:32:13.905	INFO	serving initial configuration
2024/03/05 13:32:13.912	INFO	tls	cleaning storage unit	{"storage": "FileStorage:/data/caddy"}
2024/03/05 13:32:13.914	INFO	tls	finished cleaning storage units

Make a curl request :

curl 'https://a.domain.fr/connexion' --compressed -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:123.0) Gecko/20100101 Firefox/123.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' -H 'Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3' -H 'Accept-Encoding: gzip, deflate, br' -H 'Connection: keep-alive' -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-Fetch-Dest: document' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-Site: none' -H 'Sec-Fetch-User: ?1' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'

response :

<HEAD><TITLE>Unknown Host</TITLE></HEAD>
<BODY BGCOLOR="white" FGCOLOR="black"><H1>Unknown Host</H1><HR>
<FONT FACE="Helvetica,Arial"><B>
Description: Unable to locate the server named "<em>a.domain.fr</em>" --- the server does not have a DNS entry.  Perhaps there is a misspelling in the server name, or the server no longer exists.  Double-check the name and try again.</B></FONT>
<HR>
<!-- default "Unknown Host" response (504) -->
</BODY>

Caddy logs :

2024/03/07 10:13:36.237	ERROR	http.log.access.log0	handled request	{"request": {"remote_ip": "10.33.150.1", "remote_port": "61284", "client_ip": "10.33.150.1", "proto": "HTTP/1.1", "method": "GET", "host": "a.domain.fr", "uri": "/connexion", "headers": {"User-Agent": ["Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:123.0) Gecko/20100101 Firefox/123.0"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"], "Sec-Fetch-User": ["?1"], "Cache-Control": ["no-cache"], "Accept-Language": ["fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3"], "Accept-Encoding": ["gzip, deflate, br"], "Cookie": [], "Upgrade-Insecure-Requests": ["1"], "Sec-Fetch-Dest": ["document"], "Sec-Fetch-Site": ["none"], "Pragma": ["no-cache"], "Connection": ["keep-alive"], "Sec-Fetch-Mode": ["navigate"]}}, "bytes_read": 0, "user_id": "", "duration": 0.040428296, "size": 354, "status": 504, "resp_headers": {"Content-Type": ["text/html"], "Vary": ["Accept-Encoding"], "Permissions-Policy": ["browsing-topics=()"], "Date": ["Thu, 07 Mar 2024 10:13:36 GMT"], "Cache-Control": ["no-store"], "Content-Encoding": ["gzip"], "Via": ["1.1 b2-ttheb-prx1"], "Link": ["</docs.jsonld>; rel=\"http://www.w3.org/ns/hydra/core#apiDocumentation\", </.well-known/mercure>; rel=\"mercure\""], "Server": ["Caddy"], "Content-Language": ["en"]}}

I’m not sure I follow, I don’t see any errors in your logs. Please show an example request with curl -v.

Sorry I added some infos and log with curl request

Hmm. Enable the debug global option, we might get more detail as to what’s going on in your logs. 504 status is “gateway timeout”.

Thanks, debug option didn’t help me much, but your response makes me realize this error appends only on requests to the @frontend upstream, not to the php upstream.
Then the problem should come front the @frontend upstream

Sorry

For information …

I found the cause of the error :

reverse_proxy @frontend http://{$FRONTEND_UPSTREAM}
FRONTEND_UPSTREAM=frontend:3000

(this is the frontend container hostname in docker compose)

When I set HTTP_PROXY and HTTPS_PROXY, frontend was not resolved correctly anymore.
I have to set NO_PROXY=frontend in order to not use the http_proxy for this “URL”

1 Like

Yes, that’s exactly your issue. When those environment are set, the reverse_proxy uses them to find the upstreams. If you don’t want them to be passed to the HTTP_PROXY server, add them to NO_PROXY variable, like you did.

1 Like

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