diff --git a/container/autobrr/default.nix b/container/autobrr/default.nix new file mode 100644 index 0000000..1531a0c --- /dev/null +++ b/container/autobrr/default.nix @@ -0,0 +1,64 @@ +{ lib, ... }: + +{ + systemd.tmpfiles.rules = [ + "d /var/lib/autobrr 0755 root root" + "d /var/lib/omegabrr 0755 root root" + ]; + + virtualisation.oci-containers.containers.autobrr = { + image = "ghcr.io/autobrr/autobrr:latest"; + ports = [ "192.168.42.2:7474:7474" ]; + environment = { + "TZ" = "Europe/Berlin"; + }; + volumes = [ + "/var/lib/autobrr:/config" + ]; + extraOptions = [ + "--network=ns:/var/run/netns/wg" + ]; + }; + + virtualisation.oci-containers.containers.omegabrr = { + image = "ghcr.io/autobrr/omegabrr:latest"; + ports = [ "192.168.42.2:7441:7441" ]; + volumes = [ + "/var/lib/omegabrr:/config" + ]; + extraOptions = [ + "--network=ns:/var/run/netns/wg" + ]; + }; + + systemd.services.podman-autobrr = { + bindsTo = [ "wg.service" ]; + after = lib.mkForce [ "wg.service" ]; + + serviceConfig = { + TimeoutStopSec = lib.mkForce 10; + }; + }; + + systemd.services.podman-omegabrr = { + bindsTo = [ "wg.service" ]; + after = lib.mkForce [ "wg.service" ]; + + serviceConfig = { + TimeoutStopSec = lib.mkForce 10; + }; + }; + + services.nginx.virtualHosts."autobrr.internal.kempkens.network" = { + quic = true; + http3 = true; + + onlySSL = true; + useACMEHost = "internal.kempkens.network"; + + locations."/" = { + recommendedProxySettings = true; + proxyPass = "http://192.168.42.2:7474"; + }; + }; +} diff --git a/secret/hosts/mediaserver.nix b/secret/hosts/mediaserver.nix index 97a4f00..1442743 100644 Binary files a/secret/hosts/mediaserver.nix and b/secret/hosts/mediaserver.nix differ diff --git a/system/hosts/mediaserver.nix b/system/hosts/mediaserver.nix index 83cc8f1..4424a84 100644 --- a/system/hosts/mediaserver.nix +++ b/system/hosts/mediaserver.nix @@ -24,6 +24,7 @@ in ../nixos/mediaserver-setup.nix (import ../nixos/wireguard-netns.nix (args // { inherit secret; })) + (import ../nixos/wireguard-firewall-mediaserver.nix (args // { inherit secret; })) ../nixos/prowlarr.nix ../nixos/sonarr.nix ../nixos/radarr.nix @@ -35,6 +36,7 @@ in ../nixos/container.nix ../../container/homepage-dashboard ../../container/tubearchivist + ../../container/autobrr ../../secret/container/additional-media ]; diff --git a/system/nixos/qbittorrent.nix b/system/nixos/qbittorrent.nix index 5b61b27..5a05aa0 100644 --- a/system/nixos/qbittorrent.nix +++ b/system/nixos/qbittorrent.nix @@ -25,8 +25,25 @@ "/etc/netns/wg/resolv.conf:/etc/resolv.conf:norbind" "/etc/netns/wg/nsswitch.conf:/etc/nsswitch.conf:norbind" ]; - ExecStart = "${pkgs.qbittorrent-nox}/bin/qbittorrent-nox --profile=/var/lib/qbittorrent"; + ExecStart = "${pkgs.qbittorrent-nox}/bin/qbittorrent-nox --profile=/var/lib/qbittorrent --webui-port=8071"; AmbientCapabilities = [ "CAP_NET_RAW" ]; }; }; + + services.nginx.virtualHosts."qbittorrent.internal.kempkens.network" = { + quic = true; + http3 = true; + + onlySSL = true; + useACMEHost = "internal.kempkens.network"; + + extraConfig = '' + client_max_body_size 32m; + ''; + + locations."/" = { + recommendedProxySettings = true; + proxyPass = "http://192.168.42.2:8071"; + }; + }; } diff --git a/system/nixos/sabnzbd.nix b/system/nixos/sabnzbd.nix index 31110ad..4715b71 100644 --- a/system/nixos/sabnzbd.nix +++ b/system/nixos/sabnzbd.nix @@ -2,7 +2,7 @@ { systemd.tmpfiles.rules = [ - "d /var/lib/sabnzbd 0700 media_user media_group" + "d /var/lib/sabnzbd 0750 media_user media_group" ]; # The nix-provided options force a sabnzbd-user to a certain degree diff --git a/system/nixos/wireguard-firewall-mediaserver.nix b/system/nixos/wireguard-firewall-mediaserver.nix new file mode 100644 index 0000000..e37deab --- /dev/null +++ b/system/nixos/wireguard-firewall-mediaserver.nix @@ -0,0 +1,122 @@ +{ pkgs, secret, ... }: + +# Heavily inspired by the built-in firewall scripts, minus the nice interface + +let + writeShScript = name: text: + let + dir = pkgs.writeScriptBin name '' + #! ${pkgs.runtimeShell} -e + + ip46tables() { + iptables -w "$@" + ip6tables -w "$@" + } + + ${text} + ''; + in + "${dir}/bin/${name}"; + + startScript = writeShScript "wg-firewall-start" '' + ip46tables -D INPUT -j wg-fw 2> /dev/null || true + for chain in wg-fw wg-fw-accept wg-fw-log-refuse wg-fw-refuse; do + ip46tables -F "$chain" 2> /dev/null || true + ip46tables -X "$chain" 2> /dev/null || true + done + + ip46tables -N wg-fw-accept + ip46tables -A wg-fw-accept -j ACCEPT + + ip46tables -N wg-fw-refuse + ip46tables -A wg-fw-refuse -j DROP + + ip46tables -N wg-fw-log-refuse + ip46tables -A wg-fw-log-refuse -p tcp --syn -j LOG --log-level info --log-prefix "refused connection: " + ip46tables -A wg-fw-log-refuse -m pkttype ! --pkt-type unicast -j wg-fw-refuse + ip46tables -A wg-fw-log-refuse -j wg-fw-refuse + + ip46tables -N wg-fw + + ip46tables -A wg-fw -i lo -j wg-fw-accept + + ip46tables -A wg-fw -m conntrack --ctstate ESTABLISHED,RELATED -j wg-fw-accept + + # Ports + ip46tables -A wg-fw -p tcp --dport 6801 -j wg-fw-accept -i vethwgns0 + ip46tables -A wg-fw -p tcp --dport 7474 -j wg-fw-accept -i vethwgns0 + ip46tables -A wg-fw -p tcp --dport 7878 -j wg-fw-accept -i vethwgns0 + ip46tables -A wg-fw -p tcp --dport 8071 -j wg-fw-accept -i vethwgns0 + ip46tables -A wg-fw -p tcp --dport 8080 -j wg-fw-accept -i vethwgns0 + ip46tables -A wg-fw -p tcp --dport 8989 -j wg-fw-accept -i vethwgns0 + ip46tables -A wg-fw -p tcp --dport 9696 -j wg-fw-accept -i vethwgns0 + ip46tables -A wg-fw -p tcp --dport 9999 -j wg-fw-accept -i vethwgns0 + + ip46tables -A wg-fw -p tcp --dport ${builtins.toString secret.wireguard.forwardedPort} -j wg-fw-accept -i wg0 + ip46tables -A wg-fw -p udp --dport ${builtins.toString secret.wireguard.forwardedPort} -j wg-fw-accept -i wg0 + + iptables -w -A wg-fw -p icmp --icmp-type echo-request -j wg-fw-accept + + ip6tables -A wg-fw -p icmpv6 --icmpv6-type redirect -j DROP + ip6tables -A wg-fw -p icmpv6 --icmpv6-type 139 -j DROP + ip6tables -A wg-fw -p icmpv6 -j wg-fw-accept + + ip46tables -A wg-fw -j wg-fw-log-refuse + ip46tables -A INPUT -j wg-fw + ''; + + stopScript = writeShScript "wg-firewall-stop" '' + ip46tables -D INPUT -j wg-drop 2>/dev/null || true + + ip46tables -D INPUT -j wg-fw 2>/dev/null || true + ''; + + reloadScript = writeShScript "wg-firewall-reload" '' + ip46tables -D INPUT -j wg-drop 2>/dev/null || true + ip46tables -F wg-drop 2>/dev/null || true + ip46tables -X wg-drop 2>/dev/null || true + ip46tables -N wg-drop + ip46tables -A wg-drop -j DROP + + ip46tables -A INPUT -j wg-drop + + if ${startScript}; then + ip46tables -D INPUT -j wg-drop 2>/dev/null || true + else + echo "Failed to reload firewall... Stopping" + ${stopScript} + exit 1 + fi + ''; +in +{ + systemd.services.wg-firewall = { + description = "Wireguard Firewall"; + bindsTo = [ "wg.service" ]; + after = [ "wg.service" ]; + wantedBy = [ "multi-user.target" ]; + + path = [ pkgs.iptables ]; + + # FIXME: this module may also try to load kernel modules, but + # containers don't have CAP_SYS_MODULE. So the host system had + # better have all necessary modules already loaded. + unitConfig.ConditionCapability = "CAP_NET_ADMIN"; + unitConfig.DefaultDependencies = false; + + reloadIfChanged = true; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + NetworkNamespacePath = "/var/run/netns/wg"; + BindReadOnlyPaths = [ + "/etc/netns/wg/resolv.conf:/etc/resolv.conf:norbind" + "/etc/netns/wg/nsswitch.conf:/etc/nsswitch.conf:norbind" + ]; + ExecStart = "@${startScript} wg-firewall-start"; + ExecReload = "@${reloadScript} wg-firewall-reload"; + ExecStop = "@${stopScript} wg-firewall-stop"; + }; + }; +}