Routing and rewrites

Route by hostname

Serve two local hostnames through one listener and preserve distinct application boundaries.

10 minute lesson

~~~

A single machine with a single IP address can serve many sites. The HTTP Host header and TLS SNI let one proxy serve multiple sites on one address: the client names the site it wants, and the proxy routes on that name. Each site block can have its own upstream and policy.

Map the lab hostnames

The names need to resolve first. Add them to /etc/hosts:

127.0.0.1 app.lab.test admin.lab.test

Both names point to loopback, so the same Caddy listener receives both.

Create two site blocks

http://app.lab.test:8080 {
  reverse_proxy 127.0.0.1:4001
}

http://admin.lab.test:8080 {
  reverse_proxy 127.0.0.1:4002
}

Two site addresses, one port, two different upstreams. Caddy picks the block whose hostname matches the request’s Host header.

Reload and request each name:

curl http://app.lab.test:8080/
# {"port":4001,"path":"/"}

curl http://admin.lab.test:8080/
# {"port":4002,"path":"/"}

Same IP, same port, different backends. You can prove the routing decision is purely the Host header by faking it:

curl -H "Host: admin.lab.test" http://127.0.0.1:8080/
# {"port":4002,"path":"/"}

That request never mentioned admin.lab.test in the URL. The header alone selected the admin backend.

The unmatched host

Now send a name Caddy doesn’t know:

curl -i -H "Host: other.lab.test" http://127.0.0.1:8080/

Caddy returns an empty response rather than picking a site for you. That’s the behavior you want. An unmatched Host should not silently reach a privileged backend — if it did, anyone who guessed your IP could skip the hostname entirely.

That last experiment is also the warning. Host routing is not user authorization. The client chooses the Host header, exactly like it chose the forged X-Forwarded-For earlier in the course. Routing admin.lab.test to a separate upstream organizes traffic; it doesn’t authenticate anyone. Protect an admin application inside the application or trusted access layer, and treat the hostname split as convenience, not as a security boundary.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →