Three client addresses show up in a same-host NGINX plus OpenVPN setup, one for each path a request can take. A browser hitting the tunnel address, a browser hitting the public address, and a program exiting through the gateway's internet path all look different at the listening socket. Decide which path you are looking at before you interpret the log line. The decision turns on the destination the client used, the exception it holds for the outer VPN endpoint, and whether anything translates the packet on the way.

Decide by destination, not by who the user is

Start with the address the request was sent to, because that address selects the path. A request for the host's tunnel address arrives on the tunnel interface with the client's inner address as its source. A request for the host's public address usually arrives on the internet-facing interface with the client's public address, even when the same laptop has a tunnel established at that moment. Membership in the VPN pool is therefore a property of the packet path, not a property that follows the user around.

Path the request tookSource the site normally records
Client reaches the site at its tunnel address, 10.24.0.1Client inner address, 10.24.0.20
Client reaches another internet site through the gatewayGateway public egress address, 192.0.2.44
Client reaches the gateway's public address through the endpoint exceptionClient's own public access address

That third row is the one worth checking first when a VPN user appears in the log with an address that has nothing to do with the tunnel. It also explains why two users on the same profile can produce different entries: their own access networks differ, and nothing in the tunnel overwrites that.

Why the outer endpoint creates a second public path

The client must reach the gateway's public address to establish the tunnel, so a route to that address has to exist outside the tunnel. When a client redirects all traffic inward, a sensible implementation keeps an explicit host route for the server's public address to avoid a tunnel that depends on itself. That exception is not selective about services, so any request to the same public address follows it, including a browser request for a site hosted on the gateway.

This is the mechanism behind most confusing reports in this area, and it is per client implementation rather than per server. Two clients with identical profiles can therefore behave differently. Removing the exception to "fix" the log takes the tunnel down with it, so keep it and design around it.

Read the socket, the table and the log format together

Three observations settle which path you are looking at: where the socket listens, which interface answers the destination, and what the log format actually records. If the listener is bound only to the tunnel address, a public request cannot reach it at all, which rules out two rows immediately. If the lookup for the client returns the tunnel device, the request arrived with an inner source and the log should show it.

ss -lntp 'sport = :443'
ip route get 10.24.0.20
ip route get 192.0.2.44

Then read the format rather than the line. A field fed by a forwarded header records a claim, not a socket peer, and the claim only matters when the immediate peer is a trusted proxy. Writing both values into the log settles later arguments, because the immediate peer and the substituted address are different facts and only one of them came from the network.

log_format tunneled '$remote_addr $realip_remote_addr $request $status';
grep -n 'log_format' /etc/nginx/nginx.conf

Choose the entry point you want and make DNS agree

If the site is meant to be tunnel-only, give it a name that resolves to the tunnel address for VPN clients and enforce policy on the listening socket. A split-DNS answer returning 10.24.0.1 for the internal name is a routing decision wearing the costume of a name-resolution detail. If the site must also be public, keep two names or two ports and let the log tell you which one served the request.

Allow rules follow the same logic. Permitting the tunnel pool does not authorize a public request, and it will not populate an inner address on a connection that arrived over the internet. Mixing both entry points under one name turns the recorded source into a side effect of client routing rather than a design choice.

Verify the path, then the policy

Confirm the path with a capture on the gateway and a request you control. A capture on the tunnel device and one on the public interface show which carried the bytes, and the order of packets tells you whether a translation happened between them.

tcpdump -ni tun0 port 443 -c 5
tcpdump -ni eth0 port 443 -c 5

Then verify access in both directions: the intended named entry works for the intended client, and an unapproved public path is refused rather than merely slow. A generic IP-echo website proves something about the gateway's internet exit and nothing about this same-host site. When a page and a WebSocket disagree, compare their URLs, address families and DNS answers before touching the server configuration.

ບົດຄວາມທີ່ກ່ຽວຂ້ອງ