Generate a PAC (Proxy Auto-Configuration) file that routes each browser request through a randomly selected Mullvad SOCKS5 relay. The generator uses Mullvad's public relay API and can filter by location, ownership, relay type, and measured proxy probe latency.
Inspired by: https://k4yt3x.com/using-a-random-mullvad-socks5-proxy-for-each-browser-request/
- Ruby
3.4+(tested on Ruby3.4.8) curlavailable onPATHfor proxy latency probing (primary; Ruby socket fallback is used if unavailable)- Active Mullvad VPN tunnel (WireGuard) while using the generated SOCKS5 proxies
git clone https://github.com/thomaswitt/mullvad-socks-proxy-rotator.git
cd mullvad-socks-proxy-rotator
chmod +x generate_pac.rbruby generate_pac.rb [options]Options:
-l, --location PREFIXEScomma-separated country or country-city codes (e.g.us,ca,de-fra)-m, --max-latency MSmax proxy probe latency in ms (default:80)--no-latency-checkdisable proxy latency probing and the default80msceiling-n, --top Nuse only theNlowest-latency relays after active filters (implies latency probe)-o, --output FILEoutput file path (default:proxy.pacfor PAC mode, stdout for--list/--json, use-for stdout)-t, --type TYPEserver type:wireguard(default),all--owned-onlyonly Mullvad-owned servers--include-unsafeinclude countries with questionable privacy laws (excluded by default)--no-bypassdon't add localhost/LAN bypass rules to PAC--fallback MODEfallback mode:none(default),direct--listlist matching proxies and exit-j, --jsonoutput JSON instead of PAC-h, --helpshow help
Unexpected positional arguments are rejected. For example, ruby generate_pac.rb us fails fast instead of silently generating the default global PAC.
Latency filtering is enabled by default with a strict 80ms ceiling. Relays slower than that from your machine, or unreachable from your machine, are excluded from the result. The probe measures proxy usability latency via curl --socks5-hostname, not raw TCP connect RTT to the SOCKS port. Use --no-latency-check to skip latency filtering entirely.
--top N is applied after all active filters, so it can return fewer than N relays when the current latency ceiling excludes the rest.
# 1) PAC with all safe-country WireGuard SOCKS5 relays
ruby generate_pac.rb
# 2) European subset
ruby generate_pac.rb -l it,fr,ch,de
# 3) Include countries excluded by default safety policy
ruby generate_pac.rb --include-unsafe
# 4) Top 10 US relays by measured proxy probe latency
ruby generate_pac.rb -l us -n 10
# 5) List German relays
ruby generate_pac.rb --list -l de
# 6) JSON output
ruby generate_pac.rb -j
# 7) PAC to stdout
ruby generate_pac.rb -o -
# 8) PAC with direct fallback (availability > strict fail-closed)
ruby generate_pac.rb --fallback direct
# 9) Skip latency filtering entirely
ruby generate_pac.rb --no-latency-check- Import the generated
proxy.pac. - Set mode to PAC.
- Confirm requests rotate across SOCKS5 relays.
- Open Settings -> Network Settings.
- Select
Automatic proxy configuration URLand point to your PAC file location. - Keep DNS-over-proxy behavior consistent with your privacy requirements.
- System Settings -> Network -> active interface -> Details -> Proxies.
- Enable
Automatic Proxy Configuration. - Set file URL to the generated PAC file.
- SOCKS5 proxies from Mullvad are reachable only when Mullvad VPN is connected.
- Generated PAC includes localhost/LAN bypass rules by default so local development and RFC1918 traffic still works.
- Default fallback is fail-closed (
--fallback none). Use--fallback directonly if you accept potential IP leaks. - The default latency probe uses
curl --socks5-hostnameagainst a lightweight HTTPS endpoint, so it measures proxy usability latency rather than pure SOCKS port TCP connect RTT. - SOCKS5 via PAC typically leaves DNS outside the proxy path. Disable or control WebRTC/QUIC to reduce leak risk, and enable remote DNS explicitly in Firefox if you need it.
- Countries excluded by default (
--include-unsafeoverrides):hk cn ru tr ae sg th ph my id ng il vn by kz
# Run the check-only quality gate:
# syntax + rufo check + rubocop + gem audit
rake
# Auto-format Ruby files (rufo + rubocop autocorrect)
bundle exec rake app:formatter
# Run Rufo directly
bundle exec rake app:rufo
# Run Rufo check mode
bundle exec rake app:rufo:check
# Run RuboCop checks
bundle exec rake app:rubocop
# Run security checks individually
bundle exec rake security:bundle_auditThis project is licensed under the MIT License. See LICENSE.