@marcel91200 / caddy Mirror · read-only / commits / 11b56c6c
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 14:45 UTC

reverseproxy: Fix `health_port` being ignored in health checks (#7533)

Akın Demirci committed Mar 3, 2026 at 21:10 UTC 11b56c6cfc25f8c814fa66cb02060548d12c4040
2 files changed +68
caddytest/integration/reverseproxy_test.go
+62
@@ -386,6 +386,68 @@ func TestReverseProxyHealthCheck(t *testing.T) {
386 tester.AssertGetResponse("http://localhost:9080/", 200, "Hello, World!")
387 }
388
389 +// TestReverseProxyHealthCheckPortUsed verifies that health_port is actually
390 +// used for active health checks and not the upstream's main port. This is a
391 +// regression test for https://github.com/caddyserver/caddy/issues/7524.
392 +func TestReverseProxyHealthCheckPortUsed(t *testing.T) {
393 + // upstream server: serves proxied requests normally, but returns 503 for
394 + // /health so that if health checks mistakenly hit this port the upstream
395 + // gets marked unhealthy and the proxy returns 503.
396 + upstreamSrv := &http.Server{
397 + Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
398 + if req.URL.Path == "/health" {
399 + w.WriteHeader(http.StatusServiceUnavailable)
400 + return
401 + }
402 + _, _ = w.Write([]byte("Hello, World!"))
403 + }),
404 + }
405 + ln0, err := net.Listen("tcp", "127.0.0.1:2022")
406 + if err != nil {
407 + t.Fatalf("failed to listen on 127.0.0.1:2022: %v", err)
408 + }
409 + go upstreamSrv.Serve(ln0)
410 + t.Cleanup(func() { upstreamSrv.Close(); ln0.Close() })
411 +
412 + // separate health check server on the configured health_port: returns 200
413 + // so the upstream is marked healthy only if health checks go to this port.
414 + healthSrv := &http.Server{
415 + Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
416 + _, _ = w.Write([]byte("ok"))
417 + }),
418 + }
419 + ln1, err := net.Listen("tcp", "127.0.0.1:2023")
420 + if err != nil {
421 + t.Fatalf("failed to listen on 127.0.0.1:2023: %v", err)
422 + }
423 + go healthSrv.Serve(ln1)
424 + t.Cleanup(func() { healthSrv.Close(); ln1.Close() })
425 +
426 + tester := caddytest.NewTester(t)
427 + tester.InitServer(`
428 + {
429 + skip_install_trust
430 + admin localhost:2999
431 + http_port 9080
432 + https_port 9443
433 + grace_period 1ns
434 + }
435 + http://localhost:9080 {
436 + reverse_proxy {
437 + to localhost:2022
438 +
439 + health_uri /health
440 + health_port 2023
441 + health_interval 10ms
442 + health_timeout 100ms
443 + health_passes 1
444 + health_fails 1
445 + }
446 + }
447 + `, "caddyfile")
448 + tester.AssertGetResponse("http://localhost:9080/", 200, "Hello, World!")
449 +}
450 +
451 func TestReverseProxyHealthCheckUnixSocket(t *testing.T) {
452 if runtime.GOOS == "windows" {
453 t.SkipNow()
modules/caddyhttp/reverseproxy/healthchecks.go
+6
@@ -359,6 +359,12 @@ func (h *Handler) doActiveHealthCheckForAllHosts() {
359 dialInfoUpstream = &Upstream{
360 Dial: h.HealthChecks.Active.Upstream,
361 }
362 + } else if upstream.activeHealthCheckPort != 0 {
363 + // health_port overrides the port; addr has already been updated
364 + // with the health port, so use its address for dialing
365 + dialInfoUpstream = &Upstream{
366 + Dial: addr.JoinHostPort(0),
367 + }
368 }
369 dialInfo, _ := dialInfoUpstream.fillDialInfo(repl)
370