Automatic HTTPS redirecting even domains not configured in the caddyfile

1. The problem I’m having:

I recently migrated from Nginx to Caddy a few days ago for my personal projects. New user here.

During this migration, I started a new VPS instance, replacing the nginx as a reverse proxy by caddy for my apps while decommissioning some projects I don´t need anymore.
So these projects are not added in the caddy file and I did not remove their A entry from DNS, so it continues pointing to the instance IP.
The new VPS instance keeps the old instance IP since I transferred it.

Even though these old projects are not in the Caddy file, I noticed that Caddy Automatic HTTPS continues answering their HTTP(non-SSL) requests, by redirecting them to the same domain as HTTPS(SSL).

Is there a reason for that, since this it does not match the last condition for the automatic HTTPS mentioned in the documentation?

  • :white_check_mark: If your domain’s A/AAAA records point to your server,
  • :white_check_mark: ports 80 and 443 are open externally,
  • :white_check_mark: Caddy can bind to those ports (or those ports are forwarded to Caddy),
  • :white_check_mark: your data directory is writeable and persistent,
  • :x: and your domain name appears somewhere relevant in the config,

I could reproduce the behaviour locally which is the config files and logs I will share below.

I also tried to enable the access log for the entire caddy but if I understood correctly I cannot do that without a configuration block for the domain, so there is no way I can see all the domains in this situation.

2. Error messages and/or full log output:

Docker Compose logs

 docker compose up
WARN[0000] /home/xxx/docker-compose.yaml: `version` is obsolete
[+] Running 1/0
 ✔ Container deployment-caddy-caddy-1  Created                                                                                                                                                                                                                                       0.1s
