blob: cded95dd40a297fdd63e9a2a7ea19e31a66c244f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
{ config, pkgs, ... }: {
# Secrets
sops.secrets.transmission-ovpn-config = { sopsFile = ./resources/secrets/transmission.yaml; key = "ovpn-config"; };
sops.secrets.transmission-ovpn-auth = { sopsFile = ./resources/secrets/transmission.yaml; key = "ovpn-auth"; };
# Container
containers.transmission = let
home = "/var/lib/transmission";
download-dir = "${home}/complete";
incomplete-dir = "${home}/incomplete";
in {
autoStart = true;
privateNetwork = true;
enableTun = true; # OpenVPN requires
hostBridge = "br-lan0";
localMacAddress = "02:00:00:00:00:07";
# Download dirs
bindMounts = {
"${download-dir}" = {
hostPath = "/media/ingens/media/.incomplete";
isReadOnly = false;
};
"${incomplete-dir}" = {
hostPath = "/media/ingens/media/.complete";
isReadOnly = false;
};
};
# Bind secrets
bindMounts."/run/secrets/ovpn-config.ovpn" = {
hostPath = config.sops.secrets.transmission-ovpn-config.path;
isReadOnly = true;
};
bindMounts."/run/secrets/ovpn-auth" = {
hostPath = config.sops.secrets.transmission-ovpn-auth.path;
isReadOnly = true;
};
config = { lib, config, ... }: {
# Network
networking.enableIPv6 = false; # Prevent ip leaks
networking.interfaces.eth0.useDHCP = true;
networking.firewall.interfaces = {
eth0.allowedTCPPorts = [ 80 ]; # RPC interface
# Torrent ports
tun0 = {
allowedTCPPorts = [ 51413 ];
allowedUDPPorts = [ 51413 ];
};
};
# Transmission
services.transmission = {
inherit home;
enable = true;
settings = {
inherit download-dir incomplete-dir;
};
};
# TODO remove (#258793)
systemd.services.transmission.serviceConfig = {
RootDirectoryStartOnly = lib.mkForce null;
RootDirectory = lib.mkForce null;
};
# Reverse proxy
services.caddy = {
enable = true;
virtualHosts.":80".extraConfig = ''
reverse_proxy localhost:9091
'';
};
# OpenVPN
services.openvpn.servers.main = {
config = ''
config /run/secrets/ovpn-config.ovpn
auth-user-pass /run/secrets/ovpn-auth
'';
autoStart = true;
updateResolvConf = true;
};
# VPN killswitch
networking.firewall.extraCommands = ''
# Get domain name host and port from ovpn config
SERVER_HOST=$(${pkgs.gawk}/bin/awk '/^remote /{print $2;exit}' /run/secrets/ovpn-config.ovpn)
SERVER_PORT=$(${pkgs.gawk}/bin/awk '/^remote /{print $3;exit}' /run/secrets/ovpn-config.ovpn)
# Resolve server ip from host
while [ -z "$SERVER_IP" ]; do
sleep 3
SERVER_IP=$(${pkgs.getent}/bin/getent hosts "$SERVER_HOST" 2>/dev/null | ${pkgs.gawk}/bin/awk '{print $1}')
echo "SERVER_IP: $SERVER_IP"
done
# Only allow out traffic from tun0
${pkgs.iptables}/bin/iptables -P OUTPUT DROP
${pkgs.iptables}/bin/iptables -A OUTPUT -o lo -j ACCEPT
${pkgs.iptables}/bin/iptables -A OUTPUT -o tun0 -j ACCEPT
${pkgs.iptables}/bin/iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Exception: allow established connections
${pkgs.iptables}/bin/iptables -A OUTPUT -p udp -d "$SERVER_IP" --dport "$SERVER_PORT" -j ACCEPT
# Allow DNS
DNS_IP=$(${pkgs.gawk}/bin/awk '/^nameserver /{print $2; exit}' /etc/resolv.conf)
${pkgs.iptables}/bin/iptables -A OUTPUT -o eth0 -p udp -d "$DNS_IP" --dport 53 -j ACCEPT
${pkgs.iptables}/bin/iptables -A OUTPUT -o eth0 -p tcp -d "$DNS_IP" --dport 53 -j ACCEPT
# Allow transmission RPC
'';
system.stateVersion = "26.05";
};
};
}
|