OpenVPN Bridge for Chrome
Route only Chrome's traffic through your OpenVPN server — everything else on your Mac (SSH, terminals, other apps) stays on your normal internet connection.
The problem this solves: a normal OpenVPN client (OpenVPN Connect, Tunnelblick) tunnels your entire machine. If you only need the VPN for a few websites, that's overkill — and it often breaks things like SSH sessions, local dev tools, or video calls. This project gives Chrome its own private path into the VPN and leaves the rest of the system alone.
Platform: macOS (Apple Silicon or Intel). Chrome or any Chromium browser for the extension.
How it works
A Chrome extension alone cannot speak the OpenVPN protocol — extensions can only point the browser at a proxy. So this project has two halves:
Chrome ──(extension sets SOCKS5 proxy)──▶ 127.0.0.1:1080 (gost proxy)
│ outbound bound to the
│ VPN's tun interface
▼
OpenVPN tunnel ──▶ your VPN server
vpn-bridge.shstarts OpenVPN with--route-nopull, so the tunnel comes up without touching the system routing table — no other app even knows it exists. It then starts gost, a small SOCKS5 proxy on127.0.0.1:1080whose outbound connections are pinned to the VPN's tun interface.extension/is a Chrome extension (Manifest V3) that toggles Chrome between "direct" and that local proxy — for all traffic, or only for a list of domains you choose.
DNS lookups for proxied traffic are resolved over encrypted
DNS-over-HTTPS (Cloudflare 1.1.1.1), so ISP-level DNS blocking can't
interfere and your ISP's resolver never sees them.
Beginner's guide
What you need
- A Mac with Homebrew installed
- Google Chrome (or Brave/Edge/another Chromium browser)
- An OpenVPN profile — a
.ovpnfile from your VPN provider or your own OpenVPN server
Step 1 — Get the code and tools
git clone https://github.com/deshabhishek007/chrome-openvpn.git
cd chrome-openvpn
brew install openvpn gost
Step 2 — Add your VPN profile
Copy your .ovpn file(s) into the profiles/ folder:
cp ~/Downloads/my-server.ovpn profiles/
If your VPN needs a username and password, create profiles/auth.txt
with the username on line 1 and the password on line 2.
Tip: if your profile is already imported into the OpenVPN Connect app and you can't find the original file, the app keeps copies in
~/Library/Application Support/OpenVPN Connect/profiles/— you can copy them from there and rename them to something memorable.The
profiles/folder is listed in.gitignore, so your VPN credentials can never be accidentally committed or pushed.
Step 3 — Load the extension in Chrome
- Open
chrome://extensionsin Chrome - Turn on Developer mode (toggle in the top-right corner)
- Click Load unpacked and select this project's
extension/folder
Step 4 — Start the bridge
./vpn-bridge.sh
- It asks for your Mac password once (creating a network tunnel requires admin rights).
- With one profile it connects straight away; with several it shows a
numbered menu. You can also pass a name:
./vpn-bridge.sh eumatchesmy-vpn-eu.ovpn. - Leave the terminal window running. Ctrl-C disconnects everything.
Step 5 — Turn it on in Chrome
Click the OpenVPN Bridge icon in Chrome's toolbar:
- All Chrome traffic — every site you open in Chrome goes through the VPN.
- Only these sites — list just the domains that need the VPN (one per line, subdomains included); everything else stays direct and fast.
Hit Connect — the popup shows Chrome's public IP so you can confirm
it changed. Meanwhile, ssh, curl, and every other app on your Mac
still use your normal connection. That's the whole point!
Optional: control everything from the popup
Instead of keeping a terminal open, the popup can start and stop the tunnel itself — pick a profile from the dropdown, press Start, and the proxy toggle flips on automatically. One-time setup (after loading the extension):
./host/install.sh
This wires up three things:
- A native messaging host manifest, so Chrome is allowed to launch
host/vpn-bridge-host.py— this is Chrome's sanctioned mechanism for extensions to talk to local programs, locked to this extension's ID. - A root helper at
/usr/local/libexec/vpn-bridge-helper(root-owned, read-only) that does only the privileged parts: start openvpn with--route-nopull+--script-security 1, add/remove the interface-scoped route, stop the tunnel. Profiles are referenced by name only and resolved inside this project'sprofiles/folder. - A sudoers rule (
/etc/sudoers.d/vpn-bridge) allowing your user to run exactly that one helper without a password — nothing else gains passwordless sudo.
Then reload the extension once (chrome://extensions → reload icon).
To undo it all:
sudo rm /etc/sudoers.d/vpn-bridge /usr/local/libexec/vpn-bridge-helper
rm ~/Library/Application\ Support/Google/Chrome/NativeMessagingHosts/com.vpnbridge.host.json
The terminal script keeps working either way; both control the same tunnel and proxy.
Troubleshooting
The popup says "Could not reach the internet through the proxy."
The bridge isn't running (or died). Start ./vpn-bridge.sh, or press
Start in the popup if you installed the optional control.
bind: address already in use on startup.
Something else holds port 1080. The script cleans up its own leftovers
automatically; if another app owns the port, run on a different one:
PORT=1081 ./vpn-bridge.sh and change the port in the popup to match.
The tunnel comes up but sites time out.
Check /tmp/openvpn-bridge.log. If the log looks healthy, your VPN
server may not allow forwarding to the destination. Test with:
curl --socks5-hostname 127.0.0.1:1080 https://api.ipify.org — it
should print the VPN server's IP.
"tunnel did not come up in 45s".
Usually wrong credentials (check profiles/auth.txt), a blocked UDP
port, or the server being down. The last log lines are printed with the
error.
I use a full VPN app too (OpenVPN Connect, Tunnelblick, ...). Keep it disconnected while the bridge runs. If it connects, it captures the whole system — including Chrome — and the "only Chrome" behavior is gone until you disconnect it.
Notes & limitations
- macOS only. The interface-scoped routing trick (
route -ifscope) is macOS-specific; a Linux port would use network namespaces instead. - The proxy setting applies to the whole Chrome profile (all tabs and windows), not other browsers or apps.
localhostis always bypassed, so local dev servers keep working.- Keep
.ovpnfiles andauth.txtprivate; they contain credentials.
Log in or sign up for Devpost to join the conversation.