proxy

package
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package proxy extracts real client IP, scheme, and host from trusted reverse proxy headers.

When a celeris server sits behind a load balancer or reverse proxy (e.g. Nginx, Cloudflare, AWS ALB), the TCP peer address is the proxy, not the end user. This middleware inspects X-Forwarded-For, X-Real-Ip, X-Forwarded-Proto, and X-Forwarded-Host headers -- but only when the immediate peer is in the configured Config.TrustedProxies list.

Security Model

An empty TrustedProxies list is the safe default: the middleware becomes a no-op and never trusts any forwarded header. This prevents IP spoofing when the server is exposed directly to the internet.

There is no TrustAllProxies option. Trusting all proxies defeats the purpose of the right-to-left walk and opens the door to trivial IP spoofing. If you need to trust all proxies in a controlled environment, specify the CIDR explicitly (e.g. "0.0.0.0/0").

Disable* Convention

Config uses the Disable* pattern for ForwardedProto and ForwardedHost. The Go zero value (false) means enabled, so a minimal Config literal automatically processes both headers:

server.Pre(proxy.New(proxy.Config{
    TrustedProxies: []string{"10.0.0.0/8"},
}))

To opt out of one or both, set the corresponding Disable* field:

server.Pre(proxy.New(proxy.Config{
    TrustedProxies:        []string{"10.0.0.0/8"},
    DisableForwardedProto: true,
}))

TrustedProxies

Accepts CIDR notation ("10.0.0.0/8") and bare IPs ("10.0.0.1"). Bare IPs are expanded to /32 (IPv4) or /128 (IPv6) at init time. Invalid entries cause a panic so misconfigurations surface immediately.

Common provider CIDR ranges:

TrustedHeaders

By default, "x-forwarded-for" and "x-real-ip" are inspected. These two headers have built-in logic: XFF is walked right-to-left, and X-Real-IP is validated with net/netip.ParseAddr.

Any other header name added to TrustedHeaders (e.g. "cf-connecting-ip", "true-client-ip") is treated as a single-value IP header. The value is parsed with netip.ParseAddr and used only if valid. Custom headers are checked after XFF and X-Real-IP, in order of appearance.

X-Forwarded-For Walk

The middleware walks the X-Forwarded-For chain right-to-left, skipping entries that match a trusted network. The first untrusted IP is taken as the real client IP. This algorithm is resilient against left-side spoofing because attacker-controlled entries appear on the left, while each trusted proxy appends to the right.

If a malformed (non-IP) entry is encountered during the walk, traversal stops and no client IP override is applied, falling back to the peer address.

X-Forwarded-Host Validation

When X-Forwarded-Host processing is enabled (the default), the value is validated before being applied. Values containing \r, \n, \x00, /, \, ?, #, or @ are rejected to prevent header injection and path traversal. Hosts exceeding 253 bytes (the DNS maximum per RFC 1035) are also rejected.

IPv4-Mapped IPv6

IPv4-mapped IPv6 addresses (::ffff:10.0.0.1) are normalized via netip.Addr.Unmap so that a trusted network specified as 10.0.0.0/8 correctly matches the mapped form.

ForwardedProto and ForwardedHost

By default (Disable* fields false), X-Forwarded-Proto overrides celeris.Context.Scheme and X-Forwarded-Host overrides celeris.Context.Host. Only "http" and "https" are accepted for proto; other values are silently ignored.

RFC 7239 (Forwarded) RFC 7239 (Forwarded)" aria-label="Go to RFC 7239 (Forwarded)">¶

The standard Forwarded header (RFC 7239) is not currently implemented. Most real-world proxies emit X-Forwarded-For, and the middleware focuses on that de facto standard. RFC 7239 support may be added in a future release.

Runs via Server.Pre

This middleware is designed to run via celeris.Server.Pre so that the overrides take effect before routing and before any downstream middleware reads ClientIP, Scheme, or Host.

s := celeris.New(celeris.Config{Addr: ":8080"})
s.Pre(proxy.New(proxy.Config{
    TrustedProxies: []string{"10.0.0.0/8", "172.16.0.0/12"},
}))

Downstream Middleware

Several middleware depend on proxy for correct values:

  • logger: logs c.ClientIP() — without proxy, logs the proxy's IP
  • ratelimit: keys rate limits by c.ClientIP() — without proxy, all clients behind the same proxy share one rate-limit bucket

Skip

Use Config.SkipPaths for exact path matches or Config.Skip for dynamic bypass logic.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func New

func New(config ...Config) celeris.HandlerFunc

New creates a proxy middleware that extracts real client IP, scheme, and host from trusted reverse proxy headers. Pass zero or one Config; zero-value fields are filled with safe defaults.

Example
package main

import (
	"github.com/goceleris/celeris/middleware/proxy"
)

func main() {
	// Trust Cloudflare and local reverse proxy.
	_ = proxy.New(proxy.Config{
		TrustedProxies: []string{"173.245.48.0/20", "10.0.0.0/8"},
	})
}
Example (CustomHeader)
package main

import (
	"github.com/goceleris/celeris/middleware/proxy"
)

func main() {
	// Trust Cloudflare's CF-Connecting-IP header.
	_ = proxy.New(proxy.Config{
		TrustedProxies: []string{"173.245.48.0/20"},
		TrustedHeaders: []string{"cf-connecting-ip"},
	})
}
Example (DisableForwardedProto)
package main

import (
	"github.com/goceleris/celeris/middleware/proxy"
)

func main() {
	// Disable X-Forwarded-Proto processing (X-Forwarded-Host remains enabled).
	_ = proxy.New(proxy.Config{
		TrustedProxies:        []string{"10.0.0.0/8"},
		DisableForwardedProto: true,
	})
}
Example (RealIPOnly)
package main

import (
	"github.com/goceleris/celeris/middleware/proxy"
)

func main() {
	// Only use X-Real-Ip (ignore X-Forwarded-For).
	_ = proxy.New(proxy.Config{
		TrustedProxies: []string{"10.0.0.0/8"},
		TrustedHeaders: []string{"X-Real-Ip"},
	})
}

Types

type Config

type Config struct {
	// Skip defines a function to skip this middleware for certain requests.
	Skip func(c *celeris.Context) bool

	// SkipPaths lists paths to skip (exact match).
	SkipPaths []string

	// TrustedProxies lists CIDRs or bare IPs whose forwarded headers are trusted.
	// Bare IPs are expanded to /32 (IPv4) or /128 (IPv6).
	// An empty list means no headers are trusted (safe default -- middleware is a no-op).
	// Invalid entries cause a panic at init time.
	TrustedProxies []string

	// TrustedHeaders lists which forwarded headers to inspect.
	// "x-forwarded-for" and "x-real-ip" have built-in chain-walk and validation
	// logic. Any other header name (e.g. "cf-connecting-ip") is treated as a
	// single-value IP header: the value is parsed with netip.ParseAddr and used
	// only if valid.
	// Values are lowercased at init time.
	// Default: ["x-forwarded-for", "x-real-ip"].
	TrustedHeaders []string

	// DisableForwardedProto disables processing of X-Forwarded-Proto.
	// When false (default), X-Forwarded-Proto is used to override Scheme.
	DisableForwardedProto bool

	// DisableForwardedHost disables processing of X-Forwarded-Host.
	// When false (default), X-Forwarded-Host is used to override Host.
	DisableForwardedHost bool
}

Config controls proxy header extraction behavior.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL