├── .gitignore ├── README.md ├── flake.nix ├── home-manager ├── apps │ ├── calibre.nix │ ├── mbsync.nix │ ├── vdirsyncer.nix │ └── vscode.nix ├── base.nix ├── common │ ├── aerc.nix │ ├── bash.nix │ ├── bemenu.nix │ ├── calendar.nix │ ├── catppuccin.nix │ ├── cursor-editor.nix │ ├── default.nix │ ├── fonts.nix │ ├── foot.nix │ ├── git.nix │ ├── gpg.nix │ ├── imv.nix │ ├── nix.nix │ ├── packages.nix │ ├── ruff.nix │ ├── ssh.nix │ ├── tmux.nix │ ├── udiskie.nix │ ├── watson.nix │ ├── xdg.nix │ ├── yazi.nix │ ├── ydotool.nix │ └── zoxide.nix ├── home-manager.nix ├── homeserver.nix ├── laptop.nix ├── office.nix └── sway │ ├── default.nix │ ├── mako.nix │ ├── packages.nix │ ├── sway.nix │ ├── swayimg.nix │ └── wallpaper.nix └── hosts ├── backup ├── configuration.nix ├── disko-config.nix ├── hardware-configuration.nix └── services │ ├── backups.nix │ ├── default.nix │ ├── jamia-backups.nix │ └── syncthing.nix ├── base-btrfs ├── configuration.nix ├── disko-config.nix └── hardware-configuration.nix ├── base-zfs ├── configuration.nix ├── disko-config.nix └── hardware-configuration.nix ├── homeserver ├── configuration.nix ├── hardware-configuration.nix ├── machine.nix └── services │ ├── akkoma.nix │ ├── audiobookshelf.nix │ ├── backups.nix │ ├── default.nix │ ├── gollum.nix │ ├── hass.nix │ ├── immich.nix │ ├── jackett.nix │ ├── jellyfin.nix │ ├── lidarr.nix │ ├── lubelogger.nix │ ├── miniflux.nix │ ├── misc.nix │ ├── nextcloud.nix │ ├── nginx.nix │ ├── openwebui.nix │ ├── peggy.nix │ ├── qbittorrent.nix │ ├── radarr.nix │ ├── sabnzbd.nix │ ├── samba.nix │ ├── sonarr.nix │ ├── stirling-pdf.nix │ ├── syncthing.nix │ ├── traefik.nix │ ├── transmission.nix │ ├── uptime-kuma.nix │ └── vaultwarden.nix ├── laptop ├── configuration.nix ├── hardware-configuration.nix └── services │ ├── backups.nix │ ├── default.nix │ ├── searx.nix │ └── syncthing.nix ├── minimal ├── configuration.nix ├── disko-config.nix └── hardware-configuration.nix ├── modules ├── avahi.nix ├── boot-grub.nix ├── boot.nix ├── common │ ├── default.nix │ ├── env.nix │ ├── et.nix │ ├── fwupd.nix │ ├── nix.nix │ ├── packages.nix │ ├── smartmon.nix │ ├── sops.nix │ ├── sshd.nix │ ├── tz_locale.nix │ └── users.nix ├── desktops │ ├── autossh.nix │ ├── bluetooth.nix │ ├── catppuccin.nix │ ├── default.nix │ ├── desktop.nix │ ├── mounts.nix │ ├── neovim.nix │ ├── networking.nix │ ├── users.nix │ └── virt-manager.nix ├── docker.nix ├── gnome.nix ├── libvirt.nix ├── newt.nix ├── nix-ld.nix ├── opengl-amd.nix ├── opengl-intel.nix ├── podman.nix ├── power.nix ├── sddm.nix ├── servers │ ├── default.nix │ ├── fail2ban.nix │ ├── msmtp.nix │ ├── neovim.nix │ ├── prometheus-exporters.nix │ ├── tmux.nix │ └── wireguard.nix ├── sway.nix └── zfs.nix ├── office ├── configuration.nix ├── disko-config.nix ├── hardware-configuration.nix └── services │ ├── backups.nix │ ├── default.nix │ ├── nixos.nix │ ├── searx.nix │ └── syncthing.nix └── vps ├── configuration.nix ├── disko-config.nix ├── hardware-configuration.nix └── services ├── backups.nix ├── default.nix ├── grafana.nix ├── microbin.nix ├── nextcloud.nix ├── nginx.nix ├── prometheus.nix ├── syncthing.nix ├── traefik.nix └── uptime-kuma.nix /.gitignore: -------------------------------------------------------------------------------- 1 | flake.lock 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NixOS configurations 2 | 3 | * Laptop `laptop` 4 | * Homeserver `homeserver` 5 | * Backup server `backup` 6 | * VPS cloud server `vps` 7 | * Office secondary/spare desktop `office` 8 | * Base flake install w/ home-manager and sops. Encrypted LUKS (btrfs) or ZFS 9 | - `base-btrfs` or `base-zfs` 10 | * Bare minimum flake install for testing. `minimal` 11 | 12 | Sops-nix secrets live in a private repository `nixos-secrets`. 13 | 14 | History for this repository starts as of when I removed the last of my 15 | secrets/keys/etc (2024-03-25). Prior history exists but only in local branches. 16 | This branch is kept updated using `git cherry-pick` (unless I decide to just 17 | delete the existing history). 18 | 19 | ## General Install Procedures 20 | 21 | ### Tips 22 | 23 | 1. Generate hostId: `head -c4 /dev/urandom | od -A none -t x4` 24 | 25 | ### Installing on a new machine 26 | 27 | 1. Boot installer. 28 | 2. Mount flash drive DATA 29 | 3. Install: 30 | ```bash 31 | mkdir ./mnt 32 | sudo mount /dev/disk/by-label/DATA /home/nixos/mnt 33 | rsync -av mnt/nixos . 34 | cat /home/nixos/mnt/dotfiles/ssh-scotty/.ssh/id_ed25519.pub | sudo tee /root/.ssh/authorized_keys 35 | # OR sudo passwd root 36 | ``` 37 | Login via ssh from another machine (e.g. ssh root@192.168.200.103) 38 | ```bash 39 | nix-shell -p git 40 | mount -o remount,size=8G /run/user/0 ## This is to prevent out of space error during build 41 | # Update device(s) in ~/mnt/nixos/nixos/hosts//disko-config.nix 42 | nix --experimental-features "nix-command flakes" run github:nix-community/disko -- --mode disko /home/nixos/mnt/nixos/nixos/hosts//disko-config.nix 43 | nixos-generate-config --no-filesystems --show-hardware-config --root /mnt --dir /home/nixos/mnt/nixos/nixos/hosts// 44 | nixos-install --flake /home/nixos/mnt/nixos/nixos# 45 | cp -a /home/nixos/mnt/nixos /mnt/home/firecat53/ && chown -R 20000:100 /home/mnt/firecat53/nixos 46 | umount /mnt/boot 47 | umount /mnt 48 | zfs export rpool 49 | systemctl reboot 50 | ``` 51 | 52 | ### Post install 53 | 54 | 1. Change `firecat53` user passwords. 55 | 2. Update sops key after reinstall. Commit and sync then rebuild. 56 | ```bash 57 | nix shell nixpkgs#ssh-to-age nixpkgs#sops 58 | ssh-keyscan | ssh-to-age 59 | # Set `& age.....` in nixos-secrets/.sops.yaml 60 | sops updatekeys nixos-secrets//secrets.yml 61 | sops updatekeys nixos-secrets/common/secrets.yml 62 | git add .sops.yaml / && git commit -m 'Update sops keys' 63 | ``` 64 | 65 | 3. `nix flake update` and rebuild flake on target machine after sops key is updated. 66 | 4. `sudo nmcli connection import type wireguard file /etc/wireguard/wg0.conf` 67 | for laptops/desktops 68 | 5. Update syncthing device ID's if necessary. Re-add servers on phones and 69 | wife's laptop if needed. 70 | 6. `echo nixos/flake.lock > ~/nixos/.stignore` (keep flake.lock from syncing) 71 | 72 | ## Minimal and Base Installs 73 | 74 | 1. See above [[#Installing on a New machine]] 75 | 76 | ## BACKUP server 77 | 78 | 1. See above [[#Installing on a New machine]] 79 | 2. `sudo smbpass -a jamia` 80 | 3. `ssh-keygen -f /etc/ssh/backup && chown backup: /etc/ssh/backup`. Change 81 | authorized_keys backup user in `backups.nix` for applicable machines and 82 | rebuild their flakes. 83 | 4. `sudo -i -u backup ssh -i /etc/ssh/backup ` and accept fingerprint 84 | 85 | ## LAPTOP/OFFICE desktop 86 | 87 | 1. See above [[#Installing on a New machine]] 88 | 2. Login to Vaultwarden 89 | 3. Login to Firefox Sync 90 | 4. Open Syncthing on this machine and other machines. Ensure syncing is setup. 91 | 5. Stow (dotfiles) 92 | ```bash 93 | cd home/firecat53/docs/family/scott/src/dotfiles 94 | stow -t /home/firecat53/ --dotfiles stow/ 95 | stow calibre gomuks music passwords python ssh-scotty 96 | ``` 97 | 6. Add yazi plugins 98 | ```bash 99 | ya pack -a yazi-rs/plugins:git 100 | ya pack -a yazi-rs/plugins:smart-enter 101 | ya pack -a yazi-rs/plugins:toggle-pane 102 | ``` 103 | 104 | ## Homeserver 105 | 106 | 1. TODO 107 | 108 | ## VPS (cloud server) 109 | 110 | 1. Create new (Ubuntu is fine) cloud server. Add one of the public keys. Adjust 111 | DNS 'A' records if needed. 112 | 2. SSH into the new box and update the disk device name(s) and partition layout 113 | in disko-config.nix. 114 | 3. Reboot into the 115 | [nixos-anywhere](https://github.com/nix-community/nixos-anywhere/blob/main/docs/quickstart.md) kexec image 116 | ```bash 117 | curl -L https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-kexec-installer-noninteractive-x86_64-linux.tar.gz | tar -xzf- -C /root /root/kexec/run 118 | ``` 119 | 4. From the laptop, run `nix run github:nix-community/nixos-anywhere -- --flake .#vps root@firecat53.com` 120 | 5. If problems arise, add `--no-reboot` to the above command so you can 121 | troubleshoot the new install. 122 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "System configurations"; 3 | 4 | inputs = { 5 | nixpkgs-unstable.url = "github:nixos/nixpkgs/?shallow=1&ref=nixos-unstable"; 6 | nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; 7 | 8 | disko.url = "github:nix-community/disko"; 9 | disko.inputs.nixpkgs.follows = "nixpkgs"; 10 | 11 | sops-nix.url = "github:Mic92/sops-nix"; 12 | sops-nix.inputs.nixpkgs.follows = "nixpkgs-unstable"; 13 | 14 | home-manager.url = "github:nix-community/home-manager/release-25.05"; 15 | home-manager.inputs.nixpkgs.follows = "nixpkgs"; 16 | 17 | catppuccin.url = "github:catppuccin/nix"; 18 | 19 | newt.url = "github:firecat53/newt"; 20 | newt.inputs.nixpkgs.follows = "nixpkgs-unstable"; 21 | 22 | # Personal project flakes and secrets 23 | 24 | bwm.url = "github:firecat53/bitwarden-menu"; 25 | bwm.inputs.nixpkgs.follows = "nixpkgs"; 26 | 27 | keepmenu.url = "github:firecat53/keepmenu"; 28 | keepmenu.inputs.nixpkgs.follows = "nixpkgs"; 29 | 30 | todocalmenu.url = "github:firecat53/todocalmenu"; 31 | todocalmenu.inputs.nixpkgs.follows = "nixpkgs"; 32 | 33 | urlscan.url = "github:firecat53/urlscan"; 34 | urlscan.inputs.nixpkgs.follows = "nixpkgs"; 35 | 36 | watson-dmenu.url = "github:firecat53/watson-dmenu"; 37 | watson-dmenu.inputs.nixpkgs.follows = "nixpkgs"; 38 | 39 | my-secrets.url = "/home/firecat53/nixos/nixos-secrets"; 40 | my-secrets.flake = false; 41 | 42 | neovim.url = "github:firecat53/nix-neovim"; 43 | neovim.inputs.nixpkgs.follows = "nixpkgs-unstable"; 44 | }; 45 | 46 | outputs = inputs@{ 47 | self, 48 | catppuccin, 49 | disko, 50 | home-manager, 51 | nixpkgs, 52 | nixpkgs-unstable, 53 | sops-nix, 54 | ... 55 | }: let 56 | inherit (self) outputs; 57 | # Helper function to create a nixos system configuration 58 | # Usage: 59 | # Default x86_64: mkSystem { host = "hostname"; }; 60 | # Custom system: mkSystem { host = "hostname"; system = "aarch64-linux"; }; 61 | mkSystem = { host, system ? "x86_64-linux"}: 62 | nixpkgs.lib.nixosSystem { 63 | system = system; 64 | specialArgs = { 65 | inherit inputs outputs; 66 | }; 67 | modules = [ 68 | ./hosts/${host}/configuration.nix 69 | ]; 70 | }; 71 | in { 72 | nixosConfigurations = { 73 | backup = mkSystem { host = "backup";}; 74 | homeserver = mkSystem { host = "homeserver"; }; 75 | laptop = mkSystem { host = "laptop"; }; 76 | office = mkSystem { host = "office"; }; 77 | vps = mkSystem { host = "vps"; }; 78 | minimal = mkSystem { host = "minimal"; }; 79 | base-btrfs = mkSystem { host = "base-btrfs"; }; 80 | base-zfs = mkSystem { host = "base-zfs"; }; 81 | }; 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /home-manager/apps/calibre.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | home.packages = [ 7 | pkgs.calibre 8 | ]; 9 | programs.bash.profileExtra = '' 10 | export CALIBRE_OVERRIDE_DATABASE_PATH=/home/firecat53/.local/tmp/calibre/metadata.db 11 | ''; 12 | } 13 | -------------------------------------------------------------------------------- /home-manager/apps/mbsync.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | sops.secrets.fastmail-imap = { }; 8 | home.packages = [ 9 | pkgs.isync 10 | ]; 11 | 12 | programs.mbsync = { 13 | enable = true; 14 | extraConfig = '' 15 | CopyArrivalDate yes 16 | ''; 17 | }; 18 | services.mbsync = { 19 | enable = true; 20 | frequency = "*:0/2"; 21 | verbose = false; 22 | }; 23 | accounts.email = { 24 | maildirBasePath = "mail"; 25 | accounts."firecat53.net" = { 26 | address = "scott@firecat53.net"; 27 | primary = true; 28 | userName = "scott@firecat53.net"; 29 | passwordCommand = "${pkgs.coreutils}/bin/cat ${config.sops.secrets.fastmail-imap.path}"; 30 | flavor = "fastmail.com"; 31 | aliases = [ 32 | "tech@firecat53.net" 33 | "shopping@firecat53.net" 34 | "bills@firecat53.net" 35 | "health@firecat53.net" 36 | ]; 37 | mbsync = { 38 | enable = true; 39 | create = "both"; 40 | expunge = "both"; 41 | flatten = "."; 42 | patterns = [ "*" ]; 43 | }; 44 | }; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /home-manager/apps/vdirsyncer.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | ... 5 | }: 6 | let 7 | home = "${config.home.homeDirectory}"; 8 | in 9 | { 10 | sops.secrets.nextcloud-caldav-pw = { }; 11 | 12 | programs.vdirsyncer = { 13 | enable = true; 14 | statusPath = "${home}/.cache/vdirsyncer/status/"; 15 | }; 16 | services.vdirsyncer = { 17 | enable = true; 18 | frequency = "*:0/10"; 19 | }; 20 | accounts.calendar.accounts = { 21 | calendars = { 22 | local = { 23 | path = "${home}/docs/family/scott/src/nextcloud/calendars"; 24 | type = "filesystem"; 25 | fileExt = ".ics"; 26 | }; 27 | remote = { 28 | type = "caldav"; 29 | userName = "${config.home.username}"; 30 | passwordCommand = [ 31 | "${pkgs.coreutils}/bin/cat" 32 | "${config.sops.secrets.nextcloud-caldav-pw.path}" 33 | ]; 34 | url = "https://nc.firecat53.com"; 35 | }; 36 | vdirsyncer = { 37 | enable = true; 38 | collections = [ 39 | "from a" 40 | "from b" 41 | ]; 42 | conflictResolution = null; 43 | metadata = [ 44 | "color" 45 | "displayname" 46 | ]; 47 | }; 48 | }; 49 | }; 50 | accounts.contact.accounts = { 51 | contacts = { 52 | local = { 53 | path = "${home}/docs/family/scott/src/nextcloud/contacts"; 54 | type = "filesystem"; 55 | fileExt = ".vcf"; 56 | }; 57 | remote = { 58 | type = "carddav"; 59 | userName = "${config.home.username}"; 60 | passwordCommand = [ 61 | "${pkgs.coreutils}/bin/cat" 62 | "${config.sops.secrets.nextcloud-caldav-pw.path}" 63 | ]; 64 | url = "https://nc.firecat53.com"; 65 | }; 66 | vdirsyncer = { 67 | enable = true; 68 | collections = [ 69 | "from a" 70 | "from b" 71 | ]; 72 | conflictResolution = null; 73 | metadata = [ "displayname" ]; 74 | }; 75 | }; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /home-manager/apps/vscode.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | let 6 | my-python-packages = 7 | ps: with ps; [ 8 | ipython 9 | ipdb 10 | pip 11 | python-lsp-ruff 12 | ]; 13 | in 14 | { 15 | programs.vscode = { 16 | enable = true; 17 | package = pkgs.vscode.fhsWithPackages ( 18 | ps: with ps; [ 19 | clang 20 | gnumake 21 | openssl.dev 22 | pkg-config 23 | (python3.withPackages my-python-packages) 24 | zlib 25 | ] 26 | ); 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /home-manager/base.nix: -------------------------------------------------------------------------------- 1 | { 2 | home.username = "firecat53"; 3 | home.homeDirectory = "/home/firecat53"; 4 | # Let Home Manager install and manage itself. 5 | programs.home-manager.enable = true; 6 | 7 | # This value determines the Home Manager release that your 8 | # configuration is compatible with. This helps avoid breakage 9 | # when a new Home Manager release introduces backwards 10 | # incompatible changes. 11 | # 12 | # You can update Home Manager without changing this value. See 13 | # the Home Manager release notes for a list of state version 14 | # changes in each release. 15 | home.stateVersion = "25.05"; 16 | } 17 | -------------------------------------------------------------------------------- /home-manager/common/aerc.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | { 6 | sops.secrets.fastmail-imap = { }; 7 | programs.aerc = { 8 | enable = true; 9 | extraConfig = { 10 | filters = { 11 | "text/plain" = "colorize"; 12 | "text/calendar" = "calendar"; 13 | "message/delivery-status" = "colorize"; 14 | "message/rfc822" = "colorize"; 15 | "text/html" = "w3m -T text/html -o display_link_number=1"; 16 | }; 17 | general = { 18 | unsafe-accounts-conf = true; 19 | }; 20 | openers = { 21 | "application/pdf" = "zathura"; 22 | }; 23 | ui = { 24 | border-char-vertical = "│"; 25 | border-char-horizontal = "─"; 26 | styleset-name = "catppuccin-mocha"; 27 | }; 28 | }; 29 | 30 | extraBinds = { 31 | global = { 32 | "" = ":prev-tab"; 33 | "" = ":prev-tab"; 34 | "" = ":next-tab"; 35 | "" = ":next-tab"; 36 | "\\[t" = ":prev-tab"; 37 | "\\]t" = ":next-tab"; 38 | "" = ":term"; 39 | "?" = ":help keys"; 40 | "" = ":prompt 'Quit?' quit"; 41 | "" = ":prompt 'Quit?' quit"; 42 | "" = ":suspend"; 43 | }; 44 | 45 | messages = { 46 | "q" = ":prompt 'Quit?' quit"; 47 | "j" = ":next"; 48 | "" = ":next"; 49 | "" = ":next 50%"; 50 | "" = ":next 100%"; 51 | "" = ":next 100%"; 52 | "k" = ":prev"; 53 | "" = ":prev"; 54 | "" = ":prev 50%"; 55 | "" = ":prev 100%"; 56 | "" = ":prev 100%"; 57 | "g" = ":select 0"; 58 | "G" = ":select -1"; 59 | "J" = ":next-folder"; 60 | "" = ":next-folder"; 61 | "K" = ":prev-folder"; 62 | "" = ":prev-folder"; 63 | "H" = ":collapse-folder"; 64 | "" = ":collapse-folder"; 65 | "L" = ":expand-folder"; 66 | "" = ":expand-folder"; 67 | 68 | "v" = ":mark -t"; 69 | "" = ":mark -t:next"; 70 | "V" = ":mark -v"; 71 | 72 | "T" = ":toggle-threads"; 73 | "zc" = ":fold"; 74 | "zo" = ":unfold"; 75 | "za" = ":fold -t"; 76 | "zM" = ":fold -a"; 77 | "zR" = ":unfold -a"; 78 | "" = ":fold -t"; 79 | 80 | "zz" = ":align center"; 81 | "zt" = ":align top"; 82 | "zb" = ":align bottom"; 83 | 84 | "" = ":view"; 85 | "d" = ":choose -o y 'Really delete this message' delete-message"; 86 | "D" = ":delete"; 87 | "a" = ":archive flat"; 88 | "A" = ":unmark -a:mark -T:archive flat"; 89 | 90 | "C" = ":compose"; 91 | "m" = ":compose"; 92 | 93 | "B" = ":bounce"; 94 | 95 | "rr" = ":reply -a"; 96 | "rq" = ":reply -aq"; 97 | "Rr" = ":reply"; 98 | "Rq" = ":reply -q"; 99 | 100 | "c" = ":cf"; 101 | "$" = ":term"; 102 | "!" = ":term"; 103 | "|" = ":pipe"; 104 | 105 | "/" = ":search"; 106 | "\\" = ":filter"; 107 | "n" = ":next-result"; 108 | "N" = ":prev-result"; 109 | "" = ":clear"; 110 | 111 | "s" = ":split"; 112 | "S" = ":vsplit"; 113 | 114 | "pl" = ":patch list"; 115 | "pa" = ":patch apply "; 116 | "pd" = ":patch drop "; 117 | "pb" = ":patch rebase"; 118 | "pt" = ":patch term"; 119 | "ps" = ":patch switch "; 120 | 121 | "b" = ":pipe -s urlscan -d"; 122 | }; 123 | 124 | view = { 125 | "/" = ":toggle-key-passthrough/"; 126 | "q" = ":close"; 127 | "O" = ":open"; 128 | "o" = ":open"; 129 | "S" = ":save"; 130 | "|" = ":pipe"; 131 | "D" = ":delete"; 132 | "A" = ":archive flat"; 133 | 134 | "" = ":open-link "; 135 | 136 | "f" = ":forward"; 137 | "rr" = ":reply -a"; 138 | "rq" = ":reply -aq"; 139 | "Rr" = ":reply"; 140 | "Rq" = ":reply -q"; 141 | 142 | "H" = ":toggle-headers"; 143 | "" = ":prev-part"; 144 | "" = ":prev-part"; 145 | "" = ":next-part"; 146 | "" = ":next-part"; 147 | "J" = ":next"; 148 | "" = ":next"; 149 | "K" = ":prev"; 150 | "" = ":prev"; 151 | 152 | "b" = ":pipe -s urlscan -d"; 153 | }; 154 | 155 | "view::passthrough" = { 156 | "$noinherit" = "true"; 157 | "$ex" = ""; 158 | "" = ":toggle-key-passthrough"; 159 | }; 160 | 161 | compose = { 162 | "$noinherit" = "true"; 163 | "$ex" = ""; 164 | "$complete" = ""; 165 | "" = ":prev-field"; 166 | "" = ":prev-field"; 167 | "" = ":next-field"; 168 | "" = ":next-field"; 169 | "" = ":switch-account -p"; 170 | "" = ":switch-account -p"; 171 | "" = ":switch-account -n"; 172 | "" = ":switch-account -n"; 173 | "" = ":next-field"; 174 | "" = ":prev-field"; 175 | "" = ":prev-tab"; 176 | "" = ":prev-tab"; 177 | "" = ":next-tab"; 178 | "" = ":next-tab"; 179 | }; 180 | 181 | "compose::editor" = { 182 | "$noinherit" = "true"; 183 | "$ex" = ""; 184 | "" = ":prev-field"; 185 | "" = ":prev-field"; 186 | "" = ":next-field"; 187 | "" = ":next-field"; 188 | "" = ":prev-tab"; 189 | "" = ":prev-tab"; 190 | "" = ":next-tab"; 191 | "" = ":next-tab"; 192 | }; 193 | 194 | "compose::review" = { 195 | "y" = ":send"; 196 | "n" = ":abort"; 197 | "v" = ":preview"; 198 | "p" = ":postpone"; 199 | "q" = ":choose -o d discard abort -o p postpone postpone"; 200 | "e" = ":edit"; 201 | "a" = ":attach"; 202 | "d" = ":detach"; 203 | }; 204 | 205 | terminal = { 206 | "$noinherit" = "true"; 207 | "$ex" = ""; 208 | "" = ":prev-tab"; 209 | "" = ":next-tab"; 210 | "" = ":prev-tab"; 211 | "" = ":next-tab"; 212 | }; 213 | }; 214 | }; 215 | 216 | accounts.email = { 217 | accounts.Home = { 218 | address = "scott@firecat53.net"; 219 | primary = true; 220 | aerc = { 221 | enable = true; 222 | extraAccounts = { 223 | address-book-cmd = "khard email --parsable --remove-first-line %s"; 224 | aliases = "tech@firecat53.net,shopping@firecat53.net,bills@firecat53.net,health@firecat53.net"; 225 | copy-to = "Sent"; 226 | default = "Inbox"; 227 | folders-sort = "Inbox"; 228 | from = "Scott Hansen "; 229 | outgoing = "smtps://scott%40firecat53.net@smtp.fastmail.com:465"; 230 | outgoing-cred-cmd = "cat ${config.sops.secrets.fastmail-imap.path}"; 231 | pgp-auto-sign = true; 232 | pgp-key-id = "2BD1E9815C541EA2"; 233 | source = "maildir://~/mail/firecat53.net"; 234 | source-cred-cmd = "cat ${config.sops.secrets.fastmail-imap.path}"; 235 | }; 236 | }; 237 | }; 238 | }; 239 | } 240 | -------------------------------------------------------------------------------- /home-manager/common/bash.nix: -------------------------------------------------------------------------------- 1 | { 2 | # ENV variables 3 | 4 | home.sessionPath = [ 5 | "$HOME/.local/bin" 6 | "/var/lib/flatpak/exports/bin" 7 | ]; 8 | 9 | # Bash config 10 | sops.secrets.hcloud-token = { }; 11 | programs.bash = { 12 | enable = true; 13 | enableCompletion = true; 14 | historyControl = [ 15 | "ignoredups" 16 | "ignorespace" 17 | ]; 18 | profileExtra = '' 19 | systemctl --user import-environment DESKTOP_SESSION 20 | export XDG_DATA_DIRS=$XDG_DATA_DIRS:/var/lib/flatpak/exports/share:$HOME/.local/share/flatpak/exports/share 21 | ''; 22 | shellAliases = { 23 | ".." = "cd .."; 24 | ave = "ansible-vault edit --vault-password-file=/home/firecat53/docs/family/scott/src/ansible/ansible_vault_password.py"; 25 | avv = "ansible-vault view --vault-password-file=/home/firecat53/docs/family/scott/src/ansible/ansible_vault_password.py"; 26 | bu = "et backup -c 'tmux new-session -A -s term'"; 27 | buw = "et firecat53@10.200.200.4 -c 'tmux new-session -A -s term'"; 28 | pclean = "podman ps -a | grep -v 'CONTAINER\|_config\|_data\|_run' | cut -c-12 | xargs podman rm 2>/dev/null"; 29 | piclean = "podman images | grep '' | grep -P '[1234567890abcdef]{12}' -o | xargs -L1 podman rmi 2>/dev/null"; 30 | hmd = "nix store diff-closures $(home-manager generations | head -n2 | awk '{printf \"%s \", $NF}')"; 31 | hmu = "nix flake update $HOME/nixos/nixos/home-manager/ && home-manager switch --flake /home/firecat53/nixos/nixos/home-manager"; 32 | hs = "et homeserver -c 'tmux new-session -A -s term'"; 33 | la = "ls -a --color=auto"; 34 | ll = "ls -l --color=auto"; 35 | lla = "ls -la --color=auto"; 36 | lr = "ls -lR"; 37 | ls = "ls --color=auto"; 38 | lsa = "grep alias ~/.bashrc"; 39 | lsd = "ls -dl */"; 40 | ni = "nix-store --query --requisites ~/.nix-profile | cut -d\- -f2- | sort | bat"; 41 | pas = "pbincli send"; 42 | pg = "ssh -t pangolin tmux new-session -A -s term"; 43 | sd = "sudo systemctl poweroff"; 44 | sdr = "sudo systemctl reboot"; 45 | t = "tmux new-session -A -s term"; 46 | ua = "udiskie-umount -a"; 47 | um = "udiskie-mount"; 48 | uu = "udiskie-umount"; 49 | vps = "et vps -c 'tmux new-session -A -s term'"; 50 | wanip = "curl ipinfo.io/ip"; 51 | }; 52 | initExtra = '' 53 | export HCLOUD_TOKEN=$(cat "$HOME/.config/sops-nix/secrets/hcloud-token") 54 | export MANPAGER='nvim +Man!' 55 | ''; 56 | }; 57 | 58 | ## Bat 59 | programs.bat = { 60 | enable = true; 61 | config = { 62 | style = "plain"; 63 | }; 64 | }; 65 | 66 | ## Fzf 67 | programs.fzf = { 68 | enable = true; 69 | enableBashIntegration = true; 70 | defaultCommand = "fd --type d --hidden --follow --exclude .git -E .cache -E .nvm -E .cargo -E .local/src -E .local/srv/git -E .vscode-oss -E .local/lib -E .vagrant.d -E .local/share/containers -E .nix-defexpr -E .nix-profile -E .local/state"; 71 | changeDirWidgetCommand = "fd --type d --hidden --follow --exclude .git -E .cache -E .nvm -E .cargo -E .local/src -E .local/srv/git -E .vscode-oss -E .local/lib -E .vagrant.d -E .local/share/containers -E .nix-defexpr -E .nix-profile -E .local/state"; 72 | fileWidgetCommand = "fd --type d --hidden --follow --exclude .git -E .cache -E .nvm -E .cargo -E .local/src -E .local/srv/git -E .vscode-oss -E .local/lib -E .vagrant.d -E .local/share/containers -E .nix-defexpr -E .nix-profile -E .local/state"; 73 | tmux.enableShellIntegration = true; 74 | tmux.shellIntegrationOptions = [ "-d 40%" ]; 75 | }; 76 | 77 | ## Starship 78 | programs.starship = { 79 | enable = true; 80 | enableBashIntegration = true; 81 | }; 82 | } 83 | -------------------------------------------------------------------------------- /home-manager/common/bemenu.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.bemenu = { 3 | enable = true; 4 | settings = { 5 | border = 5; 6 | border-radius = 15; 7 | ignorecase = true; 8 | index = 0; 9 | list = 25; 10 | wrap = true; 11 | ab = "#1e1e2e"; 12 | af = "#cdd6f4"; 13 | fb = "#1e1e2e"; 14 | ff = "#cdd6f4"; 15 | hb = "#1e1e2e"; 16 | hf = "#f9e2af"; 17 | nb = "#1e1e2e"; 18 | nf = "#cdd6f4"; 19 | tb = "#1e1e2e"; 20 | tf = "#f38ba8"; 21 | fn = "SauceCodePro Nerd Font 17"; 22 | scrollbar = "autohide"; 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /home-manager/common/calendar.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | let 6 | userHome = "${config.home.homeDirectory}"; 7 | in 8 | { 9 | programs.khal = { 10 | enable = true; 11 | locale = { 12 | timeformat = "%H:%M"; 13 | dateformat = "%Y-%m-%d"; 14 | longdateformat = "%Y-%m-%d"; 15 | datetimeformat = "%Y-%m-%d %H:%M"; 16 | longdatetimeformat = "%Y-%m-%d %H:%M"; 17 | firstweekday = 6; 18 | }; 19 | }; 20 | programs.khard = { 21 | enable = true; 22 | settings = { 23 | "contact table" = { 24 | display = "first_name"; 25 | group_by_addressbook = false; 26 | reverse = false; 27 | show_nicknames = false; 28 | show_uids = true; 29 | sort = "last_name"; 30 | localize_dates = true; 31 | preferred_phone_number_type = [ 32 | "pref" 33 | "cell" 34 | "home" 35 | ]; 36 | preferred_email_address_type = [ 37 | "pref" 38 | "work" 39 | "home" 40 | ]; 41 | }; 42 | general = { 43 | debug = false; 44 | default_action = "list"; 45 | editor = [ 46 | "nvim" 47 | "-i" 48 | "NONE" 49 | ]; 50 | merge_editor = "nvim -d"; 51 | }; 52 | vcard = { 53 | skip_unparsable = false; 54 | }; 55 | }; 56 | }; 57 | 58 | accounts.calendar.accounts = { 59 | calendars = { 60 | khal = { 61 | enable = true; 62 | type = "discover"; 63 | }; 64 | local = { 65 | path = "${userHome}/docs/family/scott/src/nextcloud/calendars"; 66 | type = "filesystem"; 67 | fileExt = ".ics"; 68 | }; 69 | }; 70 | }; 71 | accounts.contact.accounts = { 72 | contacts = { 73 | khard.enable = true; 74 | local = { 75 | path = "${userHome}/docs/family/scott/src/nextcloud/contacts/contacts"; 76 | type = "filesystem"; 77 | fileExt = ".vcf"; 78 | }; 79 | }; 80 | wife = { 81 | khard.enable = true; 82 | local = { 83 | path = "${userHome}/docs/family/scott/src/nextcloud/contacts/wife"; 84 | type = "filesystem"; 85 | fileExt = ".vcf"; 86 | }; 87 | }; 88 | }; 89 | } 90 | -------------------------------------------------------------------------------- /home-manager/common/catppuccin.nix: -------------------------------------------------------------------------------- 1 | { 2 | catppuccin = { 3 | enable = true; 4 | flavor = "mocha"; 5 | accent = "sapphire"; 6 | cursors.enable = true; 7 | cursors.accent = "sapphire"; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /home-manager/common/cursor-editor.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | home.packages = [ 7 | pkgs.code-cursor 8 | ]; 9 | } 10 | -------------------------------------------------------------------------------- /home-manager/common/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./aerc.nix 4 | ./bash.nix 5 | ./bemenu.nix 6 | ./calendar.nix 7 | ./catppuccin.nix 8 | ./cursor-editor.nix 9 | ./fonts.nix 10 | ./foot.nix 11 | ./git.nix 12 | ./gpg.nix 13 | ./imv.nix 14 | ./nix.nix 15 | ./packages.nix 16 | ./ruff.nix 17 | ./ssh.nix 18 | ./tmux.nix 19 | ./udiskie.nix 20 | ./watson.nix 21 | ./xdg.nix 22 | ./yazi.nix 23 | ./ydotool.nix 24 | ./zoxide.nix 25 | ]; 26 | } 27 | -------------------------------------------------------------------------------- /home-manager/common/fonts.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | # Fonts 7 | home.packages = with pkgs; [ 8 | nerd-fonts.sauce-code-pro 9 | corefonts 10 | liberation_ttf 11 | noto-fonts 12 | dejavu_fonts 13 | ]; 14 | fonts.fontconfig.enable = true; 15 | } 16 | -------------------------------------------------------------------------------- /home-manager/common/foot.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.foot = { 3 | enable = true; 4 | server.enable = true; 5 | settings = { 6 | main = { 7 | font = "SauceCodePro Nerd Font:size=17"; 8 | }; 9 | mouse = { 10 | hide-when-typing = "yes"; 11 | }; 12 | }; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /home-manager/common/git.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.git = { 3 | enable = true; 4 | aliases = { 5 | pushRemote = "!git push $(git config --get branch.$(git symbolic-ref HEAD --short).pushRemote) +@:$(git config --get branch.$(git symbolic-ref HEAD --short).merge | awk -F / '{print $NF}')"; 6 | }; 7 | delta.enable = true; 8 | delta.options = { 9 | whitespace-error-style = "22 reverse"; 10 | navigate = true; 11 | }; 12 | extraConfig = { 13 | user = { 14 | name = "Scott Hansen"; 15 | email = "tech@firecat53.net"; 16 | }; 17 | github = { 18 | user = "firecat53"; 19 | }; 20 | init = { 21 | defaultBranch = "main"; 22 | }; 23 | push = { 24 | default = "simple"; 25 | autoSetupRemote = "true"; 26 | followTags = "true"; 27 | }; 28 | pull = { 29 | rebase = "false"; 30 | }; 31 | column = { 32 | ui = "auto"; 33 | }; 34 | branch = { 35 | sort = "-committerdate"; 36 | }; 37 | tag = { 38 | sort = "version:refname"; 39 | }; 40 | diff = { 41 | algorithm = "histogram"; 42 | colorMoved = "plain"; 43 | mnemonicPrefix = "true"; 44 | renames = "true"; 45 | }; 46 | fetch = { 47 | prune = "true"; 48 | pruneTags = "true"; 49 | all = "true"; 50 | }; 51 | }; 52 | ignores = [ 53 | "*.[oa]" 54 | "*~" 55 | "*.swp" 56 | ".~lock*" 57 | "*.pyc" 58 | "*.swo" 59 | ".cache" 60 | ".ropeproject" 61 | "**/doc/tags" 62 | "venv" 63 | ".vscode" 64 | "**/.local/share/containers" 65 | "**_version.py" 66 | "/dist/" 67 | ]; 68 | signing = { 69 | key = "2BD1E9815C541EA2"; 70 | signByDefault = true; 71 | }; 72 | }; 73 | 74 | ## GH github CLI tool 75 | programs.gh = { 76 | enable = true; 77 | settings = { 78 | version = 1; 79 | git_protocol = "ssh"; 80 | aliases = { 81 | co = "pr checkout"; 82 | pv = "pr view"; 83 | }; 84 | }; 85 | }; 86 | 87 | ## gh-dash 88 | programs.gh-dash = { 89 | enable = true; 90 | settings = { 91 | prSections = [ 92 | { 93 | title = "Open PRs"; 94 | filters = "is:open user:firecat53"; 95 | } 96 | { 97 | title = "Needs My Review"; 98 | filters = "is:open review-requested:@me"; 99 | } 100 | { 101 | title = "My PRs"; 102 | filters = "is:open author:@me"; 103 | } 104 | ]; 105 | issuesSections = [ 106 | { 107 | title = "Bitwarden-menu"; 108 | filters = "is:open repo:firecat53/bitwarden-menu"; 109 | } 110 | { 111 | title = "Keepmenu"; 112 | filters = "is:open repo:firecat53/keepmenu"; 113 | } 114 | { 115 | title = "Networkmanager-Dmenu"; 116 | filters = "is:open repo:firecat53/networkmanager-dmenu"; 117 | } 118 | { 119 | title = "Urlscan"; 120 | filters = "is:open repo:firecat53/urlscan"; 121 | } 122 | { 123 | title = "Watson-Dmenu"; 124 | filters = "is:open repo:firecat53/watson-dmenu"; 125 | } 126 | { 127 | title = "Todocalmenu"; 128 | filters = "is:open repo:firecat53/todocalmenu"; 129 | } 130 | { 131 | title = "Todotxtmenu"; 132 | filters = "is:open repo:firecat53/todotxtmenu"; 133 | } 134 | ]; 135 | defaults = { 136 | view = "issues"; 137 | layout = { 138 | issues = { }; 139 | prs = { }; 140 | }; 141 | preview = { 142 | open = true; 143 | width = 60; 144 | }; 145 | }; 146 | pager = { 147 | diff = "delta"; 148 | }; 149 | repoPaths = { 150 | ":owner/:repo" = "~/.local/tmp/:repo"; 151 | "firecat53/*" = "~/docs/family/scott/src/projects/*"; 152 | }; 153 | keybindings = { 154 | issues = [ 155 | { 156 | key = "C"; 157 | command = "gh issue comment {{.IssueNumber}} --repo {{.RepoName}}"; 158 | } 159 | ]; 160 | }; 161 | }; 162 | }; 163 | 164 | } 165 | -------------------------------------------------------------------------------- /home-manager/common/gpg.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | services.gpg-agent = { 7 | enable = true; 8 | defaultCacheTtl = 60480000; 9 | maxCacheTtl = 60480000; 10 | defaultCacheTtlSsh = 60480000; 11 | maxCacheTtlSsh = 60480000; 12 | enableSshSupport = true; 13 | grabKeyboardAndMouse = false; 14 | pinentry.package = pkgs.pinentry-qt; 15 | }; 16 | programs.gpg = { 17 | enable = true; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /home-manager/common/imv.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.imv = { 3 | enable = true; 4 | settings = { 5 | binds = { 6 | n = "next"; 7 | p = "prev"; 8 | v = "overlay"; 9 | "" = "rotate by 90"; 10 | }; 11 | }; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /home-manager/common/nix.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | nix.gc = { 7 | automatic = true; 8 | frequency = "weekly"; 9 | options = "--delete-older-than 7d"; 10 | }; 11 | programs.direnv = { 12 | enable = true; 13 | enableBashIntegration = true; 14 | nix-direnv.enable = true; 15 | }; 16 | home.packages = [ pkgs.unstable.nix-search-tv ]; 17 | programs.bash.shellAliases = { 18 | ns = "nix-search-tv print | fzf --exact --preview 'nix-search-tv preview {}' --scheme history"; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /home-manager/common/packages.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | pkgs, 4 | ... 5 | }: 6 | let 7 | my-python-packages = 8 | ps: with ps; [ 9 | ansible 10 | ansible-core 11 | grip 12 | ipython 13 | ipdb 14 | pip 15 | podman 16 | python-lsp-ruff 17 | ]; 18 | in 19 | { 20 | home.packages = with pkgs; [ 21 | # Terminal tools 22 | age 23 | atool 24 | autossh 25 | bottom 26 | distrobox 27 | dua 28 | eternal-terminal 29 | fd 30 | file 31 | mosh 32 | p7zip 33 | ripgrep 34 | sops 35 | stow 36 | udiskie 37 | unzip 38 | # Terminal applications 39 | bitwarden-cli 40 | exiftool 41 | gomuks 42 | hcloud 43 | home-manager 44 | mediainfo 45 | ncspot 46 | pianobar 47 | sshfs 48 | tabview 49 | todoman 50 | w3m 51 | # Development tools 52 | ctags 53 | highlight 54 | (python3.withPackages my-python-packages) 55 | ruff 56 | tig 57 | uv 58 | # Gui applications 59 | anydesk 60 | inputs.bwm.packages.${pkgs.system}.default 61 | dmenu 62 | electrum 63 | firefox 64 | hunspell 65 | hunspellDicts.en-us-large 66 | imv 67 | keepassxc 68 | inputs.keepmenu.packages.${pkgs.system}.default 69 | libreoffice 70 | mpv 71 | pinentry-qt 72 | resources 73 | ripdrag 74 | simple-scan 75 | spotify 76 | inputs.todocalmenu.packages.${pkgs.system}.default 77 | ungoogled-chromium 78 | inputs.urlscan.packages.${pkgs.system}.default 79 | inputs.watson-dmenu.packages.${pkgs.system}.default 80 | wl-clipboard 81 | zathura 82 | zoom-us 83 | ]; 84 | } 85 | -------------------------------------------------------------------------------- /home-manager/common/ruff.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.ruff = { 3 | enable = true; 4 | settings = { 5 | line-length = 80; 6 | }; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /home-manager/common/ssh.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.ssh = { 3 | enable = true; 4 | controlMaster = "auto"; 5 | controlPath = "~/.ssh/socket-%r@%h:%p"; 6 | controlPersist = "10m"; 7 | matchBlocks = { 8 | "*" = { 9 | host = "*"; 10 | serverAliveInterval = 30; 11 | }; 12 | "home*" = { 13 | host = "home*"; 14 | port = 22; 15 | user = "firecat53"; 16 | identityFile = "~/.ssh/id_ed25519"; 17 | }; 18 | "homeserver*" = { 19 | host = "homeserver*"; 20 | hostname = "lan.firecat53.net"; 21 | }; 22 | "homeserver_wg" = { 23 | localForwards = [ 24 | { 25 | bind.address = "localhost"; 26 | bind.port = 5001; 27 | host.address = "localhost"; 28 | host.port = 5001; 29 | } 30 | ]; 31 | extraOptions = { 32 | StrictHostKeyChecking = "no"; 33 | UserKnownHostsFile = "/dev/null"; 34 | ExitOnForwardFailure = "yes"; 35 | }; 36 | }; 37 | "home" = { 38 | hostname = "192.168.200.101"; 39 | }; 40 | "backup" = { 41 | hostname = "backup"; 42 | user = "firecat53"; 43 | port = 22; 44 | identityFile = "~/.ssh/id_ed25519"; 45 | }; 46 | "vps" = { 47 | hostname = "firecat53.com"; 48 | user = "firecat53"; 49 | port = 22; 50 | identityFile = "~/.ssh/id_ed25519"; 51 | }; 52 | "office" = { 53 | hostname = "office"; 54 | user = "firecat53"; 55 | port = 22; 56 | identityFile = "~/.ssh/id_ed25519"; 57 | }; 58 | "pangolin" = { 59 | hostname = "firecat53.me"; 60 | user = "firecat53"; 61 | port = 22; 62 | identityFile = "~/.ssh/id_ed25519"; 63 | }; 64 | "github" = { 65 | hostname = "github.com"; 66 | user = "git"; 67 | identityFile = "~/.ssh/github_ed25519"; 68 | extraOptions = { 69 | PreferredAuthentications = "publickey"; 70 | }; 71 | }; 72 | "gist" = { 73 | hostname = "gist.github.com"; 74 | user = "git"; 75 | identityFile = "~/.ssh/github_ed25519"; 76 | extraOptions = { 77 | PreferredAuthentications = "publickey"; 78 | }; 79 | }; 80 | "aur" = { 81 | hostname = "aur.archlinux.org"; 82 | user = "aur"; 83 | identityFile = "~/.ssh/aur"; 84 | }; 85 | "router" = { 86 | hostname = "192.168.200.1"; 87 | user = "firecat53"; 88 | port = 22; 89 | identityFile = "~/.ssh/id_ed25519"; 90 | }; 91 | "wg" = { 92 | hostname = "127.0.0.1"; 93 | user = "firecat53"; 94 | port = 2222; 95 | identityFile = "~/.ssh/deluge_ed25519"; 96 | dynamicForwards = [ 97 | { 98 | port = 5001; 99 | } 100 | ]; 101 | proxyJump = "homeserver_wg"; 102 | extraOptions = { 103 | StrictHostKeyChecking = "no"; 104 | UserKnownHostsFile = "/dev/null"; 105 | ExitOnForwardFailure = "yes"; 106 | }; 107 | }; 108 | }; 109 | }; 110 | } 111 | -------------------------------------------------------------------------------- /home-manager/common/tmux.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.tmux = { 3 | enable = true; 4 | baseIndex = 1; 5 | clock24 = true; 6 | escapeTime = 10; 7 | historyLimit = 5000; 8 | keyMode = "vi"; 9 | newSession = true; 10 | shortcut = "a"; 11 | terminal = "tmux-256color"; 12 | extraConfig = '' 13 | set -s copy-command 'wl-copy' 14 | 15 | # Capture URL's from tmux and pass to urlscan 16 | bind-key u capture-pane \; save-buffer /tmp/tmux-buffer \; new-window -n urlscan "urlscan -cd /tmp/tmux-buffer" 17 | 18 | # Last active window 19 | unbind l 20 | bind C-a last-window 21 | bind C-d detach-client 22 | unbind " " 23 | bind " " next-window 24 | bind C-" " next-window 25 | bind C-c new-window 26 | bind C-n next-window 27 | bind C-p previous-window 28 | bind v run "tmux show-buffer | wl-paste > /dev/null" 29 | 30 | # Define sessions 31 | new -s term -n term -d -A 32 | new -s comms -n comms -d -A aerc 33 | new -s music -n music -d -A 34 | ''; 35 | }; 36 | catppuccin.tmux = { 37 | enable = true; 38 | extraConfig = '' 39 | set -g status-left "" 40 | set -g status-right-length 50 41 | set -g status-right "#{E:@catppuccin_status_host}" 42 | set -ga status-right "#{E:@catppuccin_status_uptime}" 43 | set -ga status-right "#{E:@catppuccin_status_date_time}" 44 | 45 | set -g @catppuccin_window_status_style "rounded" 46 | set -g @catppuccin_window_number_position "right" 47 | set -g @catppuccin_window_text " #{window_name}" 48 | 49 | set -g @catppuccin_window_current_text " #{window_name}" 50 | set -g @catppuccin_window_current_text_color "#{@thm_mauve}" 51 | 52 | set -g @catppuccin_status_connect_separator "yes" 53 | ''; 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /home-manager/common/udiskie.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.udiskie = { 3 | enable = true; 4 | tray = "never"; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /home-manager/common/watson.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.watson = { 3 | enable = true; 4 | enableBashIntegration = true; 5 | }; 6 | home.sessionVariables = { 7 | WATSON_DIR = "/home/firecat53/docs/family/scott/src/watson"; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /home-manager/common/xdg.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | xdg = { 8 | enable = true; 9 | }; 10 | 11 | home.packages = [ pkgs.xdg-utils ]; 12 | xdg.mime.enable = true; 13 | 14 | xdg.userDirs = { 15 | enable = true; 16 | desktop = "${config.home.homeDirectory}"; 17 | documents = "${config.home.homeDirectory}/docs"; 18 | download = "${config.home.homeDirectory}/.local/tmp"; 19 | music = "${config.home.homeDirectory}/media/music"; 20 | pictures = "${config.home.homeDirectory}/media/pictures"; 21 | publicShare = "${config.home.homeDirectory}/.local/srv/"; 22 | videos = "${config.home.homeDirectory}/media/videos"; 23 | templates = "${config.home.homeDirectory}/.local/tmp"; 24 | extraConfig = { 25 | XDG_SCREENSHOTS_DIR = "${config.home.homeDirectory}/.local/tmp"; 26 | }; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /home-manager/common/yazi.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | programs.yazi = { 7 | enable = true; 8 | package = pkgs.unstable.yazi; 9 | enableBashIntegration = true; 10 | settings = { 11 | mgr = { 12 | ratio = [ 13 | 1 14 | 3 15 | 4 16 | ]; 17 | }; 18 | opener = { 19 | extract = [ 20 | { 21 | run = "ya pub extract --list \"$@\""; 22 | desc = "Extract here"; 23 | for = "unix"; 24 | } 25 | ]; 26 | }; 27 | plugin.prepend_fetchers = [ 28 | { 29 | id = "git"; 30 | name = "*"; 31 | run = "git"; 32 | } 33 | { 34 | id = "git"; 35 | name = "*/"; 36 | run = "git"; 37 | } 38 | ]; 39 | }; 40 | keymap = { 41 | manager.prepend_keymap = [ 42 | { 43 | run = "close"; 44 | on = "q"; 45 | desc = "Close tab or quit on last tab"; 46 | } 47 | { 48 | run = "shell 'ripdrag -bx \"$@\" 2>/dev/null &' --confirm"; 49 | on = ""; 50 | desc = "Activate ripdrag for current selection"; 51 | } 52 | { 53 | run = "plugin smart-enter"; 54 | on = "l"; 55 | desc = "Enter child directory or open file"; 56 | } 57 | { 58 | run = "plugin smart-enter"; 59 | on = ""; 60 | desc = "Enter child directory or open file"; 61 | } 62 | { 63 | run = "shell $SHELL --block"; 64 | on = "!"; 65 | desc = "Open shell here"; 66 | } 67 | { 68 | run = "plugin toggle-pane max-preview"; 69 | on = "i"; 70 | desc = "Maximize or restore the preview pane"; 71 | } 72 | { 73 | run = "shell 'wl-copy < \"$@\"'"; 74 | on = "C"; 75 | desc = "Copy file contents to clipboard"; 76 | } 77 | ]; 78 | }; 79 | initLua = '' 80 | require("git"):setup() 81 | ''; 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /home-manager/common/ydotool.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | # Note: /dev/uinput needs 'user' group access. Add this to udev rules (or 7 | # system Nix config): 8 | # services.udev.extraRules = '' 9 | # KERNEL=="uinput", GROUP="users", MODE="0660", OPTIONS+="static_node=uinput" 10 | # ''; 11 | systemd.user.services = { 12 | ydotool = { 13 | Unit = { 14 | Description = "Start ydotoold"; 15 | }; 16 | Service = { 17 | ExecStart = "${pkgs.ydotool}/bin/ydotoold"; 18 | }; 19 | }; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /home-manager/common/zoxide.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.zoxide = { 3 | enable = true; 4 | enableBashIntegration = true; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /home-manager/home-manager.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | outputs, 4 | pkgs, 5 | ... 6 | }: 7 | { 8 | # Home-manager configuration 9 | home-manager = { 10 | extraSpecialArgs = { 11 | inherit inputs outputs pkgs; 12 | }; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /home-manager/homeserver.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | inputs, 4 | ... 5 | }: 6 | let 7 | secretspath = builtins.toString inputs.my-secrets; 8 | in 9 | { 10 | imports = [ 11 | ./apps/mbsync.nix 12 | ./apps/vdirsyncer.nix 13 | ]; 14 | 15 | home.username = "firecat53"; 16 | home.homeDirectory = "/home/firecat53"; 17 | 18 | programs.home-manager.enable = true; 19 | 20 | sops = { 21 | age.keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt"; 22 | defaultSopsFile = "${secretspath}/homeserver/secrets.yaml"; 23 | }; 24 | 25 | home.stateVersion = "24.11"; 26 | } 27 | -------------------------------------------------------------------------------- /home-manager/laptop.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | inputs, 4 | ... 5 | }: 6 | let 7 | secretspath = builtins.toString inputs.my-secrets; 8 | in 9 | { 10 | imports = [ 11 | ./apps/calibre.nix 12 | ./apps/vscode.nix 13 | ./common 14 | ./sway 15 | inputs.catppuccin.homeModules.catppuccin 16 | ]; 17 | 18 | home.username = "firecat53"; 19 | home.homeDirectory = "/home/firecat53"; 20 | # Let Home Manager install and manage itself. 21 | programs.home-manager.enable = true; 22 | 23 | sops = { 24 | age.keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt"; 25 | defaultSopsFile = "${secretspath}/laptop/secrets.yaml"; 26 | }; 27 | 28 | # This value determines the Home Manager release that your 29 | # configuration is compatible with. This helps avoid breakage 30 | # when a new Home Manager release introduces backwards 31 | # incompatible changes. 32 | # 33 | # You can update Home Manager without changing this value. See 34 | # the Home Manager release notes for a list of state version 35 | # changes in each release. 36 | home.stateVersion = "24.11"; 37 | } 38 | -------------------------------------------------------------------------------- /home-manager/office.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | inputs, 4 | ... 5 | }: 6 | let 7 | secretspath = builtins.toString inputs.my-secrets; 8 | in 9 | { 10 | imports = [ 11 | ./apps/calibre.nix 12 | ./apps/vscode.nix 13 | ./common 14 | ./sway 15 | inputs.catppuccin.homeModules.catppuccin 16 | ]; 17 | 18 | home.username = "firecat53"; 19 | home.homeDirectory = "/home/firecat53"; 20 | # Let Home Manager install and manage itself. 21 | programs.home-manager.enable = true; 22 | 23 | sops = { 24 | age.keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt"; 25 | defaultSopsFile = "${secretspath}/office/secrets.yaml"; 26 | }; 27 | 28 | # This value determines the Home Manager release that your 29 | # configuration is compatible with. This helps avoid breakage 30 | # when a new Home Manager release introduces backwards 31 | # incompatible changes. 32 | # 33 | # You can update Home Manager without changing this value. See 34 | # the Home Manager release notes for a list of state version 35 | # changes in each release. 36 | home.stateVersion = "24.11"; 37 | } 38 | -------------------------------------------------------------------------------- /home-manager/sway/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./mako.nix 4 | ./packages.nix 5 | ./sway.nix 6 | ./swayimg.nix 7 | ./wallpaper.nix 8 | ]; 9 | } 10 | -------------------------------------------------------------------------------- /home-manager/sway/mako.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | services.mako = { 7 | enable = true; 8 | settings = { 9 | anchor = "top-center"; 10 | font = "Sauce Code Pro 14"; 11 | }; 12 | }; 13 | home.packages = [ pkgs.libnotify ]; 14 | } 15 | -------------------------------------------------------------------------------- /home-manager/sway/packages.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | home.packages = with pkgs; [ 7 | brightnessctl 8 | fuzzel 9 | grim 10 | j4-dmenu-desktop 11 | networkmanager_dmenu 12 | pavucontrol 13 | playerctl 14 | rofi-wayland 15 | shotman 16 | slurp 17 | swayimg 18 | wdisplays 19 | wofi 20 | wtype 21 | xdotool 22 | ydotool 23 | ]; 24 | } 25 | -------------------------------------------------------------------------------- /home-manager/sway/swayimg.nix: -------------------------------------------------------------------------------- 1 | { 2 | home.file.".config/swayimg/config" = { 3 | text = '' 4 | [list] 5 | all=yes 6 | 7 | [keys] 8 | c = exec wl-copy < "%" 9 | C = exec wl-copy "%" 10 | j = next_file 11 | k = prev_file 12 | H = first_file 13 | L = last_file 14 | ''; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /home-manager/sway/wallpaper.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | systemd.user.services = { 8 | wallpaper = { 9 | Unit = { 10 | Description = "Wallpaper switcher"; 11 | ConditionEnvironment = "DESKTOP_SESSION=sway"; 12 | }; 13 | Service = { 14 | Environment = "PATH=$PATH:${ 15 | lib.makeBinPath [ 16 | pkgs.bash 17 | pkgs.coreutils-full 18 | pkgs.fd 19 | pkgs.sway 20 | ] 21 | }"; 22 | ExecStart = "${pkgs.bash}/bin/sh -c 'cp \"$(${pkgs.fd}/bin/fd . -t file $HOME/media/wallpaper | ${pkgs.coreutils-full}/bin/shuf -n 1)\" /tmp/wall.png && ${pkgs.sway}/bin/swaymsg output \"*\" bg /tmp/wall.png fill'"; 23 | }; 24 | }; 25 | }; 26 | systemd.user.timers = { 27 | wallpaper = { 28 | Unit = { 29 | Description = "Wallpaper switcher"; 30 | }; 31 | Timer = { 32 | OnUnitActiveSec = "2m"; 33 | OnBootSec = "1m"; 34 | }; 35 | }; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /hosts/backup/configuration.nix: -------------------------------------------------------------------------------- 1 | # Main configuration 2 | { 3 | inputs, 4 | ... 5 | }: 6 | { 7 | # adjust according to your platform, such as 8 | imports = [ 9 | ./disko-config.nix 10 | ./hardware-configuration.nix 11 | ./services 12 | ../modules/common 13 | ../modules/servers 14 | ../modules/boot.nix 15 | ../modules/zfs.nix 16 | inputs.disko.nixosModules.disko 17 | inputs.sops-nix.nixosModules.sops 18 | ]; 19 | 20 | networking.hostName = "backup"; # Define your hostname. 21 | networking.hostId = "fedd1234"; 22 | networking.useDHCP = false; 23 | networking.firewall.trustedInterfaces = [ "wg0" ]; 24 | systemd.network = { 25 | enable = true; 26 | networks."10-lan" = { 27 | matchConfig.Name = "eno1"; 28 | networkConfig.DHCP = "yes"; 29 | linkConfig.RequiredForOnline = "routable"; 30 | }; 31 | networks."wg0".address = [ "10.200.200.4/24" ]; 32 | }; 33 | 34 | boot.zfs.extraPools = [ "backuppool" ]; 35 | 36 | system.stateVersion = "23.11"; 37 | } 38 | -------------------------------------------------------------------------------- /hosts/backup/disko-config.nix: -------------------------------------------------------------------------------- 1 | { 2 | disko.devices = { 3 | disk = { 4 | main = { 5 | type = "disk"; 6 | device = "/dev/disk/by-id/ata-CT250MX500SSD1_2205E6046CE2"; 7 | content = { 8 | type = "gpt"; 9 | partitions = { 10 | ESP = { 11 | size = "500M"; 12 | type = "EF00"; 13 | content = { 14 | type = "filesystem"; 15 | format = "vfat"; 16 | mountpoint = "/boot"; 17 | }; 18 | }; 19 | zfs = { 20 | end = "-8G"; 21 | content = { 22 | type = "zfs"; 23 | pool = "rpool"; 24 | }; 25 | }; 26 | encryptedSwap = { 27 | size = "100%"; 28 | content = { 29 | type = "swap"; 30 | randomEncryption = true; 31 | }; 32 | }; 33 | }; 34 | }; 35 | }; 36 | }; 37 | zpool = { 38 | rpool = { 39 | type = "zpool"; 40 | mode = ""; 41 | options = { 42 | ashift = "12"; 43 | autotrim = "on"; 44 | }; 45 | rootFsOptions = { 46 | acltype = "posixacl"; 47 | canmount = "off"; 48 | compression = "lz4"; 49 | devices = "off"; 50 | dnodesize = "auto"; 51 | mountpoint = "none"; 52 | normalization = "formD"; 53 | relatime = "on"; 54 | xattr = "sa"; 55 | }; 56 | datasets = { 57 | "nixos" = { 58 | type = "zfs_fs"; 59 | options.mountpoint = "none"; 60 | }; 61 | "nixos/nix" = { 62 | type = "zfs_fs"; 63 | options.mountpoint = "legacy"; 64 | mountpoint = "/nix"; 65 | }; 66 | "nixos/root" = { 67 | type = "zfs_fs"; 68 | options.mountpoint = "legacy"; 69 | mountpoint = "/"; 70 | }; 71 | "reserved" = { 72 | type = "zfs_fs"; 73 | options.mountpoint = "none"; 74 | options.refreservation = "100G"; 75 | }; 76 | }; 77 | }; 78 | }; 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /hosts/backup/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { config, lib, pkgs, modulesPath, ... }: 5 | 6 | { 7 | imports = 8 | [ (modulesPath + "/installer/scan/not-detected.nix") 9 | ]; 10 | 11 | boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usbhid" "sd_mod" ]; 12 | boot.initrd.kernelModules = [ ]; 13 | boot.kernelModules = [ "kvm-intel" ]; 14 | boot.extraModulePackages = [ ]; 15 | 16 | # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 17 | # (the default) this is the recommended approach. When using systemd-networkd it's 18 | # still possible to use this option, but it's recommended to use it in conjunction 19 | # with explicit per-interface declarations with `networking.interfaces..useDHCP`. 20 | networking.useDHCP = lib.mkDefault true; 21 | # networking.interfaces.eno1.useDHCP = lib.mkDefault true; 22 | 23 | nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; 24 | hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 25 | } 26 | -------------------------------------------------------------------------------- /hosts/backup/services/backups.nix: -------------------------------------------------------------------------------- 1 | { 2 | # Backup user for initiating pull backups from other servers 3 | users.users.backup = { 4 | isNormalUser = true; 5 | uid = 20001; 6 | group = "root"; 7 | home = "/var/lib/backup"; 8 | createHome = true; 9 | # password: backup 10 | initialHashedPassword = "$6$Qw7LgzXEL42Q1s0U$UplFl3gpdhQmrmNNHmVt9Bxc4XByH1vBGX95b0ujumaH.V7cPKXkRtqt27vyG591tYfw/0PMkUqplETmswP.t/"; 11 | }; 12 | 13 | ### Sanoid 14 | services.sanoid = { 15 | enable = true; 16 | datasets."backuppool/homeserver/data" = { 17 | useTemplate = [ "data" ]; 18 | process_children_only = true; 19 | recursive = true; 20 | autosnap = false; 21 | autoprune = true; 22 | }; 23 | datasets."backuppool/homeserver/var/lib" = { 24 | useTemplate = [ "data" ]; 25 | process_children_only = false; 26 | autosnap = false; 27 | autoprune = true; 28 | }; 29 | datasets."backuppool/homeserver/downloads" = { 30 | useTemplate = [ "downloads" ]; 31 | process_children_only = false; 32 | }; 33 | datasets."backuppool/vps" = { 34 | useTemplate = [ "data" ]; 35 | process_children_only = true; 36 | recursive = true; 37 | autosnap = false; 38 | autoprune = true; 39 | }; 40 | templates."data" = { 41 | hourly = 48; 42 | daily = 30; 43 | monthly = 6; 44 | yearly = 0; 45 | }; 46 | templates."downloads" = { 47 | hourly = 0; 48 | daily = 2; 49 | monthly = 0; 50 | yearly = 0; 51 | }; 52 | }; 53 | 54 | ### Syncoid 55 | services.syncoid = { 56 | enable = true; 57 | user = "backup"; 58 | sshKey = "/etc/ssh/backup"; 59 | commonArgs = [ 60 | "--no-privilege-elevation" 61 | "--no-sync-snap" 62 | "--sshoption=StrictHostKeyChecking=no" # TODO - one of the systemd hardening options is causing this 63 | ]; 64 | interval = "*-*-* *:30:00"; 65 | commands.backuppool-homeserver-var-lib = { 66 | source = "backup@192.168.200.101:rpool/nixos/var/lib"; 67 | target = "backuppool/homeserver/var/lib"; 68 | }; 69 | commands.backuppool-homeserver-downloads = { 70 | source = "backup@192.168.200.101:downloadpool/downloads"; 71 | target = "backuppool/homeserver/downloads"; 72 | }; 73 | commands.backuppool-homeserver-data = { 74 | source = "backup@192.168.200.101:rpool/data"; 75 | target = "backuppool/homeserver/data"; 76 | recursive = true; 77 | extraArgs = [ 78 | "--skip-parent" 79 | ]; 80 | }; 81 | commands.backuppool-vps = { 82 | source = "backup@firecat53.com:datapool"; 83 | target = "backuppool/vps"; 84 | recursive = true; 85 | extraArgs = [ 86 | "--skip-parent" 87 | ]; 88 | }; 89 | }; 90 | } 91 | -------------------------------------------------------------------------------- /hosts/backup/services/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./backups.nix 4 | ./jamia-backups.nix 5 | ./syncthing.nix 6 | ]; 7 | } 8 | -------------------------------------------------------------------------------- /hosts/backup/services/jamia-backups.nix: -------------------------------------------------------------------------------- 1 | # Note: remember to run smbpasswd -a jamia to add allowed user 2 | { 3 | lib, 4 | pkgs, 5 | ... 6 | }: 7 | { 8 | users.users.jamia = { 9 | isNormalUser = true; 10 | # password: jamia 11 | initialHashedPassword = "$6$k8coMrkwglvFvVkR$JT7GBZ7v/iEtvVAuv9GKlE57ZqP9ztDbPoHfx6v.yYXDYo7YwXpslRqoFzKfzXpTiG6RRwztSRYmCjaiSCR.L1"; 12 | }; 13 | 14 | # Install kopia for looking at backups 15 | environment.systemPackages = with pkgs; [ 16 | kopia 17 | ]; 18 | 19 | # Ensure /home/jamia/backups is mounted at boot. 20 | # Ensure ZFS properties set `canmount=true` and `mountpoint=/home/jamia/backups` 21 | systemd.services.zfs-mount.enable = lib.mkForce true; 22 | } 23 | -------------------------------------------------------------------------------- /hosts/backup/services/syncthing.nix: -------------------------------------------------------------------------------- 1 | # Syncthing 2 | { 3 | services.syncthing = { 4 | enable = true; 5 | user = "firecat53"; 6 | group = "users"; 7 | dataDir = "/home/firecat53/.local/state/syncthing"; 8 | configDir = "/home/firecat53/.config/syncthing"; 9 | openDefaultPorts = true; 10 | settings = { 11 | gui = { 12 | insecureSkipHostcheck = true; 13 | }; 14 | options = { 15 | relaysEnabled = false; 16 | urAccepted = 3; 17 | }; 18 | devices = { 19 | "vps" = { 20 | id = "EPFW7TB-MUV25YB-P2SM66L-ENLRREJ-UJIRELD-QC2FWM4-RVSLFJY-7YWXCQ6"; 21 | addresses = [ 22 | "quic://firecat53.com:22000" 23 | "tcp://firecat53.com:22000" 24 | ]; 25 | }; 26 | "scott-laptop" = { 27 | id = "ERJHQAD-KWQH5ZJ-CAV3ZFL-IR6ECOQ-EHVL7GY-6MY5A5M-IORUVXI-NSBYOQE"; 28 | }; 29 | "scott-office" = { 30 | id = "4L73OQJ-4T6KOAR-5TJLKKY-ANBRCCB-KAOBFM7-LWVGPFK-QQ643GT-H4LIXAH"; 31 | }; 32 | "homeserver" = { 33 | id = "3WS2YZY-BCZNA5N-ZNBCA5G-JNPVFLA-FJQI2VQ-BAM5LK5-UVLWWGM-4DWTRQM"; 34 | }; 35 | }; 36 | folders = { 37 | "nixos" = { 38 | path = "/home/firecat53/nixos"; 39 | devices = [ 40 | "scott-laptop" 41 | "scott-office" 42 | "homeserver" 43 | "vps" 44 | ]; 45 | id = "smqlq-yhrua"; 46 | type = "receiveonly"; 47 | }; 48 | }; 49 | }; 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /hosts/base-btrfs/configuration.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | ... 4 | }: 5 | { 6 | imports = [ 7 | # Include the results of the hardware scan. 8 | ./disko-config.nix 9 | ./hardware-configuration.nix 10 | ../modules/common 11 | ../modules/boot.nix 12 | ../../home-manager/home-manager.nix 13 | inputs.disko.nixosModules.disko 14 | inputs.home-manager.nixosModules.home-manager 15 | inputs.sops-nix.nixosModules.sops 16 | ]; 17 | 18 | home-manager.users.firecat53 = { 19 | imports = [ 20 | ../../home-manager/base.nix 21 | ]; 22 | }; 23 | 24 | networking.hostName = "nixos"; 25 | networking.networkmanager.enable = true; 26 | 27 | # Swap (zram) 28 | zramSwap.enable = true; 29 | 30 | system.stateVersion = "25.05"; 31 | } 32 | -------------------------------------------------------------------------------- /hosts/base-btrfs/disko-config.nix: -------------------------------------------------------------------------------- 1 | { 2 | disko.devices = { 3 | disk = { 4 | main = { 5 | type = "disk"; 6 | device = "CHANGEME"; 7 | content = { 8 | type = "gpt"; 9 | partitions = { 10 | BOOT = { 11 | size = "512M"; 12 | type = "EF00"; 13 | content = { 14 | type = "filesystem"; 15 | format = "vfat"; 16 | mountpoint = "/boot"; 17 | mountOptions = [ "umask=0077" ]; 18 | }; 19 | }; 20 | LUKS = { 21 | size = "100%"; 22 | content = { 23 | type = "luks"; 24 | name = "luks"; 25 | settings = { 26 | allowDiscards = true; 27 | }; 28 | content = { 29 | type = "btrfs"; 30 | extraArgs = [ "-f" ]; 31 | subvolumes = { 32 | "/root" = { 33 | mountpoint = "/"; 34 | mountOptions = [ 35 | "compress=zstd" 36 | "noatime" 37 | ]; 38 | }; 39 | "/home" = { 40 | mountpoint = "/home"; 41 | mountOptions = [ 42 | "compress=zstd" 43 | "noatime" 44 | ]; 45 | }; 46 | "/nix" = { 47 | mountpoint = "/nix"; 48 | mountOptions = [ 49 | "compress=zstd" 50 | "noatime" 51 | ]; 52 | }; 53 | "/swap" = { 54 | mountpoint = "/.swapvol"; 55 | swap.swapfile.size = "CHANGEME"; 56 | }; 57 | }; 58 | }; 59 | }; 60 | }; 61 | }; 62 | }; 63 | }; 64 | }; 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /hosts/base-btrfs/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { config, lib, pkgs, modulesPath, ... }: 5 | 6 | { 7 | imports = 8 | [ (modulesPath + "/installer/scan/not-detected.nix") 9 | ]; 10 | 11 | boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; 12 | boot.initrd.kernelModules = [ ]; 13 | boot.kernelModules = [ "kvm-intel" ]; 14 | boot.extraModulePackages = [ ]; 15 | 16 | # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 17 | # (the default) this is the recommended approach. When using systemd-networkd it's 18 | # still possible to use this option, but it's recommended to use it in conjunction 19 | # with explicit per-interface declarations with `networking.interfaces..useDHCP`. 20 | networking.useDHCP = lib.mkDefault true; 21 | # networking.interfaces.docker0.useDHCP = lib.mkDefault true; 22 | # networking.interfaces.enp0s31f6.useDHCP = lib.mkDefault true; 23 | # networking.interfaces.virbr0.useDHCP = lib.mkDefault true; 24 | # networking.interfaces.wlp0s20f3.useDHCP = lib.mkDefault true; 25 | # networking.interfaces.wwan0.useDHCP = lib.mkDefault true; 26 | 27 | nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; 28 | hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 29 | } 30 | -------------------------------------------------------------------------------- /hosts/base-zfs/configuration.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | ... 4 | }: 5 | { 6 | imports = [ 7 | # Include the results of the hardware scan. 8 | ./disko-config.nix 9 | ./hardware-configuration.nix 10 | ../modules/common 11 | ../modules/boot.nix 12 | ../modules/zfs.nix 13 | ../../home-manager/home-manager.nix 14 | inputs.disko.nixosModules.disko 15 | inputs.home-manager.nixosModules.home-manager 16 | inputs.sops-nix.nixosModules.sops 17 | ]; 18 | 19 | home-manager.users.firecat53 = { 20 | imports = [ 21 | ../../home-manager/base.nix 22 | ]; 23 | }; 24 | 25 | networking.hostName = "nixos"; 26 | networking.hostId = "2ea7c7fb"; 27 | networking.networkmanager.enable = true; 28 | 29 | # Swap (zram) 30 | zramSwap.enable = true; 31 | 32 | system.stateVersion = "25.05"; 33 | } 34 | -------------------------------------------------------------------------------- /hosts/base-zfs/disko-config.nix: -------------------------------------------------------------------------------- 1 | # Update CHANGEME before use. 2 | { 3 | disko.devices = { 4 | disk = { 5 | main = { 6 | type = "disk"; 7 | device = "CHANGEME"; 8 | content = { 9 | type = "gpt"; 10 | partitions = { 11 | EFI = { 12 | size = "512M"; 13 | type = "EF00"; 14 | content = { 15 | type = "filesystem"; 16 | format = "vfat"; 17 | mountpoint = "/boot"; 18 | }; 19 | }; 20 | zfs = { 21 | end = "-8G"; # CHANGEME if necessary. Swap size. 22 | content = { 23 | type = "zfs"; 24 | pool = "rpool"; 25 | }; 26 | }; 27 | encryptedSwap = { 28 | size = "100%"; 29 | content = { 30 | type = "swap"; 31 | randomEncryption = true; 32 | }; 33 | }; 34 | }; 35 | }; 36 | }; 37 | }; 38 | zpool = { 39 | rpool = { 40 | type = "zpool"; 41 | mode = ""; 42 | options = { 43 | ashift = "12"; 44 | autotrim = "on"; 45 | }; 46 | rootFsOptions = { 47 | acltype = "posixacl"; 48 | canmount = "off"; 49 | compression = "on"; 50 | devices = "off"; 51 | dnodesize = "auto"; 52 | encryption = "on"; 53 | keyformat = "passphrase"; 54 | keylocation = "prompt"; 55 | mountpoint = "none"; 56 | normalization = "formD"; 57 | relatime = "on"; 58 | xattr = "sa"; 59 | }; 60 | datasets = { 61 | "nixos" = { 62 | type = "zfs_fs"; 63 | options.mountpoint = "none"; 64 | }; 65 | "nixos/nix" = { 66 | type = "zfs_fs"; 67 | options.mountpoint = "legacy"; 68 | mountpoint = "/nix"; 69 | }; 70 | "nixos/root" = { 71 | type = "zfs_fs"; 72 | options.mountpoint = "legacy"; 73 | mountpoint = "/"; 74 | }; 75 | "nixos/var" = { 76 | type = "zfs_fs"; 77 | options.mountpoint = "none"; 78 | }; 79 | "nixos/var/lib" = { 80 | type = "zfs_fs"; 81 | options.mountpoint = "legacy"; 82 | mountpoint = "/var/lib"; 83 | }; 84 | "nixos/var/lib/containers" = { 85 | type = "zfs_fs"; 86 | options.mountpoint = "none"; 87 | }; 88 | "nixos/var/lib/containers/storage" = { 89 | type = "zfs_fs"; 90 | options.mountpoint = "none"; 91 | }; 92 | "nixos/var/lib/containers/storage/volumes" = { 93 | type = "zfs_fs"; 94 | options.mountpoint = "legacy"; 95 | mountpoint = "/var/lib/containers/storage/volumes"; 96 | }; 97 | "data" = { 98 | type = "zfs_fs"; 99 | options.mountpoint = "none"; 100 | }; 101 | "data/home" = { 102 | type = "zfs_fs"; 103 | options.mountpoint = "legacy"; 104 | mountpoint = "/home"; 105 | }; 106 | "reserved" = { 107 | type = "zfs_fs"; 108 | options.mountpoint = "none"; 109 | options.refreservation = "10G"; 110 | }; 111 | }; 112 | }; 113 | }; 114 | }; 115 | } 116 | -------------------------------------------------------------------------------- /hosts/base-zfs/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { config, lib, pkgs, modulesPath, ... }: 5 | 6 | { 7 | imports = 8 | [ (modulesPath + "/installer/scan/not-detected.nix") 9 | ]; 10 | 11 | boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; 12 | boot.initrd.kernelModules = [ ]; 13 | boot.kernelModules = [ "kvm-intel" ]; 14 | boot.extraModulePackages = [ ]; 15 | 16 | # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 17 | # (the default) this is the recommended approach. When using systemd-networkd it's 18 | # still possible to use this option, but it's recommended to use it in conjunction 19 | # with explicit per-interface declarations with `networking.interfaces..useDHCP`. 20 | networking.useDHCP = lib.mkDefault true; 21 | # networking.interfaces.docker0.useDHCP = lib.mkDefault true; 22 | # networking.interfaces.enp0s31f6.useDHCP = lib.mkDefault true; 23 | # networking.interfaces.virbr0.useDHCP = lib.mkDefault true; 24 | # networking.interfaces.wlp0s20f3.useDHCP = lib.mkDefault true; 25 | # networking.interfaces.wwan0.useDHCP = lib.mkDefault true; 26 | 27 | nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; 28 | hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 29 | } 30 | -------------------------------------------------------------------------------- /hosts/homeserver/configuration.nix: -------------------------------------------------------------------------------- 1 | # Main configuration 2 | { 3 | inputs, 4 | pkgs, 5 | ... 6 | }: 7 | { 8 | # adjust according to your platform, such as 9 | imports = [ 10 | ./hardware-configuration.nix 11 | ./services 12 | ../modules/common 13 | ../modules/servers 14 | ../modules/avahi.nix 15 | ../modules/libvirt.nix 16 | ../modules/newt.nix 17 | ../modules/podman.nix 18 | ../modules/zfs.nix 19 | ../../home-manager/home-manager.nix 20 | inputs.home-manager.nixosModules.home-manager 21 | inputs.sops-nix.nixosModules.sops 22 | ]; 23 | 24 | home-manager.users.firecat53 = { 25 | imports = [ 26 | inputs.sops-nix.homeManagerModule 27 | ../../home-manager/homeserver.nix 28 | ]; 29 | }; 30 | 31 | networking.hostName = "homeserver"; # Define your hostname. 32 | networking.hostId = "abcd1234"; 33 | networking.firewall.trustedInterfaces = [ "wg0" ]; 34 | networking.useDHCP = false; 35 | 36 | systemd.network = { 37 | enable = true; 38 | netdevs = { 39 | "20-br0" = { 40 | netdevConfig = { 41 | Kind = "bridge"; 42 | Name = "br0"; 43 | }; 44 | }; 45 | }; 46 | networks = { 47 | "30-enp4s0" = { 48 | matchConfig.Name = "enp4s0"; 49 | networkConfig.Bridge = "br0"; 50 | linkConfig.RequiredForOnline = "enslaved"; 51 | }; 52 | "40-br0" = { 53 | matchConfig.Name = "br0"; 54 | address = [ "192.168.200.101/24" ]; 55 | gateway = [ "192.168.200.1" ]; 56 | dns = [ "192.168.200.1" ]; 57 | bridgeConfig = { }; 58 | linkConfig = { 59 | RequiredForOnline = "routable"; 60 | }; 61 | }; 62 | "wg0".address = [ "10.200.200.6/24" ]; 63 | }; 64 | }; 65 | 66 | ### apcupsd 67 | services.apcupsd.enable = true; 68 | 69 | ### Add extra ssh-key homeserver_ed25519.pub (needed for autossh tunnel) 70 | users.users.firecat53.openssh.authorizedKeys.keys = [ 71 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFhp4/kDcUTbR1wmIqBgGV4L+7lhfJFA2LYP6fxbjbpl ed25519-key-20180530" 72 | ]; 73 | 74 | ### Add extra media packages 75 | users.users.firecat53 = { 76 | packages = with pkgs; [ 77 | exiftool 78 | ffmpeg 79 | gdu 80 | mediainfo 81 | par2cmdline 82 | unrar 83 | ]; 84 | }; 85 | 86 | system.stateVersion = "23.11"; 87 | } 88 | -------------------------------------------------------------------------------- /hosts/homeserver/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Edit this configuration file to define what should be installed on 2 | # your system. Help is available in the configuration.nix(5) man page 3 | # and in the NixOS manual (accessible by running ‘nixos-help’). 4 | { 5 | config, 6 | lib, 7 | modulesPath, 8 | pkgs, 9 | ... 10 | }: 11 | let 12 | zfsRoot.partitionScheme = { 13 | biosBoot = "-part5"; 14 | efiBoot = "-part1"; 15 | swap = "-part4"; 16 | bootPool = "-part2"; 17 | rootPool = "-part3"; 18 | }; 19 | zfsRoot.devNodes = "/dev/disk/by-id/"; # MUST have trailing slash! /dev/disk/by-id/ 20 | zfsRoot.bootDevices = (import ./machine.nix).bootDevices; 21 | zfsRoot.mirroredEfi = "/boot/efis/"; 22 | in 23 | { 24 | imports = [ 25 | (modulesPath + "/installer/scan/not-detected.nix") 26 | ]; 27 | nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; 28 | hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 29 | hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 30 | 31 | boot.initrd.availableKernelModules = [ 32 | "ahci" 33 | "xhci_pci" 34 | "virtio_pci" 35 | "virtio_blk" 36 | "ehci_pci" 37 | "nvme" 38 | "uas" 39 | "sd_mod" 40 | "sr_mod" 41 | "sdhci_pci" 42 | ]; 43 | boot.initrd.kernelModules = [ ]; 44 | boot.kernelModules = [ 45 | "kvm-intel" 46 | "kvm-amd" 47 | ]; 48 | boot.extraModulePackages = [ ]; 49 | boot.tmp.useTmpfs = true; 50 | 51 | fileSystems = 52 | { 53 | "/" = { 54 | device = "rpool/nixos/root"; 55 | fsType = "zfs"; 56 | options = [ "X-mount.mkdir" ]; 57 | }; 58 | 59 | "/home" = { 60 | device = "rpool/data/home"; 61 | fsType = "zfs"; 62 | options = [ "X-mount.mkdir" ]; 63 | }; 64 | 65 | "/var/lib" = { 66 | device = "rpool/nixos/var/lib"; 67 | fsType = "zfs"; 68 | options = [ "X-mount.mkdir" ]; 69 | }; 70 | 71 | "/var/lib/containers/storage" = { 72 | device = "rpool/nixos/var/lib/containers/storage"; 73 | fsType = "zfs"; 74 | options = [ "X-mount.mkdir" ]; 75 | }; 76 | 77 | "/var/lib/containers/storage/volumes" = { 78 | device = "rpool/data/podman_volumes"; 79 | fsType = "zfs"; 80 | options = [ "X-mount.mkdir" ]; 81 | }; 82 | 83 | "/var/log" = { 84 | device = "rpool/nixos/var/log"; 85 | fsType = "zfs"; 86 | options = [ "X-mount.mkdir" ]; 87 | }; 88 | 89 | "/boot" = { 90 | device = "bpool/nixos/root"; 91 | fsType = "zfs"; 92 | options = [ "X-mount.mkdir" ]; 93 | }; 94 | 95 | "/mnt/media/audiobooks" = { 96 | device = "rpool/data/audiobooks"; 97 | fsType = "zfs"; 98 | options = [ "X-mount.mkdir" ]; 99 | }; 100 | 101 | "/mnt/media/cameras" = { 102 | device = "rpool/data/cameras"; 103 | fsType = "zfs"; 104 | options = [ "X-mount.mkdir" ]; 105 | }; 106 | 107 | "/mnt/media/cameras-peggy" = { 108 | device = "rpool/data/cameras-peggy"; 109 | fsType = "zfs"; 110 | options = [ "X-mount.mkdir" ]; 111 | }; 112 | 113 | "/mnt/media/ebooks" = { 114 | device = "rpool/data/ebooks"; 115 | fsType = "zfs"; 116 | options = [ "X-mount.mkdir" ]; 117 | }; 118 | 119 | "/mnt/media/music" = { 120 | device = "rpool/data/music"; 121 | fsType = "zfs"; 122 | options = [ "X-mount.mkdir" ]; 123 | }; 124 | 125 | "/mnt/media/pictures" = { 126 | device = "rpool/data/pictures"; 127 | fsType = "zfs"; 128 | options = [ "X-mount.mkdir" ]; 129 | }; 130 | 131 | "/mnt/media/video" = { 132 | device = "rpool/data/video"; 133 | fsType = "zfs"; 134 | options = [ "X-mount.mkdir" ]; 135 | }; 136 | 137 | "/mnt/media/wallpaper" = { 138 | device = "rpool/data/wallpaper"; 139 | fsType = "zfs"; 140 | options = [ "X-mount.mkdir" ]; 141 | }; 142 | 143 | "/srv" = { 144 | device = "rpool/data/srv"; 145 | fsType = "zfs"; 146 | options = [ "X-mount.mkdir" ]; 147 | }; 148 | 149 | "/var/backups" = { 150 | device = "rpool/data/var_backups"; 151 | fsType = "zfs"; 152 | options = [ "X-mount.mkdir" ]; 153 | }; 154 | 155 | "/mnt/downloads" = { 156 | device = "downloadpool/downloads"; 157 | fsType = "zfs"; 158 | options = [ "X-mount.mkdir" ]; 159 | }; 160 | "/mnt/restic" = { 161 | device = "/dev/disk/by-label/RESTIC"; 162 | fsType = "exfat"; 163 | options = [ "X-mount.mkdir" ]; 164 | }; 165 | } 166 | // (builtins.listToAttrs ( 167 | map (diskName: { 168 | name = zfsRoot.mirroredEfi + diskName + zfsRoot.partitionScheme.efiBoot; 169 | value = { 170 | device = zfsRoot.devNodes + diskName + zfsRoot.partitionScheme.efiBoot; 171 | fsType = "vfat"; 172 | options = [ 173 | "x-systemd.idle-timeout=1min" 174 | "x-systemd.automount" 175 | "noauto" 176 | "nofail" 177 | ]; 178 | }; 179 | }) zfsRoot.bootDevices 180 | )); 181 | 182 | swapDevices = map (diskName: { 183 | device = zfsRoot.devNodes + diskName + zfsRoot.partitionScheme.swap; 184 | discardPolicy = "both"; 185 | randomEncryption = { 186 | enable = true; 187 | allowDiscards = true; 188 | }; 189 | }) zfsRoot.bootDevices; 190 | 191 | boot.supportedFilesystems = [ "zfs" ]; 192 | boot.loader.efi.efiSysMountPoint = 193 | with builtins; 194 | (zfsRoot.mirroredEfi + (head zfsRoot.bootDevices) + zfsRoot.partitionScheme.efiBoot); 195 | boot.zfs.extraPools = [ "backup" ]; 196 | boot.zfs.devNodes = zfsRoot.devNodes; 197 | boot.loader.efi.canTouchEfiVariables = false; 198 | boot.loader.generationsDir.copyKernels = true; 199 | boot.loader.grub.efiInstallAsRemovable = true; 200 | boot.loader.grub.enable = true; 201 | boot.loader.grub.copyKernels = true; 202 | boot.loader.grub.configurationLimit = 15; 203 | boot.loader.grub.efiSupport = true; 204 | boot.loader.grub.zfsSupport = true; 205 | boot.loader.grub.extraInstallCommands = 206 | with builtins; 207 | (toString ( 208 | map ( 209 | diskName: 210 | "${pkgs.coreutils-full}/bin/cp -r " 211 | + config.boot.loader.efi.efiSysMountPoint 212 | + "/EFI" 213 | + " " 214 | + zfsRoot.mirroredEfi 215 | + diskName 216 | + zfsRoot.partitionScheme.efiBoot 217 | + "\n" 218 | ) (tail zfsRoot.bootDevices) 219 | )); 220 | boot.loader.grub.devices = map (diskName: zfsRoot.devNodes + diskName) zfsRoot.bootDevices; 221 | } 222 | -------------------------------------------------------------------------------- /hosts/homeserver/machine.nix: -------------------------------------------------------------------------------- 1 | { 2 | bootDevices = [ 3 | "nvme-eui.ace42e0026eed9c82ee4ac0000000001" 4 | "nvme-eui.ace42e0035b8defe2ee4ac0000000001" 5 | ]; 6 | } 7 | -------------------------------------------------------------------------------- /hosts/homeserver/services/akkoma.nix: -------------------------------------------------------------------------------- 1 | # akkoma 2 | { 3 | config, 4 | pkgs, 5 | ... 6 | }: 7 | { 8 | services.akkoma = { 9 | enable = true; 10 | config = { 11 | ":pleroma" = { 12 | ":instance" = { 13 | name = "firecat53 akkoma"; 14 | email = "scott@firecat53.net"; 15 | description = "Akkoma server"; 16 | registration_open = false; 17 | }; 18 | "Pleroma.Web.Endpoint" = { 19 | url.host = "s.firecat53.net"; 20 | http.ip = "127.0.0.1"; 21 | http.port = 4000; 22 | }; 23 | "Pleroma.Web.WebFinger" = { 24 | domain = "firecat53.net"; 25 | }; 26 | # Strips GPS, deduplicates and anonymizes filenames for uploaded files 27 | "Pleroma.Upload".filters = map (pkgs.formats.elixirConf { }).lib.mkRaw [ 28 | "Pleroma.Upload.Filter.Exiftool" 29 | "Pleroma.Upload.Filter.Dedupe" 30 | "Pleroma.Upload.Filter.AnonymizeFilename" 31 | ]; 32 | }; 33 | }; 34 | # use default ffmpeg instead of the module default ffmpeg_5 35 | extraPackages = with pkgs; [ 36 | exiftool 37 | ffmpeg-headless 38 | graphicsmagick-imagemagick-compat 39 | ]; 40 | }; 41 | services.traefik.dynamicConfigOptions.http = { 42 | middlewares.well-known-redirect.redirectRegex = { 43 | regex = "^https://(.*)/.well-known/(webfinger|nodeinfo|host-meta)(\\?.*)?$"; 44 | replacement = "https://s.$1/.well-known/$2$3"; 45 | permanent = true; 46 | }; 47 | routers = { 48 | akkoma = { 49 | rule = "Host(`s.firecat53.net`)"; 50 | service = "akkoma"; 51 | middlewares = [ "headers" ]; 52 | entrypoints = [ "websecure" ]; 53 | tls.certResolver = "le"; 54 | }; 55 | well-known-redirect = { 56 | rule = "Host(`firecat53.net`)"; 57 | service = "dummy-well-known"; 58 | middlewares = [ 59 | "headers" 60 | "well-known-redirect" 61 | ]; 62 | entrypoints = [ "websecure" ]; 63 | tls.certResolver = "le"; 64 | }; 65 | }; 66 | services = { 67 | akkoma.loadBalancer.servers = [ 68 | { 69 | url = "http://localhost:4000"; 70 | } 71 | ]; 72 | 73 | dummy-well-known.loadBalancer.servers = [ 74 | { 75 | # Redirect to nginx 76 | url = "http://localhost:${builtins.toString config.services.nginx.defaultHTTPListenPort}"; 77 | } 78 | ]; 79 | }; 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /hosts/homeserver/services/audiobookshelf.nix: -------------------------------------------------------------------------------- 1 | # Audiobookshelf 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | services.audiobookshelf = { 8 | package = pkgs.audiobookshelf; 9 | enable = true; 10 | user = "firecat53"; 11 | group = "users"; 12 | dataDir = "audiobookshelf"; 13 | }; 14 | services.traefik.dynamicConfigOptions.http.routers.audiobookshelf = { 15 | rule = "Host(`books.lan.firecat53.net`)"; 16 | service = "audiobookshelf"; 17 | middlewares = [ "headers" ]; 18 | entrypoints = [ "websecure" ]; 19 | tls = { 20 | certResolver = "le"; 21 | }; 22 | }; 23 | services.traefik.dynamicConfigOptions.http.services.audiobookshelf = { 24 | loadBalancer = { 25 | servers = [ 26 | { 27 | url = "http://localhost:8000"; 28 | } 29 | ]; 30 | }; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /hosts/homeserver/services/backups.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | { 6 | # Backup user for pull backups from backup server 7 | users.users.backup = { 8 | isNormalUser = true; 9 | uid = 20001; 10 | group = "root"; 11 | home = "/var/lib/backup"; 12 | createHome = true; 13 | openssh.authorizedKeys.keys = [ 14 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDd+gF2w6+0Rj9XFl9e8NcWRux5dKsyAMcgoM6KDH11E backup@backup" 15 | ]; 16 | }; 17 | # Postgres backup 18 | services.postgresqlBackup = { 19 | enable = true; 20 | location = "/var/backups"; 21 | backupAll = true; 22 | }; 23 | # Mysql/maridb backup 24 | services.mysqlBackup = { 25 | enable = true; 26 | location = "/var/backups"; 27 | databases = [ 28 | "nextcloud" 29 | ]; 30 | singleTransaction = true; 31 | user = "root"; 32 | }; 33 | # Sanoid 34 | services.sanoid = { 35 | enable = true; 36 | datasets."rpool/data" = { 37 | useTemplate = [ "data" ]; 38 | process_children_only = true; 39 | recursive = true; 40 | }; 41 | datasets."rpool/nixos/var/lib" = { 42 | useTemplate = [ "data" ]; 43 | process_children_only = false; 44 | recursive = false; 45 | }; 46 | datasets."backup" = { 47 | # Prune local backups 48 | useTemplate = [ "backup" ]; 49 | process_children_only = true; 50 | recursive = true; 51 | }; 52 | datasets."downloadpool" = { 53 | useTemplate = [ "downloads" ]; 54 | process_children_only = true; 55 | recursive = true; 56 | }; 57 | templates."data" = { 58 | hourly = 48; 59 | daily = 30; 60 | monthly = 6; 61 | yearly = 0; 62 | autosnap = true; 63 | autoprune = true; 64 | }; 65 | templates."backup" = { 66 | hourly = 48; 67 | daily = 30; 68 | monthly = 6; 69 | yearly = 0; 70 | autosnap = false; 71 | autoprune = true; 72 | }; 73 | templates."downloads" = { 74 | hourly = 0; 75 | daily = 2; 76 | monthly = 0; 77 | yearly = 0; 78 | autosnap = true; 79 | autoprune = true; 80 | }; 81 | }; 82 | 83 | ### Syncoid 84 | ## `backup` pool (for all data except `downloads`) 85 | services.syncoid = { 86 | enable = true; 87 | commonArgs = [ 88 | "--no-privilege-elevation" 89 | "--no-sync-snap" 90 | ]; 91 | service = { 92 | after = [ "sanoid.service" ]; 93 | wants = [ "sanoid.service" ]; 94 | serviceConfig = { 95 | Type = "oneshot"; 96 | }; 97 | }; 98 | commands.backup-data = { 99 | source = "rpool/data"; 100 | target = "backup"; 101 | service = { 102 | before = [ "syncoid-backup-var-lib.service" ]; 103 | }; 104 | recursive = true; 105 | extraArgs = [ 106 | "--skip-parent" 107 | ]; 108 | }; 109 | commands.backup-var-lib = { 110 | source = "rpool/nixos/var/lib"; 111 | target = "backup/var_lib"; 112 | service = { 113 | after = [ "syncoid-backup-data.service" ]; 114 | wants = [ "syncoid-backup-data.service" ]; 115 | }; 116 | recursive = false; 117 | extraArgs = [ 118 | "--skip-parent" 119 | ]; 120 | }; 121 | }; 122 | 123 | ### Restic 124 | sops.secrets.restic_env = { }; 125 | sops.secrets.restic_repo = { }; 126 | sops.secrets.restic_password = { }; 127 | sops.secrets.restic_local_repo = { }; 128 | sops.secrets.restic_local_password = { }; 129 | 130 | services.restic = { 131 | backups.homeserver = { 132 | user = "root"; 133 | environmentFile = "${config.sops.secrets.restic_env.path}"; 134 | repositoryFile = "${config.sops.secrets.restic_repo.path}"; 135 | passwordFile = "${config.sops.secrets.restic_password.path}"; 136 | paths = [ 137 | "/home" 138 | "/mnt/media" 139 | "/srv" 140 | "/var/backups" 141 | "/var/lib" 142 | ]; 143 | exclude = [ 144 | "/var/lib/containers/*" 145 | "!/var/lib/containers/storage" 146 | "/var/lib/containers/storage/*" 147 | "!/var/lib/containers/storage/volumes" 148 | ]; 149 | timerConfig = { 150 | OnBootSec = "15m"; 151 | OnCalendar = "daily"; 152 | Persistent = true; 153 | }; 154 | pruneOpts = [ 155 | "--keep-monthly 6" 156 | "--keep-weekly 12" 157 | "--keep-daily 30" 158 | ]; 159 | extraBackupArgs = [ 160 | "--retry-lock 30m" 161 | ]; 162 | checkOpts = [ 163 | "--with-cache" 164 | "--read-data-subset=1%" 165 | ]; 166 | }; 167 | backups.local = { 168 | user = "root"; 169 | environmentFile = "${config.sops.secrets.restic_env.path}"; 170 | repositoryFile = "${config.sops.secrets.restic_local_repo.path}"; 171 | passwordFile = "${config.sops.secrets.restic_local_password.path}"; 172 | paths = [ 173 | "/home" 174 | "/mnt/media" 175 | "/srv" 176 | "/var/backups" 177 | "/var/lib" 178 | ]; 179 | exclude = [ 180 | "/var/lib/containers/*" 181 | "!/var/lib/containers/storage" 182 | "/var/lib/containers/storage/*" 183 | "!/var/lib/containers/storage/volumes" 184 | "/var/lib/private/open-webui/*" 185 | ]; 186 | timerConfig = { 187 | OnBootSec = "15m"; 188 | OnCalendar = "daily"; 189 | Persistent = true; 190 | }; 191 | pruneOpts = [ 192 | "--keep-monthly 6" 193 | "--keep-weekly 12" 194 | "--keep-daily 30" 195 | ]; 196 | extraBackupArgs = [ 197 | "--retry-lock 30m" 198 | ]; 199 | checkOpts = [ 200 | "--with-cache" 201 | "--read-data-subset=1%" 202 | ]; 203 | }; 204 | }; 205 | } 206 | -------------------------------------------------------------------------------- /hosts/homeserver/services/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./akkoma.nix 4 | ./audiobookshelf.nix 5 | ./backups.nix 6 | ./gollum.nix 7 | ./hass.nix 8 | ./immich.nix 9 | ./jackett.nix 10 | ./jellyfin.nix 11 | ./lidarr.nix 12 | ./lubelogger.nix 13 | ./miniflux.nix 14 | ./misc.nix 15 | ./nextcloud.nix 16 | ./nginx.nix 17 | ./openwebui.nix 18 | ./peggy.nix 19 | ./qbittorrent.nix 20 | ./radarr.nix 21 | ./sabnzbd.nix 22 | ./samba.nix 23 | ./sonarr.nix 24 | ./stirling-pdf.nix 25 | ./syncthing.nix 26 | ./traefik.nix 27 | ./transmission.nix 28 | ./uptime-kuma.nix 29 | ./vaultwarden.nix 30 | ]; 31 | } 32 | -------------------------------------------------------------------------------- /hosts/homeserver/services/gollum.nix: -------------------------------------------------------------------------------- 1 | # Gollum 2 | { 3 | config, 4 | ... 5 | }: 6 | { 7 | services.gollum = { 8 | enable = true; 9 | user = "firecat53"; 10 | group = "users"; 11 | stateDir = "/home/firecat53/docs/family/scott/wiki"; 12 | emoji = true; 13 | branch = "main"; 14 | allowUploads = "page"; 15 | address = "127.0.0.1"; 16 | }; 17 | # These next four lines are to work around a bug in the gollum module when a user other than `gollum` is assigned 18 | users.groups = { 19 | gollum = { }; 20 | }; 21 | users.users.gollum.isSystemUser = true; 22 | users.users.gollum.group = "gollum"; 23 | systemd.tmpfiles.rules = [ 24 | "d '${config.services.gollum.stateDir}' - ${config.users.users.firecat53.name} ${config.users.groups.users.name} - -" 25 | ]; 26 | services.traefik.dynamicConfigOptions.http.routers.gollum = { 27 | rule = "Host(`gollum.lan.firecat53.net`)"; 28 | service = "gollum"; 29 | middlewares = [ 30 | "auth" 31 | "headers" 32 | ]; 33 | entrypoints = [ "websecure" ]; 34 | tls = { 35 | certResolver = "le"; 36 | }; 37 | }; 38 | services.traefik.dynamicConfigOptions.http.services.gollum = { 39 | loadBalancer = { 40 | servers = [ 41 | { 42 | url = "http://localhost:4567"; 43 | } 44 | ]; 45 | }; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /hosts/homeserver/services/hass.nix: -------------------------------------------------------------------------------- 1 | # Home Assistant - VM behind Traefik 2 | { 3 | services.traefik.dynamicConfigOptions.http.routers.hass = { 4 | rule = "Host(`hass.lan.firecat53.net`)"; 5 | service = "hass"; 6 | middlewares = [ "headers" ]; 7 | entrypoints = [ "websecure" ]; 8 | tls = { 9 | certResolver = "le"; 10 | }; 11 | }; 12 | services.traefik.dynamicConfigOptions.http.services.hass = { 13 | loadBalancer = { 14 | servers = [ 15 | { 16 | url = "http://192.168.200.102:8123"; 17 | } 18 | ]; 19 | }; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /hosts/homeserver/services/immich.nix: -------------------------------------------------------------------------------- 1 | # Immich 2 | { 3 | services.immich = { 4 | accelerationDevices = null; # Access all devices 5 | enable = true; 6 | group = "users"; 7 | machine-learning.enable = true; 8 | mediaLocation = "/mnt/media/immich"; 9 | settings = null; 10 | user = "immich"; 11 | }; 12 | services.immich-public-proxy = { 13 | enable = true; 14 | port = 3030; 15 | immichUrl = "http://localhost:2283"; 16 | }; 17 | 18 | # Allow hardware transcoding 19 | users.users.immich.extraGroups = [ "render" ]; 20 | 21 | services.traefik.dynamicConfigOptions.http.routers.immich = { 22 | rule = "Host(`pics.lan.firecat53.net`)"; 23 | service = "immich"; 24 | middlewares = [ "headers" ]; 25 | entrypoints = [ "websecure" ]; 26 | tls = { 27 | certResolver = "le"; 28 | }; 29 | }; 30 | services.traefik.dynamicConfigOptions.http.services.immich = { 31 | loadBalancer = { 32 | servers = [ 33 | { 34 | url = "http://localhost:2283"; 35 | } 36 | ]; 37 | }; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /hosts/homeserver/services/jackett.nix: -------------------------------------------------------------------------------- 1 | # Jackett 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | services.jackett = { 8 | package = pkgs.jackett; 9 | enable = true; 10 | user = "firecat53"; 11 | group = "users"; 12 | dataDir = "/var/lib/jackett"; 13 | }; 14 | # Disable failing tests (2025-01-15) 15 | nixpkgs.overlays = [ 16 | (final: prev: { 17 | jackett = prev.jackett.overrideAttrs { doCheck = false; }; 18 | }) 19 | ]; 20 | services.traefik.dynamicConfigOptions.http.routers.jackett = { 21 | rule = "Host(`jackett.lan.firecat53.net`)"; 22 | service = "jackett"; 23 | middlewares = [ "headers" ]; 24 | entrypoints = [ "websecure" ]; 25 | tls = { 26 | certResolver = "le"; 27 | }; 28 | }; 29 | services.traefik.dynamicConfigOptions.http.services.jackett = { 30 | loadBalancer = { 31 | servers = [ 32 | { 33 | url = "http://localhost:9117"; 34 | } 35 | ]; 36 | }; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /hosts/homeserver/services/jellyfin.nix: -------------------------------------------------------------------------------- 1 | # Jellyfin 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | services.jellyfin = { 8 | enable = true; 9 | user = "firecat53"; 10 | group = "users"; 11 | }; 12 | 13 | users.users.firecat53.extraGroups = [ "render" ]; 14 | networking.firewall.allowedUDPPorts = [ 15 | 1900 16 | 7359 17 | ]; 18 | 19 | ## Enable OpenGL hardware transcoding for Jellyfin 20 | nixpkgs.config.packageOverrides = pkgs: { 21 | vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; }; 22 | }; 23 | hardware.graphics = { 24 | enable = true; 25 | extraPackages = with pkgs; [ 26 | intel-media-driver 27 | vaapiIntel 28 | vaapiVdpau 29 | libvdpau-va-gl 30 | intel-compute-runtime 31 | ]; 32 | }; 33 | 34 | services.traefik.dynamicConfigOptions.http.routers.jellyfin = { 35 | rule = "Host(`jellyfin.lan.firecat53.net`)"; 36 | service = "jellyfin"; 37 | middlewares = [ "headers" ]; 38 | entrypoints = [ "websecure" ]; 39 | tls = { 40 | certResolver = "le"; 41 | }; 42 | }; 43 | services.traefik.dynamicConfigOptions.http.services.jellyfin = { 44 | loadBalancer = { 45 | servers = [ 46 | { 47 | url = "http://localhost:8096"; 48 | } 49 | ]; 50 | }; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /hosts/homeserver/services/lidarr.nix: -------------------------------------------------------------------------------- 1 | # Lidarr 2 | { 3 | services.lidarr = { 4 | enable = true; 5 | user = "firecat53"; 6 | group = "users"; 7 | dataDir = "/var/lib/lidarr"; 8 | }; 9 | services.traefik.dynamicConfigOptions.http.routers.lidarr = { 10 | rule = "Host(`lidarr.lan.firecat53.net`)"; 11 | service = "lidarr"; 12 | middlewares = [ "headers" ]; 13 | entrypoints = [ "websecure" ]; 14 | tls = { 15 | certResolver = "le"; 16 | }; 17 | }; 18 | services.traefik.dynamicConfigOptions.http.services.lidarr = { 19 | loadBalancer = { 20 | servers = [ 21 | { 22 | url = "http://localhost:8686"; 23 | } 24 | ]; 25 | }; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /hosts/homeserver/services/lubelogger.nix: -------------------------------------------------------------------------------- 1 | ### Lubelogger 2 | { 3 | virtualisation.oci-containers.containers.lubelogger = { 4 | image = "ghcr.io/hargata/lubelogger:latest"; 5 | autoStart = true; 6 | user = "1000:100"; 7 | ports = [ "8881:8080" ]; 8 | environment = { 9 | LC_ALL = "en_US.UTF-8"; 10 | LANG = "en_US.UTF-8"; 11 | LOGGING__LOGLEVEL__DEFAULT = "Error"; 12 | }; 13 | extraOptions = [ 14 | "--init=true" 15 | "--label=traefik.enable=true" 16 | "--label=traefik.http.routers.lubelogger.rule=Host(`cars.lan.firecat53.net`)" 17 | "--label=traefik.http.routers.lubelogger.entrypoints=websecure" 18 | "--label=traefik.http.routers.lubelogger.tls.certResolver=le" 19 | "--label=traefik.http.routers.lubelogger.middlewares=headers@file" 20 | "--label=traefik.http.services.lubelogger.loadbalancer.server.port=8080" 21 | ]; 22 | volumes = [ 23 | "/var/lib/lubelogger/config:/App/config" 24 | "/var/lib/lubelogger/data:/App/data" 25 | "/var/lib/lubelogger/translations:/App/wwwroot/translations" 26 | "/var/lib/lubelogger/documents:/App/wwwroot/documents" 27 | "/var/lib/lubelogger/images:/App/wwwroot/images" 28 | "/var/lib/lubelogger/temp:/App/wwwroot/temp" 29 | "/var/lib/lubelogger/log:/App/log" 30 | "/var/lib/lubelogger/keys:/root/.aspnet/DataProtection-Keys" 31 | ]; 32 | }; 33 | 34 | # Create lubelogger config directory 35 | systemd.tmpfiles.rules = [ 36 | "d /var/lib/lubelogger/config 0700 firecat53 users - " 37 | "d /var/lib/lubelogger/data 0700 firecat53 users - " 38 | "d /var/lib/lubelogger/translations 0700 firecat53 users - " 39 | "d /var/lib/lubelogger/documents 0700 firecat53 users - " 40 | "d /var/lib/lubelogger/images 0700 firecat53 users - " 41 | "d /var/lib/lubelogger/temp 0700 firecat53 users - " 42 | "d /var/lib/lubelogger/log 0700 firecat53 users - " 43 | "d /var/lib/lubelogger/keys 0700 firecat53 users - " 44 | ]; 45 | } 46 | -------------------------------------------------------------------------------- /hosts/homeserver/services/miniflux.nix: -------------------------------------------------------------------------------- 1 | # Miniflux 2 | { 3 | config, 4 | ... 5 | }: 6 | { 7 | sops.secrets.miniflux-env = { }; 8 | services.miniflux = { 9 | enable = true; 10 | config = { 11 | LISTEN_ADDR = "localhost:8085"; 12 | POLLING_FREQUENCY = "15"; 13 | }; 14 | adminCredentialsFile = "${config.sops.secrets.miniflux-env.path}"; 15 | }; 16 | 17 | services.traefik.dynamicConfigOptions.http.routers.miniflux = { 18 | rule = "Host(`rss.lan.firecat53.net`)"; 19 | service = "miniflux"; 20 | middlewares = [ "headers" ]; 21 | entrypoints = [ "websecure" ]; 22 | tls = { 23 | certResolver = "le"; 24 | }; 25 | }; 26 | services.traefik.dynamicConfigOptions.http.services.miniflux = { 27 | loadBalancer = { 28 | servers = [ 29 | { 30 | url = "http://localhost:8085"; 31 | } 32 | ]; 33 | }; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /hosts/homeserver/services/misc.nix: -------------------------------------------------------------------------------- 1 | # 1. Memories RSS feed 2 | # 2. Picture copy service for cameras 3 | { 4 | pkgs, 5 | ... 6 | }: 7 | { 8 | systemd.timers."memories" = { 9 | wantedBy = [ "timers.target" ]; 10 | timerConfig = { 11 | OnCalendar = "daily"; 12 | OnBootSec = "5m"; 13 | Unit = "memories.service"; 14 | }; 15 | }; 16 | systemd.services."memories" = { 17 | script = '' 18 | ${pkgs.podman}/bin/podman run --rm \ 19 | -v /home/firecat53/docs/family/scott/wiki/diary:/data/journal \ 20 | -v /mnt/media/pictures/Family\ Pictures:/data/pictures \ 21 | -v /srv/rss:/srv/rss \ 22 | memories 23 | ''; 24 | path = [ 25 | pkgs.podman 26 | pkgs.zfs 27 | ]; 28 | }; 29 | systemd.timers."picture_copy" = { 30 | enable = true; 31 | wantedBy = [ "timers.target" ]; 32 | timerConfig = { 33 | OnBootSec = "5m"; 34 | OnUnitActiveSec = "3h"; 35 | Unit = "picture_copy.service"; 36 | }; 37 | }; 38 | systemd.services."picture_copy" = { 39 | script = '' 40 | set +e 41 | ${pkgs.exiftool}/bin/exiftool -o . '-Directory/dev/null 42 | ${pkgs.exiftool}/bin/exiftool -o . '-Directory/dev/null 43 | ''; 44 | path = [ pkgs.exiftool ]; 45 | serviceConfig = { 46 | User = "firecat53"; 47 | SuccessExitStatus = [ 1 ]; # Exiftool errors on file exists when it tries to copy 48 | WorkingDirectory = "/home/firecat53/.local/tmp/untagged"; 49 | }; 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /hosts/homeserver/services/nextcloud.nix: -------------------------------------------------------------------------------- 1 | # Nextcloud 2 | { 3 | config, 4 | lib, 5 | pkgs, 6 | ... 7 | }: 8 | { 9 | sops.secrets.nextcloud-admin-password = { 10 | mode = "0440"; 11 | owner = config.users.users.nextcloud.name; 12 | group = config.users.users.nextcloud.group; 13 | }; 14 | users.users.nextcloud.extraGroups = [ 15 | "render" 16 | "users" 17 | ]; 18 | 19 | environment.systemPackages = with pkgs; [ 20 | nodejs_20 # required for Recognize 21 | ffmpeg # required for Memories 22 | ]; 23 | # Allow using /dev/dri for Memories 24 | systemd.services.phpfpm-nextcloud.serviceConfig = { 25 | PrivateDevices = lib.mkForce false; 26 | }; 27 | 28 | services.nginx.virtualHosts."nc.firecat53.net".listen = [ 29 | { 30 | addr = "127.0.0.1"; 31 | port = 8180; 32 | } 33 | ]; 34 | 35 | services.nextcloud = { 36 | enable = true; 37 | package = pkgs.nextcloud31; 38 | hostName = "nc.firecat53.net"; 39 | database.createLocally = true; 40 | configureRedis = true; 41 | appstoreEnable = true; 42 | config = { 43 | adminuser = "firecat53"; 44 | adminpassFile = "${config.sops.secrets.nextcloud-admin-password.path}"; 45 | dbtype = "mysql"; 46 | }; 47 | settings = { 48 | default_phone_region = "US"; 49 | mail_smtpmode = "sendmail"; 50 | mail_sendmailmode = "pipe"; 51 | mysql.utf8mb4 = true; 52 | memories.exiftool = "${lib.getExe pkgs.exiftool}"; 53 | memories.vod.ffmpeg = "${lib.getExe pkgs.ffmpeg-headless}"; 54 | memories.vod.ffprobe = "${pkgs.ffmpeg-headless}/bin/ffprobe"; 55 | preview_ffmpeg_path = "${pkgs.ffmpeg-headless}/bin/ffmpeg"; 56 | trusted_proxies = [ "127.0.0.1" ]; 57 | }; 58 | maxUploadSize = "10G"; # also sets post_max_size and memory_limit 59 | phpOptions = { 60 | "opcache.interned_strings_buffer" = "16"; 61 | }; 62 | }; 63 | 64 | services.traefik.dynamicConfigOptions.http.routers.nextcloud = { 65 | rule = "Host(`nc.firecat53.net`)"; 66 | service = "nextcloud"; 67 | middlewares = [ "headers" ]; 68 | entrypoints = [ "websecure" ]; 69 | tls = { 70 | certResolver = "le"; 71 | }; 72 | }; 73 | services.traefik.dynamicConfigOptions.http.services.nextcloud = { 74 | loadBalancer = { 75 | servers = [ 76 | { 77 | url = "http://localhost:8180"; 78 | } 79 | ]; 80 | }; 81 | }; 82 | 83 | systemd.timers."nextcloud-files-update" = { 84 | wantedBy = [ "timers.target" ]; 85 | timerConfig = { 86 | OnBootSec = "2m"; 87 | OnUnitActiveSec = "15m"; 88 | Unit = "nextcloud-files-update.service"; 89 | }; 90 | }; 91 | systemd.services."nextcloud-files-update" = { 92 | bindsTo = [ 93 | "mysql.service" 94 | "phpfpm-nextcloud.service" 95 | ]; 96 | after = [ 97 | "mysql.service" 98 | "phpfpm-nextcloud.service" 99 | ]; 100 | script = '' 101 | ${config.services.nextcloud.occ}/bin/nextcloud-occ files:scan -q --all 102 | ${config.services.nextcloud.occ}/bin/nextcloud-occ preview:pre-generate 103 | ''; 104 | serviceConfig = { 105 | User = "nextcloud"; 106 | }; 107 | path = [ 108 | "config.services.nextcloud" 109 | pkgs.perl 110 | ]; 111 | }; 112 | systemd.services."nextcloud-cron" = { 113 | path = [ pkgs.perl ]; 114 | }; 115 | 116 | ## Collabora (Nextcloud Office) 117 | virtualisation.oci-containers.containers.collabora = { 118 | image = "docker.io/collabora/code"; 119 | autoStart = true; 120 | environment = { 121 | aliasgroup1 = "https://nc.firecat53.net:443"; 122 | extra_params = "--o:ssl.enable=false --o:ssl.termination=true --o:mount_namespaces=false"; 123 | }; 124 | extraOptions = [ 125 | "--cap-add=MKNOD" 126 | "--label=traefik.enable=true" 127 | "--label=traefik.http.routers.collabora.rule=Host(`office.firecat53.net`) && (PathPrefix(`/lool`) || PathPrefix(`/cool`) || PathPrefix(`/browser`) || PathPrefix(`/hosting/discovery`) || PathPrefix(`/hosting/capabilities`) || PathPrefix(`/loleaflet`))" 128 | "--label=traefik.http.routers.collabora.entrypoints=websecure" 129 | "--label=traefik.http.routers.collabora.tls.certResolver=le" 130 | "--label=traefik.http.routers.collabora.middlewares=headers@file" 131 | "--label=traefik.http.services.collabora.loadbalancer.server.port=9980" 132 | ]; 133 | }; 134 | } 135 | -------------------------------------------------------------------------------- /hosts/homeserver/services/nginx.nix: -------------------------------------------------------------------------------- 1 | # Nginx 2 | { 3 | services.nginx = { 4 | enable = true; 5 | defaultHTTPListenPort = 8080; 6 | virtualHosts."lan.firecat53.net" = { 7 | locations."/misc/" = { 8 | alias = "/srv/http/"; 9 | }; 10 | locations."/rss/" = { 11 | alias = "/srv/rss/"; 12 | }; 13 | }; 14 | }; 15 | services.traefik.dynamicConfigOptions.http.routers.nginx = { 16 | rule = "Host(`lan.firecat53.net`) && ((PathPrefix(`/misc`) || PathPrefix(`/rss`)))"; 17 | service = "nginx"; 18 | middlewares = [ "headers" ]; 19 | entrypoints = [ "websecure" ]; 20 | tls = { 21 | certResolver = "le"; 22 | }; 23 | }; 24 | services.traefik.dynamicConfigOptions.http.services.nginx = { 25 | loadBalancer = { 26 | servers = [ 27 | { 28 | url = "http://localhost:8080"; 29 | } 30 | ]; 31 | }; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /hosts/homeserver/services/openwebui.nix: -------------------------------------------------------------------------------- 1 | # Open-WebUI 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | services.open-webui = { 8 | package = pkgs.unstable.open-webui; 9 | enable = true; 10 | port = 8083; 11 | }; 12 | services.traefik.dynamicConfigOptions.http.routers.openwebui = { 13 | rule = "Host(`ai.lan.firecat53.net`)"; 14 | service = "openwebui"; 15 | middlewares = [ "headers" ]; 16 | entrypoints = [ "websecure" ]; 17 | tls = { 18 | certResolver = "le"; 19 | }; 20 | }; 21 | services.traefik.dynamicConfigOptions.http.services.openwebui = { 22 | loadBalancer = { 23 | servers = [ 24 | { 25 | url = "http://localhost:8083"; 26 | } 27 | ]; 28 | }; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /hosts/homeserver/services/peggy.nix: -------------------------------------------------------------------------------- 1 | # Peggy camera backups 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | fileSystems = { 8 | "/mnt/media/cameras-peggy" = { 9 | device = "rpool/data/cameras-peggy"; 10 | fsType = "zfs"; 11 | options = [ "X-mount.mkdir" ]; 12 | }; 13 | }; 14 | 15 | systemd.timers."picture_copy_peggy" = { 16 | enable = true; 17 | wantedBy = [ "timers.target" ]; 18 | timerConfig = { 19 | OnBootSec = "5m"; 20 | OnUnitActiveSec = "3h"; 21 | Unit = "picture_copy_peggy.service"; 22 | }; 23 | }; 24 | systemd.services."picture_copy_peggy" = { 25 | script = '' 26 | ${pkgs.exiftool}/bin/exiftool -o . '-Directory/dev/null 27 | ''; 28 | path = [ pkgs.exiftool ]; 29 | serviceConfig = { 30 | User = "firecat53"; 31 | SuccessExitStatus = [ 1 ]; # Exiftool errors on file exists when it tries to copy 32 | WorkingDirectory = "/home/firecat53/.local/tmp/untagged-peggy"; 33 | }; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /hosts/homeserver/services/qbittorrent.nix: -------------------------------------------------------------------------------- 1 | ### Qbittorrent + wireguard + socks-proxy 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | systemd.services.pod-wireguard = { 8 | description = "Start podman 'wg' pod"; 9 | wants = [ "network-online.target" ]; 10 | after = [ "network-online.target" ]; 11 | requiredBy = [ 12 | "podman-wireguard-client.service" 13 | "podman-qbitorrent.service" 14 | "podman-socks-proxy.service" 15 | ]; 16 | unitConfig = { 17 | RequiresMountsFor = "/run/containers"; 18 | }; 19 | serviceConfig = { 20 | Type = "oneshot"; 21 | ExecStart = "-${pkgs.podman}/bin/podman pod create -p 8081:8081 -p 2222:22 wg"; 22 | }; 23 | path = [ 24 | pkgs.zfs 25 | pkgs.podman 26 | ]; 27 | }; 28 | virtualisation.oci-containers.containers.qbittorrent = { 29 | image = "qbittorrent"; 30 | autoStart = true; 31 | user = "1000:100"; 32 | dependsOn = [ "wireguard-client" ]; 33 | environment = { 34 | QBT_WEBUI_PORT = "8081"; 35 | }; 36 | extraOptions = [ 37 | "--init=true" 38 | "--network=container:wireguard-client" 39 | "--pod=wg" 40 | "--label=traefik.enable=true" 41 | "--label=traefik.http.routers.qbittorrent.rule=Host(`qbt.lan.firecat53.net`)" 42 | "--label=traefik.http.routers.qbittorrent.entrypoints=websecure" 43 | "--label=traefik.http.routers.qbittorrent.tls.certResolver=le" 44 | "--label=traefik.http.routers.qbittorrent.middlewares=headers@file" 45 | "--label=traefik.http.services.qbittorrent.loadbalancer.server.port=8081" 46 | ]; 47 | volumes = [ 48 | "qbittorrent_config:/config" 49 | "/mnt/downloads:/data" 50 | ]; 51 | }; 52 | # Firewall opening for the socks-proxy 53 | networking.firewall.allowedTCPPorts = [ 2222 ]; 54 | virtualisation.oci-containers.containers.socks-proxy = { 55 | image = "socks-proxy"; 56 | autoStart = true; 57 | dependsOn = [ "wireguard-client" ]; 58 | extraOptions = [ 59 | "--pod=wg" 60 | "--network=container:wireguard-client" 61 | ]; 62 | }; 63 | virtualisation.oci-containers.containers.wireguard-client = { 64 | image = "wireguard-client"; 65 | autoStart = true; 66 | volumes = [ "wireguard_config:/etc/wireguard" ]; 67 | environment = { 68 | LOCAL_NETWORKS = "10.200.200.0/24,192.168.200.0/24"; 69 | }; 70 | extraOptions = [ 71 | "--cap-add=NET_ADMIN" 72 | "--cap-add=NET_RAW" 73 | "--dns=172.16.0.1" 74 | "--pod=wg" 75 | ]; 76 | }; 77 | # For wireguard-client 78 | boot.kernel.sysctl."net.ipv4.conf.all.src_valid_mark" = 1; 79 | 80 | # For monitoring the podman containers 81 | virtualisation.oci-containers.containers.podman-exporter = { 82 | image = "podman-exporter"; 83 | autoStart = true; 84 | ports = [ "9882:9882" ]; 85 | volumes = [ "/run/podman/podman.sock:/run/podman/podman.sock" ]; 86 | environment = { 87 | CONTAINER_HOST = "unix:///run/podman/podman.sock"; 88 | }; 89 | }; 90 | } 91 | -------------------------------------------------------------------------------- /hosts/homeserver/services/radarr.nix: -------------------------------------------------------------------------------- 1 | # Radarr 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | services.radarr = { 8 | package = pkgs.radarr; 9 | enable = true; 10 | user = "firecat53"; 11 | group = "users"; 12 | dataDir = "/var/lib/radarr"; 13 | }; 14 | services.traefik.dynamicConfigOptions.http.routers.radarr = { 15 | rule = "Host(`radarr.lan.firecat53.net`)"; 16 | service = "radarr"; 17 | middlewares = [ "headers" ]; 18 | entrypoints = [ "websecure" ]; 19 | tls = { 20 | certResolver = "le"; 21 | }; 22 | }; 23 | services.traefik.dynamicConfigOptions.http.services.radarr = { 24 | loadBalancer = { 25 | servers = [ 26 | { 27 | url = "http://localhost:7878"; 28 | } 29 | ]; 30 | }; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /hosts/homeserver/services/sabnzbd.nix: -------------------------------------------------------------------------------- 1 | # Sabnzbd 2 | { 3 | config, 4 | lib, 5 | pkgs, 6 | ... 7 | }: 8 | { 9 | services.sabnzbd = { 10 | package = pkgs.sabnzbd; 11 | enable = true; 12 | }; 13 | # Override sabnzbd default 14 | systemd.tmpfiles.rules = [ 15 | "d /var/lib/sabnzbd 0700 firecat53 users - " 16 | ]; 17 | # The user/group option handling is broken and the default 8080 port conflicts with other services. 18 | # I also changed the service type to simple instead of forking so the logs show up in the journal. 19 | systemd.services.sabnzbd.serviceConfig = { 20 | Type = lib.mkForce "simple"; 21 | User = lib.mkForce "firecat53"; 22 | Group = lib.mkForce "users"; 23 | ExecStart = lib.mkForce "${config.services.sabnzbd.package}/bin/sabnzbd -f ${config.services.sabnzbd.configFile} -s 127.0.0.1:8090"; 24 | }; 25 | services.traefik.dynamicConfigOptions.http.routers.sabnzbd = { 26 | rule = "Host(`sabnzbd.lan.firecat53.net`)"; 27 | service = "sabnzbd"; 28 | middlewares = [ "headers" ]; 29 | entrypoints = [ "websecure" ]; 30 | tls = { 31 | certResolver = "le"; 32 | }; 33 | }; 34 | services.traefik.dynamicConfigOptions.http.services.sabnzbd = { 35 | loadBalancer = { 36 | servers = [ 37 | { 38 | url = "http://localhost:8090"; 39 | } 40 | ]; 41 | }; 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /hosts/homeserver/services/samba.nix: -------------------------------------------------------------------------------- 1 | # Note: remember to run smbpasswd -a to add allowed users 2 | { 3 | systemd.tmpfiles.rules = [ 4 | "d /var/lib/samba/private 0755 root root - " 5 | "d /var/log/samba/ 0755 root root - " 6 | ]; 7 | services.samba = { 8 | enable = true; 9 | openFirewall = true; 10 | settings = { 11 | global = { 12 | workgroup = "HOME"; 13 | "server string" = "homeserver"; 14 | "netbios name" = "homeserver"; 15 | "hosts allow" = "192.168.200. 10.200.200. 127.0.0.1 localhost"; 16 | "hosts deny" = "0.0.0.0/0"; 17 | "guest account" = "nobody"; 18 | "map to guest" = "bad user"; 19 | security = "user"; 20 | }; 21 | homes = { 22 | comment = "Home directories"; 23 | "valid users" = "%S"; 24 | browseable = "no"; 25 | writeable = "yes"; 26 | "read only" = "no"; 27 | }; 28 | media = { 29 | comment = "Family Media"; 30 | path = "/mnt/media"; 31 | browseable = "yes"; 32 | public = "yes"; 33 | "read only" = "yes"; 34 | "guest ok" = "yes"; 35 | "force user" = "firecat53"; 36 | "force group" = "users"; 37 | printable = "no"; 38 | writable = "no"; 39 | "write list" = "firecat53"; 40 | }; 41 | downloads = { 42 | comment = "Downloaded Media"; 43 | path = "/mnt/downloads"; 44 | "valid users" = "firecat53, chryspie"; 45 | browseable = "yes"; 46 | writeable = "yes"; 47 | "read only" = "no"; 48 | public = "no"; 49 | }; 50 | }; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /hosts/homeserver/services/sonarr.nix: -------------------------------------------------------------------------------- 1 | # Sonarr 2 | { 3 | # Sonarr broken in 24.11 due to delayed sonarr update to .NET 8 4 | # nixpkgs.config.permittedInsecurePackages = [ 5 | # "dotnet-runtime-wrapped-6.0.36" 6 | # "aspnetcore-runtime-6.0.36" 7 | # "aspnetcore-runtime-wrapped-6.0.36" 8 | # "dotnet-sdk-6.0.428" 9 | # "dotnet-sdk-wrapped-6.0.428" 10 | # ]; 11 | 12 | services.sonarr = { 13 | enable = true; 14 | user = "firecat53"; 15 | group = "users"; 16 | dataDir = "/var/lib/sonarr"; 17 | }; 18 | services.traefik.dynamicConfigOptions.http.routers.sonarr = { 19 | rule = "Host(`sonarr.lan.firecat53.net`)"; 20 | service = "sonarr"; 21 | middlewares = [ "headers" ]; 22 | entrypoints = [ "websecure" ]; 23 | tls = { 24 | certResolver = "le"; 25 | }; 26 | }; 27 | services.traefik.dynamicConfigOptions.http.services.sonarr = { 28 | loadBalancer = { 29 | servers = [ 30 | { 31 | url = "http://localhost:8989"; 32 | } 33 | ]; 34 | }; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /hosts/homeserver/services/stirling-pdf.nix: -------------------------------------------------------------------------------- 1 | ### Stirling-PDF https://github.com/Stirling-Tools/Stirling-PDF 2 | { 3 | virtualisation.oci-containers.containers.stirling-pdf = { 4 | image = "frooodle/s-pdf:latest"; 5 | autoStart = true; 6 | ports = [ "8880:8080" ]; 7 | environment = { 8 | DOCKER_ENABLE_SECURITY = "False"; 9 | }; 10 | extraOptions = [ 11 | "--init=true" 12 | "--label=traefik.enable=true" 13 | "--label=traefik.http.routers.stirling-pdf.rule=Host(`pdf.lan.firecat53.net`)" 14 | "--label=traefik.http.routers.stirling-pdf.entrypoints=websecure" 15 | "--label=traefik.http.routers.stirling-pdf.tls.certResolver=le" 16 | "--label=traefik.http.routers.stirling-pdf.middlewares=headers@file" 17 | "--label=traefik.http.services.stirling-pdf.loadbalancer.server.port=8080" 18 | ]; 19 | volumes = [ 20 | "pdf_training_data:/usr/share/tesseract-ocr/5/tessdata" 21 | "pdf_configs:/configs" 22 | "pdf_logs:/logs" 23 | ]; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /hosts/homeserver/services/syncthing.nix: -------------------------------------------------------------------------------- 1 | # Syncthing 2 | { 3 | services.syncthing = { 4 | enable = true; 5 | user = "firecat53"; 6 | group = "users"; 7 | dataDir = "/home/firecat53/.local/state/syncthing"; 8 | configDir = "/home/firecat53/.config/syncthing"; 9 | openDefaultPorts = true; 10 | settings = { 11 | gui = { 12 | insecureSkipHostcheck = true; 13 | }; 14 | options = { 15 | relaysEnabled = false; 16 | urAccepted = 3; 17 | }; 18 | devices = { 19 | "backup" = { 20 | id = "CAKABE3-JTNUTY6-6BJYHGS-7E4Z35Y-SDF5M6H-GLB6Q2G-M6FVISW-Q3AVHQV"; 21 | }; 22 | "scott-cell" = { 23 | id = "6LDX7IF-D2MWKOW-APU3AUX-WXNBWFG-PNIUAPB-QKTWZHF-7MKLPBI-M6E6AQE"; 24 | }; 25 | "vps" = { 26 | id = "EPFW7TB-MUV25YB-P2SM66L-ENLRREJ-UJIRELD-QC2FWM4-RVSLFJY-7YWXCQ6"; 27 | addresses = [ 28 | "quic://firecat53.com:22000" 29 | "tcp://firecat53.com:22000" 30 | ]; 31 | }; 32 | "scott-laptop" = { 33 | id = "ERJHQAD-KWQH5ZJ-CAV3ZFL-IR6ECOQ-EHVL7GY-6MY5A5M-IORUVXI-NSBYOQE"; 34 | }; 35 | "scott-office" = { 36 | id = "4L73OQJ-4T6KOAR-5TJLKKY-ANBRCCB-KAOBFM7-LWVGPFK-QQ643GT-H4LIXAH"; 37 | }; 38 | "chrystie-cell" = { 39 | id = "FIQHWMF-VUVWCGQ-BPUNYV5-5COXF36-OB6D52M-FSKLCYX-MWS7RWZ-KWQ56QK"; 40 | }; 41 | "chrystie-laptop" = { 42 | id = "OK2Y6E5-MITMIEJ-YHQHSZ2-VKJV2MA-GZUIAUD-UT2MW2T-QCQ4J6W-AAGILQN"; 43 | }; 44 | "peggy-laptop" = { 45 | id = "XH5MYSV-DBHQQT3-DBUIAWQ-O7ZW33E-Z5RBBOP-HM6OL7T-2DOEGES-CJB3GQE"; 46 | }; 47 | "peggy-phone" = { 48 | id = "32XWZC3-SZMQKCY-UMIUIDY-FULNDAW-VD3MQED-Z3TL4FZ-QVGPVVP-JTOCEQX"; 49 | }; 50 | }; 51 | folders = { 52 | "blackhole" = { 53 | path = "/mnt/downloads/blackhole"; 54 | devices = [ "chrystie-laptop" ]; 55 | id = "lduvp-dcpju"; 56 | }; 57 | "camera-chrystie" = { 58 | path = "/mnt/media/cameras/chrystie"; 59 | devices = [ 60 | "chrystie-laptop" 61 | "chrystie-cell" 62 | ]; 63 | id = "camera"; 64 | }; 65 | "camera-scotty" = { 66 | path = "/mnt/media/cameras/scotty"; 67 | devices = [ 68 | "scott-laptop" 69 | "scott-cell" 70 | "scott-office" 71 | ]; 72 | id = "camera-scotty"; 73 | }; 74 | "docs-scotty" = { 75 | path = "/home/firecat53/docs"; 76 | devices = [ 77 | "scott-laptop" 78 | "scott-cell" 79 | "scott-office" 80 | ]; 81 | id = "docs"; 82 | }; 83 | "docs-chrystie" = { 84 | path = "/home/chryspie/Christina-docs"; 85 | devices = [ "chrystie-laptop" ]; 86 | id = "wxbmh-jtaq9"; 87 | }; 88 | "file_xfer" = { 89 | path = "/home/firecat53/.local/tmp/file_xfer"; 90 | devices = [ 91 | "scott-cell" 92 | "scott-laptop" 93 | "scott-office" 94 | ]; 95 | id = "file_xfer"; 96 | }; 97 | "mail" = { 98 | path = "/home/firecat53/mail"; 99 | devices = [ 100 | "scott-laptop" 101 | "scott-office" 102 | ]; 103 | id = "sdgpi-zh6rd"; 104 | }; 105 | "nixos" = { 106 | path = "/home/firecat53/nixos"; 107 | devices = [ 108 | "scott-laptop" 109 | "scott-office" 110 | "backup" 111 | "vps" 112 | ]; 113 | id = "smqlq-yhrua"; 114 | type = "receiveonly"; 115 | }; 116 | "peggy-all" = { 117 | path = "/home/peggy"; 118 | devices = [ 119 | "peggy-laptop" 120 | "peggy-phone" 121 | ]; 122 | id = "wcwjd-rxyrv"; 123 | }; 124 | "peggy-camera" = { 125 | path = "/mnt/media/cameras-peggy"; 126 | devices = [ "peggy-phone" ]; 127 | id = "uvdv3-yhbx0"; 128 | }; 129 | "pictures-chrystie" = { 130 | path = "/home/chryspie/pictures"; 131 | devices = [ "chrystie-laptop" ]; 132 | id = "efadj-qkslz"; 133 | }; 134 | "shared" = { 135 | path = "/home/firecat53/shared"; 136 | devices = [ 137 | "scott-cell" 138 | "vps" 139 | "scott-laptop" 140 | "chrystie-laptop" 141 | "chrystie-cell" 142 | "scott-office" 143 | ]; 144 | id = "shared"; 145 | }; 146 | "srv" = { 147 | path = "/srv"; 148 | devices = [ 149 | "vps" 150 | "scott-laptop" 151 | "scott-office" 152 | ]; 153 | id = "srv"; 154 | }; 155 | "wallpaper" = { 156 | path = "/mnt/media/wallpaper"; 157 | devices = [ 158 | "scott-laptop" 159 | "scott-office" 160 | ]; 161 | id = "wallpaper"; 162 | }; 163 | }; 164 | }; 165 | }; 166 | services.traefik.dynamicConfigOptions.http.routers.syncthing = { 167 | rule = "Host(`syncthing.lan.firecat53.net`)"; 168 | service = "syncthing"; 169 | middlewares = [ 170 | "auth" 171 | "headers" 172 | ]; 173 | entrypoints = [ "websecure" ]; 174 | tls = { 175 | certResolver = "le"; 176 | }; 177 | }; 178 | services.traefik.dynamicConfigOptions.http.services.syncthing = { 179 | loadBalancer = { 180 | servers = [ 181 | { 182 | url = "http://localhost:8384"; 183 | } 184 | ]; 185 | }; 186 | }; 187 | } 188 | -------------------------------------------------------------------------------- /hosts/homeserver/services/traefik.nix: -------------------------------------------------------------------------------- 1 | # Traefik 2 | { 3 | config, 4 | ... 5 | }: 6 | { 7 | networking.firewall.allowedTCPPorts = [ 8 | 80 9 | 443 10 | ]; 11 | 12 | sops.secrets.basic-auth = { 13 | mode = "0440"; 14 | owner = config.users.users.traefik.name; 15 | group = config.users.users.traefik.group; 16 | }; 17 | sops.secrets.cf-api-token = { 18 | mode = "0440"; 19 | owner = config.users.users.traefik.name; 20 | group = config.users.users.traefik.group; 21 | }; 22 | systemd.services.traefik.environment = { 23 | CF_DNS_API_TOKEN_FILE = "${config.sops.secrets.cf-api-token.path}"; 24 | }; 25 | users.users.traefik.extraGroups = [ "podman" ]; 26 | services.traefik = { 27 | enable = true; 28 | staticConfigOptions = { 29 | serversTransport = { 30 | insecureSkipVerify = true; 31 | }; 32 | entryPoints = { 33 | web = { 34 | address = ":80"; 35 | http = { 36 | redirections = { 37 | entryPoint = { 38 | to = "websecure"; 39 | scheme = "https"; 40 | }; 41 | }; 42 | }; 43 | }; 44 | websecure = { 45 | address = ":443"; 46 | http = { 47 | tls = { 48 | options = "default"; 49 | }; 50 | }; 51 | }; 52 | }; 53 | providers = { 54 | docker = { 55 | endpoint = "unix:///var/run/podman/podman.sock"; 56 | exposedByDefault = false; 57 | }; 58 | }; 59 | api = { 60 | dashboard = true; 61 | }; 62 | certificatesResolvers = { 63 | le = { 64 | acme = { 65 | email = "tech@firecat53.net"; 66 | storage = "/var/lib/traefik/acme.json"; 67 | dnsChallenge = { 68 | provider = "cloudflare"; 69 | resolvers = [ "1.1.1.1:53" ]; 70 | }; 71 | }; 72 | }; 73 | }; 74 | }; 75 | dynamicConfigOptions = { 76 | http = { 77 | routers = { 78 | dashboard = { 79 | rule = "Host(`monitor.lan.firecat53.net`)"; 80 | service = "api@internal"; 81 | middlewares = [ 82 | "auth" 83 | "headers" 84 | ]; 85 | entrypoints = [ "websecure" ]; 86 | tls = { 87 | certResolver = "le"; 88 | }; 89 | }; 90 | }; 91 | middlewares = { 92 | auth = { 93 | basicAuth = { 94 | usersFile = "${config.sops.secrets.basic-auth.path}"; 95 | }; 96 | }; 97 | headers = { 98 | headers = { 99 | browserxssfilter = true; 100 | contenttypenosniff = true; 101 | customframeoptionsvalue = "SAMEORIGIN"; 102 | forcestsheader = true; 103 | framedeny = true; 104 | sslhost = "firecat53.com"; 105 | sslredirect = true; 106 | stsincludesubdomains = true; 107 | stspreload = true; 108 | stsseconds = "315360000"; 109 | }; 110 | }; 111 | }; 112 | }; 113 | tls = { 114 | options = { 115 | default = { 116 | minVersion = "VersionTLS13"; 117 | sniStrict = true; 118 | curvePreferences = [ 119 | "CurveP521" 120 | "CurveP384" 121 | ]; 122 | }; 123 | }; 124 | }; 125 | }; 126 | }; 127 | } 128 | -------------------------------------------------------------------------------- /hosts/homeserver/services/transmission.nix: -------------------------------------------------------------------------------- 1 | # Transmission 2 | { 3 | networking.firewall.allowedTCPPorts = [ 30020 ]; 4 | networking.firewall.allowedUDPPorts = [ 30020 ]; 5 | 6 | services.transmission = { 7 | enable = true; 8 | user = "firecat53"; 9 | group = "users"; 10 | openPeerPorts = true; 11 | settings = { 12 | watch-dir-enabled = true; 13 | watch-dir = "/mnt/downloads/blackhole/blackhole-iso"; 14 | rpc-port = 9091; 15 | rpc-bind-address = "127.0.0.1"; 16 | rpc-host-whitelist-enabled = true; 17 | rpc-host-whitelist = "transmission.lan.firecat53.net,transmission.firecat53.me"; 18 | rpc-whitelist-enabled = true; 19 | rpc-whitelist = "127.0.0.1"; 20 | peer-port-random-on-start = false; 21 | peer-port = 30020; 22 | incomplete-dir-enabled = true; 23 | incomplete-dir = "/mnt/downloads/incomplete"; 24 | download-dir = "/mnt/downloads/iso"; 25 | }; 26 | }; 27 | 28 | services.traefik.dynamicConfigOptions.http.routers.transmission = { 29 | rule = "Host(`transmission.lan.firecat53.net`)"; 30 | service = "transmission"; 31 | middlewares = [ 32 | "auth" 33 | "headers" 34 | ]; 35 | entrypoints = [ "websecure" ]; 36 | tls = { 37 | certResolver = "le"; 38 | }; 39 | }; 40 | services.traefik.dynamicConfigOptions.http.services.transmission = { 41 | loadBalancer = { 42 | servers = [ 43 | { 44 | url = "http://localhost:9091"; 45 | } 46 | ]; 47 | }; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /hosts/homeserver/services/uptime-kuma.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.uptime-kuma = { 3 | enable = true; 4 | }; 5 | services.traefik.dynamicConfigOptions.http.routers.up = { 6 | rule = "Host(`up.lan.firecat53.net`)"; 7 | service = "up"; 8 | middlewares = [ "headers" ]; 9 | entrypoints = [ "websecure" ]; 10 | tls = { 11 | certResolver = "le"; 12 | }; 13 | }; 14 | services.traefik.dynamicConfigOptions.http.services.up = { 15 | loadBalancer = { 16 | servers = [ 17 | { 18 | url = "http://localhost:3001"; 19 | } 20 | ]; 21 | }; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /hosts/homeserver/services/vaultwarden.nix: -------------------------------------------------------------------------------- 1 | # Vaultwarden 2 | { 3 | config, 4 | pkgs, 5 | ... 6 | }: 7 | { 8 | sops.secrets.vaultwarden-env = { }; 9 | 10 | services.vaultwarden = { 11 | enable = true; 12 | package = pkgs.vaultwarden; 13 | dbBackend = "sqlite"; 14 | config = { 15 | DOMAIN = "https://bw.lan.firecat53.net"; 16 | ROCKET_ADDRESS = "127.0.0.1"; 17 | ROCKET_PORT = "8082"; 18 | }; 19 | environmentFile = "${config.sops.secrets.vaultwarden-env.path}"; 20 | backupDir = "/var/lib/vaultwarden"; 21 | }; 22 | 23 | services.traefik.dynamicConfigOptions.http.routers.vaultwarden = { 24 | rule = "Host(`bw.lan.firecat53.net`)"; 25 | service = "vaultwarden"; 26 | middlewares = [ "headers" ]; 27 | entrypoints = [ "websecure" ]; 28 | tls = { 29 | certResolver = "le"; 30 | }; 31 | }; 32 | services.traefik.dynamicConfigOptions.http.services.vaultwarden = { 33 | loadBalancer = { 34 | servers = [ 35 | { 36 | url = "http://localhost:8082"; 37 | } 38 | ]; 39 | }; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /hosts/laptop/configuration.nix: -------------------------------------------------------------------------------- 1 | # Edit this configuration file to define what should be installed on 2 | # your system. Help is available in the configuration.nix(5) man page 3 | # and in the NixOS manual (accessible by running `nixos-help`). 4 | 5 | { 6 | inputs, 7 | ... 8 | }: 9 | { 10 | imports = [ 11 | # Include the results of the hardware scan. 12 | ./hardware-configuration.nix 13 | ./services 14 | ../modules/common 15 | ../modules/desktops 16 | ../modules/avahi.nix 17 | ../modules/boot.nix 18 | ../modules/docker.nix 19 | ../modules/libvirt.nix 20 | ../modules/nix-ld.nix 21 | ../modules/opengl-intel.nix 22 | ../modules/podman.nix 23 | ../modules/power.nix 24 | ../modules/sddm.nix 25 | ../modules/sway.nix 26 | ../modules/zfs.nix 27 | ../../home-manager/home-manager.nix 28 | inputs.home-manager.nixosModules.home-manager 29 | inputs.sops-nix.nixosModules.sops 30 | inputs.catppuccin.nixosModules.catppuccin 31 | ]; 32 | 33 | home-manager.users.firecat53 = { 34 | imports = [ 35 | inputs.sops-nix.homeManagerModule 36 | ../../home-manager/laptop.nix 37 | ]; 38 | }; 39 | 40 | networking.hostName = "laptop"; 41 | networking.hostId = "c9ed046a"; 42 | 43 | # Swap (zram) 44 | zramSwap.enable = true; 45 | 46 | # Polkit - for home-manager sway 47 | security.polkit.enable = true; 48 | 49 | # Fingerprint login 50 | services.fprintd.enable = true; 51 | 52 | system.stateVersion = "25.05"; 53 | } 54 | -------------------------------------------------------------------------------- /hosts/laptop/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { 5 | config, 6 | lib, 7 | modulesPath, 8 | ... 9 | }: 10 | 11 | { 12 | imports = [ 13 | (modulesPath + "/installer/scan/not-detected.nix") 14 | ]; 15 | 16 | boot.initrd.availableKernelModules = [ 17 | "xhci_pci" 18 | "nvme" 19 | ]; 20 | boot.initrd.kernelModules = [ ]; 21 | boot.kernelModules = [ "kvm-intel" ]; 22 | boot.extraModulePackages = [ ]; 23 | 24 | fileSystems."/" = { 25 | device = "rpool/nixos/root"; 26 | fsType = "zfs"; 27 | }; 28 | 29 | fileSystems."/home" = { 30 | device = "rpool/data/home"; 31 | fsType = "zfs"; 32 | }; 33 | 34 | fileSystems."/boot" = { 35 | device = "/dev/disk/by-uuid/7904-723D"; 36 | fsType = "vfat"; 37 | }; 38 | 39 | fileSystems."/var/lib" = { 40 | device = "rpool/nixos/var/lib"; 41 | fsType = "zfs"; 42 | }; 43 | 44 | fileSystems."/var/log" = { 45 | device = "rpool/nixos/var/log"; 46 | fsType = "zfs"; 47 | }; 48 | 49 | fileSystems."/var/lib/containers/storage/volumes" = { 50 | device = "rpool/nixos/var/lib/containers/storage/volumes"; 51 | fsType = "zfs"; 52 | }; 53 | 54 | swapDevices = [ ]; 55 | 56 | # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 57 | # (the default) this is the recommended approach. When using systemd-networkd it's 58 | # still possible to use this option, but it's recommended to use it in conjunction 59 | # with explicit per-interface declarations with `networking.interfaces..useDHCP`. 60 | networking.useDHCP = lib.mkDefault true; 61 | # networking.interfaces.enp0s31f6.useDHCP = lib.mkDefault true; 62 | # networking.interfaces.wlp0s20f3.useDHCP = lib.mkDefault true; 63 | # networking.interfaces.wwan0.useDHCP = lib.mkDefault true; 64 | 65 | nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; 66 | hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 67 | } 68 | -------------------------------------------------------------------------------- /hosts/laptop/services/backups.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | { 6 | # Sanoid 7 | services.sanoid = { 8 | enable = true; 9 | datasets."rpool/data" = { 10 | useTemplate = [ "data" ]; 11 | process_children_only = true; 12 | recursive = true; 13 | }; 14 | datasets."rpool/nixos/var/lib" = { 15 | useTemplate = [ "data" ]; 16 | process_children_only = false; 17 | recursive = false; 18 | }; 19 | datasets."rpool/nixos/var/lib/containers/storage/volumes" = { 20 | useTemplate = [ "data" ]; 21 | process_children_only = false; 22 | recursive = false; 23 | }; 24 | templates."data" = { 25 | hourly = 72; 26 | daily = 30; 27 | monthly = 0; 28 | yearly = 0; 29 | autosnap = true; 30 | autoprune = true; 31 | }; 32 | }; 33 | 34 | ### Restic 35 | sops.secrets.restic_env = { }; 36 | sops.secrets.restic_repo = { }; 37 | sops.secrets.restic_password = { }; 38 | 39 | services.restic = { 40 | backups.laptop = { 41 | user = "root"; 42 | environmentFile = "${config.sops.secrets.restic_env.path}"; 43 | repositoryFile = "${config.sops.secrets.restic_repo.path}"; 44 | passwordFile = "${config.sops.secrets.restic_password.path}"; 45 | paths = [ 46 | "/home" 47 | ]; 48 | exclude = [ 49 | "/home/firecat53/.cache" 50 | "/home/firecat53/.local/uv/" 51 | "/home/firecat53/.local/state/" 52 | "/home/firecat53/.local/tmp/iso" 53 | ]; 54 | timerConfig = { 55 | OnBootSec = "15m"; 56 | OnCalendar = "daily"; 57 | Persistent = true; 58 | }; 59 | pruneOpts = [ 60 | "--keep-monthly 6" 61 | "--keep-weekly 12" 62 | "--keep-daily 30" 63 | "--keep-hourly 72" 64 | ]; 65 | extraBackupArgs = [ 66 | "--retry-lock 30m" 67 | ]; 68 | }; 69 | }; 70 | # Allow restic-backup to restart if failed 71 | systemd.services.restic-backups-laptop = { 72 | serviceConfig = { 73 | Restart = "on-failure"; 74 | RestartSec = "20"; 75 | }; 76 | unitConfig = { 77 | StartLimitIntervalSec = 100; 78 | StartLimitBurst = 5; 79 | }; 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /hosts/laptop/services/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./backups.nix 4 | ./searx.nix 5 | ./syncthing.nix 6 | ]; 7 | } 8 | -------------------------------------------------------------------------------- /hosts/laptop/services/searx.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | environment.systemPackages = with pkgs; [ 7 | searxng 8 | ]; 9 | services.searx = { 10 | enable = true; 11 | settings = { 12 | server = { 13 | port = 8888; 14 | bind_address = "127.0.0.1"; 15 | secret_key = "64ZapANvagul"; 16 | }; 17 | }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /hosts/laptop/services/syncthing.nix: -------------------------------------------------------------------------------- 1 | # Syncthing 2 | { 3 | services.syncthing = { 4 | enable = true; 5 | user = "firecat53"; 6 | group = "users"; 7 | dataDir = "/home/firecat53/.local/state/syncthing"; 8 | configDir = "/home/firecat53/.config/syncthing"; 9 | openDefaultPorts = true; 10 | settings = { 11 | options = { 12 | relaysEnabled = false; 13 | urAccepted = 3; 14 | }; 15 | devices = { 16 | "backup" = { 17 | id = "CAKABE3-JTNUTY6-6BJYHGS-7E4Z35Y-SDF5M6H-GLB6Q2G-M6FVISW-Q3AVHQV"; 18 | }; 19 | "homeserver" = { 20 | id = "3WS2YZY-BCZNA5N-ZNBCA5G-JNPVFLA-FJQI2VQ-BAM5LK5-UVLWWGM-4DWTRQM"; 21 | addresses = [ 22 | "quic://firecat53.net:22000" 23 | "tcp://firecat53.net:22000" 24 | ]; 25 | }; 26 | "scott-cell" = { 27 | id = "6LDX7IF-D2MWKOW-APU3AUX-WXNBWFG-PNIUAPB-QKTWZHF-7MKLPBI-M6E6AQE"; 28 | }; 29 | "scott-office" = { 30 | id = "4L73OQJ-4T6KOAR-5TJLKKY-ANBRCCB-KAOBFM7-LWVGPFK-QQ643GT-H4LIXAH"; 31 | }; 32 | "vps" = { 33 | id = "EPFW7TB-MUV25YB-P2SM66L-ENLRREJ-UJIRELD-QC2FWM4-RVSLFJY-7YWXCQ6"; 34 | addresses = [ 35 | "quic://firecat53.com:22000" 36 | "tcp://firecat53.com:22000" 37 | ]; 38 | }; 39 | }; 40 | folders = { 41 | "camera-scotty" = { 42 | path = "/home/firecat53/media/cameras/scotty"; 43 | devices = [ 44 | "homeserver" 45 | "scott-cell" 46 | "scott-office" 47 | ]; 48 | id = "camera-scotty"; 49 | }; 50 | "docs-scotty" = { 51 | path = "/home/firecat53/docs"; 52 | devices = [ 53 | "homeserver" 54 | "scott-cell" 55 | "scott-office" 56 | ]; 57 | id = "docs"; 58 | }; 59 | "file_xfer" = { 60 | path = "/home/firecat53/.local/tmp/file_xfer"; 61 | devices = [ 62 | "homeserver" 63 | "scott-cell" 64 | "scott-office" 65 | ]; 66 | id = "file_xfer"; 67 | }; 68 | "mail" = { 69 | path = "/home/firecat53/mail"; 70 | devices = [ 71 | "homeserver" 72 | "scott-office" 73 | ]; 74 | id = "sdgpi-zh6rd"; 75 | }; 76 | "nixos" = { 77 | path = "/home/firecat53/nixos"; 78 | devices = [ 79 | "homeserver" 80 | "scott-office" 81 | "backup" 82 | "vps" 83 | ]; 84 | id = "smqlq-yhrua"; 85 | type = "sendreceive"; 86 | }; 87 | "shared" = { 88 | path = "/home/firecat53/shared"; 89 | devices = [ 90 | "scott-cell" 91 | "homeserver" 92 | "vps" 93 | "scott-office" 94 | ]; 95 | id = "shared"; 96 | }; 97 | "srv" = { 98 | path = "/home/firecat53/.local/srv"; 99 | devices = [ 100 | "vps" 101 | "homeserver" 102 | "scott-office" 103 | ]; 104 | id = "srv"; 105 | }; 106 | "wallpaper" = { 107 | path = "/home/firecat53/media/wallpaper"; 108 | devices = [ 109 | "homeserver" 110 | "scott-office" 111 | ]; 112 | id = "wallpaper"; 113 | }; 114 | }; 115 | }; 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /hosts/minimal/configuration.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | ... 4 | }: 5 | { 6 | imports = [ 7 | # Include the results of the hardware scan. 8 | ./disko-config.nix 9 | ./hardware-configuration.nix 10 | ../modules/boot.nix 11 | ../modules/common/users.nix 12 | inputs.disko.nixosModules.disko 13 | ]; 14 | 15 | networking.hostName = "nixos"; 16 | 17 | # Swap (zram) 18 | zramSwap.enable = true; 19 | 20 | system.stateVersion = "25.05"; 21 | } 22 | -------------------------------------------------------------------------------- /hosts/minimal/disko-config.nix: -------------------------------------------------------------------------------- 1 | { 2 | disko.devices = { 3 | disk = { 4 | main = { 5 | type = "disk"; 6 | device = "CHANGEME"; 7 | content = { 8 | type = "gpt"; 9 | partitions = { 10 | EFI = { 11 | size = "512M"; 12 | type = "EF00"; 13 | content = { 14 | type = "filesystem"; 15 | format = "vfat"; 16 | mountpoint = "/boot"; 17 | mountOptions = [ "umask=0077" ]; 18 | }; 19 | }; 20 | ROOT = { 21 | size = "100%"; 22 | content = { 23 | type = "btrfs"; 24 | extraArgs = [ "-f" ]; 25 | subvolumes = { 26 | "/root" = { 27 | mountpoint = "/"; 28 | mountOptions = [ 29 | "compress=zstd" 30 | "noatime" 31 | ]; 32 | }; 33 | "/home" = { 34 | mountpoint = "/home"; 35 | mountOptions = [ 36 | "compress=zstd" 37 | "noatime" 38 | ]; 39 | }; 40 | "/nix" = { 41 | mountpoint = "/nix"; 42 | mountOptions = [ 43 | "compress=zstd" 44 | "noatime" 45 | ]; 46 | }; 47 | "/swap" = { 48 | mountpoint = "/.swapvol"; 49 | swap.swapfile.size = "1G"; 50 | }; 51 | }; 52 | }; 53 | }; 54 | }; 55 | }; 56 | }; 57 | }; 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /hosts/minimal/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { config, lib, pkgs, modulesPath, ... }: 5 | 6 | { 7 | imports = 8 | [ (modulesPath + "/installer/scan/not-detected.nix") 9 | ]; 10 | 11 | boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; 12 | boot.initrd.kernelModules = [ ]; 13 | boot.kernelModules = [ "kvm-intel" ]; 14 | boot.extraModulePackages = [ ]; 15 | 16 | # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 17 | # (the default) this is the recommended approach. When using systemd-networkd it's 18 | # still possible to use this option, but it's recommended to use it in conjunction 19 | # with explicit per-interface declarations with `networking.interfaces..useDHCP`. 20 | networking.useDHCP = lib.mkDefault true; 21 | # networking.interfaces.docker0.useDHCP = lib.mkDefault true; 22 | # networking.interfaces.enp0s31f6.useDHCP = lib.mkDefault true; 23 | # networking.interfaces.virbr0.useDHCP = lib.mkDefault true; 24 | # networking.interfaces.wlp0s20f3.useDHCP = lib.mkDefault true; 25 | # networking.interfaces.wwan0.useDHCP = lib.mkDefault true; 26 | 27 | nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; 28 | hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 29 | } 30 | -------------------------------------------------------------------------------- /hosts/modules/avahi.nix: -------------------------------------------------------------------------------- 1 | { 2 | ## Avahi 3 | services.avahi = { 4 | enable = true; 5 | nssmdns4 = true; 6 | openFirewall = true; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /hosts/modules/boot-grub.nix: -------------------------------------------------------------------------------- 1 | { 2 | # Grub Configuration with plymouth 3 | boot = { 4 | consoleLogLevel = 0; 5 | kernelParams = [ 6 | "quiet" 7 | "udev.log_level=3" 8 | ]; 9 | initrd = { 10 | systemd = { 11 | enable = true; 12 | }; 13 | verbose = false; 14 | }; 15 | loader = { 16 | grub = { 17 | enable = true; 18 | configurationLimit = 10; 19 | }; 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /hosts/modules/boot.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | ... 5 | }: 6 | { 7 | # Systemd-boot Configuration with plymouth 8 | boot = { 9 | consoleLogLevel = 0; 10 | kernelParams = [ 11 | "quiet" 12 | "udev.log_level=3" 13 | ]; 14 | initrd = { 15 | systemd = { 16 | enable = true; 17 | }; 18 | verbose = false; 19 | }; 20 | loader = { 21 | systemd-boot = { 22 | enable = true; 23 | configurationLimit = 10; 24 | }; 25 | efi = { 26 | efiSysMountPoint = "/boot"; 27 | canTouchEfiVariables = true; 28 | }; 29 | }; 30 | plymouth = 31 | lib.mkIf (config.networking.hostName == "laptop" || config.networking.hostName == "office") 32 | { 33 | enable = true; 34 | }; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /hosts/modules/common/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./env.nix 4 | ./et.nix 5 | ./fwupd.nix 6 | ./nix.nix 7 | ./packages.nix 8 | ./smartmon.nix 9 | ./sops.nix 10 | ./sshd.nix 11 | ./tz_locale.nix 12 | ./users.nix 13 | ]; 14 | } 15 | -------------------------------------------------------------------------------- /hosts/modules/common/env.nix: -------------------------------------------------------------------------------- 1 | { 2 | # Systemwide ENV variables 3 | environment.variables = { 4 | EDITOR = "nvim"; 5 | VISUAL = "nvim"; 6 | }; 7 | 8 | ## Add ~/.local/bin to $PATH 9 | environment.localBinInPath = true; 10 | } 11 | -------------------------------------------------------------------------------- /hosts/modules/common/et.nix: -------------------------------------------------------------------------------- 1 | { 2 | ### Eternal Terminal 3 | services.eternal-terminal.enable = true; 4 | 5 | networking.firewall.allowedTCPPorts = [ 2022 ]; 6 | } 7 | -------------------------------------------------------------------------------- /hosts/modules/common/fwupd.nix: -------------------------------------------------------------------------------- 1 | { 2 | # Firmware updates - fwupd 3 | services.fwupd.enable = true; 4 | # Allow fwupd-refresh to restart if failed (after resume) 5 | systemd.services.fwupd-refresh = { 6 | serviceConfig = { 7 | Restart = "on-failure"; 8 | RestartSec = "20"; 9 | }; 10 | unitConfig = { 11 | StartLimitIntervalSec = 100; 12 | StartLimitBurst = 5; 13 | }; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /hosts/modules/common/nix.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | inputs, 4 | pkgs, 5 | ... 6 | }: 7 | let 8 | user = "firecat53"; 9 | ref = 10 | if 11 | builtins.elem config.networking.hostName [ 12 | "office" 13 | "laptop" 14 | ] 15 | then 16 | "" 17 | else 18 | "?ref=main"; 19 | flakePath = "/home/${user}/nixos/nixos${ref}"; 20 | secretspath = builtins.toString inputs.my-secrets; 21 | in 22 | { 23 | # Set github access token for nixpkgs 24 | sops.secrets.nix_access_token = { 25 | sopsFile = "${secretspath}/common/secrets.yaml"; 26 | owner = "firecat53"; 27 | }; 28 | nix.extraOptions = '' 29 | !include ${config.sops.secrets.nix_access_token.path} 30 | ''; 31 | 32 | nix.settings = { 33 | # Enable flakes 34 | experimental-features = [ 35 | "nix-command" 36 | "flakes" 37 | ]; 38 | # Trusted users 39 | trusted-users = [ 40 | "root" 41 | "${user}" 42 | ]; 43 | download-buffer-size = 500000000; 44 | }; 45 | 46 | # Enable git 47 | programs.git = { 48 | enable = true; 49 | config = { 50 | safe."directory" = "/home/${user}/nixos/nixos"; 51 | }; 52 | }; 53 | 54 | 55 | # Add unstable to flake registry to use locally (e.g. `nix run nixpkgs-unstable#hatch`) 56 | nix.registry.nixpkgs-unstable.flake = inputs.nixpkgs-unstable; 57 | 58 | # Allow unfree packages and pulling some packages from stable 59 | nixpkgs.config = { 60 | allowUnfree = true; 61 | packageOverrides = pkgs: { 62 | stable = import inputs.nixpkgs { 63 | config = config.nixpkgs.config; 64 | system = "x86_64-linux"; 65 | }; 66 | unstable = import inputs.nixpkgs-unstable { 67 | config = config.nixpkgs.config; 68 | system = "x86_64-linux"; 69 | }; 70 | }; 71 | permittedInsecurePackages = [ 72 | "olm-3.2.16" 73 | ]; 74 | }; 75 | 76 | # Show nix updates 77 | environment.shellAliases = { 78 | nd = "nix profile diff-closures --profile /nix/var/nix/profiles/system"; 79 | }; 80 | 81 | # System maintenance 82 | system.autoUpgrade = { 83 | enable = true; 84 | flake = "${flakePath}#${config.networking.hostName}"; 85 | flags = [ 86 | "-L" 87 | ]; 88 | dates = "04:40"; 89 | persistent = true; 90 | randomizedDelaySec = "45min"; 91 | }; 92 | # Allow nixos-upgrade to restart on failure (e.g. when laptop wakes up before network connection is set) 93 | systemd.services.nixos-upgrade = { 94 | preStart = "${pkgs.host}/bin/host firecat53.net"; # Check network connectivity 95 | serviceConfig = { 96 | Restart = "on-failure"; 97 | RestartSec = "120"; 98 | }; 99 | unitConfig = { 100 | StartLimitIntervalSec = 600; 101 | StartLimitBurst = 2; 102 | }; 103 | path = [ pkgs.host ]; 104 | }; 105 | nix.gc = { 106 | automatic = true; 107 | dates = "weekly"; 108 | options = "--delete-older-than 7d"; 109 | }; 110 | nix.optimise.automatic = true; 111 | 112 | ## Show installed packages 113 | environment.shellAliases = { 114 | ni = "nix-store --query --requisites /run/current-system/sw | cut -d- -f2- | sort | less"; 115 | }; 116 | } 117 | -------------------------------------------------------------------------------- /hosts/modules/common/packages.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | # General systemwide packages 7 | environment.systemPackages = with pkgs; [ 8 | bottom 9 | curl 10 | dua 11 | fd 12 | curl 13 | git 14 | jq 15 | nix-tree 16 | pciutils 17 | python3 18 | ripgrep 19 | rsync 20 | screen 21 | tmux 22 | wget 23 | wireguard-tools 24 | unstable.yazi 25 | usbutils 26 | ]; 27 | } 28 | -------------------------------------------------------------------------------- /hosts/modules/common/smartmon.nix: -------------------------------------------------------------------------------- 1 | { 2 | ### Smartmon 3 | services.smartd.enable = true; 4 | services.smartd.defaults.monitored = "-a -o on -S on -s (S/../.././01|L/../../6/02) -m root"; 5 | } 6 | -------------------------------------------------------------------------------- /hosts/modules/common/sops.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | inputs, 4 | ... 5 | }: 6 | let 7 | secretspath = builtins.toString inputs.my-secrets; 8 | in 9 | { 10 | # Sops-nix 11 | sops = { 12 | age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; 13 | defaultSopsFile = "${secretspath}/${config.networking.hostName}/secrets.yaml"; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /hosts/modules/common/sshd.nix: -------------------------------------------------------------------------------- 1 | { 2 | ### SSH 3 | services.openssh.enable = true; 4 | services.openssh.authorizedKeysFiles = [ "/etc/ssh/%u" ]; 5 | services.openssh.settings.KbdInteractiveAuthentication = false; 6 | services.openssh.settings.PasswordAuthentication = false; 7 | services.openssh.settings.PermitRootLogin = "no"; 8 | services.openssh.settings.X11Forwarding = false; 9 | services.openssh.extraConfig = '' 10 | UsePAM yes 11 | PrintMotd no 12 | TCPKeepAlive yes 13 | ClientAliveInterval 30 14 | ClientAliveCountMax 1000 15 | ''; 16 | 17 | networking.firewall.allowedTCPPorts = [ 22 ]; 18 | } 19 | -------------------------------------------------------------------------------- /hosts/modules/common/tz_locale.nix: -------------------------------------------------------------------------------- 1 | { 2 | # Set your time zone. 3 | time.timeZone = "America/Los_Angeles"; 4 | 5 | # Locale settings 6 | i18n.defaultLocale = "en_US.UTF-8"; 7 | 8 | i18n.extraLocaleSettings = { 9 | LC_ADDRESS = "en_US.UTF-8"; 10 | LC_IDENTIFICATION = "en_US.UTF-8"; 11 | LC_MEASUREMENT = "en_US.UTF-8"; 12 | LC_MONETARY = "en_US.UTF-8"; 13 | LC_NAME = "en_US.UTF-8"; 14 | LC_NUMERIC = "en_US.UTF-8"; 15 | LC_PAPER = "en_US.UTF-8"; 16 | LC_TELEPHONE = "en_US.UTF-8"; 17 | LC_TIME = "en_US.UTF-8"; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /hosts/modules/common/users.nix: -------------------------------------------------------------------------------- 1 | { 2 | users.users.root = { 3 | ## hash: mkpasswd -m SHA-512 -s (initial password: rootpassword) 4 | initialHashedPassword = "$6$SJ9TnC7TNPD86lkT$mXAlVO2L6aIaA9mtrCQTWTKNyZbETKZ2XhHOoDPWMFGnZF3vdqIBtHmHVJICNTP/yCgj28OMAsAm8wC1JM1Ui/"; 5 | }; 6 | 7 | # Normal user 8 | users.users.firecat53 = { 9 | isNormalUser = true; 10 | group = "firecat53"; 11 | extraGroups = [ 12 | "wheel" 13 | "networkmanager" 14 | "libvirtd" 15 | ]; 16 | uid = 1000; 17 | # initial password: firecat53 18 | initialHashedPassword = "$6$4uca2AGtTNxwo1bt$JJwaaNTqKF6ddXE9xLqWdmTZpElZZ5KNHEbj4jqAVY5QVknWKB4lCvzlMPZ0VLivh8FcmpGbkx5bVJhT1URpz0"; 19 | # keys: id_ed25519.pub 20 | openssh.authorizedKeys.keys = [ 21 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILdMFWLeCpeDFMKJyLaTtLgmfJ6G8HxrBObvlaBE8eoH firecat53@scotty" 22 | ]; 23 | }; 24 | users.groups.firecat53 = { 25 | gid = 1000; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /hosts/modules/desktops/autossh.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | { 6 | services.autossh.sessions = [ 7 | { 8 | name = "wg"; 9 | monitoringPort = 0; 10 | user = "firecat53"; 11 | extraArguments = "-N -o ControlMaster=no wg"; 12 | } 13 | ]; 14 | systemd.services.autossh-wg.serviceConfig = { 15 | Environment = [ 16 | "AUTOSSH_GATETIME=0" 17 | "SSH_AUTH_SOCK=/run/user/${toString config.users.users.firecat53.uid}/gnupg/S.gpg-agent.ssh" 18 | ]; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /hosts/modules/desktops/bluetooth.nix: -------------------------------------------------------------------------------- 1 | { 2 | hardware.bluetooth.enable = true; 3 | hardware.bluetooth.powerOnBoot = true; 4 | services.blueman.enable = true; 5 | } 6 | -------------------------------------------------------------------------------- /hosts/modules/desktops/catppuccin.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | environment.systemPackages = [ 7 | pkgs.catppuccin 8 | ]; 9 | } 10 | -------------------------------------------------------------------------------- /hosts/modules/desktops/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./autossh.nix 4 | ./bluetooth.nix 5 | ./catppuccin.nix 6 | ./desktop.nix 7 | ./neovim.nix 8 | ./networking.nix 9 | ./virt-manager.nix 10 | ./mounts.nix 11 | ./users.nix 12 | ]; 13 | } 14 | -------------------------------------------------------------------------------- /hosts/modules/desktops/desktop.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | services.xserver.enable = true; 7 | 8 | # Fonts 9 | fonts.packages = with pkgs; [ 10 | dejavu_fonts 11 | liberation_ttf 12 | noto-fonts 13 | noto-fonts-cjk-sans 14 | noto-fonts-cjk-serif 15 | noto-fonts-color-emoji 16 | ]; 17 | 18 | # Configure keymap in X11 19 | services.xserver.xkb.layout = "us"; 20 | services.xserver.xkb.options = "caps:escape"; 21 | 22 | # Enable CUPS to print documents. 23 | services.printing = { 24 | enable = true; 25 | cups-pdf = { 26 | enable = true; 27 | instances.pdf.settings = { 28 | Out = "\${HOME}/.local/tmp"; 29 | }; 30 | }; 31 | }; 32 | 33 | # Enable sound. 34 | security.rtkit.enable = true; 35 | services.pulseaudio.enable = false; 36 | services.pipewire = { 37 | enable = true; 38 | alsa.enable = true; 39 | alsa.support32Bit = true; 40 | pulse.enable = true; 41 | }; 42 | 43 | # Enable touchpad support (enabled default in most desktopManager). 44 | services.libinput.enable = true; 45 | 46 | # Enable flatpak support 47 | # See home-manager/bash.nix for exports/bin and $XDG_DATA_DIRS config 48 | services.flatpak.enable = true; 49 | 50 | # Allow /dev/uinput access for users (ydotool) 51 | services.udev.extraRules = '' 52 | KERNEL=="uinput", GROUP="users", MODE="0660", OPTIONS+="static_node=uinput" 53 | ''; 54 | } 55 | -------------------------------------------------------------------------------- /hosts/modules/desktops/mounts.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | environment.systemPackages = with pkgs; [ 8 | cifs-utils 9 | davfs2 10 | ]; 11 | 12 | sops.secrets = { 13 | smbcreds = { 14 | mode = "0600"; 15 | }; 16 | davfs = { 17 | mode = "0600"; 18 | path = "/etc/davfs2/secrets"; 19 | }; 20 | }; 21 | 22 | services.davfs2.enable = true; 23 | 24 | systemd.mounts = [ 25 | { 26 | description = "Samba mount for downloads"; 27 | after = [ "network-online.target" ]; 28 | wants = [ "network-online.target" ]; 29 | what = "//192.168.200.101/downloads"; 30 | where = "/mnt/homeserver-downloads"; 31 | options = "credentials=${config.sops.secrets.smbcreds.path},iocharset=utf8,rw,x-systemd.automount,uid=1000,gid=100,vers=3"; 32 | type = "cifs"; 33 | } 34 | { 35 | description = "Samba mount for homeserver media"; 36 | after = [ "network-online.target" ]; 37 | wants = [ "network-online.target" ]; 38 | what = "//192.168.200.101/media"; 39 | where = "/mnt/homeserver-media"; 40 | options = "credentials=${config.sops.secrets.smbcreds.path},iocharset=utf8,rw,x-systemd.automount,uid=1000,gid=100,vers=3"; 41 | type = "cifs"; 42 | } 43 | { 44 | description = "Nextcloud webdav mount"; 45 | after = [ "network-online.target" ]; 46 | wants = [ "network-online.target" ]; 47 | what = "https://nc.firecat53.net/remote.php/webdav"; 48 | where = "/mnt/nextcloud"; 49 | options = "x-systemd.automount,uid=1000,gid=100"; 50 | type = "davfs"; 51 | } 52 | ]; 53 | systemd.automounts = [ 54 | { 55 | description = "Samba automount for downloads"; 56 | where = "/mnt/homeserver-downloads"; 57 | wantedBy = [ "multi-user.target" ]; 58 | automountConfig = { 59 | TimeoutIdleSec = "2m"; 60 | }; 61 | } 62 | { 63 | description = "Samba automount for homeserver media"; 64 | where = "/mnt/homeserver-media"; 65 | wantedBy = [ "multi-user.target" ]; 66 | automountConfig = { 67 | TimeoutIdleSec = "2m"; 68 | }; 69 | } 70 | { 71 | description = "Nextcloud webdav automount"; 72 | where = "/mnt/nextcloud"; 73 | wantedBy = [ "multi-user.target" ]; 74 | automountConfig = { 75 | TimeoutIdleSec = "2m"; 76 | }; 77 | } 78 | ]; 79 | } 80 | -------------------------------------------------------------------------------- /hosts/modules/desktops/neovim.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | nixpkgs.overlays = [ 8 | inputs.neovim.overlays.default 9 | ]; 10 | environment.systemPackages = [ 11 | pkgs.nvim-pkg 12 | ]; 13 | } 14 | -------------------------------------------------------------------------------- /hosts/modules/desktops/networking.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | { 6 | # Networking 7 | networking.networkmanager.enable = true; 8 | networking.firewall.checkReversePath = "loose"; # Allow tunneling all wireguard traffic 9 | networking.firewall.allowedUDPPorts = [ 51820 ]; 10 | 11 | # Wireguard 12 | # To create wireguard connection: 13 | # `nmcli connection import type wireguard file /etc/wireguard/wg0.conf` 14 | sops.secrets.wg-private-key = { }; 15 | sops.secrets.wg-preshared-key = { }; 16 | sops.secrets.wg-address = { }; 17 | sops.secrets.wg-allowed-ips = { }; 18 | sops.templates."wg0.conf" = { 19 | content = '' 20 | [Interface] 21 | Address = ${config.sops.placeholder.wg-address} 22 | ListenPort = 51820 23 | PrivateKey = ${config.sops.placeholder.wg-private-key} 24 | DNS = 10.200.200.1 25 | 26 | [Peer] 27 | # OPNsense 28 | PublicKey = ADZLBwickizf71ZNv4QpcdFtyHVpe81WnzW8sMPK1Wg= 29 | PresharedKey = ${config.sops.placeholder.wg-preshared-key} 30 | AllowedIPs = ${config.sops.placeholder.wg-allowed-ips} 31 | Endpoint = wg.firecat53.net:51820 32 | PersistentKeepalive = 25 33 | ''; 34 | path = "/etc/wireguard/wg0.conf"; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /hosts/modules/desktops/users.nix: -------------------------------------------------------------------------------- 1 | { 2 | ### Make firecat53 admin user on desktops 3 | users.users.firecat53 = { 4 | extraGroups = [ 5 | "libvirtd" 6 | "networkmanager" 7 | "users" 8 | "wheel" 9 | ]; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /hosts/modules/desktops/virt-manager.nix: -------------------------------------------------------------------------------- 1 | { 2 | virtualisation.spiceUSBRedirection.enable = true; 3 | programs.virt-manager.enable = true; 4 | } 5 | -------------------------------------------------------------------------------- /hosts/modules/docker.nix: -------------------------------------------------------------------------------- 1 | # Docker 2 | { 3 | virtualisation.docker = { 4 | enable = true; 5 | }; 6 | users.users.firecat53.extraGroups = [ "docker" ]; 7 | } 8 | -------------------------------------------------------------------------------- /hosts/modules/gnome.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | services.xserver = { 7 | displayManager.gdm.enable = true; 8 | desktopManager.gnome.enable = true; 9 | }; 10 | ### Ensure system tray icons are visible 11 | environment.systemPackages = with pkgs; [ 12 | gnomeExtensions.appindicator 13 | seahorse 14 | ]; 15 | services.udev.packages = with pkgs; [ gnome-settings-daemon ]; 16 | } 17 | -------------------------------------------------------------------------------- /hosts/modules/libvirt.nix: -------------------------------------------------------------------------------- 1 | { 2 | virtualisation.libvirtd = { 3 | enable = true; 4 | onBoot = "ignore"; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /hosts/modules/newt.nix: -------------------------------------------------------------------------------- 1 | # Add the Newt wireguard tunnel utility for Pangolin 2 | { 3 | config, 4 | inputs, 5 | pkgs, 6 | ... 7 | }: 8 | { 9 | environment.systemPackages = [ 10 | inputs.newt.packages.${pkgs.system}.default 11 | ]; 12 | 13 | sops.secrets.newt-env = { }; 14 | 15 | systemd.services.newt-vpn = { 16 | description = "Newt VPN Client"; 17 | after = [ "network.target" ]; 18 | wantedBy = [ "multi-user.target" ]; 19 | path = [ inputs.newt.packages.${pkgs.system}.default ]; 20 | serviceConfig = { 21 | ExecStart = "${inputs.newt.packages.${pkgs.system}.default}/bin/newt"; 22 | EnvironmentFile = "${config.sops.secrets.newt-env.path}"; 23 | Restart = "always"; 24 | DynamicUser = true; 25 | Environment = "HOME=%t/newt-vpn"; 26 | RuntimeDirectory = "newt-vpn"; 27 | RuntimeDirectoryMode = "0700"; 28 | }; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /hosts/modules/nix-ld.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | programs.nix-ld = { 7 | enable = true; 8 | # put whatever libraries you think you might need 9 | # nix-ld includes a strong sane-default as well 10 | # in addition to these 11 | libraries = with pkgs; [ 12 | stdenv.cc.cc.lib 13 | zlib 14 | ]; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /hosts/modules/opengl-amd.nix: -------------------------------------------------------------------------------- 1 | { 2 | ## Enable OpenGL accelerated video playback 3 | hardware.graphics = { 4 | enable = true; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /hosts/modules/opengl-intel.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | ## Enable OpenGL accelerated video playback 7 | nixpkgs.config.packageOverrides = pkgs: { 8 | vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; }; 9 | }; 10 | hardware.graphics = { 11 | enable = true; 12 | extraPackages = with pkgs; [ 13 | intel-media-driver 14 | vaapiIntel 15 | vaapiVdpau 16 | libvdpau-va-gl 17 | ]; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /hosts/modules/podman.nix: -------------------------------------------------------------------------------- 1 | # Podman monitoring and setup 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | let 7 | podman-py = p: [ 8 | p.podman 9 | ]; 10 | in 11 | { 12 | environment.systemPackages = with pkgs; [ 13 | (python3.withPackages podman-py // { meta.priority = 1; }) 14 | ]; 15 | 16 | virtualisation.podman = { 17 | enable = true; 18 | }; 19 | 20 | virtualisation.containers.storage.settings = { 21 | storage = { 22 | graphroot = "/var/lib/containers/storage"; 23 | runroot = "/run/containers/storage"; 24 | }; 25 | }; 26 | 27 | environment.shellAliases = { 28 | pps = "podman ps --format 'table {{ .Names }}\t{{ .Status }}' --sort names"; 29 | pclean = "podman ps -a | grep -v 'CONTAINER\|_config\|_data\|_run' | cut -c-12 | xargs podman rm 2>/dev/null"; 30 | piclean = "podman images | grep '' | grep -P '[1234567890abcdef]{12}' -o | xargs -L1 podman rmi 2>/dev/null"; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /hosts/modules/power.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | # Power management 7 | powerManagement.powertop.enable = true; 8 | services.tlp.enable = true; 9 | 10 | systemd.services.setBatteryChargeLimit = { 11 | description = "Set battery charge limit to 75% when started and 96% when stopped"; 12 | enable = false; 13 | wantedBy = [ "multi-user.target" ]; 14 | 15 | serviceConfig = { 16 | Type = "oneshot"; 17 | RemainAfterExit = true; 18 | ExecStart = "${pkgs.tlp}/bin/tlp setcharge 75 80"; 19 | ExecStop = "${pkgs.tlp}/bin/tlp setcharge 96 100"; 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /hosts/modules/sddm.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | services.displayManager.sddm = { 7 | enable = true; 8 | enableHidpi = true; 9 | extraPackages = [ pkgs.catppuccin-sddm ]; 10 | package = pkgs.kdePackages.sddm; 11 | theme = "catppuccin-mocha"; 12 | wayland.enable = true; 13 | }; 14 | environment.systemPackages = [ 15 | (pkgs.catppuccin-sddm.override { 16 | flavor = "mocha"; 17 | font = "DevjaVu Sans"; 18 | fontSize = "17"; 19 | loginBackground = true; 20 | }) 21 | ]; 22 | } 23 | -------------------------------------------------------------------------------- /hosts/modules/servers/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./fail2ban.nix 4 | ./msmtp.nix 5 | ./neovim.nix 6 | ./prometheus-exporters.nix 7 | ./tmux.nix 8 | ./wireguard.nix 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /hosts/modules/servers/fail2ban.nix: -------------------------------------------------------------------------------- 1 | { 2 | ### Fail2ban 3 | services.fail2ban.enable = true; 4 | } 5 | -------------------------------------------------------------------------------- /hosts/modules/servers/msmtp.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | { 6 | ### Msmtp 7 | sops.secrets.email-password = { 8 | # This has to be world readable because I can't set ACLs with sops-nix for the 9 | # systemd dynamic users. TODO 10 | mode = "0444"; 11 | }; 12 | programs.msmtp = { 13 | enable = true; 14 | setSendmail = true; 15 | defaults = { 16 | aliases = "/etc/aliases"; 17 | port = 465; 18 | tls_trust_file = "/etc/ssl/certs/ca-certificates.crt"; 19 | tls = true; 20 | auth = true; 21 | tls_starttls = false; 22 | }; 23 | accounts = { 24 | default = { 25 | host = "smtp.fastmail.com"; 26 | passwordeval = "cat ${config.sops.secrets.email-password.path}"; 27 | user = "scott@firecat53.net"; 28 | from = "noreply@firecat53.net"; 29 | }; 30 | }; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /hosts/modules/servers/neovim.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.neovim = { 3 | enable = true; 4 | defaultEditor = true; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /hosts/modules/servers/prometheus-exporters.nix: -------------------------------------------------------------------------------- 1 | ### Prometheus 2 | { 3 | services.prometheus.exporters = { 4 | node = { 5 | enable = true; 6 | enabledCollectors = [ "systemd" ]; 7 | }; 8 | systemd.enable = true; 9 | zfs.enable = true; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /hosts/modules/servers/tmux.nix: -------------------------------------------------------------------------------- 1 | # TODO - host variable for status-bg color 2 | { 3 | ### Tmux 4 | programs.tmux = { 5 | enable = true; 6 | baseIndex = 1; 7 | clock24 = true; 8 | escapeTime = 10; 9 | historyLimit = 5000; 10 | keyMode = "vi"; 11 | newSession = true; 12 | shortcut = "a"; 13 | terminal = "tmux-256color"; 14 | extraConfig = '' 15 | set -s copy-command 'wl-copy' 16 | 17 | # Last active window 18 | unbind l 19 | bind C-a last-window 20 | bind C-d detach-client 21 | unbind " " 22 | bind " " next-window 23 | bind C-" " next-window 24 | bind C-c new-window 25 | bind C-n next-window 26 | bind C-p previous-window 27 | bind v run "tmux show-buffer | wl-paste > /dev/null" 28 | 29 | # Highlighting the active window in status bar 30 | setw -g window-status-current-style bg=red 31 | set -g status-bg magenta 32 | set -g status-fg black 33 | 34 | # Add uptime to status bar 35 | set -g status-interval 5 36 | set -g status-right-length 100 37 | set -g status-right "#(uptime | awk -F 'up |,' '{print \"up\",$2}' | sed 's/ / /g') #(awk -F ' ' '{print $1,$2,$3}' /proc/loadavg) \"#H\" #(date '+%H:%M %a %m-%d')" 38 | ''; 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /hosts/modules/servers/wireguard.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | let 6 | externalServers = [ "vps" ]; # Add server names to list that are not in the LAN 7 | 8 | wgEndpoint = 9 | if builtins.elem config.networking.hostName externalServers then 10 | "wg.firecat53.net:51820" 11 | else 12 | "192.168.200.1:51820"; 13 | in 14 | { 15 | # Wireguard systemd-networkd 16 | networking.firewall.checkReversePath = "loose"; # Allow tunneling all wireguard traffic 17 | networking.firewall.allowedUDPPorts = [ 51820 ]; 18 | 19 | sops.secrets.wg-private-key = { 20 | owner = "systemd-network"; 21 | }; 22 | sops.secrets.wg-preshared-key = { 23 | owner = "systemd-network"; 24 | }; 25 | systemd.network = { 26 | enable = true; 27 | netdevs = { 28 | "10-wg0" = { 29 | netdevConfig = { 30 | Kind = "wireguard"; 31 | Name = "wg0"; 32 | }; 33 | wireguardConfig = { 34 | # Must be readable by the systemd.network user 35 | PrivateKeyFile = "${config.sops.secrets.wg-private-key.path}"; 36 | ListenPort = 51820; 37 | }; 38 | wireguardPeers = [ 39 | { 40 | # Opnsense 41 | PublicKey = "ADZLBwickizf71ZNv4QpcdFtyHVpe81WnzW8sMPK1Wg="; 42 | PresharedKeyFile = "${config.sops.secrets.wg-preshared-key.path}"; 43 | AllowedIPs = [ "10.200.200.1/24" ]; 44 | Endpoint = wgEndpoint; 45 | } 46 | ]; 47 | }; 48 | }; 49 | networks.wg0 = { 50 | matchConfig.Name = "wg0"; 51 | #address = ["10.200.200.6/32"]; Set in configuration.nix for each host 52 | DHCP = "no"; 53 | dns = [ "10.200.200.1" ]; 54 | linkConfig.RequiredForOnline = "no"; 55 | networkConfig = { 56 | IPv4Forwarding = "yes"; 57 | }; 58 | }; 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /hosts/modules/sway.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | services.displayManager = { 7 | defaultSession = "sway"; 8 | sessionPackages = [ pkgs.sway ]; 9 | }; 10 | programs.sway = { 11 | enable = true; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /hosts/modules/zfs.nix: -------------------------------------------------------------------------------- 1 | # ZFS configs/backups 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | boot = { 8 | supportedFilesystems = [ "zfs" ]; 9 | zfs = { 10 | requestEncryptionCredentials = true; 11 | forceImportRoot = false; 12 | devNodes = "/dev/disk/by-id/"; 13 | }; 14 | }; 15 | 16 | environment.systemPackages = with pkgs; [ 17 | lzop 18 | mbuffer 19 | pv 20 | ]; 21 | 22 | systemd.services.zfs-mount.enable = false; 23 | services.zfs.autoScrub = { 24 | enable = true; 25 | interval = "monthly"; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /hosts/office/configuration.nix: -------------------------------------------------------------------------------- 1 | # Edit this configuration file to define what should be installed on 2 | # your system. Help is available in the configuration.nix(5) man page 3 | # and in the NixOS manual (accessible by running `nixos-help`). 4 | 5 | { 6 | inputs, 7 | ... 8 | }: 9 | { 10 | imports = [ 11 | # Include the results of the hardware scan. 12 | ./disko-config.nix 13 | ./hardware-configuration.nix 14 | ./services 15 | ../modules/common 16 | ../modules/desktops 17 | ../modules/avahi.nix 18 | ../modules/boot.nix 19 | ../modules/libvirt.nix 20 | ../modules/nix-ld.nix 21 | ../modules/opengl-amd.nix 22 | ../modules/podman.nix 23 | ../modules/sddm.nix 24 | ../modules/sway.nix 25 | ../modules/zfs.nix 26 | ../../home-manager/home-manager.nix 27 | inputs.disko.nixosModules.disko 28 | inputs.home-manager.nixosModules.home-manager 29 | inputs.sops-nix.nixosModules.sops 30 | ]; 31 | 32 | home-manager.users.firecat53 = { 33 | imports = [ 34 | inputs.sops-nix.homeManagerModule 35 | ../../home-manager/office.nix 36 | ]; 37 | }; 38 | 39 | networking.hostName = "office"; 40 | networking.hostId = "65b24ecb"; 41 | 42 | # Swap (zram) 43 | zramSwap.enable = true; 44 | 45 | system.stateVersion = "25.05"; 46 | } 47 | -------------------------------------------------------------------------------- /hosts/office/disko-config.nix: -------------------------------------------------------------------------------- 1 | { 2 | disko.devices = { 3 | disk = { 4 | main = { 5 | type = "disk"; 6 | device = "/dev/disk/by-id/nvme-Corsair_MP700_ELITE_AA0AB510009A7K"; 7 | content = { 8 | type = "gpt"; 9 | partitions = { 10 | EFI = { 11 | size = "512M"; 12 | type = "EF00"; 13 | content = { 14 | type = "filesystem"; 15 | format = "vfat"; 16 | mountpoint = "/boot"; 17 | mountOptions = [ "umask=0077" ]; 18 | }; 19 | }; 20 | zfs = { 21 | end = "-8G"; 22 | content = { 23 | type = "zfs"; 24 | pool = "rpool"; 25 | }; 26 | }; 27 | encryptedSwap = { 28 | size = "100%"; 29 | content = { 30 | type = "swap"; 31 | randomEncryption = true; 32 | }; 33 | }; 34 | }; 35 | }; 36 | }; 37 | }; 38 | zpool = { 39 | rpool = { 40 | type = "zpool"; 41 | mode = ""; 42 | options = { 43 | ashift = "12"; 44 | autotrim = "on"; 45 | }; 46 | rootFsOptions = { 47 | acltype = "posixacl"; 48 | canmount = "off"; 49 | compression = "lz4"; 50 | devices = "off"; 51 | dnodesize = "auto"; 52 | encryption = "on"; 53 | keyformat = "passphrase"; 54 | keylocation = "prompt"; 55 | mountpoint = "none"; 56 | normalization = "formD"; 57 | relatime = "on"; 58 | xattr = "sa"; 59 | }; 60 | datasets = { 61 | "nixos" = { 62 | type = "zfs_fs"; 63 | options.mountpoint = "none"; 64 | }; 65 | "nixos/nix" = { 66 | type = "zfs_fs"; 67 | options.mountpoint = "legacy"; 68 | mountpoint = "/nix"; 69 | }; 70 | "nixos/root" = { 71 | type = "zfs_fs"; 72 | options.mountpoint = "legacy"; 73 | mountpoint = "/"; 74 | }; 75 | "nixos/var" = { 76 | type = "zfs_fs"; 77 | options.mountpoint = "none"; 78 | }; 79 | "nixos/var/lib" = { 80 | type = "zfs_fs"; 81 | options.mountpoint = "legacy"; 82 | mountpoint = "/var/lib"; 83 | }; 84 | "nixos/var/lib/containers" = { 85 | type = "zfs_fs"; 86 | options.mountpoint = "none"; 87 | }; 88 | "nixos/var/lib/containers/storage" = { 89 | type = "zfs_fs"; 90 | options.mountpoint = "none"; 91 | }; 92 | "nixos/var/lib/containers/storage/volumes" = { 93 | type = "zfs_fs"; 94 | options.mountpoint = "legacy"; 95 | mountpoint = "/var/lib/containers/storage/volumes"; 96 | }; 97 | "data" = { 98 | type = "zfs_fs"; 99 | options.mountpoint = "none"; 100 | }; 101 | "data/home" = { 102 | type = "zfs_fs"; 103 | options.mountpoint = "legacy"; 104 | mountpoint = "/home"; 105 | }; 106 | "reserved" = { 107 | type = "zfs_fs"; 108 | options.mountpoint = "none"; 109 | options.refreservation = "10G"; 110 | }; 111 | }; 112 | }; 113 | }; 114 | }; 115 | } 116 | -------------------------------------------------------------------------------- /hosts/office/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { config, lib, pkgs, modulesPath, ... }: 5 | 6 | { 7 | imports = 8 | [ (modulesPath + "/installer/scan/not-detected.nix") 9 | ]; 10 | 11 | boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ]; 12 | boot.initrd.kernelModules = [ ]; 13 | boot.kernelModules = [ "kvm-amd" ]; 14 | boot.extraModulePackages = [ ]; 15 | 16 | # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 17 | # (the default) this is the recommended approach. When using systemd-networkd it's 18 | # still possible to use this option, but it's recommended to use it in conjunction 19 | # with explicit per-interface declarations with `networking.interfaces..useDHCP`. 20 | networking.useDHCP = lib.mkDefault true; 21 | # networking.interfaces.eno1.useDHCP = lib.mkDefault true; 22 | 23 | nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; 24 | hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 25 | } 26 | -------------------------------------------------------------------------------- /hosts/office/services/backups.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | { 6 | # Sanoid 7 | services.sanoid = { 8 | enable = true; 9 | datasets."rpool/data" = { 10 | useTemplate = [ "data" ]; 11 | process_children_only = true; 12 | recursive = true; 13 | }; 14 | datasets."rpool/nixos/var/lib" = { 15 | useTemplate = [ "data" ]; 16 | process_children_only = false; 17 | recursive = false; 18 | }; 19 | datasets."rpool/nixos/var/lib/containers/storage/volumes" = { 20 | useTemplate = [ "data" ]; 21 | process_children_only = false; 22 | recursive = false; 23 | }; 24 | templates."data" = { 25 | hourly = 72; 26 | daily = 30; 27 | monthly = 0; 28 | yearly = 0; 29 | autosnap = true; 30 | autoprune = true; 31 | }; 32 | }; 33 | 34 | ### Restic 35 | sops.secrets.restic_env = { }; 36 | sops.secrets.restic_repo = { }; 37 | sops.secrets.restic_password = { }; 38 | 39 | services.restic = { 40 | backups.office = { 41 | user = "root"; 42 | environmentFile = "${config.sops.secrets.restic_env.path}"; 43 | repositoryFile = "${config.sops.secrets.restic_repo.path}"; 44 | passwordFile = "${config.sops.secrets.restic_password.path}"; 45 | paths = [ 46 | "/home" 47 | ]; 48 | exclude = [ 49 | "/home/firecat53/.cache" 50 | "/home/firecat53/.local/uv/" 51 | "/home/firecat53/.local/state/" 52 | "/home/firecat53/.local/tmp/iso" 53 | ]; 54 | timerConfig = { 55 | OnBootSec = "15m"; 56 | OnCalendar = "daily"; 57 | Persistent = true; 58 | }; 59 | pruneOpts = [ 60 | "--keep-monthly 6" 61 | "--keep-weekly 12" 62 | "--keep-daily 30" 63 | "--keep-hourly 72" 64 | ]; 65 | extraBackupArgs = [ 66 | "--retry-lock 30m" 67 | ]; 68 | }; 69 | }; 70 | # Allow restic-backup to restart if failed 71 | systemd.services.restic-backups-office = { 72 | serviceConfig = { 73 | Restart = "on-failure"; 74 | RestartSec = "20"; 75 | }; 76 | unitConfig = { 77 | StartLimitIntervalSec = 100; 78 | StartLimitBurst = 5; 79 | }; 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /hosts/office/services/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./backups.nix 4 | ./nixos.nix 5 | ./searx.nix 6 | ./syncthing.nix 7 | ]; 8 | } 9 | -------------------------------------------------------------------------------- /hosts/office/services/nixos.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | let 6 | user = "firecat53"; 7 | flakePath = "/home/${user}/nixos/nixos"; 8 | in 9 | { 10 | ## Update flake inputs daily 11 | systemd.services = { 12 | flake-update = { 13 | preStart = "${pkgs.host}/bin/host firecat53.net"; # Check network connectivity 14 | unitConfig = { 15 | Description = "Update flake inputs"; 16 | StartLimitIntervalSec = 300; 17 | StartLimitBurst = 5; 18 | }; 19 | serviceConfig = { 20 | ExecStart = "${pkgs.nix}/bin/nix flake update --flake ${flakePath}"; 21 | Restart = "on-failure"; 22 | RestartSec = "30"; 23 | Type = "oneshot"; # Ensure that it finishes before starting nixos-upgrade 24 | User = "${user}"; 25 | }; 26 | before = [ "nixos-upgrade.service" ]; 27 | path = [ 28 | pkgs.nix 29 | pkgs.git 30 | pkgs.host 31 | ]; 32 | }; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /hosts/office/services/searx.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | environment.systemPackages = with pkgs; [ 7 | searxng 8 | ]; 9 | services.searx = { 10 | enable = true; 11 | settings = { 12 | server = { 13 | port = 8888; 14 | bind_address = "127.0.0.1"; 15 | secret_key = "64ZapANvagul"; 16 | }; 17 | }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /hosts/office/services/syncthing.nix: -------------------------------------------------------------------------------- 1 | # Syncthing 2 | { 3 | services.syncthing = { 4 | enable = true; 5 | user = "firecat53"; 6 | group = "users"; 7 | dataDir = "/home/firecat53/.local/state/syncthing"; 8 | configDir = "/home/firecat53/.config/syncthing"; 9 | openDefaultPorts = true; 10 | settings = { 11 | options = { 12 | relaysEnabled = false; 13 | urAccepted = 3; 14 | }; 15 | devices = { 16 | "backup" = { 17 | id = "CAKABE3-JTNUTY6-6BJYHGS-7E4Z35Y-SDF5M6H-GLB6Q2G-M6FVISW-Q3AVHQV"; 18 | }; 19 | "homeserver" = { 20 | id = "3WS2YZY-BCZNA5N-ZNBCA5G-JNPVFLA-FJQI2VQ-BAM5LK5-UVLWWGM-4DWTRQM"; 21 | addresses = [ 22 | "quic://firecat53.net:22000" 23 | "tcp://firecat53.net:22000" 24 | ]; 25 | }; 26 | "scott-cell" = { 27 | id = "6LDX7IF-D2MWKOW-APU3AUX-WXNBWFG-PNIUAPB-QKTWZHF-7MKLPBI-M6E6AQE"; 28 | }; 29 | "scott-laptop" = { 30 | id = "ERJHQAD-KWQH5ZJ-CAV3ZFL-IR6ECOQ-EHVL7GY-6MY5A5M-IORUVXI-NSBYOQE"; 31 | }; 32 | "vps" = { 33 | id = "EPFW7TB-MUV25YB-P2SM66L-ENLRREJ-UJIRELD-QC2FWM4-RVSLFJY-7YWXCQ6"; 34 | addresses = [ 35 | "quic://firecat53.com:22000" 36 | "tcp://firecat53.com:22000" 37 | ]; 38 | }; 39 | }; 40 | folders = { 41 | "camera-scotty" = { 42 | path = "/home/firecat53/media/cameras/scotty"; 43 | devices = [ 44 | "homeserver" 45 | "scott-cell" 46 | "scott-laptop" 47 | ]; 48 | id = "camera-scotty"; 49 | }; 50 | "docs-scotty" = { 51 | path = "/home/firecat53/docs"; 52 | devices = [ 53 | "homeserver" 54 | "scott-cell" 55 | "scott-laptop" 56 | ]; 57 | id = "docs"; 58 | }; 59 | "file_xfer" = { 60 | path = "/home/firecat53/.local/tmp/file_xfer"; 61 | devices = [ 62 | "homeserver" 63 | "scott-cell" 64 | "scott-laptop" 65 | ]; 66 | id = "file_xfer"; 67 | }; 68 | "mail" = { 69 | path = "/home/firecat53/mail"; 70 | devices = [ 71 | "homeserver" 72 | "scott-laptop" 73 | ]; 74 | id = "sdgpi-zh6rd"; 75 | }; 76 | "nixos" = { 77 | path = "/home/firecat53/nixos"; 78 | devices = [ 79 | "homeserver" 80 | "scott-laptop" 81 | "backup" 82 | "vps" 83 | ]; 84 | id = "smqlq-yhrua"; 85 | type = "sendreceive"; 86 | }; 87 | "shared" = { 88 | path = "/home/firecat53/shared"; 89 | devices = [ 90 | "scott-cell" 91 | "homeserver" 92 | "vps" 93 | "scott-laptop" 94 | ]; 95 | id = "shared"; 96 | }; 97 | "srv" = { 98 | path = "/home/firecat53/.local/srv"; 99 | devices = [ 100 | "vps" 101 | "homeserver" 102 | "scott-laptop" 103 | ]; 104 | id = "srv"; 105 | }; 106 | "wallpaper" = { 107 | path = "/home/firecat53/media/wallpaper"; 108 | devices = [ 109 | "homeserver" 110 | "scott-laptop" 111 | ]; 112 | id = "wallpaper"; 113 | }; 114 | }; 115 | }; 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /hosts/vps/configuration.nix: -------------------------------------------------------------------------------- 1 | # Main configuration 2 | { 3 | inputs, 4 | lib, 5 | ... 6 | }: 7 | { 8 | # adjust according to your platform, such as 9 | imports = [ 10 | ./disko-config.nix 11 | ./hardware-configuration.nix 12 | ./services 13 | ../modules/common 14 | ../modules/servers 15 | ../modules/zfs.nix 16 | inputs.disko.nixosModules.disko 17 | inputs.sops-nix.nixosModules.sops 18 | ]; 19 | 20 | # Grub needed for Hetzner VPS with ZFS on root 21 | boot.loader.grub.enable = true; 22 | boot.supportedFilesystems = [ "zfs" ]; 23 | boot.zfs.extraPools = [ "datapool" ]; 24 | 25 | fileSystems = { 26 | "/var/lib" = { 27 | device = "datapool/var-lib"; 28 | fsType = "zfs"; 29 | options = [ "X-mount.mkdir" ]; 30 | }; 31 | "/home/firecat53/shared" = { 32 | device = "datapool/shared"; 33 | fsType = "zfs"; 34 | options = [ "X-mount.mkdir" ]; 35 | }; 36 | }; 37 | 38 | networking.hostName = "vps"; # Define your hostname. 39 | networking.hostId = "6a315305"; 40 | networking.useDHCP = false; 41 | networking.firewall.trustedInterfaces = [ "wg0" ]; 42 | systemd.network = { 43 | enable = true; 44 | networks."10-lan" = { 45 | matchConfig.Name = "enp1s0"; 46 | networkConfig.DHCP = "yes"; 47 | linkConfig.RequiredForOnline = "routable"; 48 | }; 49 | networks."wg0".address = [ "10.200.200.5/24" ]; 50 | }; 51 | 52 | # Override default smartmon enable 53 | services.smartd.enable = lib.mkForce false; 54 | 55 | system.stateVersion = "23.05"; # Did you read the comment? 56 | } 57 | -------------------------------------------------------------------------------- /hosts/vps/disko-config.nix: -------------------------------------------------------------------------------- 1 | { 2 | disko.devices = { 3 | disk = { 4 | main = { 5 | type = "disk"; 6 | device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_37719368"; 7 | content = { 8 | type = "gpt"; 9 | partitions = { 10 | boot = { 11 | size = "1M"; 12 | type = "EF02"; 13 | }; 14 | ESP = { 15 | size = "512M"; 16 | type = "EF00"; 17 | content = { 18 | type = "filesystem"; 19 | format = "vfat"; 20 | mountpoint = "/boot/efi"; 21 | }; 22 | }; 23 | zfs = { 24 | end = "-4G"; 25 | content = { 26 | type = "zfs"; 27 | pool = "rpool"; 28 | }; 29 | }; 30 | encryptedSwap = { 31 | size = "100%"; 32 | content = { 33 | type = "swap"; 34 | randomEncryption = true; 35 | }; 36 | }; 37 | }; 38 | }; 39 | }; 40 | }; 41 | zpool = { 42 | rpool = { 43 | type = "zpool"; 44 | mode = ""; 45 | options = { 46 | ashift = "12"; 47 | autotrim = "on"; 48 | compatibility = "legacy"; 49 | }; 50 | # Can't use compression or dnodesize for grub legacy compatible pools 51 | rootFsOptions = { 52 | acltype = "posixacl"; 53 | canmount = "off"; 54 | devices = "off"; 55 | mountpoint = "none"; 56 | normalization = "formD"; 57 | relatime = "on"; 58 | xattr = "sa"; 59 | }; 60 | datasets = { 61 | "nixos" = { 62 | type = "zfs_fs"; 63 | options.mountpoint = "none"; 64 | }; 65 | "nixos/nix" = { 66 | type = "zfs_fs"; 67 | options.mountpoint = "legacy"; 68 | mountpoint = "/nix"; 69 | }; 70 | "nixos/root" = { 71 | type = "zfs_fs"; 72 | options.mountpoint = "legacy"; 73 | mountpoint = "/"; 74 | }; 75 | "reserved" = { 76 | type = "zfs_fs"; 77 | options.mountpoint = "none"; 78 | options.refreservation = "1G"; 79 | }; 80 | }; 81 | }; 82 | }; 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /hosts/vps/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { config, lib, pkgs, modulesPath, ... }: 5 | 6 | { 7 | imports = 8 | [ (modulesPath + "/profiles/qemu-guest.nix") 9 | ]; 10 | 11 | boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ]; 12 | boot.initrd.kernelModules = [ ]; 13 | boot.kernelModules = [ ]; 14 | boot.extraModulePackages = [ ]; 15 | 16 | # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 17 | # (the default) this is the recommended approach. When using systemd-networkd it's 18 | # still possible to use this option, but it's recommended to use it in conjunction 19 | # with explicit per-interface declarations with `networking.interfaces..useDHCP`. 20 | networking.useDHCP = lib.mkDefault true; 21 | # networking.interfaces.enp1s0.useDHCP = lib.mkDefault true; 22 | 23 | nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; 24 | } 25 | -------------------------------------------------------------------------------- /hosts/vps/services/backups.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | ... 4 | }: 5 | { 6 | # For pull backups from backup server 7 | users.users.backup = { 8 | isNormalUser = true; 9 | uid = 20001; 10 | group = "root"; 11 | home = "/var/lib/backup"; 12 | createHome = true; 13 | openssh.authorizedKeys.keys = [ 14 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDd+gF2w6+0Rj9XFl9e8NcWRux5dKsyAMcgoM6KDH11E backup@backup" 15 | ]; 16 | # password: backup 17 | initialHashedPassword = "$6$Qw7LgzXEL42Q1s0U$UplFl3gpdhQmrmNNHmVt9Bxc4XByH1vBGX95b0ujumaH.V7cPKXkRtqt27vyG591tYfw/0PMkUqplETmswP.t/"; 18 | }; 19 | 20 | ### Sanoid 21 | services.sanoid = { 22 | enable = true; 23 | datasets."datapool" = { 24 | useTemplate = [ "data" ]; 25 | process_children_only = true; 26 | recursive = true; 27 | }; 28 | templates."data" = { 29 | hourly = 48; 30 | daily = 30; 31 | monthly = 6; 32 | yearly = 0; 33 | autosnap = true; 34 | autoprune = true; 35 | }; 36 | }; 37 | 38 | ### Restic 39 | sops.secrets.restic_env = { }; 40 | sops.secrets.restic_repo = { }; 41 | sops.secrets.restic_password = { }; 42 | 43 | services.restic = { 44 | backups.vps = { 45 | user = "root"; 46 | environmentFile = "${config.sops.secrets.restic_env.path}"; 47 | repositoryFile = "${config.sops.secrets.restic_repo.path}"; 48 | passwordFile = "${config.sops.secrets.restic_password.path}"; 49 | paths = [ 50 | "/var/lib" 51 | ]; 52 | timerConfig = { 53 | OnBootSec = "15m"; 54 | OnCalendar = "daily"; 55 | RandomizedDelaySec = "3h"; 56 | Persistent = true; 57 | }; 58 | pruneOpts = [ 59 | "--keep-monthly 6" 60 | "--keep-weekly 12" 61 | "--keep-daily 30" 62 | ]; 63 | extraBackupArgs = [ 64 | "--retry-lock 30m" 65 | ]; 66 | }; 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /hosts/vps/services/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./backups.nix 4 | ./grafana.nix 5 | ./microbin.nix 6 | ./nextcloud.nix 7 | ./nginx.nix 8 | ./prometheus.nix 9 | ./syncthing.nix 10 | ./traefik.nix 11 | ./uptime-kuma.nix 12 | ]; 13 | } 14 | -------------------------------------------------------------------------------- /hosts/vps/services/grafana.nix: -------------------------------------------------------------------------------- 1 | # Grafana 2 | { 3 | services.grafana = { 4 | enable = true; 5 | settings = { 6 | server = { 7 | http_addr = "127.0.0.1"; 8 | http_port = 3000; 9 | domain = "grafana.firecat53.com"; 10 | }; 11 | }; 12 | }; 13 | services.traefik.dynamicConfigOptions.http.routers.grafana = { 14 | rule = "Host(`grafana.firecat53.com`)"; 15 | service = "grafana"; 16 | middlewares = [ "headers" ]; 17 | entrypoints = [ "websecure" ]; 18 | tls = { 19 | certResolver = "le"; 20 | }; 21 | }; 22 | services.traefik.dynamicConfigOptions.http.services.grafana = { 23 | loadBalancer = { 24 | servers = [ 25 | { 26 | url = "http://localhost:3000"; 27 | } 28 | ]; 29 | }; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /hosts/vps/services/microbin.nix: -------------------------------------------------------------------------------- 1 | # Microbin 2 | { 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | systemd.tmpfiles.rules = [ 8 | "d /var/lib/microbin 0755 firecat53 users -" 9 | ]; 10 | systemd.services.microbin = { 11 | enable = true; 12 | wantedBy = [ "multi-user.target" ]; 13 | wants = [ 14 | "network-online.target" 15 | "traefik.service" 16 | ]; 17 | after = [ 18 | "network-online.target" 19 | "traefik.service" 20 | ]; 21 | serviceConfig = { 22 | Type = "simple"; 23 | User = "firecat53"; 24 | ExecStart = "${pkgs.microbin}/bin/microbin"; 25 | }; 26 | environment = { 27 | #MICROBIN_ADMIN_USERNAME = "firecat53"; 28 | MICROBIN_BIND = "127.0.0.1"; 29 | MICROBIN_DATA_DIR = "/var/lib/microbin/"; 30 | MICROBIN_ENABLE_BURN_AFTER = "true"; 31 | MICROBIN_ENABLE_READONLY = "true"; 32 | MICROBIN_ENCRYPTION_CLIENT_SIDE = "true"; 33 | MICROBIN_ENCRYPTION_SERVER_SIDE = "true"; 34 | MICROBIN_ETERNAL_PASTA = "true"; 35 | MICROBIN_GC_DAYS = "0"; 36 | MICROBIN_HIGHLIGHTSYNTAX = "true"; 37 | MICROBIN_LIST_SERVER = "false"; 38 | MICROBIN_MAX_FILE_SIZE_ENCRYPTED_MB = "1024"; 39 | MICROBIN_MAX_FILE_SIZE_UNENCRYPTED_MB = "10000"; 40 | MICROBIN_NO_LISTING = "true"; 41 | MICROBIN_PORT = "8081"; 42 | MICROBIN_PRIVATE = "true"; 43 | MICROBIN_PUBLIC_PATH = "https://mb.firecat53.com"; 44 | MICROBIN_QR = "true"; 45 | MICROBIN_READONLY = "true"; 46 | MICROBIN_UPLOADER_PASSWORD = "paced outlying fling exploit"; 47 | MICROBIN_WIDE = "true"; 48 | }; 49 | }; 50 | 51 | ## Traefik config 52 | services.traefik.dynamicConfigOptions.http.routers.microbin = { 53 | rule = "Host(`mb.firecat53.com`)"; 54 | service = "microbin"; 55 | middlewares = [ "headers" ]; 56 | entrypoints = [ "websecure" ]; 57 | tls = { 58 | certResolver = "le"; 59 | }; 60 | }; 61 | services.traefik.dynamicConfigOptions.http.services.microbin = { 62 | loadBalancer = { 63 | servers = [ 64 | { 65 | url = "http://localhost:8081"; 66 | } 67 | ]; 68 | }; 69 | }; 70 | } 71 | -------------------------------------------------------------------------------- /hosts/vps/services/nextcloud.nix: -------------------------------------------------------------------------------- 1 | # Nextcloud 2 | { 3 | config, 4 | pkgs, 5 | ... 6 | }: 7 | { 8 | sops.secrets.nextcloud-admin-password = { 9 | # This has to be world readable because I can't set ACLs with sops-nix for the 10 | # alertmanager systemd dynamic user. TODO 11 | mode = "0440"; 12 | owner = config.users.users.nextcloud.name; 13 | group = config.users.users.nextcloud.group; 14 | }; 15 | users.users.nextcloud.extraGroups = [ "users" ]; 16 | services.nginx.virtualHosts."nc.firecat53.com".listen = [ 17 | { 18 | addr = "127.0.0.1"; 19 | port = 8082; 20 | } 21 | ]; 22 | 23 | services.nextcloud = { 24 | enable = true; 25 | package = pkgs.nextcloud31; 26 | hostName = "nc.firecat53.com"; 27 | database.createLocally = true; 28 | configureRedis = true; 29 | config = { 30 | adminuser = "firecat53"; 31 | adminpassFile = "${config.sops.secrets.nextcloud-admin-password.path}"; 32 | dbtype = "mysql"; 33 | }; 34 | settings = { 35 | default_phone_region = "US"; 36 | mail_smtpmode = "sendmail"; 37 | mail_sendmailmode = "pipe"; 38 | mysql.utf8mb4 = true; 39 | trusted_proxies = [ "127.0.0.1" ]; 40 | }; 41 | maxUploadSize = "2G"; # also sets post_max_size and memory_limit 42 | phpOptions = { 43 | "opcache.interned_strings_buffer" = "16"; 44 | }; 45 | }; 46 | 47 | services.traefik.dynamicConfigOptions.http.routers.nextcloud = { 48 | rule = "Host(`nc.firecat53.com`)"; 49 | service = "nextcloud"; 50 | middlewares = [ "headers" ]; 51 | entrypoints = [ "websecure" ]; 52 | tls = { 53 | certResolver = "le"; 54 | }; 55 | }; 56 | services.traefik.dynamicConfigOptions.http.services.nextcloud = { 57 | loadBalancer = { 58 | servers = [ 59 | { 60 | url = "http://localhost:8082"; 61 | } 62 | ]; 63 | }; 64 | }; 65 | # Rules for the NextPush app for matrix notifications 66 | services.traefik.dynamicConfigOptions.http.routers.matrix-gateway = { 67 | rule = "Host(`nc.firecat53.com`) && Path(`/_matrix/push/v1/notify`)"; 68 | service = "nextcloud"; 69 | middlewares = [ 70 | "headers" 71 | "matrix-gateway" 72 | ]; 73 | entrypoints = [ "websecure" ]; 74 | tls = { 75 | certResolver = "le"; 76 | }; 77 | }; 78 | services.traefik.dynamicConfigOptions.http.middlewares.matrix-gateway = { 79 | replacePath = { 80 | path = "/index.php/apps/uppush/gateway/matrix"; 81 | }; 82 | }; 83 | services.traefik.staticConfigOptions.entryPoints.http.transport = { 84 | respondingTimeouts = { 85 | readTimeout = "10m"; 86 | writeTimeout = "10m"; 87 | idleTimeout = "10m"; 88 | }; 89 | }; 90 | } 91 | -------------------------------------------------------------------------------- /hosts/vps/services/nginx.nix: -------------------------------------------------------------------------------- 1 | # Nginx 2 | { 3 | ## Create/chown needed files/directories 4 | systemd.tmpfiles.rules = [ 5 | "d /srv/ 0755 firecat53 users -" 6 | ]; 7 | 8 | services.nginx = { 9 | enable = true; 10 | defaultHTTPListenPort = 8080; 11 | virtualHosts."firecat53.com" = { 12 | locations."/misc/" = { 13 | alias = "/srv/http/"; 14 | }; 15 | }; 16 | }; 17 | services.traefik.dynamicConfigOptions.http.routers.nginx = { 18 | rule = "Host(`firecat53.com`) && PathPrefix(`/`)"; 19 | service = "nginx"; 20 | middlewares = [ "headers" ]; 21 | entrypoints = [ "websecure" ]; 22 | tls = { 23 | certResolver = "le"; 24 | }; 25 | }; 26 | services.traefik.dynamicConfigOptions.http.services.nginx = { 27 | loadBalancer = { 28 | servers = [ 29 | { 30 | url = "http://localhost:8080"; 31 | } 32 | ]; 33 | }; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /hosts/vps/services/syncthing.nix: -------------------------------------------------------------------------------- 1 | # Syncthing 2 | { 3 | services.syncthing = { 4 | enable = true; 5 | user = "firecat53"; 6 | group = "users"; 7 | dataDir = "/home/firecat53/.config/syncthing"; 8 | configDir = "/home/firecat53/.config/syncthing"; 9 | openDefaultPorts = true; 10 | overrideDevices = true; 11 | overrideFolders = true; 12 | settings = { 13 | options = { 14 | relaysEnabled = false; 15 | urAccepted = 3; 16 | }; 17 | gui = { 18 | insecureSkipHostcheck = true; 19 | }; 20 | devices = { 21 | "backup" = { 22 | id = "CAKABE3-JTNUTY6-6BJYHGS-7E4Z35Y-SDF5M6H-GLB6Q2G-M6FVISW-Q3AVHQV"; 23 | }; 24 | "scott-cell" = { 25 | id = "6LDX7IF-D2MWKOW-APU3AUX-WXNBWFG-PNIUAPB-QKTWZHF-7MKLPBI-M6E6AQE"; 26 | }; 27 | "homeserver" = { 28 | id = "3WS2YZY-BCZNA5N-ZNBCA5G-JNPVFLA-FJQI2VQ-BAM5LK5-UVLWWGM-4DWTRQM"; 29 | addresses = [ 30 | "quic://firecat53.net:22000" 31 | "tcp://firecat53.net:22000" 32 | ]; 33 | }; 34 | "scott-laptop" = { 35 | id = "ERJHQAD-KWQH5ZJ-CAV3ZFL-IR6ECOQ-EHVL7GY-6MY5A5M-IORUVXI-NSBYOQE"; 36 | }; 37 | "scott-office" = { 38 | id = "4L73OQJ-4T6KOAR-5TJLKKY-ANBRCCB-KAOBFM7-LWVGPFK-QQ643GT-H4LIXAH"; 39 | }; 40 | }; 41 | folders = { 42 | "nixos" = { 43 | path = "/home/firecat53/nixos"; 44 | devices = [ 45 | "homeserver" 46 | "scott-laptop" 47 | "backup" 48 | "scott-office" 49 | ]; 50 | id = "smqlq-yhrua"; 51 | type = "receiveonly"; 52 | }; 53 | "shared" = { 54 | path = "~/shared"; 55 | devices = [ 56 | "scott-cell" 57 | "homeserver" 58 | "scott-laptop" 59 | "scott-office" 60 | ]; 61 | }; 62 | "srv" = { 63 | path = "/srv"; 64 | devices = [ 65 | "homeserver" 66 | "scott-laptop" 67 | "scott-office" 68 | ]; 69 | }; 70 | }; 71 | }; 72 | }; 73 | services.traefik.dynamicConfigOptions.http.routers.syncthing = { 74 | rule = "Host(`syncthing.firecat53.com`)"; 75 | service = "syncthing"; 76 | middlewares = [ 77 | "auth" 78 | "headers" 79 | ]; 80 | entrypoints = [ "websecure" ]; 81 | tls = { 82 | certResolver = "le"; 83 | }; 84 | }; 85 | services.traefik.dynamicConfigOptions.http.services.syncthing = { 86 | loadBalancer = { 87 | servers = [ 88 | { 89 | url = "http://localhost:8384"; 90 | } 91 | ]; 92 | }; 93 | }; 94 | } 95 | -------------------------------------------------------------------------------- /hosts/vps/services/traefik.nix: -------------------------------------------------------------------------------- 1 | # Traefik 2 | { 3 | config, 4 | ... 5 | }: 6 | { 7 | networking.firewall.allowedTCPPorts = [ 8 | 80 9 | 443 10 | ]; 11 | 12 | sops.secrets.basic-auth = { 13 | mode = "0440"; 14 | owner = config.users.users.traefik.name; 15 | group = config.users.users.traefik.group; 16 | }; 17 | services.traefik = { 18 | enable = true; 19 | staticConfigOptions = { 20 | serversTransport = { 21 | insecureSkipVerify = true; 22 | }; 23 | entryPoints = { 24 | web = { 25 | address = ":80"; 26 | http = { 27 | redirections = { 28 | entryPoint = { 29 | to = "websecure"; 30 | scheme = "https"; 31 | }; 32 | }; 33 | }; 34 | }; 35 | websecure = { 36 | address = ":443"; 37 | http = { 38 | tls = { 39 | options = "default"; 40 | }; 41 | }; 42 | }; 43 | }; 44 | api = { 45 | dashboard = true; 46 | }; 47 | certificatesResolvers = { 48 | le = { 49 | acme = { 50 | email = "tech@firecat53.net"; 51 | storage = "/var/lib/traefik/acme.json"; 52 | httpChallenge = { 53 | entryPoint = "web"; 54 | }; 55 | }; 56 | }; 57 | }; 58 | }; 59 | dynamicConfigOptions = { 60 | http = { 61 | routers = { 62 | dashboard = { 63 | rule = "Host(`monitor.firecat53.com`)"; 64 | service = "api@internal"; 65 | middlewares = [ 66 | "auth" 67 | "headers" 68 | ]; 69 | entrypoints = [ "websecure" ]; 70 | tls = { 71 | certResolver = "le"; 72 | }; 73 | }; 74 | }; 75 | middlewares = { 76 | auth = { 77 | basicAuth = { 78 | usersFile = "${config.sops.secrets.basic-auth.path}"; 79 | }; 80 | }; 81 | headers = { 82 | headers = { 83 | browserxssfilter = true; 84 | contenttypenosniff = true; 85 | customframeoptionsvalue = "SAMEORIGIN"; 86 | forcestsheader = true; 87 | framedeny = true; 88 | sslhost = "firecat53.com"; 89 | sslredirect = true; 90 | stsincludesubdomains = true; 91 | stspreload = true; 92 | stsseconds = "315360000"; 93 | }; 94 | }; 95 | }; 96 | }; 97 | tls = { 98 | options = { 99 | default = { 100 | minVersion = "VersionTLS13"; 101 | sniStrict = true; 102 | curvePreferences = [ 103 | "CurveP521" 104 | "CurveP384" 105 | ]; 106 | }; 107 | }; 108 | }; 109 | }; 110 | }; 111 | } 112 | -------------------------------------------------------------------------------- /hosts/vps/services/uptime-kuma.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | ... 4 | }: 5 | { 6 | # Services on homeserver that need monitoring 7 | networking.extraHosts = '' 8 | 10.200.200.6 bw.lan.firecat53.net 9 | 10.200.200.6 cars.lan.firecat53.net 10 | 10.200.200.6 gollum.lan.firecat53.net 11 | 10.200.200.6 hass.lan.firecat53.net 12 | 10.200.200.6 jellyfin.lan.firecat53.net 13 | 10.200.200.6 monitor.lan.firecat53.net 14 | 10.200.200.6 nc.firecat53.net 15 | 10.200.200.6 pdf.lan.firecat53.net 16 | 10.200.200.6 qbt.lan.firecat53.net 17 | 10.200.200.6 radarr.lan.firecat53.net 18 | 10.200.200.6 rss.lan.firecat53.net 19 | 10.200.200.6 sabnzbd.lan.firecat53.net 20 | 10.200.200.6 sonarr.lan.firecat53.net 21 | 10.200.200.6 syncthing.lan.firecat53.net 22 | 10.200.200.6 transmission.lan.firecat53.net 23 | ''; 24 | services.uptime-kuma = { 25 | enable = true; 26 | }; 27 | services.traefik.dynamicConfigOptions.http.routers.up = { 28 | rule = "Host(`up.firecat53.com`)"; 29 | service = "up"; 30 | middlewares = [ "headers" ]; 31 | entrypoints = [ "websecure" ]; 32 | tls = { 33 | certResolver = "le"; 34 | }; 35 | }; 36 | services.traefik.dynamicConfigOptions.http.services.up = { 37 | loadBalancer = { 38 | servers = [ 39 | { 40 | url = "http://localhost:3001"; 41 | } 42 | ]; 43 | }; 44 | }; 45 | 46 | # Add script to check AirVPN exit IP and update Uptime Kuma 47 | # *NOTE* This may break with Uptime Kuma 2.x. API has not been updated in 2 years 48 | sops.secrets.airvpn-api-key = { }; 49 | sops.secrets.kuma-monitor-id = { }; 50 | sops.secrets.kuma-username = { }; 51 | sops.secrets.kuma-password = { }; 52 | 53 | environment.systemPackages = [ 54 | ( 55 | let 56 | pythonEnv = pkgs.python3.withPackages ( 57 | ps: with ps; [ 58 | requests 59 | uptime-kuma-api 60 | ] 61 | ); 62 | in 63 | pkgs.writeScriptBin "check-airvpn-ip" '' 64 | #!${pythonEnv}/bin/python3 65 | import json 66 | import os 67 | import requests 68 | import sys 69 | from uptime_kuma_api import UptimeKumaApi 70 | from uptime_kuma_api.exceptions import UptimeKumaException 71 | 72 | def get_sops_secret(key): 73 | with open(f"/run/secrets/{key}", "r") as f: 74 | return f.read().strip() 75 | 76 | def main(): 77 | # Get secrets from sops-nix 78 | airvpn_api_key = get_sops_secret("airvpn-api-key") 79 | kuma_monitor_id = get_sops_secret("kuma-monitor-id") 80 | kuma_username = get_sops_secret("kuma-username") 81 | kuma_password = get_sops_secret("kuma-password") 82 | 83 | # Get AirVPN status 84 | try: 85 | headers = {"API-KEY": airvpn_api_key} 86 | r = requests.get("https://airvpn.org/api/userinfo/", headers=headers) 87 | data = r.json() 88 | 89 | if r.status_code != 200 or data.get("result") != "ok": 90 | print("Failed to get AirVPN status") 91 | sys.exit(1) 92 | except requests.exceptions.RequestException as e: 93 | print(f"Failed to connect to AirVPN API: {str(e)}") 94 | sys.exit(1) 95 | except json.JSONDecodeError as e: 96 | print(f"Failed to parse AirVPN API response: {str(e)}") 97 | sys.exit(1) 98 | 99 | # Find the Server(QBT) connection 100 | server_ip = None 101 | for session in data.get("sessions", []): 102 | if session.get("device_name") == "Server(QBT)": 103 | server_ip = session.get("exit_ipv4") 104 | break 105 | 106 | if not server_ip: 107 | print("Could not find Server(QBT) connection") 108 | sys.exit(1) 109 | 110 | # Update Uptime Kuma monitor 111 | try: 112 | api = UptimeKumaApi("https://up.firecat53.com") 113 | api.login(kuma_username, kuma_password) 114 | api.edit_monitor(id_=int(kuma_monitor_id), hostname=server_ip) 115 | except UptimeKumaException as e: 116 | print(f"Failed to update Uptime Kuma: {str(e)}") 117 | sys.exit(1) 118 | finally: 119 | api.disconnect() 120 | 121 | print(f"Successfully updated IP address to {server_ip}") 122 | 123 | if __name__ == "__main__": 124 | main() 125 | '' 126 | ) 127 | ]; 128 | 129 | systemd.services.check-airvpn-ip = { 130 | description = "Check AirVPN IP and update Uptime Kuma"; 131 | path = [ 132 | (pkgs.python3.withPackages ( 133 | ps: with ps; [ 134 | requests 135 | uptime-kuma-api 136 | ] 137 | )) 138 | ]; 139 | serviceConfig = { 140 | Type = "oneshot"; 141 | ExecStart = "/run/current-system/sw/bin/check-airvpn-ip"; 142 | }; 143 | }; 144 | 145 | systemd.timers.check-airvpn-ip = { 146 | wantedBy = [ "timers.target" ]; 147 | timerConfig = { 148 | OnBootSec = "1m"; 149 | OnUnitActiveSec = "15m"; 150 | Unit = "check-airvpn-ip.service"; 151 | }; 152 | }; 153 | } 154 | --------------------------------------------------------------------------------