Personal Nix setup
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add options for modules

+1221 -691
-1
machines/cola/configuration.nix
··· 8 8 ./zfs.nix 9 9 ../../modules/router 10 10 ../../modules/server 11 - ../../modules/games 12 11 ]; 13 12 14 13 users.users."${user}" = {
+1
modules/base/default.nix
··· 5 5 ./nix-config.nix 6 6 ./shell.nix 7 7 ./linux.nix 8 + ./gpg.nix 8 9 ]; 9 10 }
+23
modules/base/gpg.nix
··· 1 + { lib, config, pkgs, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.gpg; 6 + in { 7 + options.modules.gpg = { 8 + enable = mkEnableOption "GnuPG"; 9 + }; 10 + 11 + config = mkIf cfg.enable { 12 + environment.systemPackages = [ 13 + pkgs.gnupg 14 + ]; 15 + 16 + programs.gnupg = { 17 + agent = { 18 + enable = true; 19 + enableSSHSupport = true; 20 + }; 21 + }; 22 + }; 23 + }
+6 -6
modules/base/linux.nix
··· 1 - { lib, config, pkgs, helpers, ... } @ inputs: 1 + { lib, pkgs, helpers, ... } @ inputs: 2 2 3 + with lib; 3 4 let 4 5 inherit (import ../../lib/colors.nix inputs) hex; 5 - inherit (lib) mkDefault mkForce; 6 6 in helpers.linuxAttrs { 7 7 environment.systemPackages = [ pkgs.sbctl ]; 8 8 ··· 31 31 }; 32 32 33 33 boot = { 34 - bootspec.enable = lib.mkDefault true; 35 - consoleLogLevel = lib.mkDefault 2; 34 + bootspec.enable = mkDefault true; 35 + consoleLogLevel = mkDefault 2; 36 36 37 37 loader = { 38 38 timeout = mkDefault 2; ··· 44 44 systemd.enable = true; 45 45 }; 46 46 47 - kernelPackages = lib.mkDefault pkgs.linuxPackages_latest; 47 + kernelPackages = mkDefault pkgs.linuxPackages_latest; 48 48 49 49 kernelParams = [ 50 50 "quiet" ··· 90 90 91 91 services.dbus.enable = true; 92 92 93 - virtualisation.oci-containers.backend = mkForce "podman"; 93 + virtualisation.oci-containers.backend = mkDefault "podman"; 94 94 }
+4 -3
modules/default.nix
··· 1 - { ... }: 2 - 3 1 { 4 2 imports = [ 5 3 ./base 4 + ./desktop 6 5 ./development 7 - ./gpg.nix 6 + ./fonts 8 7 ./nvim 8 + ./router 9 + ./server 9 10 ]; 10 11 }
+39 -19
modules/desktop/default.nix
··· 1 - { lib, user, helpers, ... }: 1 + { lib, config, user, helpers, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.desktop; 6 + in { 7 + options.modules.desktop = { 8 + enable = mkOption { 9 + default = false; 10 + example = true; 11 + description = "Whether to enable Desktop options."; 12 + type = types.bool; 13 + }; 14 + }; 2 15 3 - helpers.linuxAttrs { 16 + config.modules.server = { 17 + enable = if helpers.isLinux then (mkDefault false) else (mkForce false); 18 + }; 19 + } // helpers.linuxAttrs { 4 20 imports = [ 5 21 ./services.nix 6 22 ./session.nix 7 23 ./xdg.nix 8 - ./fonts 24 + ./fonts.nix 9 25 ]; 10 26 11 - users.users."${user}".extraGroups = [ "video" ]; 27 + config = mkIf cfg.enable { 28 + users.users."${user}".extraGroups = [ "video" ]; 12 29 13 - services = { 14 - fwupd.enable = true; 15 - pipewire = { 16 - enable = true; 17 - wireplumber.enable = true; 18 - alsa.enable = true; 19 - alsa.support32Bit = true; 20 - pulse.enable = true; 21 - jack.enable = true; 30 + services = { 31 + fwupd.enable = true; 32 + pipewire = { 33 + enable = true; 34 + wireplumber.enable = true; 35 + pulse.enable = true; 36 + jack.enable = true; 37 + alsa = { 38 + enable = true; 39 + support32Bit = true; 40 + }; 41 + }; 42 + }; 43 + 44 + hardware = { 45 + pulseaudio.enable = lib.mkForce false; 46 + steam-hardware.enable = true; 22 47 }; 23 - }; 24 48 25 - hardware = { 26 - pulseaudio.enable = lib.mkForce false; 27 - steam-hardware.enable = true; 49 + security.rtkit.enable = true; 28 50 }; 29 - 30 - security.rtkit.enable = true; 31 51 }
+36
modules/desktop/fonts.nix
··· 1 + { lib, config, pkgs, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.desktop; 6 + in { 7 + options.modules.desktop.fonts = { 8 + enable = mkOption { 9 + default = cfg.enable; 10 + example = true; 11 + description = "Whether to enable default fonts."; 12 + type = types.bool; 13 + }; 14 + }; 15 + 16 + config = mkIf cfg.fonts.enable { 17 + fonts = { 18 + fontDir.enable = true; 19 + 20 + packages = with pkgs; [ 21 + noto-fonts 22 + noto-fonts-cjk 23 + noto-fonts-emoji 24 + roboto-mono 25 + inter 26 + ]; 27 + 28 + fontconfig.defaultFonts = { 29 + serif = [ "Noto Serif" "Noto Color Emoji" ]; 30 + sansSerif = [ "Inter" "Noto Color Emoji" ]; 31 + monospace = [ "Dank Mono" "Roboto Mono" "Noto Color Emoji" ]; 32 + emoji = [ "Noto Color Emoji" ]; 33 + }; 34 + }; 35 + }; 36 + }
-67
modules/desktop/fonts/default.nix
··· 1 - { config, pkgs, lib, helpers, ... } @ inputs: 2 - 3 - let 4 - inherit (pkgs) stdenv; 5 - 6 - fontsDir = if helpers.isDarwin then 7 - "/Library/Fonts" else "/usr/share/fonts/nonfree"; 8 - 9 - in lib.mkMerge [ 10 - { 11 - age.secrets."DankMono-Regular.otf" = { 12 - symlink = false; 13 - file = ./encrypt/DankMono-Regular.otf.age; 14 - path = "${fontsDir}/DankMono-Regular.otf"; 15 - mode = "755"; 16 - }; 17 - 18 - age.secrets."DankMono-Italic.otf" = { 19 - symlink = false; 20 - file = ./encrypt/DankMono-Italic.otf.age; 21 - path = "${fontsDir}/DankMono-Italic.otf"; 22 - mode = "755"; 23 - }; 24 - 25 - age.secrets."DankMono-Bold.otf" = { 26 - symlink = false; 27 - file = ./encrypt/DankMono-Bold.otf.age; 28 - path = "${fontsDir}/DankMono-Bold.otf"; 29 - mode = "755"; 30 - }; 31 - 32 - age.secrets."codicon.otf" = { 33 - symlink = false; 34 - file = ./encrypt/codicon.otf.age; 35 - path = "${fontsDir}/codicon.otf"; 36 - mode = "755"; 37 - }; 38 - 39 - age.secrets."faicon.ttf" = { 40 - symlink = false; 41 - file = ./encrypt/faicon.ttf.age; 42 - path = "${fontsDir}/faicon.ttf"; 43 - mode = "755"; 44 - }; 45 - } 46 - 47 - (helpers.linuxAttrs { 48 - fonts = { 49 - fontDir.enable = true; 50 - 51 - packages = with pkgs; [ 52 - noto-fonts 53 - noto-fonts-cjk 54 - noto-fonts-emoji 55 - roboto-mono 56 - inter 57 - ]; 58 - 59 - fontconfig.defaultFonts = { 60 - serif = [ "Noto Serif" "Noto Color Emoji" ]; 61 - sansSerif = [ "Inter" "Noto Color Emoji" ]; 62 - monospace = [ "Dank Mono" "Roboto Mono" "Noto Color Emoji" ]; 63 - emoji = [ "Noto Color Emoji" ]; 64 - }; 65 - }; 66 - }) 67 - ]
modules/desktop/fonts/encrypt/DankMono-Bold.otf.age modules/fonts/encrypt/DankMono-Bold.otf.age
modules/desktop/fonts/encrypt/DankMono-Italic.otf.age modules/fonts/encrypt/DankMono-Italic.otf.age
modules/desktop/fonts/encrypt/DankMono-Regular.otf.age modules/fonts/encrypt/DankMono-Regular.otf.age
modules/desktop/fonts/encrypt/codicon.otf.age modules/fonts/encrypt/codicon.otf.age
modules/desktop/fonts/encrypt/faicon.ttf.age modules/fonts/encrypt/faicon.ttf.age
+21 -7
modules/desktop/services.nix
··· 1 - { user, ... }: 1 + { lib, config, user, ... }: 2 2 3 - { 4 - users.users."${user}".extraGroups = [ "video" ]; 3 + with lib; 4 + let 5 + cfg = config.modules.desktop; 6 + in { 7 + options.modules.desktop.services = { 8 + enable = mkOption { 9 + default = cfg.enable; 10 + example = true; 11 + description = "Whether to enable services."; 12 + type = types.bool; 13 + }; 14 + }; 5 15 6 - services = { 7 - printing.enable = true; 8 - flatpak.enable = true; 9 - colord.enable = true; 16 + config = mkIf cfg.services.enable { 17 + users.users."${user}".extraGroups = [ "video" ]; 18 + 19 + services = { 20 + printing.enable = true; 21 + flatpak.enable = true; 22 + colord.enable = true; 23 + }; 10 24 }; 11 25 }
+46 -31
modules/desktop/session.nix
··· 1 - { pkgs, lib, user, ... }: 1 + { lib, config, pkgs, user, ... }: 2 2 3 - { 4 - boot.plymouth.enable = true; 3 + with lib; 4 + let 5 + cfg = config.modules.desktop; 6 + in { 7 + options.modules.desktop.session = { 8 + enable = mkOption { 9 + default = cfg.enable; 10 + example = true; 11 + description = "Whether to enable session and desktop environment."; 12 + type = types.bool; 13 + }; 14 + }; 5 15 6 - services.desktopManager.plasma6.enable = true; 16 + config = mkIf cfg.session.enable { 17 + boot.plymouth.enable = true; 7 18 8 - services.displayManager = { 9 - defaultSession = "plasma"; 10 - autoLogin = { 11 - inherit user; 12 - enable = true; 19 + services = { 20 + desktopManager.plasma6.enable = true; 21 + displayManager = { 22 + defaultSession = "plasma"; 23 + autoLogin = { 24 + inherit user; 25 + enable = true; 26 + }; 27 + sddm = { 28 + enable = true; 29 + enableHidpi = true; 30 + wayland.enable = true; 31 + }; 32 + }; 13 33 }; 14 - sddm = { 15 - enable = true; 16 - enableHidpi = true; 17 - wayland.enable = true; 34 + 35 + environment.plasma6 = { 36 + excludePackages = with pkgs.kdePackages; [ 37 + elisa 38 + gwenview 39 + oxygen 40 + oxygen-sounds 41 + khelpcenter 42 + konsole 43 + ]; 18 44 }; 19 - }; 20 45 21 - environment.plasma6 = { 22 - excludePackages = with pkgs.kdePackages; [ 23 - elisa 24 - gwenview 25 - oxygen 26 - oxygen-sounds 27 - khelpcenter 28 - konsole 29 - ]; 30 - }; 46 + security = { 47 + polkit.enable = true; 48 + }; 31 49 32 - security = { 33 - polkit.enable = true; 34 - }; 35 - 36 - xdg.portal = { 37 - enable = true; 38 - xdgOpenUsePortal = false; 50 + xdg.portal = { 51 + enable = true; 52 + xdgOpenUsePortal = false; 53 + }; 39 54 }; 40 55 }
+34 -20
modules/desktop/xdg.nix
··· 1 - { lib, user, ... }: 1 + { lib, config, user, ... }: 2 2 3 - { 4 - home-manager.users.${user} = { ... }: { 5 - systemd.user.sessionVariables = { 6 - "NIXOS_OZONE_WL" = lib.mkDefault "1"; 7 - "MOZ_ENABLE_WAYLAND" = lib.mkDefault "1"; 8 - "QT_WAYLAND_DISABLE_WINDOWDECORATIONS" = lib.mkDefault "1"; 9 - "QT_WAYLAND_FORCE_DPI" = lib.mkDefault "physical"; 10 - "QT_QPA_PLATFORM" = lib.mkDefault "wayland-egl"; 3 + with lib; 4 + let 5 + cfg = config.modules.desktop; 6 + in { 7 + options.modules.desktop.xdg = { 8 + enable = mkOption { 9 + default = cfg.enable; 10 + example = true; 11 + description = "Whether to enable services."; 12 + type = types.bool; 11 13 }; 14 + }; 12 15 13 - xdg = { 14 - mimeApps = { 15 - enable = true; 16 + config = mkIf cfg.xdg.enable { 17 + home-manager.users.${user} = { ... }: { 18 + systemd.user.sessionVariables = { 19 + "NIXOS_OZONE_WL" = lib.mkDefault "1"; 20 + "MOZ_ENABLE_WAYLAND" = lib.mkDefault "1"; 21 + "QT_WAYLAND_DISABLE_WINDOWDECORATIONS" = lib.mkDefault "1"; 22 + "QT_WAYLAND_FORCE_DPI" = lib.mkDefault "physical"; 23 + "QT_QPA_PLATFORM" = lib.mkDefault "wayland-egl"; 16 24 }; 17 - userDirs = { 18 - enable = true; 19 - createDirectories = true; 25 + 26 + xdg = { 27 + mimeApps = { 28 + enable = true; 29 + }; 30 + userDirs = { 31 + enable = true; 32 + createDirectories = true; 33 + }; 34 + systemDirs.data = [ 35 + "/usr/share" 36 + "/var/lib/flatpak/exports/share" 37 + "$HOME/.local/share/flatpak/exports/share" 38 + ]; 20 39 }; 21 - systemDirs.data = [ 22 - "/usr/share" 23 - "/var/lib/flatpak/exports/share" 24 - "$HOME/.local/share/flatpak/exports/share" 25 - ]; 26 40 }; 27 41 }; 28 42 }
+23 -5
modules/development/cocoapods.nix
··· 1 - { pkgs, helpers, ... }: 1 + { lib, config, pkgs, helpers, ... }: 2 2 3 - helpers.darwinAttrs { 4 - environment.systemPackages = [ 5 - pkgs.cocoapods 6 - ]; 3 + with lib; 4 + let 5 + cfg = config.modules.development; 6 + in { 7 + options.modules.development.cocoapods = { 8 + enable = mkOption { 9 + default = cfg.enable; 10 + example = true; 11 + description = "Whether to enable Cocoapods."; 12 + type = types.bool; 13 + }; 14 + }; 15 + 16 + config.modules.development.cocoapods = { 17 + enable = if helpers.isDarwin then (mkDefault true) else (mkForce false); 18 + }; 19 + } // helpers.darwinAttrs { 20 + config = mkIf cfg.cocoapods.enable { 21 + environment.systemPackages = [ 22 + pkgs.cocoapods 23 + ]; 24 + }; 7 25 }
+12 -1
modules/development/default.nix
··· 1 - { 1 + { lib, ... }: 2 + 3 + with lib; { 4 + options.modules.development = { 5 + enable = mkOption { 6 + default = false; 7 + example = true; 8 + description = "Whether to enable Development options."; 9 + type = types.bool; 10 + }; 11 + }; 12 + 2 13 imports = [ 3 14 ./js.nix 4 15 ./cocoapods.nix
+28 -14
modules/development/js.nix
··· 1 - { pkgs, ... }: 1 + { lib, config, pkgs, ... }: 2 2 3 - { 4 - environment.variables = { 5 - PNPM_HOME = "$HOME/.local/share/pnpm"; 6 - BUN_RUNTIME_TRANSPILER_CACHE_PATH = "$HOME/.cache/bun/install/cache/@t@"; 7 - COREPACK_ENABLE_AUTO_PIN = "0"; 3 + with lib; 4 + let 5 + cfg = config.modules.development; 6 + in { 7 + options.modules.development.js = { 8 + enable = mkOption { 9 + default = cfg.enable; 10 + example = true; 11 + description = "Whether to enable JS tools."; 12 + type = types.bool; 13 + }; 8 14 }; 9 15 10 - environment.systemPackages = (with pkgs; [ 11 - bun 12 - corepack_22 13 - nodejs_22 14 - ]); 16 + config = mkIf cfg.js.enable { 17 + environment.variables = { 18 + PNPM_HOME = "$HOME/.local/share/pnpm"; 19 + BUN_RUNTIME_TRANSPILER_CACHE_PATH = "$HOME/.cache/bun/install/cache/@t@"; 20 + COREPACK_ENABLE_AUTO_PIN = "0"; 21 + }; 22 + 23 + environment.systemPackages = (with pkgs; [ 24 + bun 25 + corepack_22 26 + nodejs_22 27 + ]); 15 28 16 - environment.interactiveShellInit = '' 17 - export PATH=./node_modules/.bin:$HOME/.local/share/pnpm:$PATH 18 - ''; 29 + environment.interactiveShellInit = '' 30 + export PATH=./node_modules/.bin:$HOME/.local/share/pnpm:$PATH 31 + ''; 32 + }; 19 33 }
+53
modules/fonts/default.nix
··· 1 + { config, lib, helpers, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.fonts; 6 + fontsPath = if helpers.isDarwin then "/Library/Fonts" else "/usr/share/fonts/nonfree"; 7 + in { 8 + options.modules.fonts = { 9 + enable = mkOption { 10 + default = false; 11 + example = true; 12 + description = "Whether to enable fonts options."; 13 + type = types.bool; 14 + }; 15 + }; 16 + 17 + config = mkIf cfg.enable { 18 + age.secrets."DankMono-Regular.otf" = { 19 + symlink = false; 20 + file = ./encrypt/DankMono-Regular.otf.age; 21 + path = "${fontsPath}/DankMono-Regular.otf"; 22 + mode = "755"; 23 + }; 24 + 25 + age.secrets."DankMono-Italic.otf" = { 26 + symlink = false; 27 + file = ./encrypt/DankMono-Italic.otf.age; 28 + path = "${fontsPath}/DankMono-Italic.otf"; 29 + mode = "755"; 30 + }; 31 + 32 + age.secrets."DankMono-Bold.otf" = { 33 + symlink = false; 34 + file = ./encrypt/DankMono-Bold.otf.age; 35 + path = "${fontsPath}/DankMono-Bold.otf"; 36 + mode = "755"; 37 + }; 38 + 39 + age.secrets."codicon.otf" = { 40 + symlink = false; 41 + file = ./encrypt/codicon.otf.age; 42 + path = "${fontsPath}/codicon.otf"; 43 + mode = "755"; 44 + }; 45 + 46 + age.secrets."faicon.ttf" = { 47 + symlink = false; 48 + file = ./encrypt/faicon.ttf.age; 49 + path = "${fontsPath}/faicon.ttf"; 50 + mode = "755"; 51 + }; 52 + }; 53 + }
-7
modules/games/default.nix
··· 1 - { helpers, ... }: 2 - 3 - helpers.linuxAttrs { 4 - imports = [ 5 - ./enshrouded-server.nix 6 - ]; 7 - }
-51
modules/games/enshrouded-server.nix
··· 1 - { lib, config, pkgs, ... }: 2 - 3 - { 4 - ids.gids.steam = lib.mkDefault 10000; 5 - ids.uids.steam = lib.mkDefault 10000; 6 - 7 - users = { 8 - groups.steam.gid = config.ids.gids.steam; 9 - users.steam = { 10 - uid = config.ids.uids.steam; 11 - group = "steam"; 12 - createHome = true; 13 - home = "/var/lib/steam"; 14 - isSystemUser = true; 15 - }; 16 - }; 17 - 18 - virtualisation.oci-containers = { 19 - containers.enshrouded = rec { 20 - autoStart = false; 21 - volumes = [ 22 - "/var/lib/steam/enshrouded:/home/steam/enshrouded/savegame" 23 - "/etc/localtime:/etc/localtime:ro" 24 - ]; 25 - environment = { 26 - TZ = "Europe/London"; 27 - SERVER_IP = "0.0.0.0"; 28 - SERVER_NAME = "London Boroughs"; 29 - SERVER_PASSWORD = "deepdickgalactic"; 30 - GAME_PORT = "15636"; 31 - QUERY_PORT = "15637"; 32 - SERVER_SLOTS = "8"; 33 - }; 34 - image = "docker.io/sknnr/enshrouded-dedicated-server:proton-latest"; 35 - ports = [ 36 - "15636:15636/udp" 37 - "15637:15637/udp" 38 - ]; 39 - extraOptions = [ 40 - "--userns=keep-id" 41 - "--cap-add=NET_RAW" 42 - "--runtime=runc" 43 - ]; 44 - }; 45 - }; 46 - 47 - networking.firewall.allowedUDPPorts = [ 48 - 15636 49 - 15637 50 - ]; 51 - }
-14
modules/gpg.nix
··· 1 - { pkgs, ... }: 2 - 3 - { 4 - environment.systemPackages = [ 5 - pkgs.gnupg 6 - ]; 7 - 8 - programs.gnupg = { 9 - agent = { 10 - enable = true; 11 - enableSSHSupport = true; 12 - }; 13 - }; 14 - }
+19 -10
modules/nvim/default.nix
··· 1 - { pkgs, ... } @ inputs: 1 + { lib, config, pkgs, ... } @ inputs: 2 2 3 + with lib; 3 4 let 4 5 inherit (import ../../lib/colors.nix inputs) colors mkVimHardlineColors; 5 6 inherit (import ./theme.nix inputs) my-theme; 6 7 7 - importContents = /*lua*/ '' 8 - ''; 8 + cfg = config.modules.nvim; 9 9 10 10 initContents = " 11 11 \nlua <<EOF\n" + /* lua */ '' ··· 71 71 neovimPkg = pkgs.neovim-unwrapped; 72 72 neovim = pkgs.wrapNeovimUnstable neovimPkg neovimConfig; 73 73 in { 74 - environment.variables = { EDITOR = "vim"; }; 74 + options.modules.nvim = { 75 + enable = mkEnableOption "Neovim"; 76 + useCustomConfig = mkEnableOption "Custom Configuration"; 77 + }; 75 78 76 - environment.systemPackages = with pkgs; [ 77 - ripgrep 78 - fd 79 - bat 80 - neovim 81 - ]; 79 + config = mkIf cfg.enable { 80 + environment.variables = { EDITOR = "vim"; }; 81 + 82 + environment.systemPackages = with pkgs; if cfg.useCustomConfig then [ 83 + ripgrep 84 + fd 85 + bat 86 + neovim 87 + ] else [ 88 + neovimPkg 89 + ]; 90 + }; 82 91 }
-9
modules/router/avahi.nix
··· 1 - { ... }: 2 - 3 - { 4 - services.avahi = { 5 - enable = true; 6 - allowInterfaces = [ "intern0" ]; 7 - denyInterfaces = [ "extern0" ]; 8 - }; 9 - }
+40 -6
modules/router/default.nix
··· 1 - { helpers, ... }: 1 + { lib, config, helpers, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.router; 6 + in { 7 + options.modules.router = { 8 + enable = mkOption { 9 + default = false; 10 + example = true; 11 + description = "Whether to enable Router options."; 12 + type = types.bool; 13 + }; 2 14 3 - helpers.linuxAttrs { 15 + interfaces = { 16 + external = mkOption { 17 + default = "extern0"; 18 + type = types.str; 19 + }; 20 + internal = mkOption { 21 + default = "intern0"; 22 + type = types.str; 23 + }; 24 + }; 25 + }; 26 + 27 + config.modules.router = { 28 + enable = if helpers.isLinux then (mkDefault false) else (mkForce false); 29 + }; 30 + } // helpers.linuxAttrs { 4 31 imports = [ 5 - ./ntp.nix 6 - ./stubby.nix 32 + ./timeserver.nix 33 + ./dnsOverTLS.nix 7 34 ./dnsmasq.nix 8 35 ./nftables.nix 9 - ./miniupnpd.nix 10 - ./avahi.nix 36 + ./upnp.nix 37 + ./mdns.nix 38 + ./kernel.nix 11 39 ]; 40 + 41 + config = mkIf cfg.enable { 42 + networking.firewall.trustedInterfaces = [ 43 + cfg.interfaces.internal 44 + ]; 45 + }; 12 46 }
+47
modules/router/dnsOverTLS.nix
··· 1 + { lib, config, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.router; 6 + in { 7 + options.modules.router = { 8 + dnsOverTLS = { 9 + enable = mkOption { 10 + default = cfg.enable; 11 + description = "Whether to enable Stubby DNS proxy"; 12 + type = types.bool; 13 + }; 14 + 15 + port = mkOption { 16 + default = 53000; 17 + description = "Port for Stubby"; 18 + type = types.int; 19 + }; 20 + }; 21 + }; 22 + 23 + config = mkIf cfg.dnsOverTLS.enable { 24 + services.stubby = { 25 + enable = true; 26 + settings = { 27 + resolution_type = "GETDNS_RESOLUTION_STUB"; 28 + dns_transport_list = [ "GETDNS_TRANSPORT_TLS" ]; 29 + tls_authentication = "GETDNS_AUTHENTICATION_REQUIRED"; 30 + tls_query_padding_blocksize = 128; 31 + edns_client_subnet_private = 1; 32 + round_robin_upstreams = 1; 33 + tls_connection_retries = 5; 34 + listen_addresses = [ 35 + "127.0.0.1@${cfg.dnsOverTLS.port}" 36 + "0::1@${cfg.dnsOverTLS.port}" 37 + ]; 38 + appdata_dir = "/var/cache/stubby"; 39 + trust_anchors_backoff_time = 2500; 40 + upstream_recursive_servers = [ 41 + { address_data = "1.1.1.1"; tls_auth_name = "cloudflare-dns.com"; } 42 + { address_data = "1.0.0.1"; tls_auth_name = "cloudflare-dns.com"; } 43 + ]; 44 + }; 45 + }; 46 + }; 47 + }
+104 -65
modules/router/dnsmasq.nix
··· 1 - { config, lib, ... }: 1 + { lib, config, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.router; 6 + 7 + leaseType = types.submodule { 8 + options = { 9 + macAddress = mkOption { 10 + type = types.str; 11 + example = "00:00:00:00:00:00"; 12 + }; 13 + ipAddress = mkOption { 14 + type = types.str; 15 + example = "10.0.0.10"; 16 + }; 17 + }; 18 + }; 19 + 20 + dnsServer = if cfg.dnsOverTLS.enable 21 + then [ "127.0.0.1#${cfg.dnsOverTLS.port}" ] 22 + else [ "1.1.1.1" "1.0.0.1" ]; 23 + 24 + dhcpHost = builtins.map (lease: "${lease.macAddress},${lease.ipAddress}") cfg.dnsmasq.leases; 25 + in { 26 + options.modules.router = { 27 + dnsmasq = { 28 + enable = mkOption { 29 + default = cfg.enable; 30 + description = "Whether to enable DNSMasq"; 31 + type = types.bool; 32 + }; 33 + 34 + leases = lib.mkOption { 35 + default = []; 36 + type = lib.types.listOf leaseType; 37 + description = "List of reserved IP address leases"; 38 + }; 39 + }; 40 + }; 41 + 42 + config = mkIf cfg.dnsmasq.enable { 43 + networking.nameservers = [ "127.0.0.1" ]; 2 44 3 - { 4 - services.resolved.extraConfig = lib.mkDefault '' 5 - [Resolve] 6 - DNSStubListener=no 7 - ''; 45 + services.resolved.extraConfig = mkDefault '' 46 + [Resolve] 47 + DNSStubListener=no 48 + ''; 8 49 9 - services.dnsmasq = { 10 - enable = true; 11 - alwaysKeepRunning = true; 12 - settings = { 13 - server = if config.services.stubby.enable then [ "127.0.0.1#53000" ] else [ "1.1.1.1" "1.0.0.1" ]; 50 + services.dnsmasq = { 51 + enable = true; 52 + alwaysKeepRunning = true; 53 + settings = { 54 + server = dnsServer; 14 55 15 - # never forward plain names (without a dot or domain part) 16 - domain-needed = true; 17 - # never forward addresses in the non-routed address spaces. 18 - bogus-priv = true; 19 - # filter useless windows-originated DNS requests 20 - filterwin2k = true; 21 - # never read nameservers from /etc/resolv.conf 22 - no-resolv = true; 56 + # never forward plain names (without a dot or domain part) 57 + domain-needed = true; 58 + # never forward addresses in the non-routed address spaces. 59 + bogus-priv = true; 60 + # filter useless windows-originated DNS requests 61 + filterwin2k = true; 62 + # never read nameservers from /etc/resolv.conf 63 + no-resolv = true; 64 + 65 + cache-size = 5000; 66 + no-negcache = true; 67 + 68 + expand-hosts = true; 69 + addn-hosts = "/etc/hosts"; 23 70 24 - cache-size = 5000; 25 - no-negcache = true; 71 + dhcp-range = [ 72 + "10.0.0.2, 10.0.0.255, 255.255.255.0, 12h" 73 + "tag:${cfg.interfaces.internal}, ::1, constructor:${cfg.interfaces.internal}, ra-names, slaac, 12h" 74 + ]; 26 75 27 - expand-hosts = true; 28 - addn-hosts = "/etc/hosts"; 76 + dhcp-option = [ 77 + "option6:information-refresh-time, 6h" 78 + "option:router,10.0.0.1" 79 + "ra-param=${cfg.interfaces.internal},high,0,0" 80 + ]; 29 81 30 - dhcp-range = [ 31 - "10.0.0.2, 10.0.0.255, 255.255.255.0, 12h" 32 - "tag:intern0, ::1, constructor:intern0, ra-names, slaac, 12h" 33 - ]; 34 - dhcp-option = [ 35 - "option6:information-refresh-time, 6h" 36 - "option:router,10.0.0.1" 37 - "option:ntp-server,10.0.0.1" 38 - "ra-param=intern0,high,0,0" 39 - ]; 82 + dhcp-option = mkIf cfg.timeserver.enable [ 83 + "option:ntp-server,10.0.0.1" 84 + ]; 40 85 41 - dhcp-host = [ 42 - "98:ed:7e:c6:57:b2,10.0.0.102" # eero router 43 - "c4:f1:74:51:4c:f2,10.0.0.124" # eero router 44 - "5c:61:99:7a:16:40,10.0.0.103" # brother printer 45 - "24:e8:53:95:e4:02,10.0.0.96" # tv 46 - "34:7e:5c:31:4f:fa,10.0.0.56" # sonos 47 - "e8:9c:25:6c:40:6f,10.0.0.150" # pepper-pc 48 - ]; 86 + dhcp-host = dhcpHost; 49 87 50 - # listen only on intern0 by excluding extern0 51 - except-interface = "extern0"; 88 + # listen only on intern0 by excluding extern0 89 + except-interface = cfg.interfaces.external; 52 90 53 - # set the DHCP server to authoritative and rapic commit mode 54 - dhcp-authoritative = true; 55 - dhcp-rapid-commit = true; 91 + # set the DHCP server to authoritative and rapic commit mode 92 + dhcp-authoritative = true; 93 + dhcp-rapid-commit = true; 56 94 57 - # Detect attempts by Verisign to send queries to unregistered hosts 58 - bogus-nxdomain = "64.94.110.11"; 95 + # Detect attempts by Verisign to send queries to unregistered hosts 96 + bogus-nxdomain = "64.94.110.11"; 59 97 60 - address = [ 61 - "/cola.fable-pancake.ts.net/10.0.0.1" 62 - "/time.apple.com/10.0.0.1" 63 - "/time1.apple.com/10.0.0.1" 64 - "/time2.apple.com/10.0.0.1" 65 - "/time3.apple.com/10.0.0.1" 66 - "/time4.apple.com/10.0.0.1" 67 - "/time5.apple.com/10.0.0.1" 68 - "/time6.apple.com/10.0.0.1" 69 - "/time7.apple.com/10.0.0.1" 70 - "/time.euro.apple.com/10.0.0.1" 71 - "/time.windows.com/10.0.0.1" 72 - "/0.android.pool.ntp.org/10.0.0.1" 73 - "/1.android.pool.ntp.org/10.0.0.1" 74 - "/2.android.pool.ntp.org/10.0.0.1" 75 - "/3.android.pool.ntp.org/10.0.0.1" 76 - ]; 98 + address = [ 99 + "/cola.fable-pancake.ts.net/10.0.0.1" 100 + "/time.apple.com/10.0.0.1" 101 + "/time1.apple.com/10.0.0.1" 102 + "/time2.apple.com/10.0.0.1" 103 + "/time3.apple.com/10.0.0.1" 104 + "/time4.apple.com/10.0.0.1" 105 + "/time5.apple.com/10.0.0.1" 106 + "/time6.apple.com/10.0.0.1" 107 + "/time7.apple.com/10.0.0.1" 108 + "/time.euro.apple.com/10.0.0.1" 109 + "/time.windows.com/10.0.0.1" 110 + "/0.android.pool.ntp.org/10.0.0.1" 111 + "/1.android.pool.ntp.org/10.0.0.1" 112 + "/2.android.pool.ntp.org/10.0.0.1" 113 + "/3.android.pool.ntp.org/10.0.0.1" 114 + ]; 115 + }; 77 116 }; 78 117 }; 79 118 }
+65
modules/router/kernel.nix
··· 1 + { lib, config, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.router; 6 + in { 7 + options.modules.router = { 8 + tweakKernel = mkOption { 9 + default = cfg.enable; 10 + description = "Whether to tweak kernel configuration"; 11 + type = types.bool; 12 + }; 13 + }; 14 + 15 + config = mkIf cfg.enable { 16 + boot.initrd.systemd = { 17 + enable = true; 18 + network.enable = true; 19 + }; 20 + } // mkIf cfg.tweakKernel.enable { 21 + boot.kernel.sysctl = { 22 + "net.core.somaxconn" = 4096; 23 + "net.core.netdev_max_backlog" = 2000; 24 + 25 + "net.core.rmem_default" = 1048576; 26 + "net.core.rmem_max" = 26214400; 27 + "net.core.wmem_default" = 1048576; 28 + "net.core.wmem_max" = 16777216; 29 + "net.core.optmem_max" = 65536; 30 + 31 + "net.ipv4.tcp_rmem" = "4096 1048576 2097152"; 32 + "net.ipv4.tcp_wmem" = "4096 65536 16777216"; 33 + 34 + "net.ipv4.tcp_max_syn_backlog" = 8192; 35 + 36 + "net.ipv4.udp_rmem_min" = 8192; 37 + "net.ipv4.udp_wmem_min" = 8192; 38 + 39 + "net.ipv4.tcp_fastopen" = 3; 40 + 41 + "net.ipv4.tcp_max_tw_buckets" = 2000000; 42 + "net.ipv4.tcp_tw_reuse" = true; 43 + "net.ipv4.tcp_slow_start_after_idle" = false; 44 + "net.ipv4.tcp_mtu_probing" = true; 45 + 46 + "net.ipv4.tcp_rfc1337" = true; 47 + "net.ipv4.tcp_fin_timeout" = 10; 48 + 49 + "net.ipv4.tcp_keepalive_time" = 60; 50 + "net.ipv4.tcp_keepalive_intvl" = 10; 51 + "net.ipv4.tcp_keepalive_probes" = 6; 52 + 53 + "net.core.default_qdisc" = "cake"; 54 + "net.ipv4.tcp_congestion_control" = "bbr"; 55 + "net.ipv4.tcp_syncookies" = true; 56 + 57 + "net.ipv6.conf.all.forwarding" = true; 58 + "net.ipv6.conf.all.use_tempaddr" = false; 59 + "net.ipv6.conf.all.autoconf" = false; 60 + "net.ipv6.conf.all.accept_ra" = false; 61 + 62 + "net.ipv4.ping_group_range" = "0 65536"; 63 + }; 64 + }; 65 + }
+22
modules/router/mdns.nix
··· 1 + { lib, config, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.router; 6 + in { 7 + options.modules.router = { 8 + mdns.enable = mkOption { 9 + default = cfg.enable; 10 + description = "Whether to enable mDNS Discovery Service"; 11 + type = types.bool; 12 + }; 13 + }; 14 + 15 + config = mkIf cfg.mdns.enable { 16 + services.avahi = { 17 + enable = true; 18 + allowInterfaces = [ cfg.interfaces.internal ]; 19 + denyInterfaces = [ cfg.interfaces.external ]; 20 + }; 21 + }; 22 + }
-20
modules/router/miniupnpd.nix
··· 1 - { ... }: 2 - 3 - { 4 - services.miniupnpd = { 5 - enable = true; 6 - upnp = true; 7 - natpmp = true; 8 - internalIPs = [ "intern0" ]; 9 - externalInterface = "extern0"; 10 - appendConfig = '' 11 - ext_ip=137.220.98.13 12 - secure_mode=yes 13 - notify_interval=60 14 - clean_ruleset_interval=600 15 - uuid=78b8b903-83c1-4036-8fcd-f64aee25baca 16 - allow 1024-65535 10.0.0.0/24 1024-65535 17 - deny 0-65535 0.0.0.0/0 0-65535 18 - ''; 19 - }; 20 - }
+141 -103
modules/router/nftables.nix
··· 1 1 { config, lib, ... }: 2 2 3 + with lib; 3 4 let 5 + cfg = config.modules.router; 6 + 4 7 trustedInterfaces = 5 - lib.strings.concatMapStringsSep ", " lib.strings.escapeNixIdentifier config.networking.firewall.trustedInterfaces; 8 + strings.concatMapStringsSep ", " strings.escapeNixIdentifier config.networking.firewall.trustedInterfaces; 9 + 10 + capturePortsRules = 11 + string.concatMapStringsSep "\n" 12 + (builtins.map (port: " iifname { ${trustedInterfaces} } udp dport ${port} redirect to ${port}") cfg.nftables.capturePorts); 13 + 14 + blockForwardRules = 15 + string.concatMapStringsSep "\n" 16 + (builtins.map (mac: " iifname ${cfg.interfaces.internal} oifname != ${cfg.interfaces.internal} ether saddr = ${mac} drop")); 6 17 in { 7 - networking.firewall.checkReversePath = "loose"; 18 + options.modules.router = { 19 + nftables = { 20 + enable = mkOption { 21 + default = cfg.enable; 22 + description = "Whether to enable Router NFTables config"; 23 + type = types.bool; 24 + }; 8 25 9 - networking.nftables = { 10 - enable = true; 11 - checkRuleset = false; 12 - flushRuleset = true; 26 + capturePorts = { 27 + default = [ 53 123 ]; 28 + description = "Ports to capture and redirect to router"; 29 + type = types.listOf types.int; 30 + }; 13 31 14 - tables.filter = { 15 - family = "inet"; 16 - content = '' 17 - chain prerouting { 18 - type nat hook prerouting priority 0; policy accept; 19 - iifname { ${trustedInterfaces} } udp dport 53 redirect to 53 20 - iifname { ${trustedInterfaces} } udp dport 123 redirect to 123 21 - } 32 + blockForward = { 33 + default = []; 34 + description = "MAC Addresses of devices to block internet access for"; 35 + type = types.listOf types.str; 36 + }; 37 + }; 38 + }; 22 39 23 - chain postrouting { 24 - type nat hook postrouting priority 0; policy accept; 25 - oifname != { ${trustedInterfaces} } masquerade 26 - } 40 + config = mkIf cfg.nftables.enable { 41 + networking.useNetworkd = mkDefault true; 42 + networking.firewall = { 43 + enable = mkDefault true; 44 + checkReversePath = "loose"; 45 + }; 27 46 28 - chain input { 29 - type filter hook input priority 0; 30 - ct state { established, related } accept 31 - ct state invalid drop 32 - iifname { ${trustedInterfaces} } accept 33 - iifname { ${trustedInterfaces} } pkttype { broadcast, multicast } accept 34 - tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop 35 - tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg counter drop 36 - tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop 37 - ip protocol icmp \ 38 - icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } \ 39 - accept 40 - ip6 nexthdr icmpv6 accept 41 - udp dport 546 ct state { new, untracked } accept 42 - udp dport dhcpv6-client accept 43 - udp dport { http, https } ct state new accept 44 - tcp dport { http, https } ct state new accept 45 - udp dport 41641 ct state new accept 46 - reject with icmpx type port-unreachable 47 - } 47 + networking.nftables = { 48 + enable = mkForce true; 49 + checkRuleset = false; 50 + flushRuleset = true; 48 51 49 - chain forward { 50 - type filter hook forward priority 0; policy drop; 51 - ip6 nexthdr ipv6-icmp accept 52 - udp dport dhcpv6-client accept 53 - iifname intern0 oifname != intern0 ether saddr == ec:e5:12:1d:23:40 drop # drop tado internet traffic 54 - iifname { ${trustedInterfaces} } accept 55 - oifname { ${trustedInterfaces} } ct state { established, related } accept 56 - ct state invalid drop 57 - } 52 + tables.filter = { 53 + family = "inet"; 54 + content = '' 55 + chain prerouting { 56 + type nat hook prerouting priority 0; policy accept; 57 + ${capturePortsRules} 58 + } 58 59 59 - chain output { 60 - type filter hook output priority 0; policy accept; 61 - ip6 nexthdr ipv6-icmp accept 62 - udp dport dhcpv6-client accept 63 - iifname lo accept 64 - ct state invalid drop 65 - } 66 - ''; 67 - }; 60 + chain postrouting { 61 + type nat hook postrouting priority 0; policy accept; 62 + oifname != { ${trustedInterfaces} } masquerade 63 + } 68 64 69 - tables.arp_filter = { 70 - family = "arp"; 71 - content = '' 72 - chain input { 73 - type filter hook input priority 0; policy accept; 74 - iifname != { ${trustedInterfaces} } limit rate 1/second burst 2 packets accept 75 - } 65 + chain input { 66 + type filter hook input priority 0; 67 + ct state { established, related } accept 68 + ct state invalid drop 69 + iifname { ${trustedInterfaces} } accept 70 + iifname { ${trustedInterfaces} } pkttype { broadcast, multicast } accept 71 + tcp flags & (fin|syn|rst|ack) != syn ct state new counter drop 72 + tcp flags & (fin|syn|rst|psh|ack|urg) == fin|syn|rst|psh|ack|urg counter drop 73 + tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop 74 + ip protocol icmp \ 75 + icmp type { destination-unreachable, echo-reply, echo-request, source-quench, time-exceeded } \ 76 + accept 77 + ip6 nexthdr icmpv6 accept 78 + udp dport 546 ct state { new, untracked } accept 79 + udp dport dhcpv6-client accept 80 + udp dport { http, https } ct state new accept 81 + tcp dport { http, https } ct state new accept 82 + udp dport 41641 ct state new accept 83 + reject with icmpx type port-unreachable 84 + } 76 85 77 - chain output { 78 - type filter hook output priority 0; policy accept; 79 - } 80 - ''; 81 - }; 86 + chain forward { 87 + type filter hook forward priority 0; policy drop; 88 + ip6 nexthdr ipv6-icmp accept 89 + udp dport dhcpv6-client accept 90 + ${blockForwardRules} 91 + iifname { ${trustedInterfaces} } accept 92 + oifname { ${trustedInterfaces} } ct state { established, related } accept 93 + ct state invalid drop 94 + } 82 95 83 - tables.tagging = { 84 - family = "netdev"; 85 - content = '' 86 - chain lan { 87 - type filter hook ingress device intern0 priority -150; policy accept; 88 - jump tags 89 - } 96 + chain output { 97 + type filter hook output priority 0; policy accept; 98 + ip6 nexthdr ipv6-icmp accept 99 + udp dport dhcpv6-client accept 100 + iifname lo accept 101 + ct state invalid drop 102 + } 103 + ''; 104 + }; 90 105 91 - chain wan { 92 - type filter hook ingress device extern0 priority -149; policy accept; 93 - jump tags 94 - } 106 + tables.arp_filter = { 107 + family = "arp"; 108 + content = '' 109 + chain input { 110 + type filter hook input priority 0; policy accept; 111 + iifname != { ${trustedInterfaces} } limit rate 1/second burst 2 packets accept 112 + } 95 113 96 - chain tags { 97 - ip dscp set cs0 98 - ip6 dscp set cs0 114 + chain output { 115 + type filter hook output priority 0; policy accept; 116 + } 117 + ''; 118 + }; 99 119 100 - ip protocol udp udp sport ntp ip dscp set cs5 101 - ip6 nexthdr udp udp sport ntp ip6 dscp set cs5 120 + tables.tagging = { 121 + family = "netdev"; 122 + content = '' 123 + chain lan { 124 + type filter hook ingress device ${cfg.interfaces.internal} priority -150; policy accept; 125 + jump tags 126 + } 127 + 128 + chain wan { 129 + type filter hook ingress device ${cfg.interfaces.external} priority -149; policy accept; 130 + jump tags 131 + } 132 + 133 + chain tags { 134 + ip dscp set cs0 135 + ip6 dscp set cs0 102 136 103 - ip saddr {1.1.1.1, 1.0.0.1} ip dscp set cs5 104 - ip daddr {1.1.1.1, 1.0.0.1} ip dscp set cs5 137 + ip protocol udp udp sport ntp ip dscp set cs5 138 + ip6 nexthdr udp udp sport ntp ip6 dscp set cs5 139 + 140 + ip saddr {1.1.1.1, 1.0.0.1} ip dscp set cs5 141 + ip daddr {1.1.1.1, 1.0.0.1} ip dscp set cs5 105 142 106 - tcp dport {http, https} ip dscp set cs3 107 - tcp sport {http, https} ip dscp set cs3 108 - ip6 nexthdr tcp tcp dport {http, https} ip6 dscp set cs3 109 - ip6 nexthdr tcp tcp sport {http, https} ip6 dscp set cs3 143 + tcp dport {http, https} ip dscp set cs3 144 + tcp sport {http, https} ip dscp set cs3 145 + ip6 nexthdr tcp tcp dport {http, https} ip6 dscp set cs3 146 + ip6 nexthdr tcp tcp sport {http, https} ip6 dscp set cs3 110 147 111 - udp dport 41641 ip dscp set cs4 # tailscale 112 - udp sport 41641 ip dscp set cs4 # tailscale 148 + udp dport 41641 ip dscp set cs4 # tailscale 149 + udp sport 41641 ip dscp set cs4 # tailscale 113 150 114 - # mark some VOIP traffic as flash override (low delay) 115 - udp dport {3478-3479, 19302-19309} ip dscp set cs4 116 - udp sport {3478-3479, 19302-19309} ip dscp set cs4 117 - ip6 nexthdr udp udp dport {3478-3479, 19302-19309} ip6 dscp set cs4 118 - ip6 nexthdr udp udp sport {3478-3479, 19302-19309} ip6 dscp set cs4 119 - udp dport {7000-9000, 27000-27200} ip dscp set cs4 120 - udp sport {7000-9000, 27000-27200} ip dscp set cs4 121 - ip6 nexthdr udp udp dport {7000-9000, 27000-27200} ip6 dscp set cs4 122 - ip6 nexthdr udp udp sport {7000-9000, 27000-27200} ip6 dscp set cs4 123 - } 124 - ''; 151 + # mark some VOIP traffic as flash override (low delay) 152 + udp dport {3478-3479, 19302-19309} ip dscp set cs4 153 + udp sport {3478-3479, 19302-19309} ip dscp set cs4 154 + ip6 nexthdr udp udp dport {3478-3479, 19302-19309} ip6 dscp set cs4 155 + ip6 nexthdr udp udp sport {3478-3479, 19302-19309} ip6 dscp set cs4 156 + udp dport {7000-9000, 27000-27200} ip dscp set cs4 157 + udp sport {7000-9000, 27000-27200} ip dscp set cs4 158 + ip6 nexthdr udp udp dport {7000-9000, 27000-27200} ip6 dscp set cs4 159 + ip6 nexthdr udp udp sport {7000-9000, 27000-27200} ip6 dscp set cs4 160 + } 161 + ''; 162 + }; 125 163 }; 126 164 }; 127 165 }
-12
modules/router/ntp.nix
··· 1 - { ... }: 2 - 3 - { 4 - services.ntp = { 5 - enable = true; 6 - extraConfig = '' 7 - interface listen lo 8 - interface listen intern0 9 - interface ignore extern0 10 - ''; 11 - }; 12 - }
-23
modules/router/stubby.nix
··· 1 - { ... }: 2 - 3 - { 4 - services.stubby = { 5 - enable = true; 6 - settings = { 7 - resolution_type = "GETDNS_RESOLUTION_STUB"; 8 - dns_transport_list = [ "GETDNS_TRANSPORT_TLS" ]; 9 - tls_authentication = "GETDNS_AUTHENTICATION_REQUIRED"; 10 - tls_query_padding_blocksize = 128; 11 - edns_client_subnet_private = 1; 12 - round_robin_upstreams = 1; 13 - tls_connection_retries = 5; 14 - listen_addresses = [ "127.0.0.1@53000" "0::1@53000" ]; 15 - appdata_dir = "/var/cache/stubby"; 16 - trust_anchors_backoff_time = 2500; 17 - upstream_recursive_servers = [ 18 - { address_data = "1.1.1.1"; tls_auth_name = "cloudflare-dns.com"; } 19 - { address_data = "1.0.0.1"; tls_auth_name = "cloudflare-dns.com"; } 20 - ]; 21 - }; 22 - }; 23 - }
+29
modules/router/timeserver.nix
··· 1 + { lib, config, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.router; 6 + 7 + ntpExtraConfig = '' 8 + interface listen lo 9 + interface listen ${cfg.interfaces.internal} 10 + interface ignore ${cfg.interfaces.external} 11 + ''; 12 + in { 13 + options.modules.router = { 14 + timeserver.enable = mkOption { 15 + default = cfg.enable; 16 + description = "Whether to enable NTP Service"; 17 + type = types.bool; 18 + }; 19 + }; 20 + 21 + config = mkIf cfg.timeserver.enable { 22 + networking.timeServers = [ "time.cloudflare.com" ]; 23 + 24 + services.ntp = { 25 + enable = true; 26 + extraConfig = ntpExtraConfig; 27 + }; 28 + }; 29 + }
+34
modules/router/upnp.nix
··· 1 + { lib, config, ... }: 2 + 3 + with lib; 4 + let 5 + cfg = config.modules.router; 6 + in { 7 + options.modules.router = { 8 + upnp = { 9 + enable = mkOption { 10 + default = cfg.enable; 11 + description = "Whether to enable UPNP"; 12 + type = types.bool; 13 + }; 14 + }; 15 + }; 16 + 17 + config = mkIf cfg.upnp.enable { 18 + services.miniupnpd = { 19 + enable = true; 20 + upnp = true; 21 + natpmp = true; 22 + internalIPs = [ cfg.interfaces.internal ]; 23 + externalInterface = cfg.interfaces.external; 24 + appendConfig = '' 25 + secure_mode=yes 26 + notify_interval=60 27 + clean_ruleset_interval=600 28 + uuid=78b8b903-83c1-4036-8fcd-f64aee25baca 29 + allow 1024-65535 10.0.0.0/24 1024-65535 30 + deny 0-65535 0.0.0.0/0 0-65535 31 + ''; 32 + }; 33 + }; 34 + }
+103 -46
modules/server/caddy.nix
··· 1 - { config, ... }: 1 + { lib, config, hostname, ... }: 2 + 3 + with lib; 4 + let 5 + cfgRoot = config.modules.server; 6 + cfg = config.modules.server.caddy; 7 + 8 + exposeType = types.submodule { 9 + options = { 10 + path = mkOption { 11 + type = types.str; 12 + example = "/share/files"; 13 + }; 14 + }; 15 + }; 16 + 17 + domain = config.networking.domain; 18 + tailscaleEnabled = cfgRoot.tailscale.enable; 19 + vaultwardenEnabled = cfgRoot.vaultwarden.enable; 20 + jellyfinEnabled = cfgRoot.jellyfin.enable; 21 + hassEnabled = cfgRoot.home-assistant.enable; 22 + 23 + vaultwardenHandlerConfig = if vaultwardenEnabled then '' 24 + handle_path /vault { 25 + redir * /vault/ 26 + } 27 + 28 + handle_path /vault/* { 29 + reverse_proxy /notifications/hub/negotiate 127.0.0.1:8000 30 + reverse_proxy /notifications/hub 127.0.0.1:8001 31 + reverse_proxy localhost:8000 { 32 + header_up X-Real-IP {remote_host} 33 + } 34 + } 35 + '' else ""; 36 + 37 + jellyfinHandlerConfig = if jellyfinEnabled then '' 38 + handle_path /media { 39 + redir * /media/ 40 + } 2 41 3 - { 4 - services.tailscale.permitCertUid = config.services.caddy.user; 42 + reverse_proxy /media/* localhost:8096 { 43 + header_up X-Real-IP {remote_host} 44 + } 45 + '' else ""; 5 46 6 - services.caddy = { 7 - enable = config.services.tailscale.enable; 8 - email = "phil@kitten.sh"; 9 - extraConfig = '' 10 - (network_paths) { 11 - handle_path /home { 12 - redir * https://cola.fable-pancake.ts.net:8123 13 - } 47 + hassHandlerConfig = if hassEnabled && tailscaleEnabled then '' 48 + handle_path /home { 49 + redir * https://${hostname}.${domain}:8123 50 + } 51 + '' else ""; 14 52 15 - handle_path /vault { 16 - redir * /vault/ 17 - } 53 + tailscaleConfig = if tailscaleEnabled then '' 54 + ${hostname}.${domain} { 55 + import network_paths 56 + } 57 + '' else ""; 18 58 19 - handle_path /vault/* { 20 - reverse_proxy /notifications/hub/negotiate 127.0.0.1:8000 21 - reverse_proxy /notifications/hub 127.0.0.1:8001 22 - reverse_proxy localhost:8000 { 23 - header_up X-Real-IP {remote_host} 24 - } 25 - } 59 + exposeConfig = let 60 + configs = attrsets.mapAttrs (name: expose: '' 61 + handle_path /${name} { 62 + redir * /${name}/ 63 + } 26 64 27 - handle_path /media { 28 - redir * /media/ 65 + handle_path /${name}/* { 66 + file_server { 67 + browse 68 + root ${expose.path} 69 + hide .* 29 70 } 30 71 31 - reverse_proxy /media/* localhost:8096 { 32 - header_up X-Real-IP {remote_host} 33 - } 72 + @file path *.* 34 73 35 - handle_path /files { 36 - redir * /files/ 74 + handle_path /* { 75 + header @file +Content-Disposition attachment 37 76 } 77 + } 78 + '') cfg.exposeFolders; 79 + in string.concatMapStringsSep "\n\n" configs; 80 + in { 81 + options.modules.server.caddy = { 82 + enable = mkOption { 83 + default = false; 84 + example = true; 85 + description = "Whether to enable Caddy."; 86 + type = types.bool; 87 + }; 38 88 39 - handle_path /files/* { 40 - file_server { 41 - browse 42 - root /share/files 43 - hide .* 44 - } 89 + exposeFolders = mkOption { 90 + default = {}; 91 + description = "Folders to expose via Cadddy."; 92 + type = types.nullOr types.attrsOf exposeType; 93 + }; 94 + }; 45 95 46 - @file path *.* 96 + config = mkIf cfg.enable && cfgRoot.enable { 97 + services.tailscale = mkIf tailscaleEnabled { 98 + permitCertUid = config.services.caddy.user; 99 + }; 47 100 48 - handle_path /* { 49 - header @file +Content-Disposition attachment 50 - } 101 + services.caddy = { 102 + enable = true; 103 + email = "phil@kitten.sh"; 104 + extraConfig = '' 105 + (network_paths) { 106 + ${vaultwardenHandlerConfig} 107 + ${jellyfinHandlerConfig} 108 + ${hassHandlerConfig} 109 + ${exposeConfig} 51 110 } 52 - } 53 111 54 - cola.fable-pancake.ts.net { 55 - import network_paths 56 - } 112 + ${tailscaleConfig} 57 113 58 - :80 { 59 - import network_paths 60 - } 61 - ''; 114 + :80 { 115 + import network_paths 116 + } 117 + ''; 118 + }; 62 119 }; 63 120 }
+15 -2
modules/server/default.nix
··· 1 - { helpers, ... }: 1 + { lib, helpers, ... }: 2 + 3 + with lib; { 4 + options.modules.server = { 5 + enable = mkOption { 6 + default = false; 7 + example = true; 8 + description = "Whether to enable Server options."; 9 + type = types.bool; 10 + }; 11 + }; 2 12 3 - helpers.linuxAttrs { 13 + config.modules.server = { 14 + enable = if helpers.isLinux then (mkDefault false) else (mkForce false); 15 + }; 16 + } // helpers.linuxAttrs { 4 17 imports = [ 5 18 ./sshd.nix 6 19 ./tailscale.nix
+24 -9
modules/server/hd-idle.nix
··· 1 - { pkgs, ... }: 1 + { lib, config, pkgs, ... }: 2 + 3 + with lib; 4 + let 5 + cfgRoot = config.modules.server; 6 + cfg = config.modules.server.sshd; 7 + in { 8 + options.modules.server.hdIdle = { 9 + enable = mkOption { 10 + default = false; 11 + example = true; 12 + description = "Whether to enable hard-drive idling."; 13 + type = types.bool; 14 + }; 15 + }; 2 16 3 - { 4 - systemd.services.hd-idle = { 5 - description = "External HD spin down daemon"; 6 - wantedBy = [ "multi-user.target" ]; 7 - serviceConfig = { 8 - Type = "simple"; 9 - Restart = "always"; 10 - ExecStart = "${pkgs.hd-idle}/bin/hd-idle -i 600"; 17 + config = mkIf cfg.enable && cfgRoot.enable { 18 + systemd.services.hd-idle = { 19 + description = "External HD spin down daemon"; 20 + wantedBy = [ "multi-user.target" ]; 21 + serviceConfig = { 22 + Type = "simple"; 23 + Restart = "always"; 24 + ExecStart = "${pkgs.hd-idle}/bin/hd-idle -i 600"; 25 + }; 11 26 }; 12 27 }; 13 28 }
+69 -41
modules/server/home-assistant.nix
··· 1 - { config, ... }: 1 + { lib, config, pkgs, ... }: 2 2 3 - { 4 - users = { 5 - groups.hass.gid = config.ids.gids.hass; 6 - users.hass = { 7 - uid = config.ids.uids.hass; 8 - group = "hass"; 3 + with lib; 4 + let 5 + inherit (pkgs) stdenv; 6 + 7 + cfgRoot = config.modules.server; 8 + cfg = config.modules.server.home-assistant; 9 + 10 + containerImage = if stdenv.isAarch64 11 + then "ghcr.io/home-assistant/home-assistant:${cfg.revision}" 12 + else "ghcr.io/home-assistant/aarch64-home-assistant:${cfg.revision}"; 13 + in { 14 + options.modules.server.home-assistant = { 15 + enable = mkOption { 16 + default = false; 17 + example = true; 18 + description = "Whether to enable Home Assistant."; 19 + type = types.bool; 20 + }; 21 + 22 + revision = mkOption { 23 + default = "2024.9.2"; 24 + example = "2024.9.2"; 25 + description = "Home Assistant Revision"; 26 + type = types.str; 9 27 }; 10 28 }; 11 29 12 - virtualisation.oci-containers = { 13 - containers.hass = rec { 14 - autoStart = true; 15 - volumes = [ 16 - "/var/lib/home-assistant:/config" 17 - "/etc/localtime:/etc/localtime:ro" 18 - "/sys:/sys:ro" 19 - ]; 20 - user = "${environment.PUID}:${environment.PGID}"; 21 - environment = { 22 - TZ = "Europe/London"; 23 - PUID = "${toString config.ids.uids.hass}"; 24 - PGID = "${toString config.ids.gids.hass}"; 25 - UMASK = "007"; 30 + config = mkIf cfg.enable && cfgRoot.enable { 31 + users = { 32 + groups.hass.gid = config.ids.gids.hass; 33 + users.hass = { 34 + uid = config.ids.uids.hass; 35 + group = "hass"; 26 36 }; 27 - image = "ghcr.io/home-assistant/home-assistant:stable"; 28 - extraOptions = [ 29 - "--cap-drop=ALL" 30 - "--cap-add=CHOWN" 31 - "--cap-add=DAC_OVERRIDE" 32 - "--cap-add=FSETID" 33 - "--cap-add=FOWNER" 34 - "--cap-add=SETGID" 35 - "--cap-add=SETUID" 36 - "--cap-add=SYS_CHROOT" 37 - "--cap-add=KILL" 38 - "--cap-add=NET_RAW" 39 - "--cap-add=NET_ADMIN" 40 - "--security-opt=no-new-privileges" 41 - "--userns=keep-id" 42 - "--hostuser=hass" 43 - "--runtime=runc" 44 - "--device=/dev/ttyUSB0" 45 - "--network=host" 46 - ]; 37 + }; 38 + 39 + virtualisation.oci-containers = { 40 + containers.hass = rec { 41 + autoStart = true; 42 + volumes = [ 43 + "/var/lib/home-assistant:/config" 44 + "/etc/localtime:/etc/localtime:ro" 45 + "/sys:/sys:ro" 46 + ]; 47 + user = "${environment.PUID}:${environment.PGID}"; 48 + environment = { 49 + TZ = "Europe/London"; 50 + PUID = "${toString config.ids.uids.hass}"; 51 + PGID = "${toString config.ids.gids.hass}"; 52 + UMASK = "007"; 53 + }; 54 + image = containerImage; 55 + extraOptions = [ 56 + "--cap-drop=ALL" 57 + "--cap-add=CHOWN" 58 + "--cap-add=DAC_OVERRIDE" 59 + "--cap-add=FSETID" 60 + "--cap-add=FOWNER" 61 + "--cap-add=SETGID" 62 + "--cap-add=SETUID" 63 + "--cap-add=SYS_CHROOT" 64 + "--cap-add=KILL" 65 + "--cap-add=NET_RAW" 66 + "--cap-add=NET_ADMIN" 67 + "--security-opt=no-new-privileges" 68 + "--userns=keep-id" 69 + "--hostuser=hass" 70 + "--runtime=runc" 71 + "--device=/dev/ttyUSB0" 72 + "--network=host" 73 + ]; 74 + }; 47 75 }; 48 76 }; 49 77 }
+60 -43
modules/server/jellyfin.nix
··· 1 - { lib, pkgs, user, ... }: 1 + { lib, config, pkgs, user, ... }: 2 2 3 + with lib; 3 4 let 5 + cfgRoot = config.modules.server; 6 + cfg = config.modules.server.jellyfin; 7 + 4 8 group = "share"; 5 9 in { 6 - hardware.graphics.enable = lib.mkDefault true; 10 + options.modules.server.jellyfin = { 11 + enable = mkOption { 12 + default = false; 13 + example = true; 14 + description = "Whether to enable Jellyfin server."; 15 + type = types.bool; 16 + }; 7 17 8 - age.secrets."rclone.conf" = { 9 - symlink = true; 10 - path = "/run/secrets/rclone.conf"; 11 - file = ./encrypt/rclone.conf.age; 12 - owner = "jellyfin"; 13 - group = "${group}"; 18 + sync = mkEnableOption "Whether to sync files from remotes"; 14 19 }; 15 20 16 - users.users."${user}".extraGroups = [ "${group}" ]; 21 + config = mkIf cfg.enable && cfgRoot.enable { 22 + hardware.graphics.enable = mkDefault true; 17 23 18 - users.groups.share.gid = 1001; 24 + users.users."${user}".extraGroups = [ "${group}" ]; 19 25 20 - services.jellyfin = { 21 - enable = true; 22 - openFirewall = false; 23 - group = "${group}"; 24 - }; 26 + users.groups.share.gid = 1001; 25 27 26 - systemd.services."rclone-sync@" = { 27 - wants = [ "network-online.target" ]; 28 - description = "Sync files between different remotes via rclone"; 29 - stopIfChanged = false; 30 - serviceConfig = { 31 - Type = "simple"; 32 - User = "jellyfin"; 33 - Group = "${group}"; 34 - ExecStart = '' 35 - ${pkgs.rclone}/bin/rclone \ 36 - --config /run/secrets/rclone.conf \ 37 - -P copy \ 38 - -u \ 39 - --max-age 24h \ 40 - --multi-thread-streams 0 \ 41 - putio:%I /share/media/%I 42 - ''; 28 + services.jellyfin = { 29 + enable = true; 30 + openFirewall = false; 31 + group = "${group}"; 32 + }; 33 + } // mkIf cfg.sync { 34 + age.secrets."rclone.conf" = { 35 + symlink = true; 36 + path = "/run/secrets/rclone.conf"; 37 + file = ./encrypt/rclone.conf.age; 38 + owner = "jellyfin"; 39 + group = "${group}"; 40 + }; 41 + 42 + systemd.services."rclone-sync@" = { 43 + wants = [ "network-online.target" ]; 44 + description = "Sync files between different remotes via rclone"; 45 + stopIfChanged = false; 46 + serviceConfig = { 47 + Type = "simple"; 48 + User = "jellyfin"; 49 + Group = "${group}"; 50 + ExecStart = '' 51 + ${pkgs.rclone}/bin/rclone \ 52 + --config /run/secrets/rclone.conf \ 53 + -P copy \ 54 + -u \ 55 + --max-age 24h \ 56 + --multi-thread-streams 0 \ 57 + putio:%I /share/media/%I 58 + ''; 59 + }; 43 60 }; 44 - }; 45 61 46 - systemd.timers."rclone-sync@" = { 47 - description = "Sync files between different remotes via rclone periodically"; 48 - timerConfig = { 49 - OnBootSec = "15min"; 50 - OnUnitActiveSec="8h"; 51 - Persistent = true; 62 + systemd.timers."rclone-sync@" = { 63 + description = "Sync files between different remotes via rclone periodically"; 64 + timerConfig = { 65 + OnBootSec = "15min"; 66 + OnUnitActiveSec="8h"; 67 + Persistent = true; 68 + }; 52 69 }; 53 - }; 54 70 55 - systemd.targets.rclone-sync = { 56 - wantedBy = [ "multi-user.target" ]; 57 - wants = [ "rclone-sync@movies.timer" "rclone-sync@series.timer" ]; 71 + systemd.targets.rclone-sync = { 72 + wantedBy = [ "multi-user.target" ]; 73 + wants = [ "rclone-sync@movies.timer" "rclone-sync@series.timer" ]; 74 + }; 58 75 }; 59 76 }
+25 -8
modules/server/podman.nix
··· 1 - { ... }: 1 + { lib, config, ... }: 2 2 3 - { 4 - networking.firewall.trustedInterfaces = [ "podman0" ]; 3 + with lib; 4 + let 5 + cfgRoot = config.modules.server; 6 + cfg = config.modules.server.podman; 7 + in { 8 + options.modules.server.podman = { 9 + enable = mkOption { 10 + default = false; 11 + example = true; 12 + description = "Whether to enable Podman."; 13 + type = types.bool; 14 + }; 15 + }; 5 16 6 - virtualisation.podman = { 7 - enable = true; 8 - autoPrune.enable = true; 9 - defaultNetwork.settings = { 10 - dns_enabled = true; 17 + config = mkIf cfg.enable && cfgRoot.enable { 18 + networking.firewall.trustedInterfaces = [ "podman0" ]; 19 + virtualisation = { 20 + oci-containers.backend = "podman"; 21 + podman = { 22 + enable = true; 23 + autoPrune.enable = true; 24 + defaultNetwork.settings = { 25 + dns_enabled = true; 26 + }; 27 + }; 11 28 }; 12 29 }; 13 30 }
+23 -8
modules/server/sshd.nix
··· 1 - { user, ... }: 1 + { lib, config, user, ... }: 2 + 3 + with lib; 4 + let 5 + cfgRoot = config.modules.server; 6 + cfg = config.modules.server.sshd; 7 + in { 8 + options.modules.server.sshd = { 9 + enable = mkOption { 10 + default = false; 11 + example = true; 12 + description = "Whether to enable SSH server."; 13 + type = types.bool; 14 + }; 15 + }; 2 16 3 - { 4 - users.users."${user}".openssh.authorizedKeys.keys = [ 5 - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDZVcY+kkbEtIiYjSyIMeIJNZjUpK+kgpMQEIOqtG5GIkTV5rb9DOoruAYy1/2HPpAaDUl7ISorBc4g0v/98cEaF04PIOWpm+HctLhPNyI0f7TClQIFNU8PLO5bMzAvIdJQmJavd42cVZmz44N8C12nL3mzCIaLGsVW/iAc2H2viHoOT3ZYxhq1f0kaDhLYjaserNgLqX12E3q5f3z1HkAg2ivRt5NHs4t4N5L6dqS/GnLAaK9rT1yCuIPQT4+XvKycaos/dMLWSPzz3ROV9mATg2uzQx9DiQd7s0pQ4UjUNL/XHlVj0TnQAS6fioVlkfb6dAxzIm9D+O4NI6b2m23Jo2XXoChKkRtVbBX/bJH8YZS2QdIlwlm57yyEbipCFjha8/GH2LUSqEkAZpbDFkIl77aSDX/D+l5svXIZke3PUmL9VX31UglP6/1hqFjMNvZHMbf+bjpjw2UILPph3QogMw8LeSfndFDDtkCDuP25MyjWi4h2QGVc8ibtQnDu3Lj8HhdQ2dOXPuHgMnty9YZXWfGaStIIsS26ZiXbkvRG5e8rlIXQbz8V1aS9851ODOeoXAU87aAG8MKiWJgtrcJRtBcZJHTZHk/I/fSKsyARWz8xtfrIOsCLSWWiY0lpCUYTCrZ4uh9jFEkYda9S8efh7QmOLXraqn6Gw+psKiU9Fw==" 6 - ]; 17 + config = mkIf cfg.enable && cfgRoot.enable { 18 + users.users."${user}".openssh.authorizedKeys.keys = [ 19 + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDZVcY+kkbEtIiYjSyIMeIJNZjUpK+kgpMQEIOqtG5GIkTV5rb9DOoruAYy1/2HPpAaDUl7ISorBc4g0v/98cEaF04PIOWpm+HctLhPNyI0f7TClQIFNU8PLO5bMzAvIdJQmJavd42cVZmz44N8C12nL3mzCIaLGsVW/iAc2H2viHoOT3ZYxhq1f0kaDhLYjaserNgLqX12E3q5f3z1HkAg2ivRt5NHs4t4N5L6dqS/GnLAaK9rT1yCuIPQT4+XvKycaos/dMLWSPzz3ROV9mATg2uzQx9DiQd7s0pQ4UjUNL/XHlVj0TnQAS6fioVlkfb6dAxzIm9D+O4NI6b2m23Jo2XXoChKkRtVbBX/bJH8YZS2QdIlwlm57yyEbipCFjha8/GH2LUSqEkAZpbDFkIl77aSDX/D+l5svXIZke3PUmL9VX31UglP6/1hqFjMNvZHMbf+bjpjw2UILPph3QogMw8LeSfndFDDtkCDuP25MyjWi4h2QGVc8ibtQnDu3Lj8HhdQ2dOXPuHgMnty9YZXWfGaStIIsS26ZiXbkvRG5e8rlIXQbz8V1aS9851ODOeoXAU87aAG8MKiWJgtrcJRtBcZJHTZHk/I/fSKsyARWz8xtfrIOsCLSWWiY0lpCUYTCrZ4uh9jFEkYda9S8efh7QmOLXraqn6Gw+psKiU9Fw==" 20 + ]; 7 21 8 - services.openssh = { 9 - enable = true; 10 - openFirewall = false; 22 + services.openssh = { 23 + enable = true; 24 + openFirewall = false; 25 + }; 11 26 }; 12 27 }
+39 -19
modules/server/tailscale.nix
··· 1 - { user, ... }: 1 + { lib, config, hostname, ... }: 2 2 3 - { 4 - networking = { 5 - domain = "fable-pancake.ts.net"; 6 - firewall.trustedInterfaces = [ "tailscale0" ]; 7 - hosts."10.0.0.1" = [ "cola.fable-pancake.ts.net" "cola" ]; 8 - }; 3 + with lib; 4 + let 5 + cfgRoot = config.modules.server; 6 + cfg = config.modules.server.tailscale; 7 + in { 8 + options.modules.server.tailscale = { 9 + enable = mkOption { 10 + default = false; 11 + example = true; 12 + description = "Whether to enable Tailscale."; 13 + type = types.bool; 14 + }; 9 15 10 - age.secrets."tailscale" = { 11 - symlink = true; 12 - path = "/run/secrets/tailscale"; 13 - file = ./encrypt/tailscale.age; 16 + authKeySecret = { 17 + description = "Age Secret of auth keyfile for Tailscale."; 18 + type = types.path; 19 + }; 14 20 }; 15 21 16 - services.tailscale = { 17 - enable = true; 18 - useRoutingFeatures = "both"; 19 - extraUpFlags = [ "--advertise-exit-node" "--ssh" ]; 20 - extraDaemonFlags = [ "--no-logs-no-support" ]; 21 - authKeyFile = "/run/secrets/tailscale"; 22 - }; 22 + config = mkIf cfg.enable && cfgRoot.enable { 23 + networking = { 24 + domain = "fable-pancake.ts.net"; 25 + firewall.trustedInterfaces = [ "tailscale0" ]; 26 + hosts."10.0.0.1" = [ "${hostname}.fable-pancake.ts.net" hostname ]; 27 + }; 28 + 29 + age.secrets."tailscale" = { 30 + symlink = true; 31 + path = "/run/secrets/tailscale"; 32 + file = cfg.authKeySecret; 33 + }; 34 + 35 + services.tailscale = { 36 + enable = true; 37 + useRoutingFeatures = "both"; 38 + extraUpFlags = [ "--advertise-exit-node" "--ssh" ]; 39 + extraDaemonFlags = [ "--no-logs-no-support" ]; 40 + authKeyFile = "/run/secrets/tailscale"; 41 + }; 23 42 24 - systemd.services.tailscaled.serviceConfig.Environment = [ "TS_DEBUG_DISABLE_PORTLIST=true" ]; 43 + systemd.services.tailscaled.serviceConfig.Environment = [ "TS_DEBUG_DISABLE_PORTLIST=true" ]; 44 + }; 25 45 }
+31 -16
modules/server/vaultwarden.nix
··· 1 - { ... }: 1 + { lib, config, hostname, ... }: 2 2 3 - { 4 - services.vaultwarden = { 5 - enable = true; 6 - dbBackend = "sqlite"; 7 - config = { 8 - IP_HEADER = "X-Real-IP"; 9 - ADMIN_TOKEN = "$argon2id$v=19$m=65540,t=3,p=4$+5A5H6YiN6OxyrFggkrft8Mm+sxgh/tL3USbaYFZ/h8$qj8NjE+COL4WXjmjkPWSQk7iLfhaBfBtV6k06Bql3CQ"; 10 - PASSWORD_HINTS_ALLOWED = "false"; 11 - SIGNUPS_ALLOWED = "false"; 12 - DOMAIN = "https://cola.fable-pancake.ts.net"; 13 - WEBSOCKET_ADDRESS = "127.0.0.1"; 14 - ROCKET_ADDRESS = "127.0.0.1"; 15 - WEBSOCKET_PORT = "8001"; 16 - ROCKET_PORT = "8000"; 17 - ROCKET_LIMITS = "{json=10485760}"; 3 + with lib; 4 + let 5 + cfgRoot = config.modules.server; 6 + cfg = config.modules.server.vaultwarden; 7 + in { 8 + options.modules.server.vaultwarden = { 9 + enable = mkOption { 10 + default = false; 11 + example = true; 12 + description = "Whether to enable Vaultwarden."; 13 + type = types.bool; 14 + }; 15 + }; 16 + 17 + config = mkIf cfg.enable && cfgRoot.enable { 18 + services.vaultwarden = { 19 + enable = true; 20 + dbBackend = "sqlite"; 21 + config = { 22 + IP_HEADER = "X-Real-IP"; 23 + ADMIN_TOKEN = "$argon2id$v=19$m=65540,t=3,p=4$+5A5H6YiN6OxyrFggkrft8Mm+sxgh/tL3USbaYFZ/h8$qj8NjE+COL4WXjmjkPWSQk7iLfhaBfBtV6k06Bql3CQ"; 24 + PASSWORD_HINTS_ALLOWED = "false"; 25 + SIGNUPS_ALLOWED = "false"; 26 + DOMAIN = "https://${hostname}.fable-pancake.ts.net"; 27 + WEBSOCKET_ADDRESS = "127.0.0.1"; 28 + ROCKET_ADDRESS = "127.0.0.1"; 29 + WEBSOCKET_PORT = "8001"; 30 + ROCKET_PORT = "8000"; 31 + ROCKET_LIMITS = "{json=10485760}"; 32 + }; 18 33 }; 19 34 }; 20 35 }
+5 -5
secrets.nix
··· 6 6 { 7 7 "./modules/base/encrypt/nix-access-tokens.conf.age".publicKeys = keys; 8 8 9 - "./modules/desktop/fonts/encrypt/DankMono-Regular.otf.age".publicKeys = keys; 10 - "./modules/desktop/fonts/encrypt/DankMono-Bold.otf.age".publicKeys = keys; 11 - "./modules/desktop/fonts/encrypt/DankMono-Italic.otf.age".publicKeys = keys; 12 - "./modules/desktop/fonts/encrypt/codicon.otf.age".publicKeys = keys; 13 - "./modules/desktop/fonts/encrypt/faicon.ttf.age".publicKeys = keys; 9 + "./modules/fonts/encrypt/DankMono-Regular.otf.age".publicKeys = keys; 10 + "./modules/fonts/encrypt/DankMono-Bold.otf.age".publicKeys = keys; 11 + "./modules/fonts/encrypt/DankMono-Italic.otf.age".publicKeys = keys; 12 + "./modules/fonts/encrypt/codicon.otf.age".publicKeys = keys; 13 + "./modules/fonts/encrypt/faicon.ttf.age".publicKeys = keys; 14 14 15 15 "./modules/server/encrypt/tailscale.age".publicKeys = keys; 16 16 "./modules/server/encrypt/rclone.conf.age".publicKeys = keys;