ProtonVPN's CLI reroutes all traffic through the VPN tunnel, which kills your
SSH session. The pvpn.sh wrapper adds a routing rule that keeps SSH traffic
on the real interface so your session survives.
This guide covers a fresh Ubuntu VPS setup.
Add the Proton repo and install:
# Add Proton's apt repository
wget https://repo2.protonvpn.com/debian/dists/stable/main/binary-all/protonvpn-stable-release_1.0.8_all.deb
sudo dpkg -i protonvpn-stable-release_1.0.8_all.deb
sudo apt update
# Install the CLI
sudo apt install proton-vpn-cliThe stock proton-vpn-api-core has issues on headless servers (kill switch errors, disconnect timeouts). The patched fork fixes these.
cd ~/GitTools # or wherever you keep repos
git clone https://github.com/Yujilik/python-proton-vpn-api-core
cd python-proton-vpn-api-core
git checkout stable
sudo pip install -e . --break-system-packagesThis overrides the apt-installed python3-proton-vpn-api-core with the local
editable install. Future git pull updates apply immediately (no reinstall
needed).
The kill switch relies on NetworkManager GUI integration that doesn't exist on a headless server. It must be turned off:
protonvpn config set kill-switch offprotonvpn signin your@proton.meYou'll be prompted for your password (and 2FA if enabled).
Copy or symlink pvpn.sh and make it available in your shell:
# Option A: alias (add to ~/.zshrc or ~/.bashrc)
alias pvpn="$HOME/GitTools/RandomScripts/Utilities/pvpn.sh"
# Option B: symlink
ln -s ~/GitTools/RandomScripts/Utilities/pvpn.sh ~/bin/pvpn
chmod +x ~/GitTools/RandomScripts/Utilities/pvpn.shReload your shell (source ~/.zshrc) and you're ready.
pvpn connect [country] Connect (auto-protects SSH)
pvpn disconnect Disconnect and restore routing
pvpn reconnect [country] Disconnect + reconnect (switch servers)
pvpn status Show connection status + public IP
pvpn list List available countries
Short flags:
pvpn -c [country] Same as connect
pvpn -dc Same as disconnect
pvpn -rc [country] Same as reconnect
pvpn -s Same as status
pvpn -c jp # Connect to Japan
pvpn -c us # Connect to US
pvpn -c germany # Full country names work too
pvpn -rc nl # Switch to Netherlands without dropping SSH
pvpn -dc # Disconnect
pvpn -s # Check status + public IPBefore calling protonvpn connect, the wrapper:
- Detects your SSH client IP from
$SSH_CLIENT - Adds a host route for that IP via the real gateway/interface
- Adds a policy rule so replies from the VPS IP use the main routing table
This keeps SSH traffic off the VPN tunnel. On disconnect, the routes are cleaned up.
TimeoutError on connect -- The CLI's event timeout might be too short.
Check /usr/lib/python3/dist-packages/proton/vpn/cli/core/controller.py and
look for timeout=10 in the _wait_for_event function. Increase it to 60.
Note: this file is owned by the apt package and resets on updates.
Kill switch errors -- Make sure kill switch is off:
protonvpn config set kill-switch off
"Server list is outdated" -- Normal on first connect or after a while. The CLI fetches the latest server list from Proton's API. Takes a few seconds.
SSH drops on connect -- You ran protonvpn connect directly instead of
using the pvpn wrapper. Reboot the VPS from your provider's console, or
wait for the VPN to timeout, then reconnect.