Skip to content

How to Fix Caddy Reverse Proxy Error

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about How to Fix Caddy Reverse Proxy Error. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Caddy returns 502 Bad Gateway or dial tcp: connection refused when proxying to an upstream — the backend server is unreachable or the reverse_proxy directive is misconfigured.

The Problem

2026/06/24 10:00:00 [ERROR] dial tcp 127.0.0.1:3000: connect: connection refused

Step-by-Step Fix

Step 1: Verify backend is running

curl http://localhost:3000/health

Step 2: Configure basic reverse proxy

api.example.com {
    reverse_proxy localhost:3000
}

Step 3: Add custom headers

api.example.com {
    reverse_proxy localhost:3000 {
        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
}

Step 4: Configure health checks

api.example.com {
    reverse_proxy localhost:3000 localhost:3001 {
        health_path /health
        health_interval 10s
        health_timeout 5s
    }
}

Step 5: Load balance across multiple upstreams

api.example.com {
    reverse_proxy node1:3000 node2:3000 node3:3000 {
        lb_policy round_robin
    }
}

Step 6: Stream WebSocket connections

app.example.com {
    reverse_proxy localhost:3000 {
        # WebSocket support is automatic in Caddy
        # No special configuration needed
    }
}

Prevention Tips

  • Always configure health checks for production upstreams
  • Use header_up to forward client IP information
  • Set connection timeouts for upstream servers
  • Monitor backend health with a dedicated health endpoint

Common Mistakes with reverse proxy

  1. Using head and tail instead of pattern matching, causing runtime errors on empty lists
  2. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  3. Using return to exit a function early instead of wrapping a pure value in the monad

These mistakes appear frequently in real-world CADDY code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### Why does Caddy return 502 Bad Gateway for my reverse proxy?

The upstream server is not running or is not reachable. Verify with curl http://localhost:3000. Also check that the upstream is listening on the correct interface — if it binds to 127.0.0.1, Caddy must be on the same host.

How do I pass the client IP to the backend in Caddy?

Use header_up directives: header_up X-Forwarded-For {remote_host} and header_up X-Real-IP {remote_host}. Caddy automatically sets X-Forwarded-For in most configurations, but explicit headers give you full control.

Does Caddy automatically support WebSocket proxying?

Yes, Caddy detects WebSocket upgrades automatically and handles them without special configuration. Unlike Nginx, you do not need to manually set Upgrade or Connection headers. Caddy handles this transparently.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro