Connect the tunnel, open the same bookmark, and the allowlisted site answers exactly as it did from the office. That is the assumption most remote-access plans quietly rest on, and it holds only while three separate things stay true at once. None of them is a feature of the VPN client, and no DNS record can supply any of them. When the bookmark fails at home, the browser hands you one generic error whether the cause is a missing route, an unapproved exit address, or a proxy that replaced the source it reports. Treating those three as a single problem is how a small policy fix turns into a week of widening allowlists.

The design that survives contact with a real office network is narrower than the assumption: an explicit three-row decision table, one enforcement point that cannot be bypassed, and a denial test that proves something. Dismantling the assumption comes first, because everything after it depends on knowing which layer is misrepresenting the source.

The myth: connecting is not routing

A tunnel gets established, and the client installs routes for some set of prefixes. That is the whole of what connecting does. Whether an unrelated HTTPS request travels through the tunnel, and which public address it appears to come from when it arrives, are decisions made later by other components: the routing table picks the path, and the exit picks the source.

This is why the office and the kitchen table diverge with the same laptop, the same browser profile and the same bookmark. In the office the request leaves through a maintained public address that the site operator agreed to. Through a full tunnel it can leave through the VPN egress, which is a different address and, until someone adds it, an unapproved one. Through a split tunnel it may never enter the tunnel at all. Only two of those three paths were ever part of the agreement with the site owner, and the third one is not a fault to be patched with an extra allow entry.

Three request states, two approved exits

Write the matrix down before touching a firewall, because the table is the design and the rule is only one implementation of it. Addresses below are documentation ranges; substitute your own maintained values and keep them somewhere the site owner can audit.

Request pathSource the site seesIntended decision
Office, no tunnelOffice public exitAdmit to the application login
Remote, approved full tunnelApproved VPN egressAdmit to the same login
Remote, ordinary connectionNeither approved addressDeny at the network boundary

The middle row is where most of these plans break. What counts is the address the enforcing device observes, not the private address the laptop holds inside the tunnel and not its LAN address. A value like 10.8.0.6 means nothing to a public site, and neither does 192.168.1.44. A tunnel address is an addressing detail of the tunnel, not a credential the site can check.

If your VPN cannot provide a stable, documented egress, the matrix has no valid middle row and no amount of allowlisting will invent one. The honest options at that point are a private site reached over explicit private routes, or an identity-aware access gateway in front of the application. Both have a different contract from a public allowlist, and both are easier to explain to an auditor than a list that grew until it happened to work.

Read the source where the decision is made

Put the restriction on the device that terminates the request, and confirm that no alternate origin path skips it. The Nginx access module evaluates allow and deny directives in order, first match wins, and rules inherited from an enclosing block still apply inside the location. A narrow allow sitting next to a broad allow in the same place usually means the broad one decides. Read the whole effective configuration for that location before editing a single line of it.

server {
    listen 443 ssl;
    server_name intranet.example.com;

    set_real_ip_from 10.20.0.10;
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;

    location /app/ {
        allow 203.0.113.24;    # office public exit
        allow 198.51.100.77;   # approved VPN egress
        deny  all;
        proxy_pass http://app_backend;
    }
}

Behind a load balancer or reverse proxy, that rule sees the proxy unless you tell it otherwise. Restore the caller address only through the supported trusted-proxy mechanism, with an explicit list of proxy addresses. A request header claiming an approved address is not evidence that the caller owns it, and on a public listener an unvalidated forwarded header turns the allowlist into decoration.

Then check the other address family. A rule set that covers IPv4 only is an incomplete decision for a hostname that also answers on AAAA, and a client with working IPv6 will reach the same application by a path you never reviewed.

Split tunnel: the request that never enters

A split tunnel carries only the prefixes on its list. Internal office subnets usually make that list; a public website does not. The browser resolves the name, compares the chosen address against the routing table, and still finds the local default gateway sitting in front of it.

So the request arrives from the user home connection, gets refused, and the report reads that the VPN is broken while the tunnel is doing precisely what it was configured to do. Two fixes are legitimate: route that destination through the tunnel and let the approved egress carry it, or accept that the site is reached directly and give remote users a different approved path such as the access gateway. Widening the site public allowlist until a home address happens to be included is neither, and it removes the boundary the design was supposed to enforce. The first two keep the matrix honest; the third quietly deletes a row from it.

Prove the denial, then prove the recovery

Test with a request that exercises the real decision, from a client standing on each row of the table. A reachability check against some unrelated address-reporting page proves nothing, because that destination may follow a different route than the application does.

curl -sS -o /dev/null -w 'status=%{http_code}
' https://intranet.example.com/app/login
# repeat with the tunnel up, then with it down
tail -f /var/log/nginx/access.log | grep ' /app/'

Compare the boundary access record with what the table predicted. Then bring the tunnel down and make a fresh request that should be refused; a page already loaded, or a connection already open, tests nothing at all. If no denial appears, the enforcement point is not where you believe it is.

Keep application authentication after network admission, because an office exit and a VPN egress each stand for many people and neither identifies an individual. The instruction for users stays short: bring up the approved tunnel, then retry. That is what keeps one URL convenient while the source rule remains a decision instead of a guess.

פֿאַרבונדענע אַרטיקלען