Skip to main content
Version: Next

🔄 Reverse Proxy Configuration

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.

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
Example - App Behind Nginx
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/ServiceRecommended HeaderConfig Value
Nginx, HAProxy, ApacheX-Forwarded-Forfiber.HeaderXForwardedFor
CloudflareCF-Connecting-IP"CF-Connecting-IP"
FastlyFastly-Client-IP"Fastly-Client-IP"
GenericX-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

nginx.conf
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;
}
}
main.go
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
traefik.yaml
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: