A command runs inside the VPN namespace, a Firefox window appears, and the page still leaves over the ordinary connection. The routing setup is probably not the first thing to rebuild. Check whether the command created the browser instance you expected, or handed the URL to one that was already running somewhere else. That distinction explains the result in one step and saves an hour of nftables.

The tell is that the window appears instantly, with no cold start.

A new window is not a new instance

Desktop applications routinely reuse an existing process. A launcher inside one network namespace does not move an already-running recipient into that namespace, because the recipient was never part of the launch. Firefox's remoting behaviour is associated with profiles: launching against a profile already in use hands the arguments to the owner. The new window is real; the new network path is not.

Private browsing and the new-window option are not network isolation controls.

Neither is a command-line flag that only affects window mode. If the profile is occupied, the request goes to the process that owns it, and that process keeps whatever namespace it started with.

Force a separate instance on a separate profile

Use a dedicated profile created through the browser's supported profile workflow, and launch with that profile explicitly. On Firefox builds that support it, --new-instance asks for a new instance rather than a window inside an existing one. Check the installed build's own help output, because available flags differ by version.

Do not try to open the same live profile concurrently, and do not treat a profile-in-use warning as an instruction to delete lock files.

Run the browser under its ordinary non-root user as well. Network setup often needs administrative rights, and it is tempting to give the browser the same ones because it is part of the same experiment. The graphical browser does not need them, and running it as root creates a separate class of profile and permission problems. Keep privilege and network path as two independent decisions.

Check which process carries the traffic

On Linux, a process's network namespace is visible through its namespace link. Read it for the process you believe is making the request, then for the process that actually is.

readlink /proc/ACTUAL_PID/ns/net

Browsers run several processes, so identity matters: the content process making the connection may not be the one you inspected first. Compare the link against the namespace you intended, and confirm with a fresh, harmless request that you can attribute to one instance. Attribution is the whole test. If you cannot say which process made the connection, you have not tested the namespace.

When the namespace really is wrong

Sometimes the launcher genuinely failed and the new instance started in the wrong namespace. Check the service or wrapper that spawned it, because a unit or a desktop entry can lose the namespace when it re-executes through a session bus. Then test again from a shell inside the correct namespace before blaming the browser. One variable at a time is the only way this stays diagnosable.

Sharing a display does not share a resolver either.

If the process is in the right namespace and name resolution still fails, investigate its resolver environment as a separate problem. Another routing change cannot relocate a request that was handed to the wrong instance before it ever began.

Qillqakuna t'inkisqa