From 680c000c360d11d35b1741f7fa0339c75cef7eae Mon Sep 17 00:00:00 2001 From: Anish Lakhwara Date: Thu, 16 Oct 2025 02:37:11 -0700 Subject: [PATCH] init temp while waiting for public ip address --- README.md | 171 ++++++++++++ flake.lock | 300 ++++++++++++++++++++++ flake.nix | 59 +++++ home-manager/home.nix | 60 +++++ hosts/asusmini/atproto.nix | 75 ++++++ hosts/asusmini/auto-update.nix | 60 +++++ hosts/asusmini/default.nix | 123 +++++++++ hosts/asusmini/hardware-configuration.nix | 41 +++ secrets/pds-env.age | Bin 0 -> 1068 bytes secrets/secrets.nix | 13 + 10 files changed, 902 insertions(+) create mode 100644 README.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 home-manager/home.nix create mode 100644 hosts/asusmini/atproto.nix create mode 100644 hosts/asusmini/auto-update.nix create mode 100644 hosts/asusmini/default.nix create mode 100644 hosts/asusmini/hardware-configuration.nix create mode 100644 secrets/pds-env.age create mode 100644 secrets/secrets.nix diff --git a/README.md b/README.md new file mode 100644 index 0000000..41c5985 --- /dev/null +++ b/README.md @@ -0,0 +1,171 @@ +# Commons Computing NixOS Configuration + +Infrastructure-as-code for Commons Computing's ATProto services. + +## Services + +This flake manages the following services on `asusmini`: + +- **PDS** (Personal Data Server) - `pds.commonscomputer.com:5556` +- **Tangled Knot** (Git forge) - `knot.commonscomputer.com:5555` +- **Tangled Spindle** (CI runner) - `spindle.commonscomputer.com:6555` + +All services are proxied through Caddy with automatic HTTPS. + +## Setup + +### Prerequisites + +```bash +nix develop +``` + +Or install direnv to automatically get the devshell going. + +This provides `agenix` and `dnscontrol`. + +### Managing Secrets + +Secrets are managed with [agenix](https://github.com/ryantm/agenix). If you're unfamiliar with agenix, [here](https://www.splitbrain.org/blog/2025-07/27-agenix) is a good introduction. + +#### Adding a New User's Key + +1. Get their SSH public key (ed25519 or RSA) +2. Add it to `secrets/secrets.nix` in the appropriate key list +3. Re-encrypt all secrets: + ```bash + cd secrets + agenix -e pds-env.age # repeat for each secret + ``` + +#### Creating/Editing Secrets + +```bash +cd secrets +agenix -e pds-env.age +``` + +This opens your `$EDITOR` with the decrypted content. Save and close to re-encrypt. + +#### Adding New Secrets + +1. Add the secret to `secrets/secrets.nix`: + ```nix + "new-secret.age".publicKeys = allKeys; + ``` +2. Create it: + ```bash + cd secrets + agenix -e new-secret.age + ``` +3. Reference it in your NixOS config: + ```nix + age.secrets.new-secret = { + file = ../../secrets/new-secret.age; + mode = "0400"; + owner = "service-user"; + }; + ``` + +### Deployment + +#### Manual Deployment + +From the server: +```bash +cd /etc/nixos # or wherever this repo is cloned +git pull +sudo nixos-rebuild switch --flake .#asusmini +``` + +#### Auto-Update + +A systemd timer runs weekly to: +1. Pull latest git changes +2. Run `nix flake update` +3. Commit and push flake.lock changes +4. Run `nixos-rebuild switch` with automatic rollback on failure + +**Setup required:** +```bash +# On the server, generate SSH key for git push +ssh-keygen -t ed25519 -f /root/.ssh/commons-nix-deploy -N "" +cat /root/.ssh/commons-nix-deploy.pub +# Add the public key as a deploy key with write access to the GitHub repo + +# Configure git to use the key +cat >> /root/.ssh/config < or did:web:. + }; + # optional configuration options. the current value is the default provided to the knot server. + # appviewEndpoint = "https://tangled.sh"; # appview endpoint. + # gitUser = "git"; # user that hosts git repos and performs git operations. + # openFirewall = true; # open port 22 in the firewall for ssh. + # stateDir = "/home/${cfg.gitUser}"; # tangled knot data directory. + # repo = { + # scanPath = cfg.stateDir; # path where repositories are scanned from; + # mainBranch = "main"; # default branch name for repositories; + # }; + # motd = ""; # message of the day. the contents are shown as-is; eg. you will want to add a newline if setting a non-empty message since the knot won't do this for you. + # motdFile = null; # "file containing message of the day. the contents are shown as-is; eg. you will want to add a newline if setting a non-empty message since the knot won't do this for you." + # server = { + # listenAddr = "0.0.0.0:5555"; # address to listen on. + # internalListenAddr = "127.0.0.1:5444"; # internal address for inter-service communication. + # dbPath = "${cfg.stateDir}/knotserver.db"; # path to the database file. + # dev = false; # enable development mode (disables signature verification) + # }; + }; + + services.caddy = { + enable = true; + virtualHosts = { + "knot.commonscomputer.org".extraConfig = '' + reverse_proxy http://localhost:5555 + ''; + "pds.commonscomputer.org".extraConfig = '' + reverse_proxy http://localhost:5556 + ''; + "spindle.commonscomputer.com".extraConfig = '' + reverse_proxy http://localhost:6555 + ''; + }; + }; + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; +} diff --git a/hosts/asusmini/auto-update.nix b/hosts/asusmini/auto-update.nix new file mode 100644 index 0000000..98b6903 --- /dev/null +++ b/hosts/asusmini/auto-update.nix @@ -0,0 +1,60 @@ +{ config, pkgs, ... }: + +{ + systemd.services.auto-update = { + description = "Auto-update NixOS configuration"; + path = with pkgs; [ git nix openssh ]; + + serviceConfig = { + Type = "oneshot"; + User = "root"; + WorkingDirectory = "/etc/nixos"; + }; + + script = '' + set -e + + echo "Pulling latest changes..." + git pull + + echo "Updating flake inputs..." + nix flake update + + # Check if there are changes to commit + if ! git diff --quiet flake.lock; then + echo "Committing flake.lock updates..." + git add flake.lock + git commit -m "auto-update: flake inputs $(date -Iseconds)" + + echo "Pushing changes..." + git push + else + echo "No flake.lock changes to commit" + fi + + echo "Rebuilding system..." + if ! nixos-rebuild switch --flake .#asusmini; then + echo "Build/switch failed, staying on current generation" + exit 1 + fi + + echo "Auto-update completed successfully" + ''; + }; + + systemd.timers.auto-update = { + description = "Auto-update timer"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "weekly"; # Run weekly, adjust as needed + Persistent = true; # Run on boot if missed + RandomizedDelaySec = "1h"; # Add some randomness + }; + }; + + # TODO: Set up SSH key for git push access + # Options: + # 1. Deploy key with write access to the repo + # 2. Generate SSH key on server and add to GitHub + # Command to generate: ssh-keygen -t ed25519 -f /root/.ssh/commons-nix-deploy -N "" +} diff --git a/hosts/asusmini/default.nix b/hosts/asusmini/default.nix new file mode 100644 index 0000000..d79b294 --- /dev/null +++ b/hosts/asusmini/default.nix @@ -0,0 +1,123 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). +{ config, pkgs }: + +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + # ./atproto.nix + ./auto-update.nix + ]; + + # Bootloader. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + networking.hostName = "asusmininix"; # Define your hostname. + + # Static IP configuration + # TODO(anish): Replace with actual static IP once VLAN is configured + # networking.interfaces.eth0 = { + # useDHCP = false; + # ipv4.addresses = [{ + # address = ""; # something like "192.168.1.100" + # prefixLength = 24; # e.g., 24 for /24 subnet + # }]; + # }; + # networking.defaultGateway = ""; # e.g., "192.168.1.1" + # networking.nameservers = [ "" "" ]; # e.g., "1.1.1.1" "8.8.8.8" + + # Disable NetworkManager when using static IP + # networking.networkmanager.enable = true; + + # Tailscale + services.tailscale.enable = true; + services.tailscale.useRoutingFeatures = "both"; + + # flake config + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + # Set your time zone. + time.timeZone = "America/Vancouver"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_CA.UTF-8"; + + # Configure keymap in X11 + services.xserver.xkb = { + layout = "us"; + variant = ""; + }; + + # Define a user account. Don't forget to set a password with ‘passwd’. + users.users.bmann = { + isNormalUser = true; + description = "Boris Mann"; + extraGroups = [ "networkmanager" "wheel" ]; + packages = with pkgs; []; + }; + + users.users.anish = { + isNormalUser = true; + description = "som"; + extraGroups = [ "networkmanager" "wheel" ]; + openssh.authorizedKeys.keys = [ + # Curve + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDM0Zvei46x/yZl/IeBCq6+IYQQ0avulzVyBysF9cPigZMCybWRV7IEU+E3k9t6JrbdbdGfJkcZIWmsWDdKS8W8mBnZpVoT0ffLynu8JQ/TKdGm4Qv6bgUeKNrGsNv0ZPs2CDaGSLj0oJfRF7Ko10tcLP0vW+yujrh+y6TH/vVzJioaV4TGvtCUpn+wEQah9ROwPQLUUofsSWdnRsDJ/gp37zXWs4l5wyjSKtP3O9RZUP7kBekbSqEgSXiTk0oUQSVqIWl9NDiP6onk/gSOjXsR/JPqsSN/XI/c/yj6gyY0f51Ru2D7iBxuMJIJcWV+rU6coIj+ULcQWLzt/7TI8jq5AOOzI/ll4zbL24Eo84Rz+TP9tvMMhDZ0VaMN22AJ8qQEjc5P09tWKsX7Jg39XelyV1jHXncE4yvIE9F4RSCHzWCeKeXakizQNuzSaxTxIExRFYHjNW5bR6+3MTGwVrEIXU+qML+0yFTR86MT+tdY5AreAJQLwbog79O1NupeXJE= anish@curve" + # Box + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKN8/SH55DBiwVoSnTU8k2Pen+wmovL9QaMyehxGEsJJv/8fzwsswGalD4C/4O51LOvdu4UKkZW5hG02uVSK+58p3UV3pOPyoqsu/aDeIsWsqmTeTzUrBIWOlNzcDKnohLz2oGC5YO+wyTJ9Iteq6aGJDjErsW7sG3h5lXCs551EmJNNGhtBQaaoytMNnWqSdlVjDNCijurH7WUpp40U/RjEp532l4rX6eIIj3jBKEFbhZkFSSjqbj4xM4SyFt+Jmigb1RMjsQjmpfY1vDtM84RcYfpTUte/T5w2dkD5H6kccmWnwKSJpm9wXfx4E7lR9APdUGnau2U1+XxiD3ytGl anish@box" + # Nix-on-droid line + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJOiXBPVvZAp1fY0a0Tupxj0Ml6MoA51lvqt/jAQq249 nix-on-droid@localhost" + # Work + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC/vvh0i6+uAN0GWlK6ZfyTlc/AW54xe2CroUDsDSoGnFKeIUiSsWexobODlVakNhqwCKfsvUh6g+RdA8ZVcamATcYqxysP4X5fRksmAzRm5281O7ZBDHMB2BdcfHSTgiz7JvMRIQYWDlU8Ck6IL4wlN0b2GMUj9t/GeG37us8280rxpRNoIY7M27AJEZ7XNQhctBIVujxctVBgIMYmZiTwziU7ywJv4rNT5OAWvjRXSo1rkxdvx3VESv4y/mp8m7dEupZpIjIFsLs52+UG5LtadulUqtTWg05sCw8LEcmRhflgZSAvjw60RrKFCuWxc8+/Pmaw+zExeBMenqi0NzuTc3S3k2wCKVIZDh/0tlXzIwZ6WRqxDevUtEKfvbEFMXd8akhTfYs0dyszcFRevBxOBPbcKku+FK/HkdPLmEANvxYty3cv+Eipkz3c8JPJPvXNTXrjepXMm0LUKodO3c15hGogCOxUO38kykkyYnn+MxxHparoMfEr2+oHNpQoS5wA1G43ppqjVoRDgnhleu6ixwRkLZzphY3cnOd5jL9Ie5xIGbFWH1qSlQRdHBkHjuf85z7+QK8nFYAhmG1K3Vt3GNtF8LN1tYQkfwBJ/vsroMNzGPoq4PjVbqb80Eq+96cP89XKfU2/xw1g+p2lJDm/zC1WCjXVzf8NRwC7gqPavQ== anishlakhwara@anishs-mbp.lan" + ]; + }; + + # Allow unfree packages + nixpkgs.config.allowUnfree = true; + + # List packages installed in system profile. To search, run: + # $ nix search wget + environment.systemPackages = with pkgs; [ + vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. + wget + ]; + + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + # programs.mtr.enable = true; + # programs.gnupg.agent = { + # enable = true; + # enableSSHSupport = true; + # }; + + # List services that you want to enable: + + # Enable the OpenSSH daemon. + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "yes"; + }; + }; + + # Open ports in the firewall. + networking.firewall.allowedTCPPorts = [ 22 80 443 ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + # networking.firewall.enable = false; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It‘s perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "25.05"; # Did you read the comment? + +} diff --git a/hosts/asusmini/hardware-configuration.nix b/hosts/asusmini/hardware-configuration.nix new file mode 100644 index 0000000..3995797 --- /dev/null +++ b/hosts/asusmini/hardware-configuration.nix @@ -0,0 +1,41 @@ +# 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" "thunderbolt" "ahci" "nvme" "usb_storage" "usbhid" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/677df32e-477e-4abe-bf2e-f487a9cea7ef"; + fsType = "ext4"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/9BE2-2FFF"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + + swapDevices = + [ { device = "/dev/disk/by-uuid/4ca37db4-1819-40fc-a744-58b959da7fa0"; } + ]; + + # 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.enp89s0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlo1.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/secrets/pds-env.age b/secrets/pds-env.age new file mode 100644 index 0000000000000000000000000000000000000000..9206454ee36d630e4fa1ca0ac4efa47631cb8424 GIT binary patch literal 1068 zcmXxi?Tg!V0KjoU@FZ?bWFm|mbSi?Bnzm`0)`8F_O`7x}P11)nqBF@aX_F>tp8Ige zyxm^tn{yrtGT3CC4D{a2hk=Mg5MRs}8@?IH4xhMz!oBdt-8t0VK;PV7@cq8{$OA2< zIjTQ%Lu2f`H1-E@oPkoWB!Xa=(m)nPGsOgDOx4ODfhcyX;;<9M6i7a*Pc?@I5*cN= zAar3>o>D^3^4atl7b;Lms+KE-QO5E3q@c6O2HMq7G#n0Op3~>UUUxhXNKjV!kUOmT zft+Zu z&#-b+0Wt-ZWmq4^RkUT)h(2e=%7DS0UWrs&HOC(}&Ac7SIs!lrH|u=MvBVlSGr|Vy z&5ii~O#rbYmGlh;qnXkqZ23*N?%7~wTO931ItWFY6EMIiPNq{2hD?{4QMHCM!z_lT zge;MTqA03QJc;s*;2`LFgzVR~(CaJtwnX_dHqsaY#|thls?>altF+|w zMY9T^StA#Sh?mz0tyCn)nN3q|IiDGIF@Wm2$w~;89I}JRCqQV#es$t?qh{M|AT(X0 zHNOM#3{Xn3YS43qbu2BAIt3fX+8!BC4V5M9Nr31z!JslFvf-<=R;Xpr`LLR8PMZ0C zl+Qu7DtV>8<-mBi+$}0j)78ce83|fSGSl{upzo3zuawLIqfZ-rm_`VT;RKfDv3es- zmvkr&(-jQH0^hZYmTU`_D2bwC=Ykn9{MNwIBb>yne!7=UiUZ2PTclIa@aYtWJGMSE z8R(G4A;fSP!OhK@{jn#o zibyeXuj3?TljSNEIyMD~Hb#Uij6)qX2Q=nRpj0ZA5NZXfsuH?w2brWjphUQt=STCN zLg$k7FzCA2NT>$Wo|NODgYDCVxV82C!@Yw`xA%{1o=n9TjTeU7Z+&o|Uo*b^{R+1J z`B&Gk9ACcl_RiWu>bsXu9$n$CZ7lU3zp(Mmg!}o{%FVC$6YM$b?%79!`1Bjc9(m?~ zIzc|Qzj)*3&M9(D^dG)@Y`K^_v+(8g*qX z{fCW<=#k$#{L^1Nc=kyY`Qz^BMR@zO>*S|b>5uO1-C5jgZ~k&C!9BMMqz~_m-ar1% Hx#j-=v9XF# literal 0 HcmV?d00001 diff --git a/secrets/secrets.nix b/secrets/secrets.nix new file mode 100644 index 0000000..eef9f81 --- /dev/null +++ b/secrets/secrets.nix @@ -0,0 +1,13 @@ +let + asusmini = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK+f1Sl4jEmYyBHymiFUe6uX9c0qlARURMPfk81Anc6M root@asusmini"; + + # Generate with: ssh-keyscan or from ~/.ssh/id_ed25519.pub or ~/.ssh/id_rsa.pub + anish_curve = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDM0Zvei46x/yZl/IeBCq6+IYQQ0avulzVyBysF9cPigZMCybWRV7IEU+E3k9t6JrbdbdGfJkcZIWmsWDdKS8W8mBnZpVoT0ffLynu8JQ/TKdGm4Qv6bgUeKNrGsNv0ZPs2CDaGSLj0oJfRF7Ko10tcLP0vW+yujrh+y6TH/vVzJioaV4TGvtCUpn+wEQah9ROwPQLUUofsSWdnRsDJ/gp37zXWs4l5wyjSKtP3O9RZUP7kBekbSqEgSXiTk0oUQSVqIWl9NDiP6onk/gSOjXsR/JPqsSN/XI/c/yj6gyY0f51Ru2D7iBxuMJIJcWV+rU6coIj+ULcQWLzt/7TI8jq5AOOzI/ll4zbL24Eo84Rz+TP9tvMMhDZ0VaMN22AJ8qQEjc5P09tWKsX7Jg39XelyV1jHXncE4yvIE9F4RSCHzWCeKeXakizQNuzSaxTxIExRFYHjNW5bR6+3MTGwVrEIXU+qML+0yFTR86MT+tdY5AreAJQLwbog79O1NupeXJE= anish@curve"; + anish_work = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHOnfDvR2D2nGnC+DZYDUXiokzz+eLfZwkp+O8WjWutp anishlakhwara@Anishs-MacBook-Pro.local"; + bmann = ""; # TODO(Boris): SSH public key here + + allKeys = [ asusmini anish_curve anish_work bmann ]; +in +{ + "pds-env.age".publicKeys = allKeys; +}