A Go program that generates WireGuard configuration files for ProtonVPN servers with automatic selection of the best servers from specified countries with support of generic filters.
I wanted to automatically rotate VPN servers on my private HTPC Linux host running WireGuard, and since I'm already paying for a Proton bundle subscription, why not just use theirs? Unfortunately, as of the time of writing, they didn't have a good programmatic headless way to generate WireGuard profiles, so I did my research and reverse-engineered their APIs (which was a pain in the butt) and created this. The idea is to run this code as a daemon and restart the WireGuard client on profile file change.
- Authenticates with ProtonVPN using username/password
- Opnionally persists and refreshes login session, to function in headless mode after entering password once
- Supports 2FA authentication (TOTP only, no FIDO2/security keys)
- Creates persistent WireGuard configurations (visible in ProtonVPN dashboard)
- Automatically selects the best server (highest score, lowest load) from specified countries
- Supports both Free tier and paid tier servers (Plus and ProtonMail)
- Filters servers by features (P2P support, Secure Core)
- Generates WireGuard configuration files
- Supports VPN accelerator feature
- IPv6 support
- Clone the repository:
git clone https://github.com/hatemosphere/protonvpn-wg-confgen
cd protonvpn-wg-confgen- Build the program:
make buildOr manually with Go:
go build -o build/protonvpn-wg-confgen cmd/protonvpn-wg/main.go./build/protonvpn-wg-confgen -username <username> -countries <country-codes> [options]-username: ProtonVPN username (optional, will prompt if not provided)-countries: Comma-separated list of country codes (e.g., US,NL,CH) [Required]-output: Output WireGuard configuration file (default: protonvpn.conf)-ipv6: Enable IPv6 support (default: false)-dns: Comma-separated list of DNS servers (defaults based on IPv6 setting)-allowed-ips: Comma-separated list of allowed IPs (defaults based on IPv6 setting)-accelerator: Enable VPN accelerator (default: true)-api-url: ProtonVPN API URL (default: https://vpn-api.proton.me)-p2p-only: Use only P2P-enabled servers (default: true)-secure-core: Use only Secure Core servers for multi-hop VPN (default: false)-free-only: Use only Free tier servers (tier 0) (default: false)-device-name: Device name for WireGuard config (auto-generated if empty)-debug: Enable debug output showing all filtered servers (default: false)-duration: Certificate duration (default: 365d). Examples: 30m, 24h, 7d, 1h30m. Maximum: 365d-clear-session: Clear saved session and force re-authentication-no-session: Don't save or use session persistence-force-refresh: Force session refresh even if not close to expiration (requires re-authentication)-session-duration: Session cache duration (default: 0 = use API expiration). Examples: 12h, 24h, 7d. Max: 30d
- Generate config for best P2P server in US or Netherlands:
./build/protonvpn-wg-confgen -username myusername -countries US,NL- Generate config with custom DNS and output file:
./build/protonvpn-wg-confgen -username myusername -countries CH,DE -dns 1.1.1.1,8.8.8.8 -output switzerland.conf- Disable VPN accelerator:
./build/protonvpn-wg-confgen -username myusername -countries US -accelerator=false- Generate config with 30-day duration:
./build/protonvpn-wg-confgen -username myusername -countries US -duration 30d- Generate config without saving session (always prompt for password):
./build/protonvpn-wg-confgen -username myusername -countries US -no-session- Use session with 24-hour expiration:
./build/protonvpn-wg-confgen -username myusername -countries US -session-duration 24h- Enable IPv6 support:
./build/protonvpn-wg-confgen -username myusername -countries US -ipv6- Use Secure Core servers for enhanced privacy:
./build/protonvpn-wg-confgen -username myusername -countries NL,US -secure-core- Debug mode to see all available servers:
./build/protonvpn-wg-confgen -username myusername -countries US -debug- Use Free tier servers only:
./build/protonvpn-wg-confgen -username myusername -countries US,NL -free-onlyBy default, the tool generates IPv4-only configurations. When you enable IPv6 with the -ipv6 flag:
- Interface Address: Both IPv4 (10.2.0.2/32) and IPv6 (2a07:b944::2:2/128) addresses are assigned
- DNS Servers: IPv4 DNS (10.2.0.1) and IPv6 DNS (2a07:b944::2:1) - both ProtonVPN's internal DNS servers
- Allowed IPs: Both IPv4 (0.0.0.0/0) and IPv6 (::/0) routes are included
You can override the defaults by explicitly specifying -dns and -allowed-ips flags.
Secure Core is ProtonVPN's premium feature that routes your traffic through multiple servers before leaving the VPN network:
- First hop: Through secure servers in privacy-friendly countries (Switzerland, Iceland, Sweden)
- Second hop: To your chosen destination country
- Provides additional protection against network-based attacks
- Use the
-secure-coreflag to enable this feature - Note: Secure Core servers may have higher latency due to the multi-hop routing
Important Notes:
- Secure Core servers don't support P2P, so P2P filtering is automatically disabled when using
-secure-core - The country filter always applies to exit countries - where your traffic appears to come from
- Server names show both entry and exit countries (e.g., "IS-NL#1" = Iceland → Netherlands)
- Entry countries for Secure Core are always privacy-friendly: Switzerland (CH), Iceland (IS), Sweden (SE)
Important: This tool only works with Proton accounts configured in Single Password Mode. This is the default for all new Proton accounts. If your account uses the legacy 2-password mode (separate login and mailbox passwords), you'll need to switch to single password mode first.
The program supports the following authentication methods:
- Username/Password: Enter your ProtonVPN credentials
- 2FA (TOTP only): If enabled, you'll be prompted for your 6-digit authenticator code
Important 2FA Limitation: This tool only supports TOTP-based 2FA (authenticator apps like Google Authenticator, Authy, 1Password, etc.). FIDO2/WebAuthn security keys are NOT supported because they require browser/platform APIs for the challenge-response protocol.
If you use a security key as your only 2FA method, you have two options:
- Add TOTP as an additional 2FA method in your Proton account security settings
- Use a security key that also supports TOTP (like YubiKey with Yubico Authenticator)
The program saves your authentication session to avoid re-entering credentials:
- Sessions are stored in
~/.protonvpn-session.jsonwith secure permissions (0600) - ProtonVPN sessions expire after 30 days (from API
ExpiresInfield) - Session duration is configurable with
-session-duration(default: 0 = use API's 30 days) - Custom durations are capped at the API's expiration time
- Sessions show time until expiration when reused
- Sessions are automatically verified before use
- Sessions automatically refresh when less than 7 days remain
- Use
-clear-sessionflag to force re-authentication - Use
-force-refreshflag to force refresh even if not expiring soon - Use
-no-sessionflag to disable session persistence entirely - Sessions are user-specific and won't be used for different usernames
Once you have the WireGuard configuration file, you can use it with any WireGuard client:
sudo wg-quick up ./protonvpn.confsudo wg-quick up ./protonvpn.confImport the configuration file into your WireGuard client.
By default, the tool excludes Free tier servers and only uses paid tier servers (Plus and ProtonMail):
- Free tier (tier 0): Available with
-free-onlyflag. Limited server selection, no P2P support - Plus tier (tier 2): Default. Full feature support including P2P and Secure Core
- ProtonMail tier (tier 3): Default. Included with Proton bundle subscriptions
Important Notes:
- When using
-free-only, P2P filtering is automatically disabled since Free servers don't support P2P - Free tier servers have limited availability and may have higher load
- Secure Core requires Plus or higher subscription
- Go 1.25 or higher
- ProtonVPN account (Free tier or paid subscription)
- The program generates a new WireGuard private key for each run
- Configuration files contain sensitive information and are saved with 0600 permissions
- Never share your WireGuard configuration files
- Persistent configurations appear in your ProtonVPN dashboard and can be revoked there
- Certificates are valid for the specified duration (default: 365 days, max: 365 days)
.
├── cmd/
│ └── protonvpn-wg/ # Main application entry point
│ └── main.go # CLI entry point
├── internal/ # Private application code
│ ├── api/ # API types and data structures
│ │ └── types.go # ProtonVPN API response types
│ ├── auth/ # Authentication logic
│ │ ├── auth.go # SRP authentication implementation
│ │ ├── errors.go # Custom error types
│ │ └── session.go # Session management and refresh
│ ├── config/ # Configuration handling
│ │ ├── flags.go # Command-line flag parsing
│ │ └── types.go # Config struct and validation
│ ├── constants/ # Application constants
│ │ ├── api.go # API endpoints and headers
│ │ ├── defaults.go # Default configuration values
│ │ ├── session.go # Session-related constants
│ │ └── wireguard.go # WireGuard network constants
│ └── vpn/ # VPN functionality
│ ├── client.go # Certificate generation
│ └── servers.go # Server selection logic
├── pkg/ # Public packages
│ ├── timeutil/ # Time and duration utilities
│ │ ├── formatter.go # Duration formatting
│ │ └── parser.go # Duration parsing
│ ├── validation/ # Input validation
│ │ └── validation.go # Username and country code validation
│ └── wireguard/ # WireGuard configuration
│ ├── config.go # Config file generation
│ └── config_test.go # Config generation tests
├── vendor/ # Vendored dependencies
├── Makefile # Build automation
├── go.mod # Go module definition
├── go.sum # Module checksums
└── README.md # This file
# Format code
make fmt
# Run tests
make test
# Run linter (requires golangci-lint)
make lint
# Build for multiple platforms
make build-all
# Clean build artifacts
make cleanIf you encounter "CAPTCHA verification required" error:
- Login via ProtonVPN website first: This can help establish your account as legitimate
- Try from a different IP: VPN or residential IPs may work better than datacenter IPs
- Wait and retry: Sometimes waiting a few hours helps
- Use saved sessions: Once authenticated, sessions are saved to avoid repeated CAPTCHA challenges
If you see "This version of the app is no longer supported":
- The app version is automatically fetched from ProtonVPN's GitHub at build time
- Rebuild with
make buildto get the latest version - Override manually if needed:
make build PROTON_VERSION=X.Y.Z - Check current version:
make show-version
If you see "unexpected mailbox password request - account might still be in 2-password mode":
- Your Proton account is using the legacy 2-password mode (separate login and mailbox passwords)
- This tool only supports Single Password Mode
- To switch: Go to Proton account settings → Security → Password mode → Switch to single password
- Note: Single password mode is the default for all new Proton accounts since ~2020
If authentication succeeds but you get error 9100 when getting the VPN certificate:
- Your account has 2FA enabled, but ProtonVPN's device trust mechanism allowed login without 2FA
- The VPN certificate endpoint requires a session that was authenticated with 2FA
- Solution: Run with
-clear-sessionflag to force re-authentication, which should prompt for 2FA - If 2FA prompt still doesn't appear, try from a different IP/network to bypass device trust
- This can also occur if your account uses 2-password mode (see error 10013 above)
For detailed API documentation including endpoints, request formats, response codes, and reference implementations, see API_REFERENCE.md.
This project is licensed under the GNU General Public License v3.0.
This is required because the project uses ProtonVPN/go-vpn-lib which is licensed under GPL-3.0.