Local rotating proxy. One endpoint, ~9600 rotating IPs.
curl -x http://127.0.0.1:4123 http://httpbin.org/ip # Mullvad relay
curl -x http://127.0.0.1:4123 http://httpbin.org/ip # NordVPN server
curl -x http://127.0.0.1:4123 http://httpbin.org/ip # TOR circuit
| Source | Relays | Auth | Install needed |
|---|---|---|---|
| Mullvad | ~580 | None | No |
| NordVPN | ~9000 | Service credentials | No (requires VPN connection) |
| TOR | 1 endpoint (routes through entire TOR network) | None | Yes (local tor) |
bun install
bun run start # interactive TUI
bun run start -- --mullvad --nordvpn # skip TUINordVPN requires an active NordVPN VPN connection on the host. SOCKS5 credentials are needed. Get them at:
https://my.nordaccount.com/dashboard/nordvpn/manual-configuration/service-credentials/
Note: NordVPN currently requires the host to be connected to the VPN for proxy access. We are working on a solution to enable all NordVPN servers standalone without a VPN connection.
cp .env.example .env
# fill in NORDVPN_USERNAME and NORDVPN_PASSWORD
source .env && bun run start -- --mullvad --nordvpnTOR needs a local tor daemon:
# Debian/Ubuntu
sudo apt install tor && sudo systemctl start tor
# macOS
brew install tor && brew services start tor# curl
curl -x http://127.0.0.1:4123 http://httpbin.org/ip
# Python
proxies = {"http": "http://127.0.0.1:4123", "https": "http://127.0.0.1:4123"}
requests.get("http://httpbin.org/ip", proxies=proxies)
# SOCKS5 mode
bun run start -- --mullvad --socks5-port 1080
curl --socks5-hostname 127.0.0.1:1080 https://api.example.com
# Proxy auth
bun run start -- --mullvad --proxy-auth admin:secret123
curl -x http://127.0.0.1:4123 --proxy-user admin:secret123 http://httpbin.org/ip
# Sticky session: reuse the same relay for related requests
curl -x http://127.0.0.1:4123 \
-H 'X-Proxy-Session: checkout-flow-123' \
http://httpbin.org/ipX-Proxy-Session pins repeated HTTP requests and repeated CONNECT requests with the same header value to one relay for 5 minutes of inactivity. If that relay becomes unhealthy, relayrad automatically rebinds the session to the next working relay.
When the selected relay is TOR, relayrad also reuses the same SOCKS auth identity for the same X-Proxy-Session instead of generating a fresh one per connection. This gives the local TOR daemon a stable isolation token, but the final exit IP still depends on your TOR SocksPort isolation settings.
| Endpoint | Description |
|---|---|
GET /relays |
List available relays |
POST /rotate |
Change rotation config |
POST /relays/refresh |
Reload sources |
GET /health |
Health check |
GET /stats |
Request stats |
# filter by country, exclude some
curl 'http://127.0.0.1:4123/relays?country=se&exclude_country=us,de&sort=random'
# change rotation at runtime
curl -X POST http://127.0.0.1:4123/rotate \
-H 'content-type: application/json' \
-d '{"sort":"random","unhealthyBackoffMs":45000}'| Flag | Default | Description |
|---|---|---|
--mullvad |
auto | Mullvad source |
--tor |
off | TOR source |
--nordvpn |
off | NordVPN source |
--port, -p |
4123 |
HTTP proxy port |
--socks5-port |
off | SOCKS5 listener port |
--proxy-auth |
off | user:pass for incoming proxy auth |
--tor-port |
9050 |
TOR SOCKS5 port |
--log-proxy-sqlite |
off | SQLite log path |
--no-log-proxy-console |
off | Disable console logs |
--no-tui |
off | Skip interactive setup |
| Variable | Description |
|---|---|
RELAYRAD_HOST |
Bind host (default 127.0.0.1) |
RELAYRAD_PORT |
Bind port (default 4123) |
NORDVPN_USERNAME |
NordVPN service username |
NORDVPN_PASSWORD |
NordVPN service password |
See .env.example for all options.
Fields for GET /relays?... and POST /rotate body:
| Field | Type | Example |
|---|---|---|
country |
string | se, germany |
city |
string | stockholm |
hostname |
string | substring match |
exclude_country |
string | us,de (comma-separated) |
sort |
random, hostname, country, city |
default: random |
unhealthyBackoffMs |
number | default: 30000 |
Mullvad-specific fields (only meaningful when filtering Mullvad relays):
| Field | Type | Example | Notes |
|---|---|---|---|
provider |
string | iRegister, M247 |
Mullvad lists hosting provider per server |
ownership |
owned or rented |
Mullvad owns some servers, rents others |
NordVPN relays always have provider: "nordvpn", ownership: "rented".
TOR relay has provider: "tor-project", ownership: "owned".
- Failed relays are marked unhealthy and skipped for 30s
X-Proxy-Sessionkeeps related HTTP and CONNECT requests on one relay for 5 minutes of inactivity- TOR sticky sessions reuse one SOCKS auth identity per
X-Proxy-Session; exit IP stability depends on local TOR isolation config POST /rotatechanges behavior without restart- Mullvad: SOCKS5 per server, no auth, public endpoints
- NordVPN: SOCKS5 on
*.socks.nordhold.net:1080, requires VPN connection + service credentials - TOR: one local SOCKS5 endpoint (localhost:9050), but TOR internally routes through thousands of relays and rotates circuits per request
bun install
bun run biome-lint
bunx tsc --noEmit
bun test