commit 26af7b2dcd6f91e34da00b84069f73e09fa0514c Author: Lilac Date: Sat Jul 11 14:56:13 2026 -0400 initial commit diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..911b23b --- /dev/null +++ b/flake.lock @@ -0,0 +1,176 @@ +{ + "nodes": { + "deploy-rs": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": [ + "nixpkgs" + ], + "utils": "utils" + }, + "locked": { + "lastModified": 1781627888, + "narHash": "sha256-5yHuAh9k7rT7rtf3uRaXkiUyYvQE9oaCgzhprLm2mr8=", + "owner": "serokell", + "repo": "deploy-rs", + "rev": "6d3087eedff75a715b40c0e124ba15d2dd7bec28", + "type": "github" + }, + "original": { + "owner": "serokell", + "repo": "deploy-rs", + "type": "github" + } + }, + "disko": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1781152676, + "narHash": "sha256-RxWs5ND31KzTG7wvMM+PMfUjyNpmIEr999lqNARaM5o=", + "owner": "nix-community", + "repo": "disko", + "rev": "ff8702b4de27f72b4c78573dfb89ec74e36abdf1", + "type": "github" + }, + "original": { + "id": "disko", + "type": "indirect" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1783740085, + "narHash": "sha256-qajyHfZY29G2oEQk+uHxmsJcRoBUBXP9maTpFlwP/dI=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "3cd22efe6471dc7365c822bd9ad73a21e55f38fb", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "release-26.05", + "repo": "home-manager", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1780930886, + "narHash": "sha256-rppURzHviaQN131F+nLiLdGfcb0uCd9gGP0E5+iw9MI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8c3cede7ddc26bd659d2d383b5610efbd2c7a16e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1783703440, + "narHash": "sha256-O3/YajjWo001VUIgD8BwaRdSNLUFe7nZ1qV5TwhRBcw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8f0500b9660505dc3cb647775fe9a978a74b5283", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-26.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "deploy-rs": "deploy-rs", + "disko": "disko", + "home-manager": "home-manager", + "nixpkgs": "nixpkgs_2", + "sops-nix": "sops-nix" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1783174389, + "narHash": "sha256-aCWC8ngycU7OdJrU2+Je3qf+1a2ykuBvpPhZT/9tXMc=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "f1406619a3884cd5c47992a70b8b35c9c0fcb4c9", + "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" + } + }, + "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" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..3e2bcdd --- /dev/null +++ b/flake.nix @@ -0,0 +1,80 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; + + deploy-rs.url = "github:serokell/deploy-rs"; + deploy-rs.inputs.nixpkgs.follows = "nixpkgs"; + + home-manager.url = "github:nix-community/home-manager/release-26.05"; + home-manager.inputs.nixpkgs.follows = "nixpkgs"; + + sops-nix.url = "github:Mic92/sops-nix"; + sops-nix.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = inputs@{ self, nixpkgs, deploy-rs, disko, home-manager, sops-nix, ... }: + { + nixosConfigurations = { + desktop = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = { + inherit inputs; + }; + modules = [ + home-manager.nixosModules.home-manager + sops-nix.nixosModules.sops + + ./hosts/desktop/default.nix + ]; + }; + + vps = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = { + inherit inputs; + }; + modules = [ + ./hosts/vps/default.nix + ]; + }; + }; + + homeConfigurations.lilac = home-manager.lib.homeManagerConfiguration { + pkgs = import nixpkgs { + system = "x86_64-linux"; + }; + modules = [ + ./home/lilac.nix + ]; + }; + + # nix run github:nix-community/nixos-anywhere -- --flake .# --phases install root@
+ # nix run github:serokell/deploy-rs + deploy.nodes = { + vps = { + hostname = "10.0.0.3"; + sshUser = "root"; + magicRollbackTimeout = 120; + profiles.system = { + user = "root"; + remoteBuild = false; + path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.vps; + }; + }; + + desktop = { + hostname = "10.0.0.2"; + sshUser = "root"; + magicRollbackTimeout = 120; + profiles.system = { + user = "root"; + remoteBuild = false; + path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.desktop; + }; + }; + }; + checks = { + x86_64-linux = deploy-rs.lib.x86_64-linux.deployChecks self.deploy; + }; + }; +} diff --git a/home/lilac.nix b/home/lilac.nix new file mode 100644 index 0000000..047aa36 --- /dev/null +++ b/home/lilac.nix @@ -0,0 +1,50 @@ +{ config, pkgs, ... }: + +{ + home.username = "olive"; + home.homeDirectory = "/olive"; + + home.packages = with pkgs; [ + tor-browser + + git + kitty + zsh + helix + ]; + + programs.git = { + enable = true; + settings = { + user = { + name = "Lilac"; + email = "lilac@grasswren.net"; + }; + core = { + editor = "hx"; + }; + init = { + defaultBranch = "main"; + }; + }; + }; + + programs.zsh = { + enable = true; + + enableCompletion = true; + autosuggestion.enable = true; + syntaxHighlighting.enable = true; + + shellAliases = { + ls = "ls -A"; + }; + }; + + home.sessionVariables = { + EDITOR = "hx"; + }; + + programs.home-manager.enable = true; + home.stateVersion = "26.05"; +} diff --git a/home/root.nix b/home/root.nix new file mode 100644 index 0000000..75675b0 --- /dev/null +++ b/home/root.nix @@ -0,0 +1,8 @@ +{ config, lib, pkgs, ... }: + +{ + home.username = "root"; + home.homeDirectory = "/root"; + + +} diff --git a/home/tools.nix b/home/tools.nix new file mode 100644 index 0000000..e06ca89 --- /dev/null +++ b/home/tools.nix @@ -0,0 +1,34 @@ +{ config, lib, pkgs, ... }: + +{ + home.packages = with pkgs; [ + git + zsh + helix + ]; + + programs.git = { + enable = true; + settings = { + user.name = "Lilac"; + user.email = "lilac@grasswren.net"; + core.editor = "hx"; + init.defaultBranch = "main"; + }; + }; + + programs.zsh = { + enable = true; + enableCompletion = true; + autosuggestion.enable = true; + syntaxHighlighting.enable = true; + + shellAliases = { + ls = "ls -A"; + }; + }; + + home.sessionVariables = { + EDITOR = "hx"; + }; +} diff --git a/hosts/desktop/default.nix b/hosts/desktop/default.nix new file mode 100644 index 0000000..99ff97d --- /dev/null +++ b/hosts/desktop/default.nix @@ -0,0 +1,63 @@ +{ config, lib, pkgs, ... }: + +{ + imports = [ + ./hardware-configuration.nix + ../../modules/network.nix + ../../modules/ssh.nix + ../../modules/wireguard.nix + ../../modules/gitea.nix + ]; + + boot.kernel.sysctl = { + "net.ipv4.ip_forward" = 1; + }; + network.node = "desktop"; + + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.kernelPackages = pkgs.linuxPackages_latest; + + networking.hostName = "desktop"; + networking.networkmanager.enable = true; + + time.timeZone = "America/Toronto"; + + i18n.defaultLocale = "en_US.UTF-8"; + i18n.extraLocaleSettings = { + LC_ADDRESS = "en_US.UTF-8"; + LC_IDENTIFICATION = "en_US.UTF-8"; + LC_MEASUREMENT = "en_US.UTF-8"; + LC_MONETARY = "en_US.UTF-8"; + LC_NAME = "en_US.UTF-8"; + LC_NUMERIC = "en_US.UTF-8"; + LC_PAPER = "en_US.UTF-8"; + LC_TELEPHONE = "en_US.UTF-8"; + LC_TIME = "en_US.UTF-8"; + }; + + services.xserver.enable = true; + services.displayManager.sddm.enable = true; + services.desktopManager.plasma6.enable = true; + services.xserver.xkb = { + layout = "us"; + variant = ""; + }; + + services.pulseaudio.enable = false; + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + }; + + programs.git.enable = true; + programs.zsh.enable = true; + + nixpkgs.config.allowUnfree = true; + system.stateVersion = "26.05"; +} diff --git a/hosts/desktop/hardware-configuration.nix b/hosts/desktop/hardware-configuration.nix new file mode 100644 index 0000000..ecb7876 --- /dev/null +++ b/hosts/desktop/hardware-configuration.nix @@ -0,0 +1,31 @@ +# 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" "ehci_pci" "ahci" "usbhid" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/d7450680-7d53-4842-83c5-7fc32526dff1"; + fsType = "ext4"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/D148-4AB8"; + fsType = "vfat"; + options = [ "fmask=0077" "dmask=0077" ]; + }; + + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/vps/default.nix b/hosts/vps/default.nix new file mode 100644 index 0000000..6bf892c --- /dev/null +++ b/hosts/vps/default.nix @@ -0,0 +1,30 @@ +{ config, lib, pkgs, ... }: + +{ + imports = [ + ./hardware-configuration.nix + ../../modules/network.nix + ../../modules/ssh.nix + ../../modules/wireguard.nix + ../../modules/http-forwarding.nix + ]; + + network.node = "vps"; + + networking.hostName = "vps"; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + environment.systemPackages = with pkgs; [ + git + wireguard-tools + nftables + vim + ]; + + system.stateVersion = "26.05"; +} diff --git a/hosts/vps/hardware-configuration.nix b/hosts/vps/hardware-configuration.nix new file mode 100644 index 0000000..95f2a28 --- /dev/null +++ b/hosts/vps/hardware-configuration.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, ... }: + +{ + boot = { + initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ]; + kernelModules = [ ]; + extraModulePackages = [ ]; + loader.systemd-boot.enable = true; + loader.efi.canTouchEfiVariables = true; + loader.efi.efiSysMountPoint = "/boot"; + }; + + fileSystems."/" = { device = "/dev/vda2"; fsType = "ext4"; }; + fileSystems."/boot" = { device = "/dev/vda1"; fsType = "vfat"; }; + swapDevices = [ ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + virtualisation.hypervGuest.enable = true; +} diff --git a/modules/gitea.nix b/modules/gitea.nix new file mode 100644 index 0000000..9326e01 --- /dev/null +++ b/modules/gitea.nix @@ -0,0 +1,43 @@ +{ config, lib, pkgs, ... }: + +{ + sops = { + defaultSopsFile = ./secrets.yaml; + defaultSopsFormat = "yaml"; + age.keyFile = "/var/lib/sops-nix/key.txt"; + + secrets.gitea_database_password = { + owner = "gitea"; + }; + }; + + services.postgresql = { + enable = true; + ensureDatabases = [ "gitea" ]; + ensureUsers = [{ + name = "gitea"; + ensureDBOwnership = true; + }]; + }; + + services.gitea = { + enable = true; + appName = "Lilac's Code"; + database = { + type = "postgres"; + host = "/run/postgres"; + name = "gitea"; + user = "gitea"; + passwordFile = config.sops.secrets.gitea_database_password.path; + }; + }; + + services.caddy = { + enable = true; + virtualHosts."code.grasswren.net".extraConfig = '' + reverse_proxy localhost:3000 + ''; + }; + + networking.firewall.allowedTCPPorts = [ 3000 ]; +} diff --git a/modules/http-forwarding.nix b/modules/http-forwarding.nix new file mode 100644 index 0000000..684ab47 --- /dev/null +++ b/modules/http-forwarding.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +{ + networking.firewall.enable = true; + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + networking.nftables.enable = true; + networking.nftables.tables.nat = { + family = "ip"; + content = '' + chain prerouting { + type nat hook prerouting priority dstnat; policy accept; + + iifname "enp1s0" tcp dport 80 dnat to 10.0.0.2:80 + iifname "enp1s0" tcp dport 443 dnat to 10.0.0.2:443 + } + chain postrouting { + type nat hook postrouting priority srcnat; policy accept; + + oifname "wg0" masquerade + } + ''; + }; + + boot.kernel.sysctl = { + "net.ipv4.ip_forward" = 1; + }; +} diff --git a/modules/network.nix b/modules/network.nix new file mode 100644 index 0000000..19fe41b --- /dev/null +++ b/modules/network.nix @@ -0,0 +1,41 @@ +{ config, lib, pkgs, ... }: + +{ + options.network = { + nodes = lib.mkOption { type = lib.types.attrsOf + (lib.types.submodule ({ name, config, ... }: { + options = { + id = lib.mkOption { type = lib.types.int; }; + ssh = lib.mkOption { type = lib.types.str; }; + vpn = lib.mkOption { type = lib.types.str; }; + address-vpn = lib.mkOption { type = lib.types.str; }; + address-pub = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; }; + }; + config = { + address-vpn = "10.0.0.${toString config.id}"; + }; + })); + }; + node = lib.mkOption { type = lib.types.str; }; + }; + config.network = { + nodes = { + laptop = { + id = 1; + ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKhCH6YN63AWFsR1wZ6wJdZ2jlTtYBSkY5FnLrWoLKeg"; + vpn = "n+9eh8VUP9NCnjPL0Z/KPc0TQCQloXE2Ipc5+CBtJjU="; + }; + desktop = { + id = 2; + ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFdOUv+mUhnS2sbahlqcqm9Ili16/rOk2WAlMSXrjnHu"; + vpn = "7BcwtszpzS4ABDwKwMaiJ7F35sJRa89fBbuh80Sk8Uk="; + }; + vps = { + id = 3; + ssh = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGiiLFiy+UcOi0RgZ1Xvuzl4C5aiZ+bcGaOmQcI/UBXp"; + vpn = "c5irm217aE+QVwHYmnQh4r91u2fZmQKBIWVgFVMaEwU="; + address-pub = "216.128.177.13"; + }; + }; + }; +} diff --git a/modules/secrets.yaml b/modules/secrets.yaml new file mode 100644 index 0000000..b8e469f --- /dev/null +++ b/modules/secrets.yaml @@ -0,0 +1,16 @@ +gitea_database_password: ENC[AES256_GCM,data:bL0VpnAk8rglXmjIWwpKiFnadYQVmPkR0Jq6o+ecFIPWDLt3YCD1LdBHd2E=,iv:4sMOZ5V4XopzuLcDxtwTFDbjkeeUoqggN4wAQIQvB/o=,tag:5iqAYIt0cCBoEMF/ySrO1A==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCVCtsSnhnQWplWGNqWDNv + M2UycWRBZmVDZnpQNWJwOWRFeVBxQ0hsZEd3CmhXc2JxNFNMdGNhTFFYbWVVQ0E0 + enRRQjJ2WnlPSGgyOUZZQUxNRGl4bXcKLS0tIDFMRm1TN0dOM05YaXhaNlQwVGFW + WStnazd3RkRNRUZ2N3VWR0dEM2h4MFUK8BmxNJC07XpjM0/ONRyhQFJqNDDeebeH + 8TgZukSjeq++fdaSNQQfRHX33MjhIkv5ynPaNi+dJ/m4INv5kfKGEA== + -----END AGE ENCRYPTED FILE----- + recipient: age1ttmws269mrs30f65qwky5rzkwuq0dcfgrhgegxr7u9x9ty2nqfxq9v8dwu + lastmodified: "2026-07-05T03:11:33Z" + mac: ENC[AES256_GCM,data:2SaYCBj/U/JFUMejMZeGLhzcQk0O5+UkZ8xOHJJj5zwS6n1N8ns8sJOPixErOR2rm/Gnd1QG/KLqkQFdbKjTEpAYDUB65LOqatKWD3uGqrO8/Yu+3bvJSMahuJIJCTAm8zG8tvYpYdijiFBzw2tCgji83tjOBXn7YnM1R09jY2o=,iv:syC6kINOgG9NA8cxWGa3WzWy9e7JawHS6U5e3uUS3uM=,tag:YRlrjHgx1gGTUrq5NTvu3w==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.1 diff --git a/modules/ssh.nix b/modules/ssh.nix new file mode 100644 index 0000000..59caa9e --- /dev/null +++ b/modules/ssh.nix @@ -0,0 +1,27 @@ +{ config, lib, pkgs, ... }: + +let + me = config.network.nodes.${config.network.node}; +in +{ + networking.firewall = { + enable = true; + interfaces.wg0.allowedTCPPorts = [ 22 ]; + }; + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "prohibit-password"; + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + }; + listenAddresses = [{ + addr = me.address-vpn; + port = 22; + }]; + }; + users.users.root.openssh.authorizedKeys.keys = [ + config.network.nodes.laptop.ssh + config.network.nodes.desktop.ssh + ]; +} diff --git a/modules/wireguard.nix b/modules/wireguard.nix new file mode 100644 index 0000000..f1bd786 --- /dev/null +++ b/modules/wireguard.nix @@ -0,0 +1,38 @@ +{ config, lib, pkgs, ... }: + +let + me = config.network.nodes.${config.network.node}; +in +{ + networking = { + firewall = { + allowedUDPPorts = [ 51820 ]; + trustedInterfaces = [ "wg0" ]; + }; + wireguard.interfaces."wg0" = { + ips = [ "${me.address-vpn}/24" ]; + listenPort = 51820; + generatePrivateKeyFile = true; + privateKeyFile = "/var/lib/wireguard/wg0.key"; + peers = lib.mapAttrsToList (name: peer: { + publicKey = peer.vpn; + allowedIPs = + if config.network.node == "vps" + then [ "${peer.address-vpn}/32" ] + else [ "10.0.0.0/24" ]; + endpoint = + if peer.address-pub != null + then "${peer.address-pub}:51820" + else null; + persistentKeepalive = + if peer.address-pub != null + then 25 + else null; + }) (lib.filterAttrs (name: _: + if config.network.node == "vps" + then name != "vps" + else name == "vps" + ) config.network.nodes); + }; + }; +}