Files
fiber/docs/guide/reverse-proxy.md
2026-03-17 21:47:21 -04:00

6.8 KiB

id, title, description, sidebar_position
id title description sidebar_position
reverse-proxy 🔄 Reverse Proxy Configuration Learn how to set up reverse proxies like Nginx or Traefik to enable modern HTTP capabilities in your Fiber application, including HTTP/2 and HTTP/3 (QUIC) support. This guide also covers basic reverse proxy configuration and links to external documentation. 4

Reverse Proxies

Running Fiber behind a reverse proxy is a common production setup. Reverse proxies can handle:

  • HTTPS/TLS termination (offloading SSL certificates)
  • Protocol upgrades (HTTP/2, HTTP/3 support)
  • Request routing & load balancing
  • Caching & compression
  • Security features (rate limiting, WAF, DDoS mitigation)

Some Fiber features (like SendEarlyHints) require HTTP/2 or newer, which is easiest to enable using a reverse proxy.

Getting the Real Client IP Address

When your Fiber application is behind a reverse proxy, the TCP connection comes from the proxy server, not the actual client. To get the real client IP address, you need to configure Fiber to read it from proxy headers like X-Forwarded-For.

:::warning Security Warning Proxy headers can be easily spoofed by malicious clients. Always configure TrustProxyConfig to validate the proxy IP address, otherwise attackers can forge headers to bypass IP-based access controls, rate limiting, or geolocation features.

In addition, your reverse proxy should be configured to set or overwrite the forwarding header you choose (for example, X-Forwarded-For) based on the real client connection, or to use its real IP / PROXY protocol features. Do not simply pass through client-supplied forwarding headers, or c.IP() may still be controlled by an attacker even when TrustProxyConfig is correct. :::

Configuration

To enable reading the client IP from proxy headers, you must configure three settings:

  1. TrustProxy - Enable proxy header trust (must be true)
  2. ProxyHeader - Specify which header contains the client IP
  3. TrustProxyConfig - Define which proxy IPs to trust
app := fiber.New(fiber.Config{
    // Enable proxy support
    TrustProxy: true,

    // Read client IP from X-Forwarded-For header
    ProxyHeader: fiber.HeaderXForwardedFor,

    // Trust requests from your Nginx proxy
    TrustProxyConfig: fiber.TrustProxyConfig{
        // Option 1: Trust specific proxy IPs
        Proxies: []string{"10.10.0.58", "192.168.1.0/24"},

        // Option 2: Or trust all private IPs (useful for internal load balancers)
        // Private: true,
    },
})

Common Proxy Headers

Different proxies use different headers:

Proxy/Service Recommended Header Config Value
Nginx, HAProxy, Apache X-Forwarded-For fiber.HeaderXForwardedFor
Cloudflare CF-Connecting-IP "CF-Connecting-IP"
Fastly Fastly-Client-IP "Fastly-Client-IP"
Generic X-Real-IP "X-Real-IP"

TrustProxyConfig Options

The TrustProxyConfig struct provides multiple ways to specify trusted proxies:

TrustProxyConfig: fiber.TrustProxyConfig{
    // Specific IPs or CIDR ranges
    Proxies: []string{
        "10.10.0.58",           // Single IP
        "192.168.0.0/24",       // CIDR range
        "2001:db8::/32",        // IPv6 range
    },

    // Or use convenience flags:
    Loopback:   true,  // Trust 127.0.0.0/8, ::1/128
    LinkLocal:  true,  // Trust 169.254.0.0/16, fe80::/10
    Private:    true,  // Trust 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7
    UnixSocket: true,  // Trust Unix domain socket connections
},

Complete Example with Nginx

server {
    listen 443 ssl;
    http2 on;
    server_name example.com;

    ssl_certificate     /etc/ssl/certs/example.crt;
    ssl_certificate_key /etc/ssl/private/example.key;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
package main

import (
    "log"

    "github.com/gofiber/fiber/v3"
)

func main() {
    app := fiber.New(fiber.Config{
        TrustProxy:        true,
        ProxyHeader:       fiber.HeaderXForwardedFor,
        EnableIPValidation: true,
        TrustProxyConfig: fiber.TrustProxyConfig{
            // Trust localhost since Nginx is on the same machine
            Loopback: true,
        },
    })

    app.Get("/", func(c fiber.Ctx) error {
        // This will now return the real client IP from X-Forwarded-For
        // instead of 127.0.0.1
        return c.SendString("Your IP: " + c.IP())
    })

    log.Fatal(app.Listen(":3000"))
}

Testing Your Configuration

You can verify your configuration is working:

app.Get("/debug", func(c fiber.Ctx) error {
    return c.JSON(fiber.Map{
        "c.IP()":           c.IP(),                    // Should show real client IP
        "X-Forwarded-For":  c.Get("X-Forwarded-For"),  // Raw header value
        "IsProxyTrusted":   c.IsProxyTrusted(),        // Should be true
        "RemoteIP":         c.RequestCtx().RemoteIP().String(), // Proxy IP
    })
})

Enabling HTTP/2

Popular choices include Nginx and Traefik.

Nginx Example

See the Complete Example with Nginx above for a full configuration with HTTP/2 enabled.

Traefik Example
entryPoints:
  websecure:
    address: ":443"

http:
  routers:
    app:
      rule: "Host(`example.com`)"
      entryPoints:
        - websecure
      service: app
      tls: {}

  services:
    app:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:3000"

With this configuration, Traefik terminates TLS and serves your app over HTTP/2.

HTTP/3 (QUIC) Support

Early Hints (103 responses) are defined for HTTP and can be delivered over HTTP/1.1 and HTTP/2/3. In practice, browsers process 103 most reliably over HTTP/2/3. Many reverse proxies also support HTTP/3 (QUIC):

  • Nginx
  • Traefik

Enabling HTTP/3 is optional but can provide lower latency and improved performance for clients that support it. If you enable HTTP/3, your Early Hints responses will still work as expected. For more details, see the official documentation: