Proxy still on the old tunnel address after a VPN reconnect?
A reconnect can leave your forwarder bound to an address the tunnel no longer owns. Four ordered checks, a numbered handover and a real test request.
Restarting the VPN client proves only that the tunnel came back. It says nothing about the proxy that was told to leave through it. Squid, tinyproxy and most other forwarders hold the local source address they resolved at startup until something forces them to reload. When a reconnect hands out a new tunnel address, the forwarder either fails every outgoing connect or starts leaving through your ordinary route.
That second failure is the dangerous one: the tunnel is up, pages load, and only the exit address is wrong.
Start with the listener, not the tunnel
Three addresses are in play, and a reconnect moves only some of them. The listener is where your browser points, usually 127.0.0.1 or a LAN address, and it does not care that the tunnel changed. The outgoing local source is what the forwarder asks the kernel to use when it dials the next hop, and that one is tied to the tunnel device. The public exit is what a web server logs, which may be a translated address several hops away.
A public IP lookup answers only the last question. It cannot tell you which local address a forwarder should bind, because one public exit can hide several internal sources. Read the address from whoever owns the connection: the client's status output, the interface itself, or the namespace where the tunnel lives. Grabbing the first interface whose name looks like a tunnel gives the wrong answer as soon as a second profile exists.
Container and namespace layouts break the assumption quietly. A forwarder in one network namespace cannot bind a tunnel that exists in another, and no amount of configuration editing repairs that.
Four checks before you edit anything
Work through these in order. The first check that fails is where you stop, because the later ones assume the earlier ones hold.
- Confirm the tunnel in use is the profile the proxy was built around, not a second profile that connected on its own.
- Print the address currently on that device and compare it with the address in the running configuration.
- Ask the forwarder what source it resolved, rather than what the file on disk claims.
- Confirm traffic from the forwarder is actually subject to the routing and firewall policy you expect.
The device address is easy: ip -4 addr show dev tun0 prints the current one, and ip -4 route get 1.1.1.1 shows which interface the kernel would choose for that destination. A forwarder that binds an exact address fails loudly when the address disappears. A forwarder that binds a device, or falls back to the default source, keeps working and leaks, which is the quiet outcome.
Match the documentation to the release you run, not to the top search result. Squid's outgoing-address directive is documented for v7 and earlier, and the v8 documentation states plainly that the directive is unavailable there, so a script built around it does not survive that boundary (see the Squid tcp_outgoing_address reference). Validate with the product's own parser before anything is reloaded: squid -k parse reports errors and exits without touching the running process.
Number each tunnel and discard stale swaps
A reconnect is a handover, and handovers need an order. Tag every observed connection with a counter or timestamp that increments on each successful establishment, then carry that tag inside the candidate configuration. When the tag on a candidate is older than the current one, drop the candidate instead of applying it, because a slow update written for the previous tunnel will otherwise overwrite the settings for the current one. Coalesce bursts of events so a flapping link produces one transition rather than fifteen.
Sequence the work in four moves: invalidate the old egress state, wait for the connection owner to report completion, build only the managed fragment, then validate and activate through the service manager. Regenerating the whole file from two address values is how listener restrictions, authentication and destination policy quietly disappear. Respect a deliberate stop too. A helper that keeps dialing a tunnel the user turned off is a bug, not resilience.
Open sockets will not follow the new address
Reconfiguring the forwarder says nothing about connections that are already established. Whether they drain or die depends on the product, so observe the behaviour instead of assuming it.
A request served over a socket opened before the swap still leaves through the old path, even when the new configuration is correct. If that matters, decide explicitly: allow a short drain window and stop admitting new work, or terminate the old sockets and accept the errors. Then test with a fresh connection and keep that result separate from the drain check. Source binding is not a security boundary either. When traffic must never touch the ordinary route, enforce it with marks and firewall rules, DNS and IPv6 included, so a failed reload leaves the proxy explicitly down instead of open.
Prove the new egress with a fresh request
What matters is a request opened after activation, not a ping and not a page that was already cached. Ask the proxy for a real URL and read the exit address the far end reports, then compare it with the client's own view of the tunnel when the provider exposes one.
Keep the parse, the reload and the request as separate commands so a failure points at a single step. The first two change nothing when they fail, which is exactly why they run before the restart.
squid -k parse
sudo squid -k reconfigure
curl -x http://127.0.0.1:3128 -sS -o /dev/null -w '%{http_code} %{remote_ip}\n' https://example.comIf the reload fails, stop the service and repair the fragment; a proxy serving with stale egress is worse than a short outage. If the reload succeeds but the fresh request still exits somewhere unexpected, return to the routing check instead of editing addresses again. Record the tunnel generation you validated against, so the next reconnect has something concrete to compare.