package middleware import ( "net" "net/http" "strings" ) // RealIP rewrites RemoteAddr from common reverse-proxy headers so downstream // rate limiters and loggers see the original client IP. Trusted unconditionally; // terminate this header at your proxy. func RealIP(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if ip := clientIP(r); ip != "" { r.RemoteAddr = ip + ":0" } next.ServeHTTP(w, r) }) } func clientIP(r *http.Request) string { if ip := r.Header.Get("X-Real-IP"); ip != "" { if parsed := net.ParseIP(strings.TrimSpace(ip)); parsed != nil { return parsed.String() } } if xff := r.Header.Get("X-Forwarded-For"); xff != "" { first := strings.TrimSpace(strings.SplitN(xff, ",", 2)[0]) if parsed := net.ParseIP(first); parsed != nil { return parsed.String() } } return "" }