Radiator Server Documentation — v10.33.3

PROXY Protocol Support

How to configure PROXY protocol v2 support in Radiator Server to preserve original client IP addresses when using load balancers like HAProxy or AWS NLB.

Table of Contents
  • PROXY Protocol Support
  • Overview
  • Configuration
  • RADIUS TCP
  • RADIUS UDP
  • TACACS+ (TCP or TLS)
  • Connection Flow
  • How It Works
  • 1. Check the proxy IP against ip-accept
  • 2. Read the PROXY header
  • 3. Look up the client
  • 4. Run the TLS handshake (TLS listeners only)
  • Connection setup timeout
  • Statistics and Counters
  • Logging
  • Security Considerations
  • HTTP Listeners
  • See Also

PROXY Protocol Support

Radiator Server supports the PROXY protocol (version 2) for preserving client IP addresses when connections are proxied through load balancers like HAProxy, AWS Network Load Balancer, or other TCP proxies.

Overview

When a load balancer or proxy sits in front of Radiator, the server sees the proxy IP address, not the real client. The PROXY protocol fixes this. The proxy adds a small header at the start of the connection. The header carries the real client IP address and port.

Radiator supports PROXY protocol v2 only. Version 2 is binary, fast to parse, and supported by all modern load balancers. Version 1 (text format) is not supported.

PROXY protocol works on these listeners:

  • RADIUS over TCP
  • RADIUS over UDP
  • RadSec (RADIUS over TLS)
  • TACACS+ over TCP
  • TACACS+ over TLS

On TLS listeners, the proxy sends the PROXY header before the TLS handshake. Radiator reads the header first and then starts TLS with the bytes that follow.

Configuration

Add proxy-protocol v2; inside the listen block.

RADIUS TCP

servers {
    radius "RADIUS_TCP_1812" {
        listen {
            protocol tcp;
            port 1812;
            ip 0.0.0.0;
            proxy-protocol v2;
            ip-accept "ACCEPT_PROXIES";
        }
        clients "CLIENTS_RADIUS_ALL";
    }
}

RADIUS UDP

servers {
    radius "RADIUS_UDP_1812" {
        listen {
            protocol udp;
            port 1812;
            ip 0.0.0.0;
            proxy-protocol v2;
            ip-accept "ACCEPT_PROXIES";
        }
        clients "CLIENTS_RADIUS_ALL";
    }
}

UDP behaviour: Radiator sends UDP replies straight to the real client IP from the PROXY header. Replies do not go back through the proxy. Make sure Radiator has a route to the client network. If you need replies to return through the proxy, use TCP.

TACACS+ (TCP or TLS)

servers {
    tacacs-plus "TACACS_PLUS_1049" {
        listen {
            protocol tcp;
            port 49;
            ip 0.0.0.0;
            proxy-protocol v2;
            ip-accept "ACCEPT_PROXIES";
        }
        clients "CLIENTS_TACACS_ALL";
    }
}

For TACACS+ over TLS, change protocol tcp; to protocol tls; and add a tls { ... } block. RadSec uses the same form: protocol tls; plus a tls { ... } block on a RADIUS server.

Connection Flow

The following diagram shows how an incoming RADIUS or TACACS+ connection is processed with PROXY protocol enabled:

How It Works

Radiator processes a new connection in this order.

1. Check the proxy IP against ip-accept

Radiator first checks the IP of the direct peer (the load balancer) against the ip-accept list. If the proxy IP is not allowed, the connection is rejected. This stops untrusted hosts from sending fake PROXY headers.

2. Read the PROXY header

Radiator reads the PROXY v2 header. The header gives:

  • Real client IP address and port
  • Destination IP address and port
  • Transport (TCP or UDP, IPv4 or IPv6)

When proxy-protocol v2; is set, every connection must start with a valid PROXY v2 header. There is no fallback. Connections without a header are rejected.

3. Look up the client

Radiator looks up the client using the real client IP from the PROXY header, not the proxy IP. Client matching, shared secrets, and policies all use the real client address.

4. Run the TLS handshake (TLS listeners only)

On RadSec and TACACS+ TLS listeners, the TLS handshake runs after the PROXY header is parsed. The first byte after the header must be the TLS ClientHello.

Connection setup timeout

Reading the PROXY header and, on TLS listeners, the TLS handshake must finish inside one time limit. Radiator picks the limit in this order:

  1. The timeout on the matching ip-accept entry.
  2. The timeout on the listen block.
  3. A built-in default of 10 seconds.

Increase the listener timeout for slow load balancers. Use an ip-accept timeout to override the limit for one source prefix.

Statistics and Counters

Radiator tracks several counters related to PROXY protocol processing:

CounterDescription
IpAcceptDenyConnections rejected at IP-accept pre-admission check
ProxyProtocolErrorsFailed to parse or invalid PROXY protocol headers
ClientsDenyClient lookup failed for the proxied address
RequestsSuccessfully processed requests
RepliesSuccessfully sent replies

Monitor these counters to detect:

  • Misconfigured load balancers sending invalid headers
  • Unauthorized proxies attempting connections
  • Client configuration issues with proxied addresses

Logging

When PROXY protocol is enabled, log entries show both addresses:

  • peer_addr: the real client address from the PROXY header.
  • proxy_addr: the direct proxy address. Only logged when it differs from peer_addr.

All request processing uses the real client address.

Example log entry on a RadSec listener:

{
  "peer_addr": "203.0.113.1",
  "proxy_addr": "10.0.1.5",
  "message": "Accepting Radius TLS client connection"
}

TACACS+ TLS listeners use the same fields, with messages such as Accepting TACACS+ TLS client connection.

Security Considerations

  1. Always restrict proxies with ip-accept. Only trusted load balancers should be able to send PROXY headers:

    ip-accept "TRUSTED_PROXIES" {
        client "LOAD_BALANCERS" {
            source {
                ip 10.0.1.0/24;
            }
        }
    }
    
  2. Watch the ProxyProtocolErrors counter. A sudden rise often means a misconfigured proxy or an attack.

  3. Define RADIUS and TACACS+ clients by their real IP addresses, not by proxy addresses.

HTTP Listeners

HTTP listeners do not use PROXY protocol. Use the standard X-Forwarded-For header instead.

See Also

Navigation
  • About Radiator software development security

  • Architecture Overview

  • Backend Load Balancing

  • Basic Installation

  • Built-in Environment Variables

  • Comparison Operators

  • Configuration Editor

  • Configuration Import and Export

  • Containers

  • Data Types

  • Duration Units

  • Environment Variables

  • Execution Context

  • Execution Pipelines

  • Filters

  • Getting a Radiator License

  • Health check /live and /ready

  • High Availability and Load Balancing

  • High availability identifiers

  • HTTP Basic Authentication

  • Introduction

  • Linux systemd support

  • Local AAA Backends

  • Log storage and formatting

  • Management API privilege levels

  • Namespaces

  • Password Hashing

  • Probabilistic Sampling

  • Prometheus scraping

  • PROXY Protocol Support

  • Radiator server health and boot up logic

  • Radiator sizing

  • Radiator software releases

  • Rate Limiting

  • Rate Limiting Algorithms

  • Reverse Dynamic Authorization

  • Service Level Objective

  • TACACS+ Authentication, Authorization, and Accounting

  • Template Rendering CLI

  • Tools radiator-client

  • TOTP/HOTP Authentication

  • What is Radiator?

  • YubiKey Authentication

  • YubiKey Context Variables