An open API service indexing awesome lists of open source software.

https://github.com/wolffshots/tailscale-wireguard-plex

Instructions and scripts for getting Tailscale to work nicely with a Wireguard VPN on Linux (or in Docker) and optionally getting Plex to bypass both
https://github.com/wolffshots/tailscale-wireguard-plex

docker docker-compose exit-node mullvad protonvpn systemd tailscale tailscaled vpn wireguard wireguard-vpn

Last synced: 6 months ago
JSON representation

Instructions and scripts for getting Tailscale to work nicely with a Wireguard VPN on Linux (or in Docker) and optionally getting Plex to bypass both

Awesome Lists containing this project

README

        

# Getting Tailscale and Wireguard playing together nicely

Update 2: I have since found a nice way to have everything containerised so you don't have to mess with networking on the host at all. You can see details at my repo over at [connectorr](https://github.com/wolffshots/connectorr) but the basic idea is a [Gluetun](https://github.com/qdm12/gluetun) container for VPN communication and then you can opt other stacks in by using the [connectorr](https://github.com/wolffshots/connectorr) to route traffic through the VPN by default but it has built in support for having certain subnets bypassed and can do stuff like health checks.
I've included an example stack here with a [Gluetun](https://github.com/qdm12/gluetun) container and Tailscale container using it as a gateway for most communication except the local network or other Tailscale machines. Then I can use that Tailscale machine as an exit node from other devices when I want to route something through the VPN. If I want to route something through on the same machine then I just drop another [connectorr](https://github.com/wolffshots/connectorr) into whatever stack I want to route for.
With this solution I can very easily opt other containers in to routing through the VPN and either leave Plex routing normally on the host or add it container that just isn't opted in.

