Watching free-to-view television in the UK is a frustrating experience. We have some excellent channels and content, but the options to watch online are fragmented and often advert-strewn. Bizarrely, the best option I’ve found is Zattoo, a Swiss streaming service which does things “right”. There’s a great selection of channels, the interface is simple to navigate, timeshifting is trivial and there’s an excellent PVR function. It is everything I’d hope for in a TV service at a fair price.
But it isn’t available in the UK. The service is geoblocked.
I subscribe to Mullvad’s VPN service. Running this, I can access Zattoo on my laptop or phone. That is fine, but I’d rather watch on the big TV.
My TV runs RokuOS. There’s no Mullvad VPN app for this. I have an Xbox Series S connected to it which could play video, but there’s no VPN app for that, either.
In the past, I’ve used a Raspberry PI 3 running RaspAP to create a wireless access point to connect such devices to a VPN. It “works”, to some extent, but I’ve found the connection to be flaky. As I’ve recently set up my newest Firebat T8 Plus with Proxmox, I decided to use this beautiful little cuboid of joy to provide a gateway to my VPN.
Setting up the container in Proxmox ๐
My Proxmox configuration is quite vanilla. I have the default network bridge set up to one of my ethernet interfaces. For my container template, I used the debian-12-standard_12.2-1_amd64.tar.zst
bundle. I kept most settings at default, whilst allocating 512MB RAM and 4GB disk to the container. That’s probably overkill for this job. I used the default bridge for networking and logged on as root
via the console.
Configuring Debian ๐
Annoyingly, networking is not set up by default on this Debian image. I edited /etc/network/interfaces
and added:
auto eth0
iface eth0 inet dhcp
I started the interface with ifup eth0
before pinging google.com
to confirm it was working. As this was a success, I proceeded to update the system and install the needed packages:
apt update
apt full-upgrade
apt install wireguard resolvconf iptables
Configuring the VPN ๐
Mullvad offer WireGuard configurations for their service. I selected a Linux configuration with a Swiss endpoint and copied the generated text. I pasted this into a new file at /etc/wireguard/wg0.conf
. I then used the superb AllowedIPs calculator to generate a list of IPs which should be passed through the VPN (using 0.0.0.0/0
in the “Allowed IPs” field and my local subnet and the Mullvad endpoint IP in the “Disallowed IPs” field). I manually edited the wg0.conf
file to include these:
[Interface]
# Device: Mullvad Words
PrivateKey = REDACTED
Address = 10.66.170.166/32
DNS = 10.64.0.1
[Peer]
PublicKey = REDACTED
AllowedIPs = 0.0.0.0/2, 64.0.0.0/3, 96.0.0.0/4, 112.0.0.0/5, 120.0.0.0/6, 124.0.0.0/7, 126.0.0.0/8, 128.0.0.0/2, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/11, 193.32.0.0/18, 193.32.64.0/19, 193.32.96.0/20, 193.32.112.0/21, 193.32.120.0/22, 193.32.124.0/23, 193.32.126.0/24, 193.32.127.0/26, 193.32.127.64/30, 193.32.127.68/32, 193.32.127.70/31, 193.32.127.72/29, 193.32.127.80/28, 193.32.127.96/27, 193.32.127.128/25, 193.32.128.0/17, 193.33.0.0/16, 193.34.0.0/15, 193.36.0.0/14, 193.40.0.0/13, 193.48.0.0/12, 193.64.0.0/10, 193.128.0.0/9, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 224.0.0.0/3
Endpoint = 193.32.127.69:51808
I brought up the WireGuard tunnel with:
systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0
When I ran dig TXT +short o-o.myaddr.l.google.com @ns1.google.com
to test my external IP address, I was rewarded with a Swiss address. Result!
Setting up forwarding for the gateway ๐
Next, i needed to set up IP forwarding so the container would function as a gateway. I edited the file /etc/sysctl.d/99-sysctl.conf
and uncommented the line net.ipv4.ip_forward=1
. The setting was activated by running sysctl -p
.
Finally, I had to add some iptables
forwarding magic to the wg0.conf
file, to ensure incoming packets would be sent through the VPN, and return packets to established connections would come back to the requestor. The final wg0.conf
looks a bit like this:
[Interface]
# Device: Mullvad Words
PrivateKey = REDACTED
Address = 10.66.170.166/32
DNS = 10.64.0.1
PostUp = iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE; iptables -A FORWARD -i eth0 -o wg0 -j ACCEPT; iptables -A FORWARD -i wg0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
[Peer]
PublicKey = REDACTED
AllowedIPs = 0.0.0.0/2, 64.0.0.0/3, 96.0.0.0/4, 112.0.0.0/5, 120.0.0.0/6, 124.0.0.0/7, 126.0.0.0/8, 128.0.0.0/2, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/11, 193.32.0.0/18, 193.32.64.0/19, 193.32.96.0/20, 193.32.112.0/21, 193.32.120.0/22, 193.32.124.0/23, 193.32.126.0/24, 193.32.127.0/26, 193.32.127.64/30, 193.32.127.68/32, 193.32.127.70/31, 193.32.127.72/29, 193.32.127.80/28, 193.32.127.96/27, 193.32.127.128/25, 193.32.128.0/17, 193.33.0.0/16, 193.34.0.0/15, 193.36.0.0/14, 193.40.0.0/13, 193.48.0.0/12, 193.64.0.0/10, 193.128.0.0/9, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 224.0.0.0/3
Endpoint = 193.32.127.69:51808
Of course, I had to reload the configuration with systemctl restart wg-quick@wg0
for the changes to take effect.
Using the VPN with the Xbox ๐
Using the VPN involved accessing the “Advanced” network settings on the Xbox, selecting a Static IP and copying all of the settings from the previous dynamic allocation, except for the Gateway address which was set to the IP of the new container.
I then opened the Edge browser, navigated to Zattoo and started streaming. No problems!
I’d love to hear comments and suggestions on Bluesky!