Tutorial: Track Real Client IP Addresses in Access Server Behind a Proxy, Load Balancer, or Cloudflare
Learn how to verify real client IP addresses in Access Server when deployed behind a proxy, reverse proxy, load balancer, or Cloudflare — covers X-Forwarded-For, CF-Connecting-IP, and configuring a custom HTTP header for the proxied IP.
Overview
When you deploy Access Server behind a proxy, reverse proxy, or load balancer, Access Server receives the web request from that intermediary rather than directly from the client.
Starting with Access Server 3.2.2, you can identify both addresses associated with these web requests:
Request IP: The IP address from which Access Server directly receives the request. In a proxied deployment, this is typically the IP address of the proxy, reverse proxy, or load balancer facing Access Server.
Proxied IP: The real client IP address, or original client IP, supplied in a supported HTTP header by the proxy, reverse proxy, or load balancer.
Access Server detects X-Forwarded-For and CF-Connecting-IP by default. CF-Connecting-IP is the header Cloudflare injects to identify the original visitor IP address. You can also configure another header, such as X-Real-IP, when your infrastructure uses a different header for the client address.
This tutorial shows you how to verify the Request IP and Proxied IP in the Activity Log and Access Server logs, test header detection with the Web API, and configure a custom proxied-IP header.
Tracking the original client IP is especially useful for auditing and troubleshooting production secure remote access deployments that place Access Server behind a proxy or load balancer.
Prerequisites
Before you begin, ensure you have:
Access Server 3.2.2 or newer.
Admin Web UI access.
Console access and the ability to get root access.
An administrator account configured in Access Server.
A proxy, reverse proxy, or load balancer for Step 1.
Optional: A remote computer from which you can run Web API requests for Steps 2 and 3.
Note
In our documentation, we use example IPv4 addresses and subnets reserved for documentation, such as 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24.
Ensure you replace them with valid IPv4 addresses and subnets for your network(s).
How Access Server detects X-Forwarded-For and CF-Connecting-IP
By default, Access Server can detect the original client IP from these HTTP request headers:
X-Forwarded-ForCF-Connecting-IP
A proxy or load balancer can add one of these headers before forwarding a request to Access Server.
For example:
Client 192.0.2.5 | v Proxy / Load Balancer 198.51.100.5 | | X-Forwarded-For: 192.0.2.5 v Access Server
Access Server can then record:
Request IP: 198.51.100.5 Proxied IP: 192.0.2.5
Important
HTTP forwarding headers can be supplied by a client or a proxy. Treat the Proxied IP as trustworthy only when your network architecture ensures that Access Server receives these requests through a trusted proxy, reverse proxy, or load balancer.
Don't use a forwarded IP address by itself as proof of client identity.
Use this procedure when Access Server is already behind a proxy, reverse proxy, or load balancer that adds the original client IP to the web request.
Verify the addresses in the Activity Log
From a client device, access the Admin Web UI through the proxy, reverse proxy, or load balancer.
Sign in to the Admin Web UI.
Navigate to Status → Activity Log.
Locate the
WEB_ADMINlogin activity you just generated.Review Request IP.
This should display the address from which Access Server directly received the request, which is typically the proxy, reverse proxy, or load balancer IP.
Review Proxied IP.
This should display the real client IP address supplied in the forwarded HTTP header.
Optional: Sign in to the Client Web UI.
Locate the corresponding
WEB_CLIENTactivity in the Activity Log.Verify its Request IP and Proxied IP values.
Verify the addresses in the Access Server log
From the client device, sign in to the Admin Web UI through the proxy, reverse proxy, or load balancer.
Connect to the console and get root privileges.
Review:
/var/log/openvpnas.log
Locate the
WEB_ADMINrequest corresponding to your login.Example:
2026-07-29T21:05:59+0000 [stdout#info] [WEB] OUT: '2026-07-29T21:05:59+0000 [twisted.python.log#info] "198.51.100.5 [192.0.2.5]" - - [29/Jul/2026:21:05:59 +0000] "POST /api/auth/login/userpassword HTTP/2" 200 460 "-"
In this example:
Request IP: 198.51.100.5Proxied IP: 192.0.2.5
Confirm that the Request IP matches the proxy-facing address.
Confirm that the Proxied IP matches the original client IP.
Expected result: The Activity Log and Access Server log show the intermediary address as the Request IP and the original client address as the Proxied IP.
Use this procedure to test Access Server's proxied-IP detection without configuring a proxy or load balancer first.
The example manually sends an X-Forwarded-For header to simulate the header a proxy would normally add.
Tip
This tutorial uses cURL to call the Access Server Web API. You can also use the embedded Swagger UI. Refer to Tutorial: Test the New Web API (OpenAPI) in Access Server 3.0.
Connect to the console and get root privileges.
Run the following API call from a remote machine to generate web request traffic to your Access Server:
curl -X 'POST' 'https://203.0.113.51/api/auth/login/userpassword' -H 'accept: application/json' -H 'Content-Type: application/json' -H "X-Forwarded-For: 192.0.2.52" -d '{"username": "<ADMIN_USERNAME>3","password": "<ADMIN_PASSWORD>4", "request_admin":"true"}' -k -v
Replace
203.0.113.5with your Access Server address.Replace
192.0.2.5with the test Proxied IP.Replace
<ADMIN_USERNAME>with your administrator username.Replace
<ADMIN_PASSWORD>with the administrator password.Important
Supplying passwords directly on the command line can expose them through shell history or the process list. Use test credentials and protect or remove command history as appropriate for your environment.
Review the verbose cURL output.
Locate
X-Forwarded-For: 192.0.2.5.Example output on the client side confirming that the request included the
x-Forwarded-ForHTTP header:> POST /api/auth/login/userpassword HTTP/2 > Host: 203.0.113.5 > User-Agent: curl/8.5.0 > accept: application/json > Content-Type: application/json > X-Forwarded-For: 192.0.2.5 > Content-Length: 50
Example output on the Access Server side confirming the Request IP is
198.51.100.5and the Proxied IP is192.0.2.5:2026-07-29T23:49:01+0000 [stdout#info] [WEB] OUT: '2026-07-29T23:49:01+0000 [twisted.python.log#info] "198.51.100.5 [192.0.2.5]" - - [29/Jul/2026:23:49:00 +0000] "POST /api/auth/login/userpassword HTTP/2" 200 460 "-" "curl/8.5.0"'
Access Server detects X-Forwarded-For and CF-Connecting-IP by default.
If your proxy, reverse proxy, or load balancer uses another HTTP header for the original client IP, configure Access Server to detect that header instead.
The following example uses X-Real-IP as our custom HTTP header to inject the real/original client IP address. Replace it with one of your preference.
Connect to the console and get root privileges.
Configure
X-Real-IPas the proxied-IP header:sacli -k "cs.proxied_ip_header" -v "X-Real-IP" ConfigPut
Restart Access Server:
sacli start
From a remote computer, run the following to test:
curl -X 'POST' 'https://203.0.113.5/api/auth/login/userpassword' -H 'accept: application/json' -H 'Content-Type: application/json' -H "X-Real-IP: 192.0.2.5" -d '{"username": "<ADMIN_USERNAME>","password": "<ADMIN_PASSWORD>", "request_admin":"true"}' -k -vReplace the Access Server address and credentials with values for your environment.
Review the verbose cURL output.
Confirm the header output:
Example output on the client side confirming that it contains the X
-Real-IPHTTP header:> POST /api/auth/login/userpassword HTTP/2 > Host: 203.0.113.5 > User-Agent: curl/8.5.0 > accept: application/json > Content-Type: application/json > X-Real-IP: 192.0.2.5 > Content-Length: 50
Example output on the Access Server side confirming the Request IP is
198.51.100.5and the Proxied IP is 192.0.2.5:2026-07-29T23:49:01+0000 [stdout#info] [WEB] OUT: '2026-07-29T23:49:01+0000 [twisted.python.log#info] "198.51.100.5 [192.0.2.5]" - - [29/Jul/2026:23:49:00 +0000] "POST /api/auth/login/userpassword HTTP/2" 200 460 "-" "curl/8.5.0"'