This is just an example, see [connectorr](https://github.com/wolffshots/connectorr) for more context
```yml
services:
tailscale:
image: tailscale/tailscale
container_name: tailscale
cap_add:
- NET_ADMIN
- SYS_MODULE
volumes:
- ./tailscale/state:/var/lib/tailscale
environment:
- TS_STATE_DIR=/var/lib/tailscale/
- TS_AUTHKEY=${TS_AUTHKEY}
- TS_EXTRA_ARGS=--advertise-exit-node
- TS_HOSTNAME=${TS_HOSTNAME}
- TS_USERSPACE=true
network_mode: service:connectorr
restart: always
healthcheck:
test: tailscale status --peers=false --json | grep -q 'Online.*true'
connectorr:
image: ghcr.io/wolffshots/connectorr:latest
cap_add:
- NET_ADMIN
environment:
- GATEWAY_IP=172.21.0.2
- BYPASS_IP=172.21.0.1
- BYPASS_SUBNETS=192.168.88.0/24
restart: unless-stopped
networks:
wgnet:
ipv4_address: 172.21.0.22
networks:
wgnet:
external: true
```

---

Update 1: Before I get into the details of how I worked out how to do this I have since found an alternative to these changes that may suit more people more is to use Wireguard and Tailscale in a Docker compose stack and then just use that Tailscale container as an exit node or alternatively the Wireguard container's network as a the network for whatever other container you want to route through it. See [compose.yml](./compose.yml) for how you could set something like that up.

---

Instructions and scripts for getting Tailscale to work nicely with a Wireguard VPN on Linux and optionally getting Plex or another app to bypass both.

The instructions are primarily aimed at my use case which is Ubuntu Server (so with `systemd`) but the basic idea and scripts should work with any Unix system that uses `iproute2` (or something similar).

The script included with this project (`split_routes`) can be used to add, delete and refresh `ip rule`s and `ip route`s even outside of this use case. You should be able to adapt it to work with things other than Plex.

## Wireguard changes
Run `sudo systemctl edit [email protected]` to edit the override file for the `wg-quick` service for profile `wg0.conf`.

```
# /etc/systemd/system/[email protected]/override.conf

[Unit]
Before=tailscaled.service plexmediaserver.service
```
This just tells the `wg-quick` service for profile `wg0.conf` that it should start before the `tailscaled` and `plexmediaserver` services. If you don't plan to use Plex then you can just leave out `plexmediaserver.service`.
This is important because the `wg-quick` script inserts ip rules _above_ whatever is currently in your rules. This means it takes precedence over Tailscale and our Plex rules if it starts _after_ them.

## Tailscale changes
Run `sudo systemctl edit tailscaled.service` to edit the override file for the `tailscaled` service

```
# /etc/systemd/system/tailscaled.service.d/override.conf

[Unit]
[email protected]

[Service]
ExecStartPre=-/usr/sbin/ip rule add pref 65 table 52
ExecStop=-/usr/sbin/ip rule del pref 65 table 52
```
This adds a rule to check table 52 and since it's preference if 65 it should happen before routing stuff through Wireguard. This allows traffic to check the Tailscale table by default and then route everything that doesn't match that through the Wireguard VPN.
If you're interested you can check the Tailscale table with `ip route show table 52` (while Tailscale is up). It should show the same IPs as are allocated to your devices on your Tailnet (as you should be able to see with `tailscale status`)

If you set the Tailscale device as an exit node then connecting to it should allow you to use the Wireguard VPN connection as well.

## Plex or other excluded routes changes

You can follow similar steps to make any other app excluded from the Wireguard routing.

You'll need to add some rules for Plex to your config and there are a couple ways of doing that.
The first way is a little more robust in case IPs change but is has some security considerations because it allows the `plex` user to change rules and routes without a password.

### 1. Allowing the `plex` user permissions to `ip rule` and `ip route`

1. Copy the `split_routes` script in this project to somewhere accessible to the `plex` user like `/usr/local/bin`

2. Run `sudo systemctl edit plexmediaserver.service` to edit the override file for the `plexmediaserver` service
```
# /etc/systemd/system/plexmediaserver.service.d/override.conf

[Unit]
[email protected] tailscaled.service

[Service]
ExecStartPre=-/usr/local/bin/split_routes refresh plexroute 60 plex.tv app.plex.tv metadata.provider.plex.tv v4.plex.tv resources-cdn.plexapp.com meta.plex.tv download.plex.tv assets.plex.tv analytics.plex.tv plex.direct
ExecStop=-/usr/local/bin/split_routes del plexroute
```

You may need to add `..plex.direct` and `..plex.direct` to the start and stop script list. I got the identifier from my Plex logs but am not 100% sure of the meaning of it.

3. Create a `sudoer` file for the `plex` user to use `sudo ip route`, `sudo ip rule` and `sudo iptables ... --set-mark 1` without a password for the script.
`sudo vim /etc/sudoers.d/plex`
```
plex ALL=(ALL) NOPASSWD: /sbin/ip route add *, /sbin/ip route del *, /sbin/ip rule add to *, /sbin/ip rule del to *, /sbin/ip rule del from *, /usr/sbin/iptables -t mangle -A PREROUTING -p tcp --dport 32400 -j MARK --set-mark 1, /usr/sbin/iptables -t mangle -D PREROUTING -p tcp --dport 32400 -j MARK --set-mark 1, /usr/sbin/iptables -t mangle -A OUTPUT -p tcp --sport 32400 ! -d 192.168.88.0/24 -j MARK --set-mark 1, /usr/sbin/iptables -t mangle -D OUTPUT -p tcp --sport 32400 ! -d 192.168.88.0/24 -j MARK --set-mark 1, /sbin/ip rule add fwmark 1 table plexroute, /sbin/ip rule del fwmark 1 table plexroute
```

### 2. Runnning the script in a `cron` job

1. Edit the `crontab` for the `root` user with `sudo crontab -e`

```
# macro command
@reboot sleep 60 && /usr/local/bin/split_routes refresh plexroute 60 plex.tv app.plex.tv metadata.provider.plex.tv v4.plex.tv resources-cdn.plexapp.com meta.plex.tv download.plex.tv assets.plex.tv analytics.plex.tv plex.direct
# m h dom mon dow command
00 12 * * * /usr/local/bin/split_routes refresh plexroute 60 plex.tv app.plex.tv metadata.provider.plex.tv v4.plex.tv resources-cdn.plexapp.com meta.plex.tv download.plex.tv assets.plex.tv analytics.plex.tv plex.direct
```

This example runs the script to refresh the routes at noon every day and on boot. The `sleep` might not be necessary but the idea is to allow Wireguard and Tailscale a little extra time since we can't trigger the script explicitly after they start.