{ config, lib, input, pkgs, ... }: let sefidelKeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILN14b5Fu+StHeMXq4ClyLG4G+/vCAfS7adxceEFria/ openpgp:0x1D5BCD11" ]; maintainerKeys = [ ] ++ sefidelKeys; poorObfuscation = y: x: "${x}@${y}"; in { imports = [ ]; deployment = { targetHost = "kanata.bee-polaris.ts.net"; targetUser = "root"; }; boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; boot.supportedFilesystems = [ "zfs" ]; networking.hostId = "31cc5527"; networking.hostName = "kanata"; # Erase your darlings boot.initrd.postDeviceCommands = lib.mkAfter '' zfs rollback -r rpool/local/root@blank ''; boot.kernelModules = [ "r8169" ]; boot.initrd.kernelModules = [ "r8169" ]; boot.initrd.network.enable = true; boot.initrd.network.ssh = { enable = true; # Using the same port as the actual SSH daemon will cause the clients to # throw errors related to host key mismatch. port = 2222; hostKeys = [ # XXX: This has to be manually generated during NixOS install. # The files are then copied to initrd secrets during activation. "/persist/initrd/ssh_host_rsa_key" "/persist/initrd/ssh_host_ed25519_key" ]; authorizedKeys = maintainerKeys; }; boot.initrd.network.postCommands = '' cat < /root/.profile if pgrep -x "zfs" > /dev/null then zfs load-key -a killall zfs else echo "ZFS is not running -- this could be a sign of failure." fi EOF ''; modules.tailscale-initrd = { enable = true; # XXX: This has to be manually generatd during NixOS install. # The files are then copied to initrd secrets during activation. tailscaleStatePath = "/persist/initrd/tailscale-initrd.state"; }; services.openssh.enable = true; users.users.root.openssh.authorizedKeys.keys = maintainerKeys; # NOTE: managed by modules.persistence # TODO: remove? # fileSystems."/persist".neededForBoot = true; # # services.openssh.hostKeys = [ # { # path = "/persist/ssh/ssh_host_ed25519_key"; # type = "ed25519"; # } # { # path = "/persist/ssh/ssh_host_rsa_key"; # type = "rsa"; # bits = 4096; # } # ]; sops.defaultSopsFile = ./secrets/secrets.yaml; powerManagement.cpuFreqGovernor = "ondemand"; sops.secrets.zfs-smol-key = { }; sops.secrets.nextcloud-admin-pass = { owner = "nextcloud"; }; sops.secrets.acme-credentials = { owner = "acme"; }; sops.secrets.grafana-admin-pass = { owner = "grafana"; }; sops.secrets.cf-kusanari-kanata-credentials = { owner = "cloudflared"; }; sops.secrets.nitter-account-jsonl = { }; sops.secrets.interlink-password = { }; sops.secrets.interlink-ovpn = { }; sops.secrets.interlink-ovpn-creds = { }; sops.secrets.proton-private-key = { }; sops.secrets.attic-credentials = { }; # TODO: insecure? sops.secrets.invidious-hmac = { mode = "0444"; }; sops.secrets.transmission-extra-config = { owner = "transmission"; }; boot.kernel.sysctl."net.ipv4.ip_forward" = 1; boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = 1; networking.firewall.enable = true; networking.nat = { enable = true; internalInterfaces = [ "ve-+" ]; externalInterface = "enp3s0"; # Lazy IPv6 connectivity for the container enableIPv6 = true; }; services.tailscale = { enable = true; useRoutingFeatures = "both"; openFirewall = true; }; services.nginx.enable = true; services.cloudflared = { enable = true; tunnels."bf6dcc14-d315-41c7-b798-3fe0e0e968eb" = { default = "http_status:404"; }; }; networking.firewall.allowedTCPPorts = [ 80 443 ]; modules = { persistence.directories = [ "/var/lib/tailscale" "/var/lib/nixos-containers" ]; persistence = { enable = true; storagePath = "/persist"; }; # NOTE: This module only populates route entries, # each service needs to be enabled individually. expose = { enable = true; routes = { "dns.kusanari.network".to = "http://localhost:4000"; "metrics.kusanari.network".to = "http://localhost:4001"; "nitter.kusanari.network".to = "http://localhost:4002"; "invidious.kusanari.network".to = "http://localhost:4003"; "hydra.kusanari.network".to = "http://localhost:4004"; "cache.kusanari.network".to = "http://localhost:4005"; "torrent.kusanari.network".to = "http://localhost:4006"; # Nginx pre-configured routes "nextcloud.kusanari.network" = { to = "https://localhost:443"; configureNginx = false; }; }; ssl = { enable = true; acmeHost = "kusanari.network"; }; tailscaleIp = "100.93.1.1"; # kusanari-kanata @ core cloudflareUUID = "bf6dcc14-d315-41c7-b798-3fe0e0e968eb"; secrets.cloudflare-credentials = config.sops.secrets.cf-kusanari-kanata-credentials.path; }; services.nginx.enable = true; services.acme = { enable = true; email = poorObfuscation "sefidel.net" "postmaster"; certs = { "kusanari.network" = { subDomains = [ "nitter" "nextcloud" "jellyfin" "dns" "metrics" "invidious" "hydra" "cache" "torrent" ]; }; }; secrets.acme-credentials = config.sops.secrets.acme-credentials.path; }; services.metrics = { enable = true; realHost = "metrics.kusanari.network"; secrets.adminPassword = config.sops.secrets.grafana-admin-pass.path; }; services.postgresql.enable = true; services.blocky = { enable = true; realHost = "dns.kusanari.network"; }; services.nextcloud = rec { enable = true; ssl = { enable = true; acmeHost = domain; }; domain = "kusanari.network"; realHost = "nextcloud.kusanari.network"; secrets.admin-pass = config.sops.secrets.nextcloud-admin-pass.path; }; services.nitter = { enable = true; title = "Kusanari Nitter"; domain = "kusanari.network"; realHost = "nitter.kusanari.network"; secrets.nitter-guest-accounts = config.sops.secrets.nitter-account-jsonl.path; }; services.invidious = { enable = true; domain = "kusanari.network"; realHost = "invidious.kusanari.network"; secrets.invidious-hmac-key = config.sops.secrets.invidious-hmac.path; }; services.hydra = { enable = true; baseURL = "https://hydra.kusanari.network"; }; services.atticd = { enable = true; hosts = [ "cache.kusanari.network" ]; baseURL = "https://cache.kusanari.network/"; storagePath = "/smol/archive/attic"; watchStore = true; secrets.attic-credentials = config.sops.secrets.attic-credentials.path; }; services.transmission = { enable = true; home = "/smol/sandbox/torrent"; secrets.transmission-extra-config = config.sops.secrets.transmission-extra-config.path; }; }; containers.v-interlink = { autoStart = true; enableTun = true; # Tailscale authkeys expire after 90 days, which means if a system # restarts, there's a high chance that the key will be invalid. # Therefore, we use classic authentication with non-ephemeral storage. ephemeral = false; privateNetwork = true; hostAddress = "172.16.1.1"; localAddress = "172.16.1.2"; bindMounts."/run/secrets/interlink-password".hostPath = config.sops.secrets.interlink-password.path; # bindMounts."/run/secrets/interlink-ovpn".hostPath = config.sops.secrets.interlink-ovpn.path; # bindMounts."/run/secrets/interlink-ovpn-creds".hostPath = config.sops.secrets.interlink-ovpn-creds.path; config = { config, pkgs, lib, ... }: { services.tailscale = { enable = true; useRoutingFeatures = "both"; extraUpFlags = [ "--advertise-exit-node=true" ]; }; networking.openconnect.interfaces.openconnect0 = { autoStart = true; gateway = "133.242.23.15"; # JP#11 # gateway = "133.242.17.239"; # JP#1 protocol = "anyconnect"; user = "sk146241"; passwordFile = "/run/secrets/interlink-password"; extraOptions = { servercert = "pin-sha256:42cxGem/A2lRRPLefN3tSlPHFD1mK0BLh7tbUJeXvhE="; # JP#11 # servercert = "pin-sha256:OvJIFf7gPPbnR7tdG0Uj10GET5eynt+o5pfKBIEA+ws="; # JP#1 }; }; systemd.services.openconnect-openconnect0 = { serviceConfig = { # XXX: On initial startup, the service would fail with # 'No route to host'. Restart = "on-failure"; RestartSec = "5s"; }; }; # services.openvpn.servers.interlink-sekai = { # autoStart = true; # config = "config /run/secrets/interlink-ovpn"; # up = "echo nameserver $nameserver | ${pkgs.openresolv}/sbin/resolvconf -m 0 -a $dev"; # down = "${pkgs.openresolv}/sbin/resolvconf -d $dev"; # }; system.stateVersion = "24.05"; }; }; networking.firewall.allowedUDPPorts = [ 51820 ]; containers.v-proton-jp43 = { autoStart = true; enableTun = true; # Tailscale authkeys expire after 90 days, which means if a system # restarts, there's a high chance that the key will be invalid. # Therefore, we use classic authentication with non-ephemeral storage. ephemeral = false; privateNetwork = true; hostAddress = "172.16.1.3"; localAddress = "172.16.1.4"; bindMounts."/run/secrets/proton-private-key".hostPath = config.sops.secrets.proton-private-key.path; config = { config, pkgs, lib, ... }: { services.tailscale = { enable = true; useRoutingFeatures = "both"; extraUpFlags = [ "--advertise-exit-node=true" ]; }; networking.firewall.allowedUDPPorts = [ 51820 ]; networking.wg-quick.interfaces.wg0 = { autostart = true; address = [ "10.2.0.2/32" ]; listenPort = 51820; privateKeyFile = "/run/secrets/proton-private-key"; peers = [{ publicKey = "7FslkahrdLwGbv4QSX5Cft5CtQLmBUlpWC382SSF7Hw="; # Exclude 100.64.0.0/10 allowedIPs = [ "0.0.0.0/0" # "0.0.0.0/2" # "64.0.0.0/3" # "96.0.0.0/6" # "100.0.0.0/10" # "100.128.0.0/9" # "101.0.0.0/8" # "102.0.0.0/7" # "104.0.0.0/5" # "112.0.0.0/4" # "128.0.0.0/1" ]; endpoint = "103.125.235.19:51820"; }]; }; system.stateVersion = "24.05"; }; }; # This option defines the first version of NixOS you have installed on this particular machine, # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions. # # Most users should NEVER change this value after the initial install, for any reason, # even if you've upgraded your system to a new NixOS release. # # This value does NOT affect the Nixpkgs version your packages and OS are pulled from, # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how # to actually do that. # # This value being lower than the current NixOS release does NOT mean your system is # out of date, out of support, or vulnerable. # # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration, # and migrated your data accordingly. # # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion . system.stateVersion = "24.05"; # Did you read the comment? }