This episode covers load balancing strategies: multiple backends, the round_robin, least_conn, ip_hash, and other policies, active and passive health checks, upstream configuration with weights and timeouts, and horizontal scaling use cases.

A single application isn't always enough. When traffic grows, you add a second instance, a third, and so on — and then you need something that distributes requests fairly among them. That's load balancing, and Caddy has it built right into the reverse_proxy directive.
Registering multiple backends is as easy as writing several addresses:
app.example.com {
reverse_proxy localhost:8080 localhost:8081
}Caddy distributes requests automatically. The default policy is round_robin — each request goes to the next backend in turn.
A policy determines how a request picks a backend:
app.example.com {
reverse_proxy {
to localhost:8080 localhost:8081 localhost:8082
lb_policy least_conn
}
}Some policies target specific requests to the same backend:
ip_hash example:
app.example.com {
reverse_proxy {
to localhost:8080 localhost:8081
lb_policy ip_hash
}
}lb_policy ip_hash ensures the same client always reaches the same backend — useful for applications with light state.
Caddy probes backends periodically:
app.example.com {
reverse_proxy {
to localhost:8080 localhost:8081
health_uri /healthz
health_interval 10s
health_timeout 5s
}
}health_uri /healthz — the path that gets probed.health_interval 10s — probe every 10 seconds.health_timeout 5s — a backend is considered failed if it doesn't respond within 5 seconds.Without probing, Caddy judges health from actual request responses:
app.example.com {
reverse_proxy {
to localhost:8080 localhost:8081
max_fails 3
fail_duration 30s
}
}Not all backends are equally strong. Give weights so bigger backends receive more:
app.example.com {
reverse_proxy {
to localhost:8080 localhost:8081 localhost:8082
lb_policy round_robin
}
}Weights are written as a list with options:
app.example.com {
reverse_proxy {
to http://localhost:8080 http://localhost:8081
dial_timeout 10s
max_conns_per_host 500
}
}For slow backends:
app.example.com {
reverse_proxy {
to localhost:8080
transport http {
response_header_timeout 30s
}
}
}caddy reload applies pool changes without dropping connections.caddy reload --config Caddyfile reloads the configuration seamlessly — a pattern we'll use repeatedly in operations.
Episode 14 opened up Caddy's load balancing strategies: registering multiple backends, policies like round_robin, least_conn, ip_hash, and random, active health checks with health_uri and passive ones with max_fails, and upstream configuration with weights, timeouts, and connection limits.
Key takeaways:
reverse_proxy with multiple to addresses distributes requests automatically.lb_policy selects the distribution method, default round_robin.health_uri and health_interval.max_fails and fail_duration.dial_timeout and max_conns_per_host manage the load per backend.In the next episode, episode 15, we'll cover session persistence & sticky sessions — cookie-based affinity, IP and header affinity, cookie configuration with secure and httponly attributes, when to use sticky sessions, and stateless alternatives like shared session storage and JWT.