# Routing kiwifarms.st through ProtonVPN on OPNsense
A walkthrough for using OPNsense policy-based routing to send traffic for a specific destination out a ProtonVPN WireGuard tunnel, while leaving the rest of your traffic on your normal WAN.
---
## 1. Generate the ProtonVPN WireGuard config
Log into [account.protonvpn.com](https://account.protonvpn.com) → **Downloads** → **WireGuard configuration**.
- Pick a server (any country works; if you want a specific exit, note where it is).
- Give the config a name like `opnsense-kf`.
- Leave NetShield / Moderate NAT / etc. at defaults unless you have a reason.
- Download the `.conf` file.
Open it in a text editor — you'll need these values:
| Field | Section | Example |
|---|---|---|
| `PrivateKey` | `[Interface]` | (your private key) |
| `Address` | `[Interface]` | `10.2.0.2/32` |
| `DNS` | `[Interface]` | `10.2.0.1` |
| `PublicKey` | `[Peer]` | (server's public key) |
| `Endpoint` | `[Peer]` | `185.159.157.1:51820` |
| `AllowedIPs` | `[Peer]` | `0.0.0.0/0, ::/0` |
---
## 2. Create the WireGuard instance in OPNsense
**VPN → WireGuard → Instances → +**
- **Name:** `ProtonVPN`
- **Private key:** paste the `PrivateKey` from the config (OPNsense derives the public key)
- **Listen port:** leave blank or set `51820`
- **Tunnel address:** the `Address` value (e.g. `10.2.0.2/32`)
- **DNS server:** leave blank for selective routing (handle DNS separately, see step 10)
Save, but don't enable yet.
---
## 3. Create the peer
**VPN → WireGuard → Peers → +**
- **Name:** `ProtonVPN-Server`
- **Public key:** the `PublicKey` from `[Peer]`
- **Allowed IPs:** `0.0.0.0/0, ::/0`
- **Endpoint address:** the IP from `Endpoint` (before the colon)
- **Endpoint port:** the port from `Endpoint` (after the colon)
- **Keepalive:** `25`
Save.
Go back to your Instance, attach this Peer to it, enable it, and tick the master **Enable WireGuard** checkbox at the top of the Instances page.
---
## 4. Assign the WireGuard interface
**Interfaces → Assignments**
- Pick `wg0` (or whatever the WG instance shows) from the dropdown → **Add**
- Click the new `OPT*` interface
- Enable it, name the description `PROTONVPN`
- Leave IPv4/IPv6 config type as **None**
- Save, apply
---
## 5. Create the gateway
**System → Gateways → Configuration → Add**
- **Name:** `PROTONVPN_GW`
- **Interface:** `PROTONVPN`
- **Address family:** IPv4
- **Gateway:** the Proton tunnel gateway, typically `10.2.0.1`
- **Far Gateway:** ✓ check this (it's outside the interface subnet since you have a `/32`)
- **Monitor IP:** `10.2.0.1` or `1.1.1.1` — something reachable through the tunnel
Save, apply.
> Confirm the gateway shows **Online** under **System → Gateways → Status** after a minute. If it doesn't, the tunnel isn't actually up — check **VPN → WireGuard → Status** for handshake.
---
## 6. Outbound NAT for the tunnel
**Firewall → NAT → Outbound**
If you're on **Automatic**, switch to **Hybrid** and save. Then add a rule:
- **Interface:** `PROTONVPN`
- **Source:** `LAN net` (or specific clients/network you want to allow out the tunnel)
- **Destination:** any
- **Translation:** Interface address
Save, apply.
---
## 7. Alias for kiwifarms.st
**Firewall → Aliases → Add**
- **Name:** `KIWIFARMS`
- **Type:** **Host(s)** with the FQDN entered (OPNsense will resolve and refresh it periodically — older versions called this "Hostname")
- **Content:** `kiwifarms.st` (and `www.kiwifarms.st` if you want)
- **Description:** anything you like
Save, apply.
> **Note:** kiwifarms.st has had hosting/IP churn over the past few years. The hostname alias handles that automatically as long as the domain still resolves. If they switch domains entirely, update the alias. If they're behind a reverse proxy or CDN-style host, the IP set may include addresses shared with other sites.
---
## 8. The policy routing rule
**Firewall → Rules → LAN → Add**
> Place this **above** your default LAN → any allow rule.
- **Action:** Pass
- **Interface:** LAN
- **Direction:** in
- **Protocol:** any
- **Source:** `LAN net` (or a specific host/alias if only one machine should use the tunnel)
- **Destination:** single host or alias → `KIWIFARMS`
- **Description:** `KF via ProtonVPN`
- Click **Advanced features** → scroll to **Gateway** → select `PROTONVPN_GW`
Save, apply.
---
## 9. Kill-switch rule (recommended)
If the tunnel drops, the policy rule above stops matching and traffic falls back to your normal WAN — defeating the point.
Add a **block** rule **below** the pass rule:
- **Action:** Block
- **Interface:** LAN
- **Source:** `LAN net`
- **Destination:** `KIWIFARMS`
- **Description:** `Block KF if VPN down`
> **Order matters:** pass-via-VPN first, block second.
For more reliable kill-switch behavior, also enable **System → Settings → General → "Skip rules when gateway is down"** (or the per-rule equivalent). This makes the pass rule disappear when Proton is offline, letting the block rule catch the traffic.
---
## 10. DNS consideration
Your router (Unbound, by default) will resolve `kiwifarms.st` over your normal WAN. That lookup leaks the fact that *someone* on your network asked for that domain to your ISP/DNS provider.
If that matters to you:
- **Option A (simpler):** Add a domain override in **Services → Unbound DNS → Overrides** for `kiwifarms.st` pointing to a DNS server reachable through the tunnel (e.g. `10.2.0.1`, Proton's DNS).
- **Option B:** Run a second Unbound or dnscrypt-proxy bound to the VPN interface and forward only that domain to it.
Option A is usually sufficient.
---
## 11. Test
From a LAN client:
```bash
# Should show your normal WAN IP
curl https://ifconfig.me
# Should show an IP that exits via Proton
curl --resolve kiwifarms.st:443:$(dig +short kiwifarms.st | head -1) \
https://kiwifarms.st -o /dev/null -s -w "%{remote_ip}\n"
```
Easier check: load the site in a browser and look at any "what's my IP" widget the site itself shows, or check Proton's dashboard for active sessions.
Dead stupid check: add ipconfig.me to the earlier alias and then see if your IP changes after you remove it. If it does, it works!
---
## Troubleshooting
If the tunnel handshake fails, the most common causes are:
- Wrong `PrivateKey` paste
- Wrong `Endpoint` port
- The Proton account already has that config "in use" elsewhere — each downloaded config is bound to a session, so generate a fresh one if in doubt