Attaching to caddy-1
caddy-1  | {"level":"info","ts":1719722741.5432565,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
caddy-1  | {"level":"info","ts":1719722741.5438507,"msg":"adapted config to JSON","adapter":"caddyfile"}
caddy-1  | {"level":"warn","ts":1719722741.5438595,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
caddy-1  | {"level":"info","ts":1719722741.5443277,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
caddy-1  | {"level":"info","ts":1719722741.5443966,"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}
caddy-1  | {"level":"info","ts":1719722741.5444095,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
caddy-1  | {"level":"info","ts":1719722741.5444424,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00051f680"}
caddy-1  | {"level":"debug","ts":1719722741.5446239,"logger":"http.auto_https","msg":"adjusted config","tls":{"automation":{"policies":[{"subjects":["website1.local"]},{}]}},"http":{"servers":{"remaining_auto_https_redirects":{"listen":[":80"],"routes":[{},{}]},"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"headers","response":{"set":{"Content-Type":["text/html"]}}},{"body":"\u003chtml\u003e\n\t\u003chead\u003e\u003ctitle\u003eFoo\u003c/title\u003e\u003c/head\u003e\n\t\u003cbody\u003eFoo\u003c/body\u003e\n\u003c/html\u003e","handler":"static_response","status_code":200}]}]}],"terminal":true}],"tls_connection_policies":[{}],"automatic_https":{}}}}}
caddy-1  | {"level":"warn","ts":1719722741.5448084,"logger":"pki.ca.local","msg":"installing root certificate (you might be prompted for password)","path":"storage:pki/authorities/local/root.crt"}
caddy-1  | {"level":"info","ts":1719722741.5452461,"msg":"define JAVA_HOME environment variable to use the Java trust"}
caddy-1  | {"level":"info","ts":1719722741.545256,"msg":"warning: \"certutil\" is not available, install \"certutil\" with \"apt install libnss3-tools\" or \"yum install nss-tools\" and try again"}
caddy-1  | {"level":"info","ts":1719722741.551656,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"ac4e7c9d-0272-4794-9c18-0e6cfb59cf2e","try_again":1719809141.551649,"try_again_in":86399.999998045}
caddy-1  | {"level":"info","ts":1719722741.5517325,"logger":"tls","msg":"finished cleaning storage units"}
caddy-1  | {"level":"info","ts":1719722741.5725906,"msg":"certificate installed properly in linux trusts"}
caddy-1  | {"level":"info","ts":1719722741.5729814,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
caddy-1  | {"level":"debug","ts":1719722741.5732636,"logger":"http","msg":"starting server loop","address":"[::]:443","tls":true,"http3":true}
caddy-1  | {"level":"info","ts":1719722741.573287,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
caddy-1  | {"level":"debug","ts":1719722741.5733366,"logger":"http","msg":"starting server loop","address":"[::]:80","tls":false,"http3":false}
caddy-1  | {"level":"info","ts":1719722741.5733504,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
caddy-1  | {"level":"info","ts":1719722741.573356,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["website1.local"]}
caddy-1  | {"level":"warn","ts":1719722741.5738323,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [website1.local]: no OCSP server specified in certificate","identifiers":["website1.local"]}
caddy-1  | {"level":"debug","ts":1719722741.5738556,"logger":"tls.cache","msg":"added certificate to cache","subjects":["website1.local"],"expiration":1719765631,"managed":true,"issuer_key":"local","hash":"40e9cdbd7a4f224d57f4e2e5a00ecba5743a87be9828bff8a06b4b921825b482","cache_size":1,"cache_capacity":10000}
caddy-1  | {"level":"debug","ts":1719722741.5739062,"logger":"events","msg":"event","name":"cached_managed_cert","id":"f715482b-3662-456b-99b6-2ec0f0ec17e1","origin":"tls","data":{"sans":["website1.local"]}}
caddy-1  | {"level":"info","ts":1719722741.5740986,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
caddy-1  | {"level":"info","ts":1719722741.5741107,"msg":"serving initial configuration"}

Wget requests logs

➜  ~ wget -v --max-redirect=0 http://website2.local
--2024-06-29 21:47:16--  http://website2.local/
Resolving website2.local (website2.local)... 127.0.0.1
Connecting to website2.local (website2.local)|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 308 Permanent Redirect
Location: https://website2.local/ [following]
0 redirections exceeded.
➜  ~ wget -v --max-redirect=0 http://website1.local
--2024-06-29 21:47:27--  http://website1.local/
Resolving website1.local (website1.local)... 127.0.0.1
Connecting to website1.local (website1.local)|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 308 Permanent Redirect
Location: https://website1.local/ [following]
0 redirections exceeded.

3. Caddy version:

2.8.4

4. How I installed and ran Caddy:

a. System environment:

  • Linux: Linux vini 6.5.0-41-generic #41~22.04.2-Ubuntu SMP PREEMPT_DYNAMIC Mon Jun 3 11:32:55 UTC 2 x86_64 x86_64 x86_64 GNU/Linux

  • Docker version: 27.0.2

b. Command:

docker compose up

c. docker-compose file:

version: "3.7"
name: deployment-caddy
services:
  caddy:
    image: caddy:2.8.4
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./site:/srv
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - caddy
volumes:
  caddy_data:
    external: true
  caddy_config:

networks:
  caddy:

d. My complete Caddy config:

{
  debug
}
website1.local {
	header Content-Type text/html
  	respond <<HTML
  		<html>
  			<head><title>Foo</title></head>
  			<body>Foo</body>
  		</html>
  		HTML 200

}

e. /etc/hosts:

127.0.0.1 website1.local
127.0.0.1 website2.local

That condition has to do whether Automatic HTTPS (the feature name) is enabled, and this feature enables HTTP->HTTPS redirects in general. Since you have at least one domain which causes Automatic HTTPS to enable, the redirects are set up.

We actually insert two routes in the HTTP server, one matching each configured hostname, and another as a catch-all. It’s done this way, so you can write your own http://your-domain.com site block to override a specific domain’s HTTP routes, or a http:// site block which overrides the catch-all.

So if you want different behaviour, just configure Caddy to do something different with a http:// site block for unknown domains.

1 Like

I see. My intention was just drop the connection without answer.

I did a quick test and It worked when I answered with a response code. It keeps the HTTP redirect for the configured domain.:

Caddyfile

{
  debug
}
website1.local {
	header Content-Type text/html
  	respond <<HTML
  		<html>
  			<head><title>Foo</title></head>
  			<body>Foo</body>
  		</html>
  		HTML 200

}

http:// {
  respond 404
}

wget test

➜  ~ wget -v --max-redirect=0 http://website1.local
--2024-06-29 23:50:18--  http://website1.local/
Resolving website1.local (website1.local)... 127.0.0.1
Connecting to website1.local (website1.local)|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 308 Permanent Redirect
Location: https://website1.local/ [following]
0 redirections exceeded.
➜  ~ wget -v --max-redirect=0 http://website2.local
--2024-06-29 23:50:23--  http://website2.local/
Resolving website2.local (website2.local)... 127.0.0.1
Connecting to website2.local (website2.local)|127.0.0.1|:80... connected.
HTTP request sent, awaiting response... 404 Not Found
2024-06-29 23:50:23 ERROR 404: Not Found.


But if I close the connection directly, it propagates for the configured domain as well:

Caddyfile

{
  debug
}
website1.local {
	header Content-Type text/html
  	respond <<HTML
  		<html>
  			<head><title>Foo</title></head>
  			<body>Foo</body>
  		</html>
  		HTML 200

}

http:// {
  respond {
      close
  }
}

wget test

➜  ~ wget -v --max-redirect=0 http://website1.local
--2024-06-29 23:52:48--  http://website1.local/
Resolving website1.local (website1.local)... 127.0.0.1
Connecting to website1.local (website1.local)|127.0.0.1|:80... failed: Connection refused.
➜  ~ wget -v --max-redirect=0 http://website2.local
--2024-06-29 23:52:51--  http://website2.local/
Resolving website2.local (website2.local)... 127.0.0.1
Connecting to website2.local (website2.local)|127.0.0.1|:80... failed: Connection refused.

So my option to keep the close connection as default to http:// would be configured the redirect manually to the configured domains?

Thank you!

You could use the abort directive instead.

3 Likes

That works perfectly!

{
  debug
}
website1.local {
	header Content-Type text/html
  	respond <<HTML
  		<html>
  			<head><title>Foo</title></head>
  			<body>Foo</body>
  		</html>
  		HTML 200

}

http:// {
  abort
}

Thank you!

2 Likes

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