74 lines
2.9 KiB
Nix
74 lines
2.9 KiB
Nix
# services/imgur-vpn.nix — route imgur out a WireGuard tunnel, network-wide
|
|
#
|
|
# imgur geo-blocks UK IPs, so LAN clients need a non-UK exit for imgur only.
|
|
# imgur.com / i.imgur.com / api.imgur.com all resolve to two Fastly anycast
|
|
# /24s; we send just those prefixes down the tunnel and leave everything else
|
|
# on eno1.
|
|
#
|
|
# ponytail: static prefixes, not a DNS-driven nftset. Other Fastly customers
|
|
# sharing these /24s ride the tunnel too — harmless, just a longer path. If
|
|
# that ever matters, add dnsmasq `nftset=` + fwmark policy routing instead.
|
|
#
|
|
# Setup (one-off, on the mediaserver):
|
|
# 1. Fill in peerPublicKey / peerEndpoint / tunnelAddress below from your
|
|
# VPN provider's WireGuard config (pick a non-UK exit).
|
|
# 2. Write the private key, no trailing newline, readable by systemd-network:
|
|
# install -m600 -o systemd-network -g systemd-network \
|
|
# /dev/stdin /var/secrets/wg-imgur.key <<< '<PRIVATE_KEY>'
|
|
# 3. Rebuild. Verify: curl --interface wg-imgur https://api.imgur.com/
|
|
{ config, lib, ... }:
|
|
let
|
|
# --- provider details: fill these in ---
|
|
peerPublicKey = "@PEER_PUBLIC_KEY@";
|
|
peerEndpoint = "@HOST_OR_IP@:51820";
|
|
tunnelAddress = "@TUNNEL_IP@/32"; # address the provider assigned us
|
|
|
|
# imgur's Fastly anycast prefixes.
|
|
imgurNets = [ "199.232.192.0/24" "199.232.196.0/24" ];
|
|
in
|
|
{
|
|
config = lib.mkIf (config.networking.hostName == "FredOS-Mediaserver") {
|
|
|
|
systemd.network = {
|
|
netdevs."30-wg-imgur" = {
|
|
netdevConfig = {
|
|
Name = "wg-imgur";
|
|
Kind = "wireguard";
|
|
};
|
|
# Key read at runtime — keeps flake eval pure (hosts build from Forgejo).
|
|
wireguardConfig.PrivateKeyFile = "/var/secrets/wg-imgur.key";
|
|
wireguardPeers = [{
|
|
PublicKey = peerPublicKey;
|
|
Endpoint = peerEndpoint;
|
|
# Doubles as the tunnel's crypto-routing scope: only imgur goes in.
|
|
AllowedIPs = imgurNets;
|
|
PersistentKeepalive = 25;
|
|
}];
|
|
};
|
|
|
|
networks."30-wg-imgur" = {
|
|
matchConfig.Name = "wg-imgur";
|
|
address = [ tunnelAddress ];
|
|
# Plain main-table routes: destination-based, so no fwmark/ip-rule
|
|
# machinery and no rp_filter breakage on the reply path.
|
|
routes = map (n: { Destination = n; }) imgurNets;
|
|
linkConfig.RequiredForOnline = "no";
|
|
};
|
|
};
|
|
|
|
# LAN sources must be NAT'd to the tunnel address, and TCP MSS clamped —
|
|
# the tunnel's 1420 MTU otherwise black-holes full-size segments.
|
|
networking.nftables.tables.router-nat.content = lib.mkAfter ''
|
|
chain wg_imgur_postrouting {
|
|
type nat hook postrouting priority 101; policy accept;
|
|
oifname "wg-imgur" masquerade
|
|
}
|
|
'';
|
|
networking.nftables.tables.filter.content = lib.mkAfter ''
|
|
chain wg_imgur_mss {
|
|
type filter hook forward priority 0; policy accept;
|
|
oifname "wg-imgur" tcp flags syn tcp option maxseg size set rt mtu
|
|
}
|
|
'';
|
|
};
|
|
}
|