commit b48074e201988da190681ac289d111e114358b10
Author: Max Koon <22125083+k2on@users.noreply.github.com>
Date: Fri Aug 15 19:27:17 2025 -0400
feat: inital public commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..202e3a7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+**/.terraform/*
+
+*.tfstate
+*.tfstate.*
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..4581bf0
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "secrets"]
+ path = secrets
+ url = ssh://git@ssh.koon.us/max/secrets.git
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8b245ce
--- /dev/null
+++ b/README.md
@@ -0,0 +1,72 @@
+
+
+
+
+Koon Family OS
+
+
+More info at max.koon.us/posts/os
+
+
+## Deploy
+
+### Ark
+
+```sh
+nix-shell -p neofetch --run "neofetch"
+ ▗▄▄▄ ▗▄▄▄▄ ▄▄▄▖ admin@ark
+ ▜███▙ ▜███▙ ▟███▛ ---------
+ ▜███▙ ▜███▙▟███▛ OS: NixOS 25.11.20250806.c2ae88e (Xantusia) x86_64
+ ▜███▙ ▜██████▛ Host: HP 829A
+ ▟█████████████████▙ ▜████▛ ▟▙ Kernel: 6.12.40
+ ▟███████████████████▙ ▜███▙ ▟██▙ Uptime: 12 days, 1 hour, 39 mins
+ ▄▄▄▄▖ ▜███▙ ▟███▛ Packages: 373 (nix-system), 111 (nix-user)
+ ▟███▛ ▜██▛ ▟███▛ Shell: bash 5.3.0
+ ▟███▛ ▜▛ ▟███▛ Terminal: /dev/pts/0
+▟███████████▛ ▟██████████▙ CPU: Intel i5-6500T (4) @ 3.100GHz
+▜██████████▛ ▟███████████▛ GPU: Intel HD Graphics 530
+ ▟███▛ ▟▙ ▟███▛ Memory: 2259MiB / 7818MiB
+ ▟███▛ ▟██▙ ▟███▛
+ ▟███▛ ▜███▙ ▝▀▀▀▀
+ ▜██▛ ▜███▙ ▜██████████████████▛
+ ▜▛ ▟████▙ ▜████████████████▛
+ ▟██████▙ ▜███▙
+ ▟███▛▜███▙ ▜███▙
+ ▟███▛ ▜███▙ ▜███▙
+ ▝▀▀▀ ▀▀▀▀▘ ▀▀▀▘
+```
+
+```sh
+just rebuild-ark
+```
+
+### Max's Laptop
+
+```sh
+nix-shell -p neofetch --run "neofetch"
+ ▗▄▄▄ ▗▄▄▄▄ ▄▄▄▖ max@nixos
+ ▜███▙ ▜███▙ ▟███▛ ---------
+ ▜███▙ ▜███▙▟███▛ OS: NixOS 25.05.20250807.e728d7a (Warbler) aarch64
+ ▜███▙ ▜██████▛ Host: Apple MacBook Pro (14-inch, M2 Pro, 2023)
+ ▟█████████████████▙ ▜████▛ ▟▙ Kernel: 6.14.8-asahi
+ ▟███████████████████▙ ▜███▙ ▟██▙ Uptime: 3 days, 2 hours, 11 mins
+ ▄▄▄▄▖ ▜███▙ ▟███▛ Packages: 1936 (nix-system), 1277 (nix-user)
+ ▟███▛ ▜██▛ ▟███▛ Shell: bash 5.2.37
+ ▟███▛ ▜▛ ▟███▛ Resolution: 3024x1890
+▟███████████▛ ▟██████████▙ DE: Plasma 6.3.6 (Wayland)
+▜██████████▛ ▟███████████▛ WM: kwin
+ ▟███▛ ▟▙ ▟███▛ Icons: breeze [GTK2/3]
+ ▟███▛ ▟██▙ ▟███▛ Terminal: alacritty
+ ▟███▛ ▜███▙ ▝▀▀▀▀ CPU: (12) @ 2.424GHz
+ ▜██▛ ▜███▙ ▜██████████████████▛ Memory: 10290MiB / 15424MiB
+ ▜▛ ▟████▙ ▜████████████████▛
+ ▟██████▙ ▜███▙
+ ▟███▛▜███▙ ▜███▙
+ ▟███▛ ▜███▙ ▜███▙
+ ▝▀▀▀ ▀▀▀▀▘ ▀▀▀▘
+```
+
+```sh
+just rebuild
+```
+
diff --git a/assets/logo.png b/assets/logo.png
new file mode 100644
index 0000000..961d245
Binary files /dev/null and b/assets/logo.png differ
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..41a353b
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,367 @@
+{
+ "nodes": {
+ "flake-compat": {
+ "locked": {
+ "lastModified": 1688025799,
+ "narHash": "sha256-ktpB4dRtnksm9F5WawoIkEneh1nrEvuxb5lJFt1iOyw=",
+ "owner": "nix-community",
+ "repo": "flake-compat",
+ "rev": "8bf105319d44f6b9f0d764efa4fdef9f1cc9ba1c",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "flake-compat",
+ "type": "github"
+ }
+ },
+ "flake-parts": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "nixvim",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1754091436,
+ "narHash": "sha256-XKqDMN1/Qj1DKivQvscI4vmHfDfvYR2pfuFOJiCeewM=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "67df8c627c2c39c41dbec76a1f201929929ab0bd",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "flake-parts_2": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "terranix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1736143030,
+ "narHash": "sha256-+hu54pAoLDEZT9pjHlqL9DNzWz0NbUn8NEAHP7PQPzU=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "b905f6fc23a9051a6e1b741e1438dbfc0634c6de",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "home-manager": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1753592768,
+ "narHash": "sha256-oV695RvbAE4+R9pcsT9shmp6zE/+IZe6evHWX63f2Qg=",
+ "owner": "nix-community",
+ "repo": "home-manager",
+ "rev": "fc3add429f21450359369af74c2375cb34a2d204",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "ref": "release-25.05",
+ "repo": "home-manager",
+ "type": "github"
+ }
+ },
+ "ixx": {
+ "inputs": {
+ "flake-utils": [
+ "nixvim",
+ "nuschtosSearch",
+ "flake-utils"
+ ],
+ "nixpkgs": [
+ "nixvim",
+ "nuschtosSearch",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1748294338,
+ "narHash": "sha256-FVO01jdmUNArzBS7NmaktLdGA5qA3lUMJ4B7a05Iynw=",
+ "owner": "NuschtOS",
+ "repo": "ixx",
+ "rev": "cc5f390f7caf265461d4aab37e98d2292ebbdb85",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NuschtOS",
+ "ref": "v0.0.8",
+ "repo": "ixx",
+ "type": "github"
+ }
+ },
+ "nixos-apple-silicon": {
+ "inputs": {
+ "flake-compat": "flake-compat",
+ "nixpkgs": "nixpkgs"
+ },
+ "locked": {
+ "lastModified": 1748659443,
+ "narHash": "sha256-dav2hzyCmXZ3n6lEZrfZBG51+g6PUhkzRl3d6Ypd9x0=",
+ "owner": "nix-community",
+ "repo": "nixos-apple-silicon",
+ "rev": "3ddc251d2acce5019b0fa770e224d068610a34e4",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "ref": "release-2025-05-30",
+ "repo": "nixos-apple-silicon",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1748460289,
+ "narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs_2": {
+ "locked": {
+ "lastModified": 1754563854,
+ "narHash": "sha256-YzNTExe3kMY9lYs23mZR7jsVHe5TWnpwNrsPOpFs/b8=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "e728d7ae4bb6394bbd19eec52b7358526a44c414",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-25.05",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixvim": {
+ "inputs": {
+ "flake-parts": "flake-parts",
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "nuschtosSearch": "nuschtosSearch",
+ "systems": "systems_2"
+ },
+ "locked": {
+ "lastModified": 1754262585,
+ "narHash": "sha256-Yz5dJ0VzGRzSRHdHldsWQbuFYmtP3NWNreCvPfCi9CI=",
+ "owner": "nix-community",
+ "repo": "nixvim",
+ "rev": "ab1b5962e1ca90b42de47e1172e0d24ca80e6256",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "ref": "nixos-25.05",
+ "repo": "nixvim",
+ "type": "github"
+ }
+ },
+ "nuschtosSearch": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "ixx": "ixx",
+ "nixpkgs": [
+ "nixvim",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1753771532,
+ "narHash": "sha256-Pmpke0JtLRzgdlwDC5a+aiLVZ11JPUO5Bcqkj0nHE/k=",
+ "owner": "NuschtOS",
+ "repo": "search",
+ "rev": "2a65adaf2c0c428efb0f4a2bc406aab466e96a06",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NuschtOS",
+ "repo": "search",
+ "type": "github"
+ }
+ },
+ "plasma-manager": {
+ "inputs": {
+ "home-manager": [
+ "home-manager"
+ ],
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1754501628,
+ "narHash": "sha256-FExJ54tVB5iu7Dh2tLcyCSWpaV+lmUzzWKZUkemwXvo=",
+ "owner": "nix-community",
+ "repo": "plasma-manager",
+ "rev": "cca090f8115c4172b9aef6c5299ae784bdd5e133",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "plasma-manager",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "home-manager": "home-manager",
+ "nixos-apple-silicon": "nixos-apple-silicon",
+ "nixpkgs": "nixpkgs_2",
+ "nixvim": "nixvim",
+ "plasma-manager": "plasma-manager",
+ "sops-nix": "sops-nix",
+ "terranix": "terranix",
+ "unstable": "unstable"
+ }
+ },
+ "sops-nix": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1754328224,
+ "narHash": "sha256-glPK8DF329/dXtosV7YSzRlF4n35WDjaVwdOMEoEXHA=",
+ "owner": "mic92",
+ "repo": "sops-nix",
+ "rev": "49021900e69812ba7ddb9e40f9170218a7eca9f4",
+ "type": "github"
+ },
+ "original": {
+ "owner": "mic92",
+ "repo": "sops-nix",
+ "type": "github"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ },
+ "systems_2": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ },
+ "systems_3": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ },
+ "terranix": {
+ "inputs": {
+ "flake-parts": "flake-parts_2",
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "systems": "systems_3"
+ },
+ "locked": {
+ "lastModified": 1749381683,
+ "narHash": "sha256-16z7tXZch12SAd3d8tbAiEOamyq3zFbw1oUq/ipmTkM=",
+ "owner": "terranix",
+ "repo": "terranix",
+ "rev": "9d2370279d595be9e728b68d29ff0b546d88e619",
+ "type": "github"
+ },
+ "original": {
+ "owner": "terranix",
+ "repo": "terranix",
+ "type": "github"
+ }
+ },
+ "unstable": {
+ "locked": {
+ "lastModified": 1754498491,
+ "narHash": "sha256-erbiH2agUTD0Z30xcVSFcDHzkRvkRXOQ3lb887bcVrs=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "c2ae88e026f9525daf89587f3cbee584b92b6134",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..1759e6b
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,127 @@
+{
+ description = "Koon OS";
+
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.05";
+
+ unstable.url = "github:nixos/nixpkgs?ref=nixos-unstable";
+
+ nixos-apple-silicon.url =
+ "github:nix-community/nixos-apple-silicon?ref=release-2025-05-30";
+
+ home-manager = {
+ url = "github:nix-community/home-manager?ref=release-25.05";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ plasma-manager = {
+ url = "github:nix-community/plasma-manager";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.home-manager.follows = "home-manager";
+ };
+
+ nixvim = {
+ url = "github:nix-community/nixvim?ref=nixos-25.05";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ sops-nix = {
+ url = "github:mic92/sops-nix";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ terranix = {
+ url = "github:terranix/terranix";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+ };
+
+ outputs = { self, nixpkgs, unstable, nixos-apple-silicon, home-manager
+ , plasma-manager, nixvim, sops-nix, terranix, ... }: {
+
+ packages.aarch64-linux =
+ let
+ system = "aarch64-linux";
+
+ pkgs = import unstable {
+ inherit system;
+ config = {
+ allowUnfree = true;
+ };
+ };
+
+ terraform = pkgs.terraform.withPlugins (p: [
+ p.pocketid
+ p.local
+ ]);
+ terraformConfiguration = terranix.lib.terranixConfiguration {
+ inherit system;
+ modules = [ ./infra/config.nix ];
+ };
+ in {
+ deploy = pkgs.writeShellScriptBin "deploy" ''
+ echo Deploying Infrastructure...
+
+ export TF_VAR_pocketid_api_token=$(${pkgs.sops}/bin/sops -d --extract '["pocketid-api-token"]' secrets/secrets.yaml)
+
+ cd infra
+
+ cp ${terraformConfiguration} config.tf.json
+
+ ${terraform}/bin/terraform init
+ ${terraform}/bin/terraform apply
+
+ rm -f config.tf.json
+
+ echo Done
+
+ echo Encrypting secrets
+
+ cd ../secrets
+
+ ${pkgs.sops}/bin/sops -e -i sops/oauth.yaml
+
+ echo Done
+ '';
+ };
+
+ nixosConfigurations = {
+ max = let
+ system = "aarch64-linux";
+ pkgs-unstable = import unstable { inherit system; };
+ secrets = import ./secrets;
+ in nixpkgs.lib.nixosSystem {
+ inherit system;
+ specialArgs = { inherit pkgs-unstable secrets; };
+ modules = [
+ ./host/max/default.nix
+ nixos-apple-silicon.nixosModules.apple-silicon-support
+ sops-nix.nixosModules.sops
+ home-manager.nixosModules.home-manager
+ {
+ home-manager.useGlobalPkgs = true;
+ home-manager.useUserPackages = true;
+ home-manager.extraSpecialArgs = { inherit secrets; };
+ home-manager.users.max = { config, pkgs, lib, ... }: {
+ imports = [
+ sops-nix.homeManagerModules.sops
+ nixvim.homeManagerModules.nixvim
+ plasma-manager.homeManagerModules.plasma-manager
+ ./host/max/home.nix # Import your home.nix here
+ ];
+ };
+ }
+ ];
+ };
+
+ ark = let system = "x86_64-linux";
+ in unstable.lib.nixosSystem {
+ inherit system;
+ modules = [
+ ./host/ark/default.nix
+ sops-nix.nixosModules.sops
+ ];
+ };
+ };
+ };
+}
diff --git a/host/ark/default.nix b/host/ark/default.nix
new file mode 100644
index 0000000..bba351f
--- /dev/null
+++ b/host/ark/default.nix
@@ -0,0 +1,62 @@
+{ config, lib, pkgs, ... }: {
+ imports = [
+ ./hardware-configuration.nix
+ ./options.nix
+ ../common/core/default.nix
+ ./user.nix
+ ./sops.nix
+
+ ./service/audio.nix
+ ./service/auth.nix
+ ./service/docs.nix
+ ./service/git.nix
+ ./service/home.nix
+ ./service/photos.nix
+ ./service/radicale.nix
+ ./service/wakapi.nix
+ ];
+
+ # Use the systemd-boot EFI boot loader.
+ boot.loader.systemd-boot.enable = true;
+ boot.loader.efi.canTouchEfiVariables = true;
+
+ networking.hostName = "ark"; # Define your hostname.
+
+ oauth.name = "KoonFamily";
+ oauth.secrets = import ./oauth-secrets.nix;
+
+ security.sudo.wheelNeedsPassword = false;
+
+ services.cloudflared = {
+ enable = true;
+ tunnels = {
+ "91d31395-fbc7-45a1-ae13-148957b32ecd" = {
+ credentialsFile = config.sops.secrets.tunnel-credentials.path;
+ ingress = {
+ "auth.koon.us" = "http://localhost:1411";
+ "photos.koon.us" = "http://localhost:2283";
+ "home.koon.us" = "http://localhost:8123";
+ "docs.koon.us" = "http://localhost:3004";
+ "git.koon.us" = "http://localhost:3000";
+ "ssh.koon.us" = "ssh://localhost:2222";
+ "audio.koon.us" = "http://localhost:8021";
+ "radicale.koon.us" = "http://localhost:5232";
+ "waka.koon.us" = "http://localhost:3006";
+ };
+ default = "http_status:404";
+ };
+ };
+ };
+
+ fileSystems."/mnt/hdd" = {
+ device = "/dev/sdb";
+ fsType = "ext4";
+ };
+
+ services.openssh.enable = true;
+
+ networking.firewall.allowedTCPPorts = [ 8123 22 ];
+
+ system.stateVersion = "25.05"; # Did you read the comment?
+}
+
diff --git a/host/ark/hardware-configuration.nix b/host/ark/hardware-configuration.nix
new file mode 100644
index 0000000..956f4a6
--- /dev/null
+++ b/host/ark/hardware-configuration.nix
@@ -0,0 +1,39 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+ imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
+
+ boot.initrd.availableKernelModules =
+ [ "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" = {
+ device = "/dev/disk/by-uuid/56034a80-72ea-4e67-be41-2e8cb642fb44";
+ fsType = "ext4";
+ };
+
+ fileSystems."/boot" = {
+ device = "/dev/disk/by-uuid/DE8B-01DE";
+ fsType = "vfat";
+ options = [ "fmask=0022" "dmask=0022" ];
+ };
+
+ swapDevices = [ ];
+
+ # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
+ # (the default) this is the recommended approach. When using systemd-networkd it's
+ # still possible to use this option, but it's recommended to use it in conjunction
+ # with explicit per-interface declarations with `networking.interfaces..useDHCP`.
+ networking.useDHCP = lib.mkDefault true;
+ # networking.interfaces.eno1.useDHCP = lib.mkDefault true;
+ # networking.interfaces.wlp1s0.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
+ hardware.cpu.intel.updateMicrocode =
+ lib.mkDefault config.hardware.enableRedistributableFirmware;
+}
diff --git a/host/ark/options.nix b/host/ark/options.nix
new file mode 100644
index 0000000..c4233cf
--- /dev/null
+++ b/host/ark/options.nix
@@ -0,0 +1,7 @@
+{ lib, ... }: {
+ options.oauth = {
+ name = lib.mkOption { type = lib.types.str; };
+ secrets = lib.mkOption { type = lib.types.attrs; };
+ };
+
+}
diff --git a/host/ark/service/audio.nix b/host/ark/service/audio.nix
new file mode 100644
index 0000000..9840857
--- /dev/null
+++ b/host/ark/service/audio.nix
@@ -0,0 +1,6 @@
+{ ... }: {
+ services.audiobookshelf = {
+ enable = true;
+ port = 8021;
+ };
+}
diff --git a/host/ark/service/auth.nix b/host/ark/service/auth.nix
new file mode 100644
index 0000000..f339e33
--- /dev/null
+++ b/host/ark/service/auth.nix
@@ -0,0 +1,14 @@
+{ config, pkgs, ... }: {
+ services.pocket-id = {
+ enable = true;
+ settings = {
+ APP_URL = "https://auth.koon.us";
+ TRUST_PROXY = true;
+ ANALYTICS_DISABLED = true;
+
+ UI_CONFIG_DISABLED = true;
+
+ APP_NAME = config.oauth.name;
+ };
+ };
+}
diff --git a/host/ark/service/docs.nix b/host/ark/service/docs.nix
new file mode 100644
index 0000000..c3d4084
--- /dev/null
+++ b/host/ark/service/docs.nix
@@ -0,0 +1,94 @@
+{ config, lib, pkgs, ... }: {
+ nixpkgs.config.allowUnfree = true;
+
+ services.outline = {
+ enable = true;
+ publicUrl = "https://docs.koon.us";
+ port = 3004;
+ forceHttps = true;
+ storage.storageType = "local";
+ logo = "https://i.imgur.com/fKJ1I63.png";
+ oidcAuthentication = {
+ authUrl = "https://auth.koon.us/authorize";
+ tokenUrl = "https://auth.koon.us/api/oidc/token";
+ userinfoUrl = "https://auth.koon.us/api/oidc/userinfo";
+ clientId = "";
+ clientSecretFile = config.sops.secrets."docs/clientSecret".path;
+ scopes = [ "openid" "email" "profile" ];
+ usernameClaim = "preferred_username";
+ displayName = config.oauth.name;
+ };
+ };
+
+ systemd.services.outline = {
+ script =
+ let
+ localPostgresqlUrl = "postgres://localhost/outline?host=/run/postgresql";
+ cfg = config.services.outline;
+ in lib.mkForce ''
+ export SECRET_KEY="$(head -n1 ${lib.escapeShellArg cfg.secretKeyFile})"
+ export UTILS_SECRET="$(head -n1 ${lib.escapeShellArg cfg.utilsSecretFile})"
+ ${lib.optionalString (cfg.storage.storageType == "s3") ''
+ export AWS_SECRET_ACCESS_KEY="$(head -n1 ${lib.escapeShellArg cfg.storage.secretKeyFile})"
+ ''}
+ ${lib.optionalString (cfg.slackAuthentication != null) ''
+ export SLACK_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.slackAuthentication.secretFile})"
+ ''}
+ ${lib.optionalString (cfg.googleAuthentication != null) ''
+ export GOOGLE_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.googleAuthentication.clientSecretFile})"
+ ''}
+ ${lib.optionalString (cfg.azureAuthentication != null) ''
+ export AZURE_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.azureAuthentication.clientSecretFile})"
+ ''}
+ ${lib.optionalString (cfg.oidcAuthentication != null) ''
+ export OIDC_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.oidcAuthentication.clientSecretFile})"
+ export OIDC_CLIENT_ID="$(cat ${config.sops.secrets."docs/clientId".path})"
+ ''}
+ ${lib.optionalString (cfg.sslKeyFile != null) ''
+ export SSL_KEY="$(head -n1 ${lib.escapeShellArg cfg.sslKeyFile})"
+ ''}
+ ${lib.optionalString (cfg.sslCertFile != null) ''
+ export SSL_CERT="$(head -n1 ${lib.escapeShellArg cfg.sslCertFile})"
+ ''}
+ ${lib.optionalString (cfg.slackIntegration != null) ''
+ export SLACK_VERIFICATION_TOKEN="$(head -n1 ${lib.escapeShellArg cfg.slackIntegration.verificationTokenFile})"
+ ''}
+ ${lib.optionalString (cfg.smtp != null) ''
+ export SMTP_PASSWORD="$(head -n1 ${lib.escapeShellArg cfg.smtp.passwordFile})"
+ ''}
+
+ ${
+ if (cfg.databaseUrl == "local") then
+ ''
+ export DATABASE_URL=${lib.escapeShellArg localPostgresqlUrl}
+ export PGSSLMODE=disable
+ ''
+ else
+ ''
+ export DATABASE_URL=${lib.escapeShellArg cfg.databaseUrl}
+ ''
+ }
+
+ ${cfg.package}/bin/outline-server
+ '';
+ };
+ # systemd.services.outline = {
+ # serviceConfig = {
+ # # Load the client ID from the sops secret file
+ # ExecStartPre = let
+ # script = pkgs.writeShellScript "outline-set-oauth" ''
+ # CLIENT_ID=$(cat ${config.sops.secrets."docs/clientId".path})
+ # # Export as environment variable that Outline will use
+ # echo "OIDC_CLIENT_ID=$CLIENT_ID" >> $RUNTIME_DIRECTORY/env
+ # '';
+ # in "+${script}";
+ #
+ # # Load the environment file
+ # EnvironmentFile = "-/run/outline/env";
+ # };
+ #
+ # # Ensure sops secrets are available before starting
+ # after = [ "sops-nix.service" ];
+ # wants = [ "sops-nix.service" ];
+ # };
+}
diff --git a/host/ark/service/git.nix b/host/ark/service/git.nix
new file mode 100644
index 0000000..7d71782
--- /dev/null
+++ b/host/ark/service/git.nix
@@ -0,0 +1,111 @@
+{ lib, config, pkgs, ... }: {
+ services.gitea = {
+ enable = true;
+ user = "git";
+ group = "git";
+ database = {
+ user = "git";
+ name = "git";
+ type = "postgres";
+ };
+ settings = {
+ server = {
+ DOMAIN = "git.koon.us";
+ ROOT_URL = "https://git.koon.us";
+ HTTP_PORT = 3000;
+ LANDING_PAGE = "/max";
+ SSH_DOMAIN = "ssh.koon.us";
+ SSH_PORT = 2222;
+ START_SSH_SERVER = true;
+ };
+ oauth2_client = {
+ ACCOUNT_LINKING = "auto";
+ ENABLE_AUTO_REGISTRATION = true;
+ UPDATE_AVATAR = true;
+ USERNAME = "email";
+ };
+ service = {
+ DISABLE_REGISTRATION = true;
+ ENABLE_PASSWORD_SIGNIN_FORM = false;
+ ENABLE_PASSKEY_AUTHENTICATION = false;
+
+ SHOW_MILESTONES_DASHBOARD_PAGE = false;
+ };
+ "service.explore" = {
+ DISABLE_USERS_PAGE = true;
+ DISABLE_ORGANIZATIONS_PAGE = true;
+ DISABLE_CODE_PAGE = true;
+ };
+ };
+ };
+
+ users.users.git = {
+ isSystemUser = true;
+ group = "git";
+ home = "/var/lib/gitea";
+ description = "Git server (Gitea)";
+ createHome = true;
+ };
+ users.groups.git = { };
+
+ systemd.services.gitea = {
+ serviceConfig = {
+ RestartSec = "60"; # Retry every minute
+ };
+ preStart = let
+ exe = lib.getExe config.services.gitea.package;
+
+ clientIdPath = config.sops.secrets."git/clientId".path;
+ clientSecretPath = config.sops.secrets."git/clientSecret".path;
+
+ args = lib.escapeShellArgs (lib.concatLists [
+ [ "--name" config.oauth.name ]
+ [ "--provider" "openidConnect" ]
+ # [ "--key" config.oauth.secrets.git.clientId ]
+ [
+ "--auto-discover-url"
+ "https://auth.koon.us/.well-known/openid-configuration"
+ ]
+ [ "--scopes" "email" ]
+ [ "--scopes" "profile" ]
+ [ "--group-claim-name" "groups" ]
+ [ "--admin-group" "admin" ]
+ [ "--skip-local-2fa" ]
+ ]);
+ in lib.mkAfter ''
+ CLIENT_ID=$(cat ${clientIdPath})
+ CLIENT_SECRET=$(cat ${clientSecretPath})
+
+ provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${config.oauth.name}' | cut -f1)
+
+ if [[ -z "$provider_id" ]]; then
+ ${exe} admin auth add-oauth ${args} --key "$CLIENT_ID" --secret "$CLIENT_SECRET"
+ else
+ ${exe} admin auth update-oauth --id "$provider_id" ${args} --key "$CLIENT_ID" --secret "$CLIENT_SECRET"
+ fi
+
+ mkdir -p /var/lib/gitea/custom/public/assets/img/
+
+ ln -sf ${
+ ./git/assets/img/logo.svg
+ } /var/lib/gitea/custom/public/assets/img/logo.svg
+ ln -sf ${
+ ./git/assets/img/favicon.svg
+ } /var/lib/gitea/custom/public/assets/img/favicon.svg
+
+ mkdir -p /var/lib/gitea/custom/templates/base/
+ ln -sf ${
+ ./git/templates/base/head_navbar.tmpl
+ } /var/lib/gitea/custom/templates/base/head_navbar.tmpl
+ ln -sf ${
+ ./git/templates/base/footer_content.tmpl
+ } /var/lib/gitea/custom/templates/base/footer_content.tmpl
+
+ mkdir -p /var/lib/gitea/custom/templates/custom/
+ ln -sf ${
+ ./git/templates/custom/header.tmpl
+ } /var/lib/gitea/custom/templates/custom/header.tmpl
+
+ '';
+ };
+}
diff --git a/host/ark/service/git/assets/css/custom.css b/host/ark/service/git/assets/css/custom.css
new file mode 100644
index 0000000..34b5f9b
--- /dev/null
+++ b/host/ark/service/git/assets/css/custom.css
@@ -0,0 +1,15 @@
+/* custom.css */
+:root {
+ --color-primary: #2e7d32;
+ --color-primary-dark: #1b5e20;
+}
+
+/* Hide "Powered by Gitea" */
+.footer .ui.container .ui.left {
+ display: none;
+}
+
+/* Custom header background */
+.ui.top.menu {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+}
diff --git a/host/ark/service/git/assets/img/favicon.svg b/host/ark/service/git/assets/img/favicon.svg
new file mode 100644
index 0000000..364038c
--- /dev/null
+++ b/host/ark/service/git/assets/img/favicon.svg
@@ -0,0 +1,6 @@
+
diff --git a/host/ark/service/git/assets/img/logo.svg b/host/ark/service/git/assets/img/logo.svg
new file mode 100644
index 0000000..364038c
--- /dev/null
+++ b/host/ark/service/git/assets/img/logo.svg
@@ -0,0 +1,6 @@
+
diff --git a/host/ark/service/git/templates/base/footer_content.tmpl b/host/ark/service/git/templates/base/footer_content.tmpl
new file mode 100644
index 0000000..221452c
--- /dev/null
+++ b/host/ark/service/git/templates/base/footer_content.tmpl
@@ -0,0 +1,3 @@
+
diff --git a/host/ark/service/git/templates/base/head_navbar.tmpl b/host/ark/service/git/templates/base/head_navbar.tmpl
new file mode 100644
index 0000000..8043f33
--- /dev/null
+++ b/host/ark/service/git/templates/base/head_navbar.tmpl
@@ -0,0 +1,190 @@
+{{$notificationUnreadCount := 0}}
+{{if and .IsSigned .NotificationUnreadCount}}
+ {{$notificationUnreadCount = call .NotificationUnreadCount ctx}}
+{{end}}
+{{$activeStopwatch := NIL}}
+{{if and .IsSigned EnableTimetracking .GetActiveStopwatch}}
+ {{$activeStopwatch = call .GetActiveStopwatch ctx}}
+{{end}}
+
diff --git a/host/ark/service/git/templates/custom/header.tmpl b/host/ark/service/git/templates/custom/header.tmpl
new file mode 100644
index 0000000..21e63b1
--- /dev/null
+++ b/host/ark/service/git/templates/custom/header.tmpl
@@ -0,0 +1,10 @@
+
diff --git a/host/ark/service/home.nix b/host/ark/service/home.nix
new file mode 100644
index 0000000..85ed873
--- /dev/null
+++ b/host/ark/service/home.nix
@@ -0,0 +1,28 @@
+{ pkgs, ... }: {
+ virtualisation.oci-containers = let
+ hass_config = pkgs.writeText "configuration.yaml" ''
+ # Discovery
+ default_config:
+
+ # Web Server configuration
+ http:
+ server_host: 127.0.0.1
+ use_x_forwarded_for: true
+ trusted_proxies: 127.0.0.1
+ '';
+ in {
+ backend = "podman";
+ containers.homeassistant = {
+ volumes = [
+ "home-assistant:/config"
+ # "/data/docker/hass:/config"
+ "${hass_config}:/config/configuration.yaml"
+ # "/run/secrets/home-assistant:/config/secrets.yaml"
+ ];
+ environment.TZ = "America/New_York";
+ image =
+ "ghcr.io/home-assistant/home-assistant:stable"; # Warning: if the tag does not change, the image will not be updated
+ extraOptions = [ "--network=host" ];
+ };
+ };
+}
diff --git a/host/ark/service/photos.nix b/host/ark/service/photos.nix
new file mode 100644
index 0000000..89feb53
--- /dev/null
+++ b/host/ark/service/photos.nix
@@ -0,0 +1,117 @@
+{ lib, config, pkgs, ... }: {
+ sops = {
+ templates = {
+ "immich-config.json" = {
+ content = builtins.toJSON {
+ passwordLogin.enabled = false;
+
+ # We will do this ourselves
+ backup.database.enabled = false;
+
+ oauth = {
+ enabled = true;
+ autoLaunch = true;
+ autoRegister = true;
+ buttonText =
+ lib.strings.concatStrings [ "Login To " config.oauth.name ];
+ clientId = config.sops.placeholder."photos/clientId";
+ clientSecret = config.sops.placeholder."photos/clientSecret";
+ issuerUrl = "https://auth.koon.us/.well-known/openid-configuration";
+ };
+ };
+ owner = config.users.users.immich.name;
+ mode = "0400";
+ restartUnits = [ "immich-server.service" "pocket-id.service" ];
+ };
+ };
+ };
+
+ services.immich = {
+ enable = true;
+ port = 2283;
+ environment.IMMICH_CONFIG_FILE = config.sops.templates."immich-config.json".path;
+ accelerationDevices = null;
+
+ machine-learning.environment = {
+ HF_XET_CACHE = "/var/cache/immich/huggingface-xet";
+ };
+
+ };
+
+ users.users.immich = {
+ home = "/var/lib/immich";
+ createHome = true;
+ extraGroups = [ "video" "render" ];
+ };
+
+ hardware.graphics = {
+ enable = true;
+ extraPackages = with pkgs; [ intel-media-driver ];
+ };
+ environment.sessionVariables = { LIBVA_DRIVER_NAME = "iHD"; };
+
+ services.restic.backups = {
+ immich-local = {
+ repository = "/mnt/hdd/restic/immich";
+ passwordFile = config.sops.secrets.restic-password.path;
+ initialize = true;
+ paths = [ "/var/lib/immich/upload" "/var/backup/immich" ];
+ backupPrepareCommand = ''
+ mkdir -p /var/backup/immich
+
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
+
+ ${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
+ --clean \
+ --if-exists \
+ --dbname=immich > /var/backup/immich/postgres.sql
+ '';
+ backupCleanupCommand = ''
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
+ '';
+ };
+ immich-remote = {
+ repository = "rest:http://m1:8000/immich";
+ passwordFile = config.sops.secrets.restic-password.path;
+ initialize = true;
+ paths = [ "/var/lib/immich/upload" "/var/backup/immich" ];
+ backupPrepareCommand = ''
+ mkdir -p /var/backup/immich
+
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
+
+ ${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
+ --clean \
+ --if-exists \
+ --dbname=immich > /var/backup/immich/postgres.sql
+ '';
+ backupCleanupCommand = ''
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
+ '';
+ };
+ };
+
+ environment.systemPackages = with pkgs;
+ let
+ scripts = with pkgs; {
+ restore_immich_pg = writeShellScriptBin "restore_immich_pg" ''
+ ${pkgs.sudo}/bin/sudo -u postgres psql --dbname=immich < /var/backup/immich/postgres.sql
+ '';
+ restore_immich = writeShellScriptBin "restore_immich" ''
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
+
+ ${pkgs.sudo}/bin/sudo ${restic}/bin/restic -r /mnt/hdd/restic/immich restore latest --target /
+
+ ${scripts.restore_immich_pg}/bin/restore_immich_pg
+
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
+ ${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
+ '';
+ };
+ in [ scripts.restore_immich_pg scripts.restore_immich ];
+}
diff --git a/host/ark/service/radicale.nix b/host/ark/service/radicale.nix
new file mode 100644
index 0000000..0a5016e
--- /dev/null
+++ b/host/ark/service/radicale.nix
@@ -0,0 +1,9 @@
+{ ... }: {
+ services.radicale = {
+ enable = true;
+ settings = {
+ auth.type = "none";
+ server.hosts = [ "0.0.0.0:5232" ];
+ };
+ };
+}
diff --git a/host/ark/service/wakapi.nix b/host/ark/service/wakapi.nix
new file mode 100644
index 0000000..4289050
--- /dev/null
+++ b/host/ark/service/wakapi.nix
@@ -0,0 +1,28 @@
+{ config, ... }:
+{
+
+ nixpkgs.overlays = [
+ (final: prev: {
+ wakapi = prev.wakapi.overrideAttrs (oldAttrs: rec {
+ src = final.fetchFromGitHub {
+ owner = "k2on";
+ repo = "wakapi";
+ rev = "theming";
+ # hash = "";
+ hash = "sha256-mbQ2cA9tbuDA5OXEP+qVfsrBC90budAzWE7x4oN6ypY=";
+ };
+ # vendorHash = final.lib.fakeHash;
+ vendorHash = "sha256-lb6u9NQbB3bizIRbCRaB7Ngv9T5mAYtSl+g13gL7VEU=";
+ });
+ })
+ ];
+
+ services.wakapi = {
+ enable = true;
+ passwordSaltFile = config.sops.secrets."waka-password-salt".path;
+ settings = {
+ server.port = 3006;
+ app.avatar_url_template = "https://auth.koon.us/api/users/fbffa48a-faf7-4230-a89f-0da184f5948c/profile-picture.png";
+ };
+ };
+}
diff --git a/host/ark/sops.nix b/host/ark/sops.nix
new file mode 100644
index 0000000..049ad8d
--- /dev/null
+++ b/host/ark/sops.nix
@@ -0,0 +1,50 @@
+{ config, ... }:
+{
+ sops = {
+
+ defaultSopsFile = ../../secrets/sops/host/ark/default.yaml;
+ validateSopsFiles = false;
+
+ age.keyFile = "/var/lib/sops-nix/key.txt";
+
+ secrets = {
+ "host_age_key" = {
+ path = "/var/lib/sops-nix/key.txt";
+ };
+
+ "restic-password" = {};
+ "tunnel-credentials" = {};
+ "admin-password" = {};
+
+ "waka-password-salt" = {
+ owner = config.users.users.wakapi.name;
+ };
+
+ "photos/clientId" = {
+ sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
+ };
+ "photos/clientSecret" = {
+ sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
+ };
+
+ "git/clientId" = {
+ sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
+ owner = config.services.gitea.user;
+ };
+ "git/clientSecret" = {
+ sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
+ owner = config.services.gitea.user;
+ };
+
+ "docs/clientId" = {
+ sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
+ owner = config.services.outline.user;
+ };
+ "docs/clientSecret" = {
+ sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
+ owner = config.services.outline.user;
+ };
+
+ };
+ };
+}
diff --git a/host/ark/user.nix b/host/ark/user.nix
new file mode 100644
index 0000000..bcf2d5a
--- /dev/null
+++ b/host/ark/user.nix
@@ -0,0 +1,12 @@
+{ pkgs, config, ... }: {
+
+ sops.secrets.admin-password.neededForUsers = true;
+ users.mutableUsers = false;
+
+ users.users.admin = {
+ isNormalUser = true;
+ extraGroups = [ "wheel" ];
+ hashedPasswordFile = config.sops.secrets.admin-password.path;
+ packages = with pkgs; [ tree vim tmux restic ];
+ };
+}
diff --git a/host/common/core/default.nix b/host/common/core/default.nix
new file mode 100644
index 0000000..0cd2eee
--- /dev/null
+++ b/host/common/core/default.nix
@@ -0,0 +1,9 @@
+{ inputs, ... }: {
+ time.timeZone = "America/New_York";
+
+ services.tailscale.enable = true;
+
+ # security.sudo.wheelNeedsPassword = false;
+
+ nix.settings.experimental-features = [ "nix-command" "flakes" ];
+}
diff --git a/host/common/optional/browser.nix b/host/common/optional/browser.nix
new file mode 100644
index 0000000..1080cfe
--- /dev/null
+++ b/host/common/optional/browser.nix
@@ -0,0 +1,63 @@
+{ lib, ... }: {
+ programs.firefox = let
+ lock-false = {
+ Value = false;
+ Status = "locked";
+ };
+ lock-true = {
+ Value = true;
+ Status = "locked";
+ };
+ lock-empty-string = {
+ Value = "";
+ Status = "locked";
+ };
+ in {
+ enable = true;
+ policies = {
+ DisableTelemetry = true;
+ DisableFirefoxStudies = true;
+ DontCheckDefaultBrowser = true;
+ DisablePocket = true;
+ DisableAccounts = true;
+
+ Preferences = {
+ "extensions.pocket.enabled" = lock-false;
+ "browser.topsites.contile.enabled" = lock-false;
+ "browser.newtabpage.pinned" = lock-empty-string;
+ "browser.newtabpage.activity-stream.showSponsored" = lock-false;
+ "browser.newtabpage.activity-stream.system.showSponsored" = lock-false;
+ "browser.newtabpage.activity-stream.showSponsoredTopSites" = lock-false;
+ };
+
+ ExtensionSettings = {
+ "uBlock0@raymondhill.net" = {
+ install_url =
+ "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi";
+ installation_mode = "force_installed";
+ };
+ "{446900e4-71c2-419f-a6a7-df9c091e268b}" = {
+ install_url =
+ "https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi";
+ installation_mode = "force_installed";
+ };
+ "{d7742d87-e61d-4b78-b8a1-b469842139fa}" = {
+ install_url =
+ "https://addons.mozilla.org/firefox/downloads/latest/vimium-ff/latest.xpi";
+ installation_mode = "force_installed";
+ };
+ "myallychou@gmail.com" = {
+ install_url =
+ "https://addons.mozilla.org/firefox/downloads/latest/youtube-recommended-videos/latest.xpi";
+ installation_mode = "force_installed";
+ };
+
+ };
+
+ UserMessaging = {
+ UrlbarInterventions = false;
+ SkipOnboarding = true;
+ };
+ };
+ };
+}
diff --git a/host/common/optional/desktop.nix b/host/common/optional/desktop.nix
new file mode 100644
index 0000000..eb4c1cd
--- /dev/null
+++ b/host/common/optional/desktop.nix
@@ -0,0 +1,28 @@
+{ pkgs, ... }: {
+ services = {
+ desktopManager.plasma6.enable = true;
+
+ displayManager.sddm.enable = true;
+ displayManager.sddm.wayland.enable = true;
+ };
+
+ environment.systemPackages = with pkgs; [
+ kdePackages.discover # Optional: Install if you use Flatpak or fwupd firmware update sevice
+ kdePackages.kcalc # Calculator
+ kdePackages.kcharselect # Tool to select and copy special characters from all installed fonts
+ kdePackages.kcolorchooser # A small utility to select a color
+ kdePackages.kolourpaint # Easy-to-use paint program
+ kdePackages.ksystemlog # KDE SystemLog Application
+ kdePackages.sddm-kcm # Configuration module for SDDM
+ kdiff3 # Compares and merges 2 or 3 files or directories
+ kdePackages.isoimagewriter # Optional: Program to write hybrid ISO files onto USB disks
+ kdePackages.partitionmanager # Optional Manage the disk devices, partitions and file systems on your computer
+ kdePackages.merkuro
+ kdePackages.korganizer
+ kdePackages.kdepim-addons
+ hardinfo2 # System information and benchmarks for Linux systems
+ haruna # Open source video player built with Qt/QML and libmpv
+ wayland-utils # Wayland utilities
+ wl-clipboard # Command-line copy/paste utilities for Wayland
+ ];
+}
diff --git a/host/common/optional/email.nix b/host/common/optional/email.nix
new file mode 100644
index 0000000..f047774
--- /dev/null
+++ b/host/common/optional/email.nix
@@ -0,0 +1 @@
+{ ... }: { programs.thunderbird.enable = true; }
diff --git a/host/common/optional/fonts.nix b/host/common/optional/fonts.nix
new file mode 100644
index 0000000..6501c95
--- /dev/null
+++ b/host/common/optional/fonts.nix
@@ -0,0 +1,18 @@
+{ pkgs, ... }: {
+ fonts.packages = with pkgs; [
+ monocraft
+
+ (stdenv.mkDerivation {
+ name = "apple-color-emoji";
+ src = fetchurl {
+ url =
+ "https://github.com/samuelngs/apple-emoji-linux/releases/download/v17.4/AppleColorEmoji.ttf";
+ sha256 = "1wahjmbfm1xgm58madvl21451a04gxham5vz67gqz1cvpi0cjva8";
+ };
+ dontUnpack = true;
+ installPhase = ''
+ install -Dm644 $src $out/share/fonts/truetype/AppleColorEmoji.ttf
+ '';
+ })
+ ];
+}
diff --git a/host/common/optional/locale.nix b/host/common/optional/locale.nix
new file mode 100644
index 0000000..525ce99
--- /dev/null
+++ b/host/common/optional/locale.nix
@@ -0,0 +1,14 @@
+{ pkgs, ... }: {
+ i18n.defaultLocale = "en_US.UTF-8";
+ i18n.supportedLocales = [ "en_US.UTF-8/UTF-8" "zh_CN.UTF-8/UTF-8" ];
+ i18n.inputMethod = {
+ enabled = "fcitx5";
+ fcitx5.addons = with pkgs; [
+ # fcitx5-gtk # alternatively, kdePackages.fcitx5-qt
+ kdePackages.fcitx5-qt # alternatively, kdePackages.fcitx5-qt
+ fcitx5-chinese-addons # table input method support
+ fcitx5-nord # a color theme
+ ];
+ };
+
+}
diff --git a/host/common/optional/yubikey.nix b/host/common/optional/yubikey.nix
new file mode 100644
index 0000000..5c35151
--- /dev/null
+++ b/host/common/optional/yubikey.nix
@@ -0,0 +1,32 @@
+{ lib, pkgs, ... }:
+{
+ environment.systemPackages = with pkgs; [
+ yubioath-flutter # gui
+ yubikey-manager # `ykman`
+ pam_u2f # yubikey with sudo
+ ];
+
+ services.pcscd.enable = true;
+ services.udev.packages = [ pkgs.yubikey-personalization ];
+
+ services.yubikey-agent.enable = true;
+
+ security.pam = {
+ sshAgentAuth.enable = true;
+ u2f = {
+ enable = true;
+ settings = {
+ cue = true;
+ authFile = "/home/max/.config/Yubico/u2f_keys";
+ };
+ };
+ services = {
+ login.u2fAuth = true;
+ sudo = {
+ u2fAuth = true;
+ sshAgentAuth = true;
+ };
+ };
+
+ };
+}
diff --git a/host/max/default.nix b/host/max/default.nix
new file mode 100644
index 0000000..ec97a3a
--- /dev/null
+++ b/host/max/default.nix
@@ -0,0 +1,116 @@
+{ pkgs, config, pkgs-unstable, ... }: {
+ imports = [
+ ./hardware-configuration.nix
+ ../common/core/default.nix
+ ./user.nix
+ ./work.nix
+ ./sops.nix
+
+ ../common/optional/yubikey.nix
+
+ ../common/optional/browser.nix
+ ../common/optional/desktop.nix
+ ../common/optional/fonts.nix
+ ../common/optional/locale.nix
+ ../common/optional/email.nix
+
+ ./zero-cache.nix
+ ];
+ services.zero-cache.enable = false;
+
+ # Use the systemd-boot EFI boot loader.
+ boot.loader.systemd-boot.enable = true;
+ boot.loader.efi.canTouchEfiVariables = false;
+
+ boot.m1n1CustomLogo = ../../assets/logo.png;
+
+ hardware = {
+ asahi = {
+ peripheralFirmwareDirectory = ./firmware;
+ useExperimentalGPUDriver = true;
+ experimentalGPUInstallMode = "replace";
+ setupAsahiSound = true;
+ };
+ };
+
+ # networking.hostName = "nixos"; # Define your hostname.
+ # Pick only one of the below networking options.
+ networking.networkmanager.enable =
+ true; # Easiest to use and most distros use this by default.
+
+ hardware.bluetooth = {
+ enable = true;
+ powerOnBoot = true;
+ };
+
+ environment.variables = {
+ XDG_DATA_HOME = "/home/max/.local/share";
+ GSK_RENDERER = "ngl";
+ EDITOR = "nvim";
+ };
+
+ programs.wireshark.enable = true;
+ programs.adb.enable = true;
+
+ programs.kdeconnect.enable = true;
+ environment.systemPackages = with pkgs; [
+ vim
+ git
+ wget
+
+ # mpc
+ gurk-rs
+ libreoffice-qt
+ # ncmpcpp
+
+ brave
+
+ signal-desktop
+ gnupg
+
+ (pass.withExtensions (exts: [ exts.pass-otp ]))
+
+ pinentry
+ pinentry-curses
+ pinentry-qt
+
+ zathura
+
+ fzf
+ ffmpeg
+ ripgrep
+ unzip
+ zbar
+ tt
+ sc-im
+ libqalculate
+ librespeed-cli
+
+ tea
+
+ kubectl
+ cloudflared
+ # gcc
+
+ prismlauncher
+
+ gimp
+ inkscape
+
+ wireshark
+
+ # arm support
+ pkgs-unstable.sparrow
+ ];
+
+ programs.zsh.enable = true;
+
+ programs.gnupg.agent = {
+ enable = true;
+ pinentryPackage = pkgs.pinentry-qt;
+ enableSSHSupport = true;
+ };
+
+ system.stateVersion = "25.05";
+
+}
diff --git a/host/max/firmware/all_firmware.tar.gz b/host/max/firmware/all_firmware.tar.gz
new file mode 100755
index 0000000..a0b04f2
Binary files /dev/null and b/host/max/firmware/all_firmware.tar.gz differ
diff --git a/host/max/firmware/kernelcache.release.mac14j b/host/max/firmware/kernelcache.release.mac14j
new file mode 100755
index 0000000..9f95e2b
Binary files /dev/null and b/host/max/firmware/kernelcache.release.mac14j differ
diff --git a/host/max/hardware-configuration.nix b/host/max/hardware-configuration.nix
new file mode 100644
index 0000000..0dcaf10
--- /dev/null
+++ b/host/max/hardware-configuration.nix
@@ -0,0 +1,35 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+ imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
+
+ boot.initrd.availableKernelModules = [ "usb_storage" "sdhci_pci" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" = {
+ device = "/dev/disk/by-uuid/664ec8c7-4c36-414c-bf99-c5346a4579dd";
+ fsType = "ext4";
+ };
+
+ fileSystems."/boot" = {
+ device = "/dev/disk/by-uuid/02E4-1CF8";
+ fsType = "vfat";
+ options = [ "fmask=0022" "dmask=0022" ];
+ };
+
+ swapDevices = [ ];
+
+ # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
+ # (the default) this is the recommended approach. When using systemd-networkd it's
+ # still possible to use this option, but it's recommended to use it in conjunction
+ # with explicit per-interface declarations with `networking.interfaces..useDHCP`.
+ networking.useDHCP = lib.mkDefault true;
+ # networking.interfaces.wlan0.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
+}
diff --git a/host/max/home.nix b/host/max/home.nix
new file mode 100644
index 0000000..5288c94
--- /dev/null
+++ b/host/max/home.nix
@@ -0,0 +1,18 @@
+{ ... }:
+
+{
+ imports = [
+ ./home/sops.nix
+ ./home/ssh.nix
+ ./home/git.nix
+
+ ./home/browser.nix
+ ./home/desktop.nix
+ ./home/nvim.nix
+ ./home/terminal.nix
+ ];
+
+ home.username = "max";
+ home.homeDirectory = "/home/max";
+ home.stateVersion = "25.05";
+}
diff --git a/host/max/home/browser.nix b/host/max/home/browser.nix
new file mode 100644
index 0000000..1038302
--- /dev/null
+++ b/host/max/home/browser.nix
@@ -0,0 +1,57 @@
+{
+ programs.firefox = {
+ enable = true;
+ profiles = {
+ personal = {
+ id = 0;
+ name = "1. Personal";
+ isDefault = true;
+ settings = {
+ "browser.search.defaultenginename" = "ddg";
+ "browser.search.order.1" = "ddg";
+
+ "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
+ };
+ search = {
+ force = true;
+ default = "ddg";
+ order = [ "ddg" "google" ];
+ };
+ userChrome = builtins.readFile ./browser/userChrome.css;
+ };
+ work = {
+ id = 1;
+ name = "2. Work";
+ settings = {
+ "browser.search.defaultenginename" = "ddg";
+ "browser.search.order.1" = "ddg";
+
+ "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
+ };
+ search = {
+ force = true;
+ default = "ddg";
+ order = [ "ddg" "google" ];
+ };
+ userChrome = builtins.readFile ./browser/userChrome.css;
+ };
+ school = {
+ id = 2;
+ name = "3. School";
+ settings = {
+ "browser.search.defaultenginename" = "ddg";
+ "browser.search.order.1" = "ddg";
+
+ "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
+ };
+ search = {
+ force = true;
+ default = "ddg";
+ order = [ "ddg" "google" ];
+ };
+ userChrome = builtins.readFile ./browser/userChrome.css;
+ };
+
+ };
+ };
+}
diff --git a/host/max/home/browser/userChrome.css b/host/max/home/browser/userChrome.css
new file mode 100644
index 0000000..da75be5
--- /dev/null
+++ b/host/max/home/browser/userChrome.css
@@ -0,0 +1,6 @@
+.browserContainer > findbar {
+ top: 0 !important;
+ position: fixed !important;
+ width: 1000px !important;
+ right: 0 !important;
+}
diff --git a/host/max/home/desktop.nix b/host/max/home/desktop.nix
new file mode 100644
index 0000000..61f21f8
--- /dev/null
+++ b/host/max/home/desktop.nix
@@ -0,0 +1,15 @@
+{ lib, ... }: {
+ programs.plasma = {
+ enable = true;
+ workspace = { wallpaper = "/home/max/bg.jpg"; };
+
+ kwin = { virtualDesktops = { number = 9; }; };
+
+ input = {
+ keyboard = {
+ options = [ "caps:escape" ];
+ layouts = [ { layout = "us"; } { layout = "cn"; } ];
+ };
+ };
+ };
+}
diff --git a/host/max/home/git.nix b/host/max/home/git.nix
new file mode 100644
index 0000000..ec16b17
--- /dev/null
+++ b/host/max/home/git.nix
@@ -0,0 +1,29 @@
+{ lib, ... }:
+let
+ publicGitEmail = "22125083+k2on@users.noreply.github.com";
+ publicKey = "/home/max/.ssh/id_maxkey.pub";
+in
+{
+ programs.git = {
+ enable = true;
+ userName = "Max Koon";
+ userEmail = publicGitEmail;
+ extraConfig = {
+ init.defaultBranch = "main";
+
+ commit.gpgsign = true;
+ gpg.format = "ssh";
+ user.signing.key = publicKey;
+ gpg.ssh.allowedSignersFile = "/home/max/.ssh/allowed_signers";
+ };
+
+ signing = {
+ signByDefault = true;
+ key = publicKey;
+ };
+ };
+
+ home.file.".ssh/allowed_signers".text = ''
+ ${publicGitEmail} ${lib.fileContents ../keys/id_maxkey.pub}
+ '';
+}
diff --git a/host/max/home/nvim.nix b/host/max/home/nvim.nix
new file mode 100644
index 0000000..8f8aae2
--- /dev/null
+++ b/host/max/home/nvim.nix
@@ -0,0 +1,262 @@
+{ pkgs, ... }: {
+ programs.nixvim = {
+ enable = true;
+
+ colorschemes.one.enable = true;
+
+ globals = {
+ mapleader = " ";
+ maplocalleader = " ";
+ };
+
+ clipboard = {
+ providers.wl-copy.enable = true;
+ register = "unnamedplus";
+ };
+
+ opts = {
+ background = "light";
+ relativenumber = true;
+ cursorline = true;
+ number = true;
+
+ signcolumn = "yes";
+
+ updatetime = 250;
+
+ list = true;
+ listchars.__raw = "{ tab = '» ', trail = '·', nbsp = '␣' }";
+
+ };
+
+ extraConfigLua = ''
+ require('stay-centered').setup({ enable = true })
+ require('mini.ai').setup()
+ '';
+
+ keymaps = [
+ {
+ mode = "n";
+ key = "";
+ action = "nohlsearch";
+ }
+ {
+ mode = "n";
+ key = "a";
+ action.__raw = "function() require'harpoon':list():add() end";
+ }
+ {
+ mode = "n";
+ key = "";
+ action.__raw =
+ "function() require'harpoon'.ui:toggle_quick_menu(require'harpoon':list()) end";
+ }
+ {
+ mode = "n";
+ key = "";
+ action.__raw = "function() require'harpoon':list():select(1) end";
+ }
+ {
+ mode = "n";
+ key = "";
+ action.__raw = "function() require'harpoon':list():select(2) end";
+ }
+ {
+ mode = "n";
+ key = "";
+ action.__raw = "function() require'harpoon':list():select(3) end";
+ }
+ {
+ mode = "n";
+ key = "";
+ action.__raw = "function() require'harpoon':list():select(4) end";
+ }
+
+ {
+ mode = "n";
+ key = "b";
+ action = "Neotree";
+ }
+ {
+ mode = "n";
+ key = "l";
+ action = "Neotree reveal";
+ }
+ ];
+
+ diagnostic.settings.virtual_text = true;
+
+ userCommands.W.command = "w";
+
+ plugins = {
+
+ sleuth.enable = true;
+ lastplace.enable = true;
+
+ gitsigns.enable = true;
+ highlight-colors.enable = true;
+ todo-comments.enable = true;
+ # smear-cursor.enable = true;
+ goyo.enable = true;
+
+ treesitter = {
+ enable = true;
+ settings = {
+ ensureInstalled =
+ [ "typescript" "rust" "php" "blade" "python" "nix" ];
+
+ highlight = { enable = true; };
+
+ indent = { enable = true; };
+ };
+ };
+
+ lsp = {
+ enable = true;
+
+ servers = {
+ ts_ls.enable = true;
+ rust_analyzer = {
+ enable = true;
+ installCargo = true;
+ installRustc = true;
+ };
+ clangd.enable = true;
+ tailwindcss.enable = true;
+ phpactor.enable = true;
+ pylsp.enable = true;
+ pyright.enable = true;
+ nixd.enable = true;
+ };
+
+ keymaps = {
+ extra = [
+ {
+ mode = "n";
+ key = "gd";
+ action.__raw = "require('telescope.builtin').lsp_definitions";
+ options = { desc = "LSP: [G]oto [D]efinition"; };
+ }
+ {
+ mode = "n";
+ key = "gr";
+ action.__raw = "require('telescope.builtin').lsp_references";
+ options = { desc = "LSP: [G]oto [R]eferences"; };
+ }
+ ];
+
+ lspBuf = {
+ "." = {
+ mode = [ "n" "x" ];
+ action = "code_action";
+ desc = "Code action";
+ };
+ };
+ };
+ };
+
+ lazydev.enable = true;
+ luasnip.enable = true;
+
+ telescope = {
+ enable = true;
+
+ extensions = {
+ fzf-native.enable = true;
+ ui-select.enable = true;
+ };
+
+ keymaps = {
+ "sf" = {
+ mode = "n";
+ action = "find_files";
+ options = { desc = "[S]earch [F]iles"; };
+ };
+ "sk" = {
+ mode = "n";
+ action = "live_grep";
+ options = { desc = "[S]earch [S]tring"; };
+ };
+ };
+ settings = {
+ extensions.__raw =
+ "{ ['ui-select'] = { require('telescope.themes').get_dropdown() } }";
+ };
+ };
+
+ cmp = {
+ enable = true;
+ settings = {
+ snippet = {
+ expand = ''
+ function(args)
+ require('luasnip').lsp_expand(args.body)
+ end
+ '';
+ };
+
+ completion = { completeopt = "menu,menuone,noinsert"; };
+ formatting = {
+ format = ''require("nvim-highlight-colors").format'';
+ };
+ mapping = {
+ "" = "cmp.mapping.confirm { select = true }";
+ "" = "cmp.mapping.select_next_item()";
+ "" = "cmp.mapping.select_prev_item()";
+ "" = "cmp.mapping.select_next_item()";
+ "" = "cmp.mapping.select_prev_item()";
+ "" = "cmp.mapping.select_next_item()";
+ "" = "cmp.mapping.select_prev_item()";
+ };
+ sources = [
+ {
+ name = "lazydev";
+
+ group_index = 0;
+ }
+ { name = "nvim_lsp"; }
+ { name = "luasnip"; }
+ { name = "path"; }
+ { name = "nvim_lsp_signature_help"; }
+ ];
+ };
+ };
+
+ harpoon = {
+ enable = true;
+ settings.settings = { save_on_toggle = true; };
+ };
+ neo-tree = {
+ enable = true;
+ extraOptions = {
+ filesystem = {
+ filtered_items = {
+ visible = true;
+ };
+ };
+ };
+ };
+ wakatime.enable = true;
+ autoclose.enable = true;
+ ts-autotag.enable = true;
+ spider = {
+ enable = true;
+ extraOptions = {
+ subwordMovement = true;
+ skipInsignificantPunctuation = false;
+ };
+ keymaps = {
+ motions = {
+ "w" = "w";
+ "e" = "e";
+ "b" = "b";
+ };
+ };
+ };
+
+ };
+
+ extraPlugins = with pkgs.vimPlugins; [ stay-centered-nvim mini-ai ];
+
+ };
+}
diff --git a/host/max/home/sops.nix b/host/max/home/sops.nix
new file mode 100644
index 0000000..7cb30c0
--- /dev/null
+++ b/host/max/home/sops.nix
@@ -0,0 +1,19 @@
+{ ... }:
+{
+ sops = {
+
+ age.keyFile = "/home/max/.config/sops/age/keys.txt";
+
+ defaultSopsFile = ../../../secrets/sops/host/max/default.yaml;
+ validateSopsFiles = false;
+
+ secrets = {
+ "ssh_keys/max" = {
+ path = "/home/max/.ssh/id_maxkey";
+ };
+ "waka_config" = {
+ path = "/home/max/.wakatime.cfg";
+ };
+ };
+ };
+}
diff --git a/host/max/home/ssh.nix b/host/max/home/ssh.nix
new file mode 100644
index 0000000..bf13c78
--- /dev/null
+++ b/host/max/home/ssh.nix
@@ -0,0 +1,45 @@
+{ ... }:
+{
+ programs.ssh = {
+ enable = true;
+
+ extraConfig = ''
+ Host m1
+ HostName m1
+ User admin
+
+ Host surface
+ HostName surface
+ User admin
+
+ Host ark
+ HostName ark
+ User admin
+
+ Host pi
+ HostName 192.168.0.143
+ User admin
+
+ Host ssh.koon.us
+ HostName ssh.koon.us
+ ProxyCommand cloudflared access ssh --hostname %h
+ User git
+
+ AddKeysToAgent yes
+ '';
+
+ matchBlocks = {
+ "git" = {
+ host = "github.com";
+ user = "git";
+ identityFile = [
+ "~/.ssh/id_maxkey"
+ ];
+ };
+ };
+ };
+
+ home.file = {
+ ".ssh/id_maxkey.pub".source = ../keys/id_maxkey.pub;
+ };
+}
diff --git a/host/max/home/terminal.nix b/host/max/home/terminal.nix
new file mode 100644
index 0000000..83b17d5
--- /dev/null
+++ b/host/max/home/terminal.nix
@@ -0,0 +1,69 @@
+{ pkgs, ... }: {
+ programs.alacritty = {
+ enable = true;
+ theme = "one_light";
+ settings = {
+ font = {
+ normal.family = "Monocraft";
+ size = 10;
+ };
+ };
+ };
+
+ programs.lf = { enable = true; };
+
+ programs.tmux = {
+ enable = true;
+ mouse = true;
+ keyMode = "vi";
+ shell = "${pkgs.zsh}/bin/zsh";
+ extraConfig = ''
+ set -g status-style bg=white
+
+ bind h select-pane -L
+ bind j select-pane -D
+ bind k select-pane -U
+ bind l select-pane -R
+ '';
+ };
+
+ programs.zsh = {
+ enable = true;
+ enableCompletion = true;
+ autosuggestion = {
+ enable = true;
+ highlight = "fg=#bbbbbb";
+ };
+ syntaxHighlighting.enable = true;
+ dotDir = ".config/zsh";
+ autocd = true;
+
+ # initExtra = builtins.readFile ./zsh-nix-shell.zsh;
+
+ shellAliases = {
+ ll = "ls -la --color";
+ v = "nvim";
+ vi = "nvim";
+ vim = "nvim";
+
+ k = "kubectl";
+
+ tt = "tt --theme one-light -n 10";
+
+ bible = "nvim ~/bible.txt -R";
+ notes = "nvim ~/notes";
+ home = "sudo nvim /etc/nixos/home.nix";
+ wttr = "curl wttr.in/Clemson";
+
+ docx-to-pdf = "libreoffice --headless --convert-to pdf";
+ };
+
+ plugins = [{
+ name = "vi-mode";
+ src = pkgs.zsh-vi-mode;
+ file = "share/zsh-vi-mode/zsh-vi-mode.plugin.zsh";
+ }];
+ };
+
+ programs.starship = { enable = true; };
+}
diff --git a/host/max/keys/id_maxkey.pub b/host/max/keys/id_maxkey.pub
new file mode 100644
index 0000000..4826bac
--- /dev/null
+++ b/host/max/keys/id_maxkey.pub
@@ -0,0 +1 @@
+sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIMywmwW37vjQSd9lqYh9IhGYce9Bi24sTyG3zffpdaJrAAAABHNzaDo= max@koon
diff --git a/host/max/sops.nix b/host/max/sops.nix
new file mode 100644
index 0000000..5018a99
--- /dev/null
+++ b/host/max/sops.nix
@@ -0,0 +1,25 @@
+{ config, lib, ... }:
+{
+ sops = {
+
+ age.keyFile = if builtins.pathExists /var/lib/sops-nix/key.txt then
+ "/var/lib/sops-nix/key.txt"
+ else
+ "/home/max/.config/sops/age/keys.txt" # temp decrypt key
+ ;
+
+ defaultSopsFile = ../../secrets/sops/host/max/default.yaml;
+ validateSopsFiles = false;
+
+ secrets = {
+ "host_age_key" = {
+ path = "/var/lib/sops-nix/key.txt";
+ };
+ "yubico/u2f_keys" = {
+ owner = config.users.users.max.name;
+ inherit (config.users.users.max) group;
+ path = "/home/max/.config/Yubico/u2f_keys";
+ };
+ };
+ };
+}
diff --git a/host/max/user.nix b/host/max/user.nix
new file mode 100644
index 0000000..ca7dd93
--- /dev/null
+++ b/host/max/user.nix
@@ -0,0 +1,13 @@
+{ pkgs, config, ... }: {
+
+ sops.secrets.max-password.neededForUsers = true;
+ users.mutableUsers = false;
+
+ users.users.max = {
+ isNormalUser = true;
+ hashedPasswordFile = config.sops.secrets.max-password.path;
+ extraGroups = [ "wheel" "networkmanager" "video" "wireshark" "kvm" ];
+ packages = with pkgs; [ tree ];
+ shell = pkgs.zsh;
+ };
+}
diff --git a/host/max/work.nix b/host/max/work.nix
new file mode 100644
index 0000000..966f70b
--- /dev/null
+++ b/host/max/work.nix
@@ -0,0 +1,31 @@
+{ config, secrets, ... }: {
+
+
+ services.openvpn.servers = {
+ ris = {
+ config = "config /etc/openvpn/ris/config.ovpn ";
+ updateResolvConf = true;
+ autoStart = false;
+ };
+ };
+
+ sops.secrets = {
+ "ris-vpn/key" = {
+ sopsFile = ../../secrets/sops/host/max/work.yaml;
+ owner = config.users.users.root.name;
+ inherit (config.users.users.root) group;
+ path = "/etc/openvpn/ris/vpnclient.rismedia.com.key";
+ };
+ };
+
+ environment.etc."openvpn/ris/config.ovpn" = {
+ text = secrets.work.ris.vpn.config;
+ };
+ environment.etc."openvpn/ris/vpnclient.rismedia.com.crt" = {
+ text = secrets.work.ris.vpn.crt;
+ };
+
+ networking.extraHosts = ''
+ ${secrets.work.ris.extraHosts}
+ '';
+}
diff --git a/host/max/zero-cache.nix b/host/max/zero-cache.nix
new file mode 100644
index 0000000..90ee2fc
--- /dev/null
+++ b/host/max/zero-cache.nix
@@ -0,0 +1,84 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+
+let
+ cfg = config.services.zero-cache;
+ inherit (lib)
+ mkEnableOption
+ mkIf
+ ;
+
+ litestream = pkgs.buildGoModule rec {
+ pname = "litestream-zero";
+ version = "0.3.13+z0.0.6";
+
+ src = pkgs.fetchFromGitHub {
+ owner = "rocicorp";
+ repo = "litestream";
+ rev = "zero@v0.0.6";
+ sha256 = "sha256-sBKmz2fBoYzYi1kUVeiugLBLPdqHc+fXCBkI8Cttakg=";
+ };
+
+ vendorHash = "sha256-PlfDJbhzbH/ZgtQ35KcB6HtPEDTDgss7Lv8BcKT/Dgg=";
+
+ ldflags = [
+ "-s"
+ "-w"
+ "-X main.Version=${version}"
+
+ # nix does not like to build with this
+ # "-extldflags '-static'"
+
+ ];
+
+ doCheck = false;
+
+ tags = [
+ "osusergo"
+ "netgo"
+ "sqlite_omit_load_extension"
+ ];
+
+ subPackages = [ "cmd/litestream" ];
+ };
+
+ zero-cache = pkgs.buildNpmPackage rec {
+ name = "zero-cache";
+ src = pkgs.fetchFromGitHub {
+ owner = "rocicorp";
+ repo = "mono";
+ rev = "zero/v0.23.2025081401";
+ hash = "sha256-NQcG/vnfUmle/6eNXXmnMqzNvniK8R/mO5RYdMX9pnE=";
+ };
+
+ npmDepsHash = "sha256-9vX9eODN8AfcLcMSjm6KzAAUmPIHfe2BILt0juya5us=";
+ makeCacheWritable = true;
+ npmFlags = [ "--legacy-peer-deps" ];
+ };
+
+in
+{
+ options = {
+ services.zero-cache = {
+ enable = mkEnableOption "Zero-cache, the server component of the Zero sync engine.";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ systemd.services.zero-cache = {
+ description = "Zero Cache";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ Type = "oneshot";
+ ExecStart = "${zero-cache}/bin/zero-cache";
+ RemainAfterExit = true;
+ };
+ };
+ };
+}
+
diff --git a/infra/.terraform.lock.hcl b/infra/.terraform.lock.hcl
new file mode 100644
index 0000000..aa0ed95
--- /dev/null
+++ b/infra/.terraform.lock.hcl
@@ -0,0 +1,16 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/local" {
+ version = "2.5.3"
+ hashes = [
+ "h1:6ADVoHtXiWFhClkKa1vnBycJxqnL0GjHMZAQipa4SEU=",
+ ]
+}
+
+provider "registry.terraform.io/trozz/pocketid" {
+ version = "0.1.5"
+ hashes = [
+ "h1:egwnwPepmLF/OAE96D7RxGlsXYlUVZi3CuFhAH69iVE=",
+ ]
+}
diff --git a/infra/config.nix b/infra/config.nix
new file mode 100644
index 0000000..b48da62
--- /dev/null
+++ b/infra/config.nix
@@ -0,0 +1,93 @@
+{
+ terraform = {
+ required_providers = {
+ pocketid = {
+ source = "trozz/pocketid";
+ };
+ };
+ };
+ provider.pocketid = {
+ base_url = "https://auth.koon.us";
+ api_token = "\${var.pocketid_api_token}";
+ };
+
+ variable.pocketid_api_token = {
+ type = "string";
+ sensitive = true;
+ description = "PocketID API token";
+ };
+
+ resource.pocketid_client.photos = {
+ name = "Photos";
+ callback_urls = [
+ "https://photos.koon.us/auth/login"
+ "https://photos.koon.us/user-settings"
+ "app.immich:///oauth-callback"
+ ];
+ is_public = false;
+ pkce_enabled = false;
+ };
+
+ resource.pocketid_client.git = {
+ name = "Git";
+ callback_urls = [
+ "https://git.koon.us/user/oauth2/KoonFamily/callback"
+ ];
+ is_public = false;
+ pkce_enabled = false;
+ };
+
+ resource.pocketid_client.docs = {
+ name = "Docs";
+ callback_urls = [
+ "https://docs.koon.us/*"
+ ];
+ is_public = false;
+ pkce_enabled = false;
+ };
+
+ output = {
+ photos_client_id = {
+ value = "\${pocketid_client.photos.id}";
+ };
+
+ photos_client_secret = {
+ value = "\${pocketid_client.photos.client_secret}";
+ sensitive = true;
+ };
+
+ git_client_id = {
+ value = "\${pocketid_client.git.id}";
+ };
+
+ git_client_secret = {
+ value = "\${pocketid_client.git.client_secret}";
+ sensitive = true;
+ };
+
+ docs_client_id = {
+ value = "\${pocketid_client.docs.id}";
+ };
+
+ docs_client_secret = {
+ value = "\${pocketid_client.docs.client_secret}";
+ sensitive = true;
+ };
+ };
+
+ resource.local_file.oauth_config = {
+ filename = "\${path.module}/../secrets/sops/oauth.yaml";
+ content = ''
+ photos:
+ clientId: ''${pocketid_client.photos.id}
+ clientSecret: ''${pocketid_client.photos.client_secret}
+ git:
+ clientId: ''${pocketid_client.git.id}
+ clientSecret: ''${pocketid_client.git.client_secret}
+ docs:
+ clientId: ''${pocketid_client.docs.id}
+ clientSecret: ''${pocketid_client.docs.client_secret}
+ '';
+ file_permission = "0600";
+ };
+}
diff --git a/justfile b/justfile
new file mode 100644
index 0000000..edb98a4
--- /dev/null
+++ b/justfile
@@ -0,0 +1,31 @@
+default:
+ @just --list
+
+list:
+ @just --list
+
+add-secrets:
+ git -C secrets add .
+
+rebuild:
+ just add-secrets
+
+ git add .
+ sudo nixos-rebuild switch --flake '.?submodules=1#max'
+
+rebuild-ark:
+ just add-secrets
+
+ git add .
+ nixos-rebuild --flake '.?submodules=1#ark' --build-host admin@100.98.252.15 --target-host admin@100.98.252.15 --use-remote-sudo --fast switch
+
+push-secrets:
+ just add-secrets
+
+ git -C secrets commit
+ git -C secrets push
+
+push:
+ git add .
+ git commit
+ git push
diff --git a/secrets b/secrets
new file mode 160000
index 0000000..7a4d9d5
--- /dev/null
+++ b/secrets
@@ -0,0 +1 @@
+Subproject commit 7a4d9d5e4783115c397624304930ce1b79422a4c
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000..f476c23
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,10 @@
+{ pkgs ? import {} }:
+
+pkgs.mkShell {
+ packages = [
+ pkgs.age
+ pkgs.ssh-to-age
+ pkgs.sops
+ pkgs.just
+ ];
+}