Automatically forward subdomain to port on localhost

1. Caddy version (caddy version):


2. How I run Caddy:

as a homebrew service on macOS with:
brew services start caddy

a. System environment:


b. Command:

/usr/local/opt/caddy/bin/caddy run --config /usr/local/etc/Caddyfile

c. Service/unit/compose file:

This is the default homebrew.caddy.service installed by brew install caddy:

Description=Homebrew generated unit for caddy


ExecStart=/usr/local/opt/caddy/bin/caddy run --config /usr/local/etc/Caddyfile

d. My complete Caddyfile or JSON config:

3000.localhost {
    tls internal
    reverse_proxy localhost:3000

3001.localhost {
    tls internal
    reverse_proxy localhost:3001

3002.localhost {
    tls internal
    reverse_proxy localhost:3002

3020.localhost {
    tls internal
    reverse_proxy localhost:3020

4000.localhost {
    tls internal
    reverse_proxy localhost:4000

5000.localhost {
    tls internal
    reverse_proxy localhost:5000

6000.localhost {
    tls internal
    reverse_proxy localhost:6000

7000.localhost {
    tls internal
    reverse_proxy localhost:7000

8000.localhost {
    tls internal
    reverse_proxy localhost:8000

3. The problem I’m having:

I’m working with a microservices architecture and often have to spin up multiple front-ends running on different ports, the above config is working for me but I have to add a new config section for each new service I start on a different port, this is starting to get messy.

It would be cool if I could instead configure caddy to capture the subdomain and reverse proxy automaticaly to that port on localhost but I can’t figure out a way to do this in the Caddyfile.

4. Error messages and/or full log output:


5. What I already tried:

I’ve read through the docs but can’t figure out if what I’m trying is possble

6. Links to relevant resources:

Any help would be much appreciated.


Maybe a snippet is what you’re after?

(sub2port) {
    {args.0}.localhost {
        tls internal
        reverse_proxy localhost:{args.0}

import sub2port 3000
import sub2port 3001

That does clean things up quite a bit thanks.
would be great to not have to list out all the ports though

Maybe something like this:

:443 {
	tls internal {

	@portLocalhost header_regexp port Host ^([0-9]+)\.localhost$
	handle @portLocalhost {
		reverse_proxy localhost:{re.port.1}

	handle {
		respond "Bad hostname" 400

But a config like this would only be appropriate for development/local use. I cannot recommend this kind of pattern for production. Using on_demand opens you up for abuse unless you configure Caddy with the ask option to limit the domains for which certificates are issued.


This works perfectly thanks so much .

I get this is a very stupid thing to do in prod but it makes spinning up local servers with tls so easy, thanks again

1 Like

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