Reverse proxy does not listen for http when address specified

1. The problem I’m having:

Can’t reverse proxy http → https while specifying a listen address. As soon as I specify the listen address and http transport, it gives me an error on my browser that my Client sent an HTTP request to an HTTPS server.

If I use:

caddy reverse-proxy --insecure --from :8005 --to https://localhost:8006

…then I have success. However as soon as I specify a --from address (even with http transport) it stops functioning with the error noted below:

It looks like it is trying to set up an HTTPS listener despite the http transport specified in --from

2. Error messages and/or full log output:

Command and log when it doesn’t work is:

# caddy reverse-proxy --insecure --from http://127.0.0.1:8005 --to https://localhost:8006
2025/01/04 07:54:39.371	WARN	admin	admin endpoint disabled
2025/01/04 07:54:39.371	INFO	http	enabling automatic HTTP->HTTPS redirects	{"server_name": "proxy"}
2025/01/04 07:54:39.371	INFO	tls.cache.maintenance	started background certificate maintenance	{"cache": "0xc0003ce620"}
2025/01/04 07:54:39.372	INFO	tls	cleaning storage unit	{"description": "FileStorage:/root/.local/share/caddy"}
2025/01/04 07:54:39.373	INFO	tls	finished cleaning storage units
2025/01/04 07:54:39.391	INFO	pki.ca.local	root certificate is already trusted by system	{"path": "storage:pki/authorities/local/root.crt"}
2025/01/04 07:54:39.392	INFO	http	enabling HTTP/3 listener	{"addr": ":8005"}
2025/01/04 07:54:39.392	INFO	failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size for details.
2025/01/04 07:54:39.392	INFO	http.log	server running	{"name": "proxy", "protocols": ["h1", "h2", "h3"]}
2025/01/04 07:54:39.392	INFO	http.log	server running	{"name": "remaining_auto_https_redirects", "protocols": ["h1", "h2", "h3"]}
2025/01/04 07:54:39.392	INFO	http	enabling automatic TLS certificate management	{"domains": ["127.0.0.1"]}
2025/01/04 07:54:39.393	WARN	tls	stapling OCSP	{"error": "no OCSP stapling for [127.0.0.1]: no OCSP server specified in certificate", "identifiers": ["127.0.0.1"]}
Caddy proxying http://127.0.0.1:8005 -> localhost:8006

Command and log when it does work (listen address not specified):

# caddy reverse-proxy --from :8005 --to https://localhost:8006 --insecure
2025/01/04 07:39:12.085	WARN	admin	admin endpoint disabled
2025/01/04 07:39:12.086	INFO	tls.cache.maintenance	started background certificate maintenance	{"cache": "0xc0002d8460"}
2025/01/04 07:39:12.086	INFO	http.log	server running	{"name": "proxy", "protocols": ["h1", "h2", "h3"]}
Caddy proxying http://:8005 -> localhost:8006
2025/01/04 07:39:12.086	INFO	tls	cleaning storage unit	{"description": "FileStorage:/root/.local/share/caddy"}
2025/01/04 07:39:12.087	INFO	tls	finished cleaning storage units
^C2025/01/04 07:39:26.947	INFO	shutting down	{"signal": "SIGINT"}
2025/01/04 07:39:26.947	WARN	exiting; byeee!! 👋	{"signal": "SIGINT"}
2025/01/04 07:39:26.948	INFO	tls.cache.maintenance	stopped background certificate maintenance	{"cache": "0xc0002d8460"}
2025/01/04 07:39:26.948	INFO	shutdown complete	{"signal": "SIGINT", "exit_code": 0}

3. Caddy version:

Version 2.6.2 (Debian 12)

4. How I installed and ran Caddy:

a. System environment:

Debian 12.8

b. Command:

caddy reverse-proxy --insecure --from http://127.0.0.1:8005 --to https://localhost:8006

c. Service/unit/compose file:

d. My complete Caddy config:

n/a (command line)

5. Links to relevant resources:

n/a

It does not appear possible to do what I wanted to do (listen on an address:port for an http connection and reverse proxy it to address2:port2) solely on the command line.

It works with a CaddyFile:

:8005 {
    bind 127.0.0.1
    reverse_proxy https://localhost:8006 {
        transport http {
            tls_insecure_skip_verify
        }
    }
}

Part of my problem was that the command-line documentation is wrong:

# caddy reverse-proxy --help
...
If the --from address has a host or IP, Caddy will attempt to serve the
proxy over HTTPS with a certificate (unless overridden by the HTTP scheme
or port).
...

This is wrong. If a host or IP is given Caddy will always attempt to serve the proxy over HTTPS, regardless if the HTTP scheme is given. Overrides to this behaviour do not appear to be possible.

Out of curiosity, I tried your command with the current version of Caddy, 2.9.0, and it worked perfectly fine on first try with the command-line version, sans Caddyfile.

So the true solution appears to be: upgrade Caddy!
2.6.2 is from 2022.

On the other hand, Caddy is probably overkill for such a simple task. The handy little tool stunnel might be all you need.

Fair enough! I tend to be conservative and first try solutions with distribution-provided tools, but I should have tried a more recent version before posting.

Actually, I like it. It’s elegant and now that I understand it a bit better, a great drop-in solution for these very problems. I like having a swiss army knife available that’s easy to drop in a config for.