A small Python utility that fetches Mullvad's public WireGuard relay inventory, derives the corresponding SOCKS5 endpoints, and writes consumable relay lists for automation or browser PAC scripts. See docs/spec.md for detailed requirements and design notes.
uv sync
uv run python build_relay_list.py --limit 20 --emit-canonical-json --verboseArtifacts are written to build/mullvad_relays.json, build/mullvad_relays.txt, and build/mullvad_relays.pac by default. Including --emit-canonical-json also produces build/mullvad_relays_canonical.json, a validated-but-unenriched Mullvad payload that downstream tooling can reshape into other formats.
The text artifact is a newline-delimited list of socks5://host:port URLs that can be fed directly into tools such as Mubeng without any additional transformation:
# fetch a fresh list (canonical + enriched artifacts)
uv run python build_relay_list.py --emit-canonical-json --no-cache --verbose
# sample the first 20 proxies and verify them with mubeng
head -n 20 build/mullvad_relays.txt > build/mullvad_relays_subset.txt
mubeng -f build/mullvad_relays_subset.txt --check --timeout 8s --goroutine 10 --output build/mubeng_checked.txt
# inspect results
cat build/mubeng_checked.txtThe PAC artifact embeds the same endpoint list for browser automation.
- Include Mullvad-owned relays in Sweden alongside rented servers:
uv run python build_relay_list.py --countries sw --include-owned --providers-allow mullvad - United States & Canada relays from specific providers:
uv run python build_relay_list.py --countries us ca --providers-allow "m247,datacamp"
Country filters accept full names, two-letter ISO prefixes, or location IDs (e.g. us-chi). Provider filters are case-insensitive.
Use the verifier to confirm SOCKS5 endpoints against custom targets (e.g., Binance public API):
uv run python scripts/verify_proxies.py --json build/mullvad_relays.json --limit 3 --http-url https://api.binance.com/api/v3/pingSet --ws-url when you need to exercise an alternate WebSocket endpoint. Binance's WebSocket API expects JSON subscription payloads, so stick with the default echo server or implement a custom checker message before relying on WebSocket success ratios for Binance targets.
The pipeline supports enrichment via Proxy Scraper Checker to validate and augment relay metadata with latency and availability information.
Install the proxy-scraper-checker binary using mise:
mise install --from git+https://github.com/monosans/proxy-scraper-checker.git --language=rust proxy-scraper-checkerAfter installation, the enricher can process JSON exports from proxy-scraper-checker to enhance relay metadata:
from mullvad.proxy_checker import ProxyScraperChecker
from mullvad.enrich import enrich_relays
# Load proxy-scraper-checker results
checker = ProxyScraperChecker(Path("proxy_checker_results.json"))
result = enrich_relays(relays, proxy_checker=checker)The ProxyScraperChecker supports various JSON output formats from proxy-scraper-checker:
Direct format (array of proxy objects):
[
{
"socks5_endpoint": "relay.example.com:1080",
"availability": "up",
"latency_ms": 45,
"country": "Sweden",
"city": "Stockholm",
"source": "proxy-scraper-checker",
"protocol": "socks5"
}
]Wrapped format (proxies under key):
{
"proxies": [
{
"endpoint": "relay.example.com:1080",
"status": "up",
"latency": 89,
"country": "Netherlands",
"protocol": "socks5"
}
]
}Alternative field mappings:
- Endpoint:
socks5_endpoint,endpoint,proxy, orhost+port - Availability:
availability,status, oralive - Latency:
latency_ms,latency, orping - Protocol detection:
protocolortype(must be "socks5")
The enricher automatically maps these field variations to a consistent internal format.
uv run pytest- Using a Random Mullvad SOCKS5 Proxy for Each Browser Request — baseline workflow that inspired this automation.