Automated Mullvad VPN rotation for UniFi Dream Router
Hop between 100+ Mullvad WireGuard servers on a schedule, with smart selection and manual override capabilities. Named after Mullvad's mole mascot β always burrowing through a new tunnel.
- Automated Rotation β Switches servers twice daily (configurable) via cron
- Weighted-Random Selection β Avoids recently-used servers for better distribution
- Manual Control β CLI tool for instant server switching when needed
- Lock Protection β Prevent auto-rotation when you've manually selected a server
- Boot Persistence β Survives router reboots with proper systemd integration
- Automatic Rollback β Falls back to previous config if rotation fails
- Split-Tunnel Routing β Routes only specific VLANs through VPN (e.g., IoT network)
- Remote Access β UniFi WireGuard Server clients also route through Mullvad
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β UniFi Dream Router (UDR) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββ β
β β WireGuard β β Rotation System β β
β β (wgclt1) β β ββββββββββββββββββββββββββββββββββ β β
β β β β β mullvad-rotate.sh (cron) β β β
β β β’ Table = off βββββββ β β’ Weighted-random selection β β β
β β β’ 107 configs β β β β’ Avoids last 10 servers β β β
β β β β ββββββββββββββββββββββββββββββββββ β β
β ββββββββββ¬ββββββββββ β ββββββββββββββββββββββββββββββββββ β β
β β β β mullvad-switch.sh (CLI) β β β
β β β β β’ Manual server selection β β β
β β β β β’ Lock/unlock rotation β β β
β β β ββββββββββββββββββββββββββββββββββ β β
β β ββββββββββββββββββββββββββββββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββ β
β β split-vpn β Routes VPN VLAN (br50) traffic β
β β (table 178) β through wgclt1 interface β
β β β β
β β β’ Policy routes β βββββββββββββββ βββββββββββββββ β
β β β’ MASQUERADE β β br50 β β Other β β
β β β’ Mark: 0x169 βββββββ VPN VLAN β β VLANs ββββΊWANβ
β ββββββββββββββββββββ β192.168.50.x β β β β
β βββββββββββββββ βββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- UniFi Dream Router (UDR) with SSH access enabled
- Mullvad VPN subscription with WireGuard configs
- Dedicated VLAN for VPN traffic (e.g., br50 / 192.168.50.0/24)
- Basic familiarity with command line
Download all WireGuard configuration files from Mullvad's website for your desired servers.
# On your Mac/Linux machine
for conf in *.conf; do
# Remove IPv6 addresses and DNS line
sed -i.bak \
-e 's/,.*:.*\/[0-9]*//g' \
-e '/^DNS/d' \
"$conf"
# Add Table = off after [Interface]
sed -i '' '/\[Interface\]/a\
Table = off
' "$conf"
done# Create directories
ssh root@<UDR-IP> "mkdir -p /data/mullvad-rotation/configs"
# Upload configs
scp *.conf root@<UDR-IP>:/data/mullvad-rotation/configs/
# Upload rotation scripts
scp mullvad-switch.sh mullvad-rotate.sh install-rotation.sh \
root@<UDR-IP>:/data/mullvad-rotation/ssh root@<UDR-IP>
cd /data/mullvad-rotation
chmod +x install-rotation.sh
./install-rotation.shSee DEPLOYMENT_GUIDE.md for detailed step-by-step instructions.
mullvad-switch statusOutput:
Mullvad VPN Status:
==========================================
Current Server: us-nyc-wg-501
Last Rotation: 2025-12-16T03:00:00-05:00
Rotation Status: Active
WireGuard: Connected to 146.70.165.2:51820
==========================================
mullvad-switch list# Switch to specific server (rotation continues normally)
mullvad-switch switch us-nyc-wg-501
# Switch and lock for 24 hours (prevents auto-rotation)
mullvad-switch switch us-lax-wg-303 --lock
# Unlock to resume auto-rotation
mullvad-switch unlock# Rotate now (respects locks)
mullvad-rotate
# Rotate now (bypasses locks)
mullvad-rotate --force| Setting | Location | Default | Description |
|---|---|---|---|
| Rotation schedule | crontab -e |
0 3,15 * * * |
3am & 3pm daily |
| History avoidance | mullvad-rotate.sh:18 |
10 | Skip last N servers |
| Lock duration | mullvad-switch.sh:282 |
24 hours | Auto-unlock time |
| Route table | split-vpn/vpn/vpn.conf |
178 | Policy routing table |
| VPN VLAN | split-vpn/vpn/vpn.conf |
br50 | Interface to route |
See CONFIGURATION.md for all options.
/data/mullvad-rotation/
βββ configs/ # Mullvad WireGuard configs (107 servers)
βββ logs/
β βββ rotation.log # Auto-rotation history
β βββ switch.log # Manual switch history
β βββ cron.log # Cron execution logs
βββ state.json # Current state & rotation history
βββ mullvad-switch.sh # Manual control CLI
βββ mullvad-rotate.sh # Automated rotation script
βββ install-rotation.sh # Installation script
βββ restore-after-update.sh # Post-firmware-update recovery
/data/split-vpn/
βββ vpn/
β βββ vpn.conf # Split-VPN routing configuration
β βββ updown.sh # Routing script
βββ cleanup-unifi-conflicts.sh # Boot-time NAT/route fixes
/etc/wireguard/
βββ wgclt1.conf # Active WireGuard config
/etc/systemd/system/
βββ split-vpn.service # systemd service unit
- Router NextDNS CLI + Mullvad (wgclt1) egress runbook (sanitized/public) β Canonical setup doc
Never commit to Git:
configs/*.confβ Contains WireGuard private keysstate.jsonβ Contains rotation historylogs/β May contain server IPs/etc/wireguard/wgclt1.confβ Active private key
The included .gitignore protects these files automatically.
Dream Router 7 is a newer device with uncertain /etc/ persistence across firmware updates. MoleHopper includes a restoration script:
# After a firmware update, if services aren't working:
/data/mullvad-rotation/restore-after-update.shAll scripts and configs live in /data/ which persists across updates.
- Cron triggers
mullvad-rotate.shat scheduled times - Weighted selection picks a server, favoring those not recently used
- WireGuard is restarted with the new config
- split-vpn is restarted to apply routing rules
- State is saved to track history and enable smart selection
The system handles edge cases:
- If rotation fails, it rolls back to the previous working config
- If locked, rotation is skipped (unless forced)
- Boot-time conflicts with UniFi's routing are automatically cleaned up
Issues and pull requests welcome. Please ensure no private keys or sensitive data are included in submissions.
MIT License β See LICENSE for details.
- split-vpn by peacey β Policy-based routing for UniFi
- Mullvad VPN β Privacy-focused VPN provider