---
title: "How to route one browser through WireGuard"
description: "Send one browser profile through a WireGuard tunnel while every other app keeps your normal connection. Import a .conf file. No admin rights needed."
url: "https://donutbrowser.com/docs/guides/wireguard-one-browser/"
---

# How to route one browser through WireGuard

The WireGuard app picks routes by destination address only, so with `AllowedIPs = 0.0.0.0/0` every app on your computer uses the tunnel. Donut Browser runs WireGuard inside the app for one browser profile at a time. The tunnel needs no administrator rights and adds no network adapter, and your other apps keep their normal connection. You need Donut Browser [installed](https://donutbrowser.com/docs/install) and a WireGuard `.conf` file from your VPN provider or your own server.

## How it works

Donut runs WireGuard in user space, as a separate background process for each VPN config. The process opens a SOCKS5 port on `127.0.0.1`, and profiles that use the VPN connect to it through Donut's local relay. Nothing changes your system routes. Profiles that share one VPN share one process.

All of the profile's traffic goes through the tunnel, host name lookups included. UDP goes through it too, so WebRTC and QUIC work.

## 1. Get a config with one peer

Download a WireGuard config from your provider, or export the client config of your own server. It looks like this:

```ini
[Interface]
PrivateKey = <base64 private key>
Address = 10.66.0.2/32
DNS = 10.66.0.1

[Peer]
PublicKey = <base64 public key>
Endpoint = de.vpn.example.com:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
```

Donut reads these keys:

| Key | Required | What Donut does with it |
| --- | --- | --- |
| `PrivateKey`, `Address` | Yes | `Address` can hold an IPv4 and an IPv6 address, separated by a comma. |
| `PublicKey`, `Endpoint` | Yes | Exactly one `[Peer]` section. A config with more peers is refused. |
| `DNS` | No | One IPv4 address. Anything else (a list, an IPv6 address or a host name) is replaced with `1.1.1.1`. Lookups go through the tunnel either way. |
| `PresharedKey`, `PersistentKeepalive` | No | Used as given. |
| `AllowedIPs`, `MTU` | No | Read but not used. All of the profile's traffic uses the tunnel, with an MTU of 1420. |

Other keys, such as `ListenPort` or `PostUp`, are ignored. Keys must use this exact spelling.

## 2. Import the config

1. Open **Network** in the sidebar (**Cmd/Ctrl+Shift+N**) and switch to the **VPNs** tab.
2. Click **Import**. The dialog **Import VPN Config** opens.
3. Drop the `.conf` file on it, click to browse, or paste the text with **Cmd/Ctrl+V**.
4. Check the **VPN Name**, which comes from the file name, and click **Import VPN**.

Without a file, click **New VPN** and fill in **Create WireGuard VPN** by hand: **Private Key**, **Address**, **Peer Public Key**, **Peer Endpoint**, and the optional fields. After you save a VPN, you can only rename it. To change a key or the endpoint, delete the VPN and import it again.

## 3. Test the tunnel

Click the check pill in the **Status** column of the VPN. Donut starts the tunnel, asks for your public IP through it up to three times, and shows **Valid** when an IP comes back. This is a live connection test, so **Invalid** also covers a server that does not answer.

## 4. Give the VPN to a profile

For a new profile, click **New** on the **Profiles** page (**Cmd/Ctrl+N**). In **Create new profile**, open the proxy picker. VPNs are listed under **VPNs**, each with a **WG** badge. Donut tests the VPN again before it makes the profile.

For an existing profile, stop it, open its panel with the info button on its row, and choose the VPN in **Network** → **VPN**. A profile uses a proxy or a VPN, not both, so choosing a VPN removes its proxy.

## 5. Set the timezone and language

Donut cannot measure a VPN's exit when it creates a profile. A profile made with a VPN therefore gets no timezone or language from the exit. The browser then reports its own value, which is your computer's timezone. At launch, Donut shows "Nothing was verified against the exit" with the exit's location. A site that compares your IP with your timezone sees the gap.

Choose one of these fixes:

- On Pro, Team or Enterprise, open the profile panel → **Fingerprint** and set **Timezone (IANA)**, **Primary Language (navigator.language)** and **Languages (JSON array)** to the exit's country. Stop the profile before you edit it.
- On any plan, create the profile with the [local API](https://donutbrowser.com/docs/quickstart) and pin the location to the exit IP with `wayfern_config.geoip`. Donut looks the IP up in its local GeoIP database and writes the timezone, language and coordinates. Find the exit IP by opening [What is my IP](https://donutbrowser.com/tools/what-is-my-ip) in a profile that uses the VPN.

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/profiles \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "DE via WireGuard",
    "browser": "wayfern",
    "vpn_id": "<vpn id>",
    "wayfern_config": { "geoip": "203.0.113.80" }
  }'
```

**Generate random fingerprint on every launch** also reads the location through the VPN, but it gives the profile a new device at every start. Do not use it for accounts that must keep one device.

## 6. Launch and confirm

Launch the profile and open [What is my IP](https://donutbrowser.com/tools/what-is-my-ip) and the [WebRTC leak test](https://donutbrowser.com/tools/webrtc-leak-test). Both must show the VPN's exit, never your own IP. Open the same page in another browser on your computer: it still shows your normal IP.

## Import the VPN with the API

`POST /v1/vpns/import` takes the file text and its name. VPN routes work on every plan.

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/vpns/import \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  --data "$(jq -n --rawfile conf de.conf '{filename: "de.conf", name: "DE WireGuard", content: $conf}')"
```

```python
import os, pathlib, requests

conf = pathlib.Path("de.conf").read_text()
response = requests.post(
    "http://127.0.0.1:10108/v1/vpns/import",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={"filename": "de.conf", "name": "DE WireGuard", "content": conf},
    timeout=30,
)
response.raise_for_status()
print(response.json()["id"])
```

Then set `vpn_id` on a profile with `PUT /v1/profiles/{id}`. An empty string removes the VPN. A parse error comes back as a bare `400`, so test a new config in the app first. See [Import a VPN](https://donutbrowser.com/docs/rest-api#import-vpn).

## Troubleshooting

| Message | What to do |
| --- | --- |
| "Content does not appear to be a valid VPN configuration" | The text has no `[Interface]` or `[Peer]` section. Paste the whole file. |
| "Invalid WireGuard config: Missing Endpoint in [Peer]" (or `PrivateKey`, `Address`, `PublicKey`) | Add the missing key. Check its spelling and capitals. |
| "… is not valid base64 …" or "… decoded to N bytes (expected 32) …" | A key is cut or has extra characters. Copy it again. |
| "Config declares 2 [Peer] sections; exactly one peer is supported" | Keep one `[Peer]` section, or make one config per peer. |
| "VPN does not respond" before a launch | The server did not answer the handshake. Check the endpoint and port, and that your network allows outbound UDP. |
| "Couldn't start the VPN connection: …" | The tunnel failed at launch. The detail often reads "Handshake failed after 5 attempts". Check the keys and the endpoint. |
| "The selected VPN isn't working, so the profile wasn't created." | The test before profile creation failed. Fix the VPN first. |

## Related

- [Proxies, VPNs and DNS](https://donutbrowser.com/docs/proxies#wireguard-vpn): the VPN settings in the app.
- [How to match a browser's timezone and language to its proxy](https://donutbrowser.com/docs/guides/match-timezone-to-proxy)
- [How to use VLESS, Trojan or Shadowsocks in one browser](https://donutbrowser.com/docs/guides/vless-trojan-shadowsocks)

Donut Browser is free, and WireGuard works on every plan. [Download it](https://donutbrowser.com/) for macOS, Windows or Linux.
