Something doesn’t add up. Is what you’ve posted the 100% full picture without any alterations?
Your first curl command gets an Etag and content-length back as if it was serving a file from the file_server, which only appears in your error handler.
Your second curl command doesn’t get any of that, indicating it isn’t even getting into the error handler. But there’s no other file_server specified in your posted config.
I think some other shenanigans are up, and that Caddy is actually working fine.
I managed to reproduce the problem partially when the /404.html does not exist in /etc/caddy/static.
So that the “fallback” file_server throws an error (and returns early, I assume), and the headers handler created by the header directive isn’t executed.
However, this does not explain why you get different results when reaching the same server over different interfaces/IPs.
Would you mind rerunning your curl commands?
Just to double-check, it has nothing to do with caddy serving two different configs between the tests?
Also, are you running caddy run with the -watch or -resume flag? You mentioned both in your opening post:
Excerpt from caddy run -help:
-resume
Use saved config, if any (and prefer over --config file)
The saved config is not the Caddyfile, but the internal json config every Config Adapters — Caddy Documentation translates to.
You can print the internal json config by running curl localhost:2019/config/ from within your Docker container.
Would be nice if you could provide some logs and perhaps this json config, to nail this issue further down