{ config , pkgs , inputs , system , lib , settings , ... }: { imports = [ ./hardware-configuration.nix ./containers.nix ./caddy.nix ./gui.nix ./drives.nix ./games/palworld.nix ./games/minecraft inputs.lastfm-status.nixosModules.default inputs.confess.nixosModules.${system}.default inputs.common-modules.nixosModules.nixos-upgrade inputs.common-modules.nixosModules.qbittorrent-nox inputs.common-modules.nixosModules.unpackerr ]; nixpkgs.config.allowUnfree = true; system.autoUpgrade = { enable = true; allowReboot = true; flake = "/etc/nixos"; updateFlake = true; # minecraft plugin auto update extraCommands = let plugins = [ "9eGKb6K1" # https://modrinth.com/plugin/simple-voice-chat "1u6JkXh5" # https://modrinth.com/plugin/worldedit ]; in '' ./games/minecraft/modrinth-plugin-list.sh paper 1.21.1 ${builtins.concatStringsSep " " plugins} > games/minecraft/paper-vanilla-plugins.nix git add games/minecraft/paper-vanilla-plugins.nix git commit games/minecraft/paper-vanilla-plugins.nix -m "Updated games/minecraft/paper-vanilla-plugins.nix" ''; failureNotification = { enable = true; ntfyUrlFile = "/etc/secrets/failureNotification.env"; }; }; nix = { gc = { automatic = true; dates = "weekly"; }; optimise = { automatic = true; dates = [ "06:00" ]; }; settings = { experimental-features = [ "nix-command" "flakes" ]; auto-optimise-store = true; allowed-users = [ "@wheel" "owo" ]; }; }; boot = { supportedFilesystems = [ "btrfs" "mergerfs" ]; tmp.cleanOnBoot = true; kernelPackages = pkgs.linuxPackages_latest; loader = { systemd-boot.enable = true; efi.canTouchEfiVariables = true; }; }; systemd.services = { caddy.serviceConfig.ReadWriteDirectories = lib.mkForce [ "/var/lib/caddy" "/run/mastodon-web" ]; mautrix-telegram.path = with pkgs; [ lottieconverter # for animated stickers conversion, unfree package ffmpeg # if converting animated stickers to webm (very slow!) ]; tailscaled.environment = { TS_NO_LOGS_NO_SUPPORT = "true"; }; }; networking = { hostName = "server"; networkmanager.enable = true; nameservers = [ "127.0.0.1" # cloudflare "1.1.1.1" "1.0.0.1" ]; firewall = { enable = true; allowedUDPPortRanges = with config.services.coturn; [ { from = min-port; to = max-port; } ]; allowedUDPPorts = [ config.services.blocky.settings.ports.dns # coturn 3478 5349 ]; allowedTCPPorts = [ config.services.blocky.settings.ports.dns # HTTP/HTTPS 80 443 # coturn 3478 5349 config.services.forgejo.settings.server.SSH_PORT ]; }; }; time.timeZone = "Europe/Tallinn"; i18n = { defaultLocale = "en_GB.UTF-8"; extraLocaleSettings = { LC_ADDRESS = "et_EE.UTF-8"; LC_IDENTIFICATION = "et_EE.UTF-8"; LC_MEASUREMENT = "et_EE.UTF-8"; LC_MONETARY = "et_EE.UTF-8"; LC_NAME = "et_EE.UTF-8"; LC_NUMERIC = "et_EE.UTF-8"; LC_PAPER = "et_EE.UTF-8"; LC_TELEPHONE = "et_EE.UTF-8"; LC_TIME = "et_EE.UTF-8"; }; }; hardware = { nvidia = { package = config.boot.kernelPackages.nvidiaPackages.stable; modesetting.enable = true; open = false; }; nvidia-container-toolkit.enable = true; }; virtualisation.docker = { enable = true; autoPrune.enable = true; }; environment.systemPackages = with pkgs; [ mergerfs mergerfs-tools ffmpeg # nextcloud ]; programs = { mosh.enable = true; git.enable = true; fish.enable = true; ssh.startAgent = true; }; security = { sudo.wheelNeedsPassword = false; acme = { acceptTerms = true; defaults.email = "ssl@catnip.ee"; certs = { ${config.services.coturn.realm} = { webroot = settings.turnAcmeDir; postRun = "systemctl restart coturn.service"; group = config.systemd.services.coturn.serviceConfig.Group; }; }; }; }; services = { syncthing = { enable = true; guiAddress = "0.0.0.0:8384"; openDefaultPorts = true; }; confess-web = { enable = true; port = 8011; reverseProxy = true; trustedProxy = "127.0.0.1"; environmentFile = "/etc/secrets/confess.env"; }; mastodon = { enable = true; localDomain = "fedi.catnip.ee"; streamingProcesses = 10; extraConfig = { SMTP_TLS = "true"; }; smtp = { authenticate = true; user = "mastodon@catnip.ee"; passwordFile = "/etc/secrets/mastodon-smtp"; createLocally = false; host = "mx1.sly.ee"; port = 465; fromAddress = "mastodon@catnip.ee"; }; }; lastfm-status = { enable = true; port = 4014; }; unpackerr = { enable = true; # Stores UN_SONARR_0_API_KEY, UN_RADARR_0_API_KEY environmentFile = "/etc/secrets/unpackerr.env"; user = "owo"; group = "users"; settings = { debug = false; quiet = false; # How often to poll sonarr and radarr. # Recommend 1m-5m. Uses Go Duration. interval = "2m"; start_delay = "1m"; retry_delay = "5m"; parallel = 1; # Use these configurations to control the file modes used for newly extracted # files and folders. Recommend 0644/0755 or 0666/0777. file_mode = "0644"; dir_mode = "0755"; sonarr = [ { url = "http://localhost:8989"; paths = [ "/mnt/drive1/torrents/downloads" "/mnt/drive2/torrents" "/mnt/seagate-8tb-1/torrents" "/mnt/seagate-8tb-2/torrents" ]; protocols = "torrent"; timeout = "100s"; delete_delay = "10m"; } ]; radarr = [ { url = "http://localhost:7878"; paths = [ "/mnt/drive1/torrents/downloads" "/mnt/drive2/torrents" "/mnt/seagate-8tb-1/torrents" "/mnt/seagate-8tb-2/torrents" ]; protocols = "torrent"; timeout = "100s"; delete_delay = "10m"; } ]; }; }; qbittorrent-nox = { enable = true; openFirewall = true; user = "owo"; group = "users"; webuiPort = settings.ports.qbittorrent; torrentingPort = settings.ports.qbittorrent-torrent; }; scrutiny = { enable = true; collector.enable = true; settings.web.listen.port = 4012; }; # /var/lib/gitea-runner gitea-actions-runner = { package = pkgs.forgejo-actions-runner; instances = { forge = { enable = true; url = "https://forge.catnip.ee"; name = "runner"; labels = [ "latest-debian:docker://node:current" "latest-alpine:docker://node:current-alpine" ]; tokenFile = "/etc/secrets/gitea-actions-runner.env"; }; }; }; # /var/lib/forgejo/ forgejo = { enable = true; package = pkgs.forgejo; database.type = "postgres"; secrets.mailer.PASSWD = "/etc/secrets/forge-email"; settings = { server = { DOMAIN = "forge.catnip.ee"; HTTP_PORT = 4005; SSH_PORT = 2222; START_SSH_SERVER = true; ROOT_URL = "https://${config.services.forgejo.settings.server.DOMAIN}"; }; mailer = { ENABLED = true; FROM = "forge@catnip.ee"; PROTOCOL = "smtps"; SMTP_ADDR = "mx1.sly.ee"; SMTP_PORT = 465; USER = "forge@catnip.ee"; }; service = { DISABLE_REGISTRATION = true; }; }; }; # /var/lib/nextcloud nextcloud = { enable = true; package = pkgs.nextcloud30; hostName = "cloud.catnip.ee"; https = true; configureRedis = true; config = { adminuser = "admin"; dbhost = "localhost:${toString config.services.mysql.replication.masterPort}"; dbtype = "mysql"; adminpassFile = "/etc/secrets/nextcloud"; }; autoUpdateApps.enable = true; database.createLocally = true; extraApps = with config.services.nextcloud.package.packages.apps; { inherit contacts calendar tasks mail; # integration_github = pkgs.fetchNextcloudApp { # url = "https://github.com/nextcloud-releases/integration_github/releases/download/v2.0.7/integration_github-v2.0.7.tar.gz"; # sha256 = "sha256-2X/bNQNs3gC/EKeLQKjzMTslUPY6uHWcoT7wayhFQXk="; # license = "agpl3Only"; # }; }; extraAppsEnable = true; settings = { enable_previews = true; enabledPreviewProviders = [ "OC\\Preview\\OpenDocument" "OC\\Preview\\PDF" "OC\\Preview\\MSOffice2003" "OC\\Preview\\MSOfficeDoc" "OC\\Preview\\Image" "OC\\Preview\\Photoshop" "OC\\Preview\\TIFF" "OC\\Preview\\SVG" "OC\\Preview\\Font" "OC\\Preview\\MP3" "OC\\Preview\\Movie" "OC\\Preview\\MKV" "OC\\Preview\\MP4" "OC\\Preview\\AVI" ]; }; }; # /var/lib/mysql mysql = { enable = true; ensureDatabases = [ "nextcloud" ]; ensureUsers = [ { name = "nextcloud"; ensurePermissions = { "nextcloud.*" = "ALL PRIVILEGES"; }; } ]; }; nginx.virtualHosts.${config.services.nextcloud.hostName} = { listen = [ { addr = "127.0.0.1"; port = settings.ports.nextcloud; } ]; }; tailscale = { enable = true; useRoutingFeatures = "server"; extraUpFlags = [ "--advertise-exit-node" ]; permitCertUid = "caddy"; port = 0; }; blocky = { enable = true; settings = { caching = { minTime = "5m"; maxTime = "30m"; prefetching = true; }; ports.dns = 53; upstreams.groups.default = [ "1.1.1.1" "1.0.0.1" ]; bootstrapDns = [ "tcp+udp:1.1.1.1" "https://1.1.1.1/dns-query" ]; customDNS = let localDomains = names: ip: builtins.listToAttrs (map (x: { name = x; value = ip; }) names); in { mapping = localDomains [ "catnip.ee" "files.internal" "qbittorrent.internal" "scrutiny.internal" "archive.internal" "epic.internal" "sonarr.internal" "radarr.internal" "prowlarr.internal" "bazarr.internal" "lidarr.internal" "syncthing.internal" ] "100.93.150.89"; }; conditional = let opennic = names: ip: builtins.listToAttrs (map (x: { name = x; value = ip; }) names); in { mapping = opennic [ "epic" "geek" "chan" "fur" "cyb" "oss" "pirate" "neo" "libre" "dyn" "glue" "indy" "bbs" "gopher" "null" "o" "oz" "parody" "bazar" "coin" "lib" "emc" "ku" "uu" "ti" "te" ] "138.197.140.189"; }; blocking = { blackLists = { ads = [ "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" ]; }; clientGroupsBlock.default = [ "ads" ]; }; }; }; lidarr.enable = true; # port 8686, /var/lib/lidarr prowlarr.enable = true; # port 9696, /var/lib/prowlarr radarr.enable = true; # port 7878, /var/lib/radarr sonarr.enable = true; # port 8989, /var/lib/sonarr bazarr.enable = true; # port 6767, /var/lib/bazarr # /var/lib/plex plex = { enable = true; openFirewall = true; }; coturn = rec { enable = true; no-cli = true; no-tcp-relay = true; min-port = 49000; max-port = 50000; use-auth-secret = true; static-auth-secret-file = "/etc/secrets/coturn"; realm = "turn.catnip.ee"; cert = "${config.security.acme.certs.${realm}.directory}/full.pem"; pkey = "${config.security.acme.certs.${realm}.directory}/key.pem"; extraConfig = '' # for debugging verbose # ban private IP ranges no-multicast-peers denied-peer-ip=0.0.0.0-0.255.255.255 denied-peer-ip=10.0.0.0-10.255.255.255 denied-peer-ip=100.64.0.0-100.127.255.255 denied-peer-ip=127.0.0.0-127.255.255.255 denied-peer-ip=169.254.0.0-169.254.255.255 denied-peer-ip=172.16.0.0-172.31.255.255 denied-peer-ip=192.0.0.0-192.0.0.255 denied-peer-ip=192.0.2.0-192.0.2.255 denied-peer-ip=192.88.99.0-192.88.99.255 denied-peer-ip=192.168.0.0-192.168.255.255 denied-peer-ip=198.18.0.0-198.19.255.255 denied-peer-ip=198.51.100.0-198.51.100.255 denied-peer-ip=203.0.113.0-203.0.113.255 denied-peer-ip=240.0.0.0-255.255.255.255 denied-peer-ip=::1 denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255 denied-peer-ip=100::-100::ffff:ffff:ffff:ffff denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff ''; }; # /var/lib/postgresql postgresql = { enable = true; package = pkgs.postgresql_16; enableTCPIP = true; initialScript = pkgs.writeText "backend-initScript" '' CREATE USER "matrix-synapse"; CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" LOCALE 'C' ENCODING 'UTF8' TEMPLATE template0; ''; identMap = '' superuser_map root mastodon superuser_map mastodon mastodon superuser_map root matrix-synapse superuser_map matrix-synapse matrix-synapse superuser_map root forgejo superuser_map forgejo forgejo superuser_map root postgres superuser_map postgres postgres ''; authentication = pkgs.lib.mkOverride 10 '' #type database DBuser auth-method optional_ident_map local sameuser all peer map=superuser_map ''; }; # /var/lib/mautrix-telegram mautrix-telegram = { enable = true; environmentFile = "/etc/secrets/mautrix-telegram.env"; settings = { homeserver = { address = "http://localhost:${toString settings.ports.synapse}"; domain = "catnip.ee"; }; appservice = { address = "http://localhost:${toString settings.ports.mautrix-telegram}"; port = settings.ports.mautrix-telegram; provisioning.enabled = false; id = "telegram"; public = { enabled = true; prefix = "/telegram"; external = "https://matrix.catnip.ee/telegram"; }; }; bridge = { encryption.allow = true; permissions = { "@admin:catnip.ee" = "admin"; "@kaya:catnip.ee" = "admin"; "catnip.ee" = "full"; "*" = "relaybot"; }; animated_sticker = { target = "gif"; args = { width = 256; height = 256; fps = 30; # only for webm background = "020202"; # only for gif, transparency not supported }; }; }; telegram = { device_info = { device_model = "GooglePixel 6"; system_version = "SDK 32"; app_version = "8.7.4 (26367)"; lang_code = "en"; system_lang_code = "en"; }; }; }; }; # /var/lib/matrix-synapse matrix-synapse = { enable = true; extraConfigFiles = [ "/etc/secrets/synapse.yaml" ]; settings = { enable_registration = true; registration_requires_token = true; max_upload_size = "250M"; server_name = "catnip.ee"; public_baseurl = "https://matrix.catnip.ee/"; # Note: email submodule is defined in /etc/secrets/synapse.yaml as matrix doesnt merge the fields and it will fail to run # email = { # smtp_host = "mx1.sly.ee"; # smtp_user = "matrix@catnip.ee"; # smtp_pass = ""; # force_tls = true; # notif_from = "Matrix "; # app_name = "Catnip.ee matrix"; # }; server_notices = { system_mxid_localpart = "server"; system_mxid_display_name = "Server Notices"; system_mxid_avatar_url = "mxc://catnip.ee/LhehrbXOjfnhaJvFEWsXPtnm"; room_name = "Server Notices"; auto_join = true; }; database = { name = "psycopg2"; args = { database = "matrix-synapse"; user = "matrix-synapse"; }; }; app_service_config_files = [ # sudo rm /var/lib/matrix-synapse/telegram-registration.yaml # sudo cp /var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse/ # sudo chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/telegram-registration.yaml # sudo systemctl restart matrix-synapse "/var/lib/matrix-synapse/telegram-registration.yaml" "/var/lib/mautrix-discord/registration.yaml" ]; listeners = [ { bind_addresses = [ "127.0.0.1" ]; port = 8008; resources = [ { compress = true; names = [ "client" "federation" ]; } ]; tls = false; type = "http"; x_forwarded = true; } ]; turn_uris = [ "turn:${config.services.coturn.realm}:3478?transport=udp" "turn:${config.services.coturn.realm}:3478?transport=tcp" ]; turn_user_lifetime = "1h"; }; }; openssh = { enable = true; settings = { PasswordAuthentication = false; PermitRootLogin = "no"; }; }; # /var/lib/ntfy-sh/ ntfy-sh = { enable = true; settings = { listen-http = ":4006"; base-url = "https://ntfy.catnip.ee"; }; }; # /var/lib/jellyfin jellyfin.enable = true; cloudflare-dyndns = { enable = true; apiTokenFile = "/etc/secrets/cloudflare-dyndns.env"; domains = [ "catnip.ee" ]; }; }; users = { defaultUserShell = pkgs.fish; users = { caddy.extraGroups = [ config.services.mastodon.group # since caddy is serving mastodon files it needs access to it config.systemd.services.coturn.serviceConfig.Group # caddy user needs to be part of coturn's group for certs ]; owo = { isNormalUser = true; extraGroups = [ "networkmanager" "wheel" "docker" ]; openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDhXnulnINZ/hBBwHhzl35UsFcFUwxwaaFVFwCgIgOHmlJhknhpq5UQDbV6JoouFMgN48uBDD5/vcYjvS0UYFMBTox0MmJK+Yt4AnNusHkf8j1XCiXxHsicQilxJgu7yZJJRd2TAIqWlautW+VjuXOssN08x0pvtiupefDz6Li7A4SnS1iGsNTgypJaemquEYRge3hC043kaubuSgqNKknK65zA9aLp9h31r9W5K6N+k+ll+TPyyWZdsJMnaqWmoIS1+fpAdG5wMPZbR503dLPFzdprwy8FSoTzkD8aKyEdtzzQboS3b7s2DfFvOy3uoKy5bcMOl6Fm1dos90TFiOjCQmF9+WKG8qteeAtizd04Fmi8JRipODCgkvDFj8YAHaB2w5+xNpCYwJTOdHQZflOo25725aIDXZ2afg3evSdVZgJ0PPiWs6fnJMqbJCrzLsBxfN7vAbWzHHTBIuXrtidwY/x/XTs5n4mm4OukyOQF5YjYXy39WIlzjk3uMR0m8ec= lain@navi" # desktop "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDTbuZLmu2F2EWMl1cXwZqYQwuFDyMyPf+d6MospDs+UaFzKFJdtDlb5+uFkkz9gHf8rCBOnXi6bLGgZNxUhTgEBka0RQVCIqRDjOJAWtwG0zLg/mQ9c1Ug2/9kH/PRjy+GGGzz3GVw7HNZNUjAkNr/kIX4t0L8uBqqkgcM/woBH8S/rV3Xs30XWi9mNkx1J4Z5fqtBBeF2GAd02i2PsUMnGfZSwwJy3mhBhI+Vw5mtsS1QJWd9LrsRfLbtzVHWm4MGr3O0F34ij8BV1uzaHfopn0vKilI/dq8HfjuYjKr33CB5f3C1OdcuFfwqE3ZDxZcaOshqXimt9MrYLXaMv0i7I7a3r33ij2hl9d9oh3Z72yt+wAAdgTJ23Xrwzr4P9Iu4BsayG5bQC6IVLv3Eef5TcPKSXmmtCr2hFLYUMQmlPptrUOf1tmB/7oYo3vJe2cz07PxuxZZ20F3MXugoUTfsnuwAH2chT4xL/TnS4Kbs12QoPFjdG1v/0Z8fVD1ysoU= mina@navi" # laptop ]; packages = with pkgs; [ firefox helix mpv croc ffmpeg speedtest-cli htop progress duperemove tmux ]; }; }; }; system.stateVersion = "23.05"; }