Compare commits

...

15 commits

Author SHA1 Message Date
c3996f55ce
update nixpkgs channel to 25.11 2025-12-01 21:48:56 -05:00
a58e66c747
auto commit on build
.sops.yaml
secrets.yaml

auto commit on build

hosts/blob/hardware-configuration.nix
2025-12-01 21:48:55 -05:00
693a1514be
don't finish args 2025-12-01 21:47:36 -05:00
0f05c5da6c
there shall be no impurity 2025-12-01 21:47:36 -05:00
e2bf8e9496
reset for another try at deploying blob 2025-12-01 21:47:33 -05:00
4c4b859ed0
this should be per host 2025-12-01 21:45:49 -05:00
754e4c945e
update the shell 2025-12-01 21:45:43 -05:00
9f388d75d8
forgot to change the blobercraft path to blob 2025-11-26 14:27:22 -05:00
3d71ed911d
update readme 2025-11-26 14:27:01 -05:00
d2e20817b4
rename blobercraft -> blob 2025-11-26 14:25:01 -05:00
c753407691
wireguard 2025-11-26 13:55:08 -05:00
8e5d215275
fancy new runner 2025-11-26 13:20:46 -05:00
d28ec06ae9
deploy-rs + nixos-anywhere 2025-11-25 14:24:11 -05:00
469f4dcd43
add some terminfo to make sshing much easier 2025-11-25 10:28:33 -05:00
37fa6c9f05
more secure servers 2025-11-25 10:25:47 -05:00
23 changed files with 436 additions and 109 deletions

View file

@ -11,7 +11,8 @@ keys:
- &hosts: - &hosts:
- &dev-vm age1rjtqzmywfr3zuzz0cn8eqnwp3x8ypzya9gcv6kvtplhudar5eayqq83ey4 - &dev-vm age1rjtqzmywfr3zuzz0cn8eqnwp3x8ypzya9gcv6kvtplhudar5eayqq83ey4
- &crayon age1pnu4tkdxfcnefntdw262k4m8wuv3qe2894s4e6w5j8yshg8vlu6q9uq5tv - &crayon age1pnu4tkdxfcnefntdw262k4m8wuv3qe2894s4e6w5j8yshg8vlu6q9uq5tv
- &blobercraft age167gn88rldpmqmjhm9nl0gv05ms4tn37jx2nxwklfvs3xymfp9y7sa8vurh - &blob age1kardawqarv498rwayadsmnlx62kvjgduvhhg3drx39xacn9u3ajq5d0qra
# new-host marker
creation_rules: creation_rules:
- path_regex: secrets.yaml$ - path_regex: secrets.yaml$
key_groups: key_groups:
@ -19,4 +20,5 @@ creation_rules:
- *dev - *dev
- *dev-vm - *dev-vm
- *crayon - *crayon
- *blobercraft - *blob
# new-host ptr marker

View file

@ -1,25 +0,0 @@
IP ?=
HOST ?=
deploy:
# push flake config to a remote server
ifeq ($(IP),)
$(error IP not set)
endif
ifeq ($(HOST),)
$(error HOST not set)
endif
ifneq ($(shell git diff),)
git add .
git commit -m "auto commit on build" -m "`PAGER=cat git diff --name-only --cached`"
endif
rsync -azr ./ crown@$(IP):~/flake-config
ssh crown@$(IP) "sudo NIX_CONFIG='experimental-features = flakes pipe-operators' nixos-rebuild switch --flake ~/flake-config#$(HOST)"
sops:
# update sops keys
sops updatekeys secrets.yaml
.DEFAULT_GOAL := default
.PHONY: default deploy sops
default:
# noop

View file

@ -7,7 +7,7 @@ That's it, have fun poking around.
## Systems ## Systems
I suppose if you're trying to understand my config you'd need to know where I suppose if you're trying to understand my config you'd need to know where
this stuff is deployed and what for. this stuff is deployed and what for.
- blobercraft - blob
- This is my main homelab server. It's used for my media (jellyfin) along - This is my main homelab server. It's used for my media (jellyfin) along
with some other stuff that you can find by looking at my config. with some other stuff that you can find by looking at my config.
- crayon - crayon
@ -21,19 +21,14 @@ that I thought a new user might want to understand as nix is rather poorly
documented. documented.
## Maintaining ## Maintaining
I've included a make file to keep remote systems up to date, here's an example I've included a dev shell to keep the system up to date. To enter the shell run:
of what I use to deploy to crayon:
```sh ```sh
make deploy IP=squi.bid HOST=crayon nix develop
``` ```
This step requires the remote system to have a crown user who can execute sudo Once you've entered the shell will give you a rundown on what you can do.
commands without an interactive prompt.
I'll probably end up switching to something more standard once I've got the
time.
## TODO: ## TODO:
- [ ] blobercraft - [ ] blob
- [ ] add a git backup for everything on crayon (if possible) - [ ] add a git backup for everything on crayon (if possible)
- [ ] ff sync server - [ ] ff sync server
- [ ] crayon - [ ] crayon

101
flake.lock generated
View file

@ -22,6 +22,64 @@
"type": "github" "type": "github"
} }
}, },
"deploy-rs": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": [
"nixpkgs"
],
"utils": "utils"
},
"locked": {
"lastModified": 1762286984,
"narHash": "sha256-9I2H9x5We6Pl+DBYHjR1s3UT8wgwcpAH03kn9CqtdQc=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "9c870f63e28ec1e83305f7f6cb73c941e699f74f",
"type": "github"
},
"original": {
"owner": "serokell",
"repo": "deploy-rs",
"type": "github"
}
},
"disko": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1764017209,
"narHash": "sha256-RoJGCtKExXXkNCZUmmxezG3eOczEOTBw38DaZGSYJC0=",
"owner": "nix-community",
"repo": "disko",
"rev": "ec8eabe00c4ee9a2ddc50162c125f0ec2a7099e1",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "disko",
"type": "github"
}
},
"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"
}
},
"nid": { "nid": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -44,22 +102,24 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1762498405, "lastModified": 1764522689,
"narHash": "sha256-Zg/SCgCaAioc0/SVZQJxuECGPJy+OAeBcGeA5okdYDc=", "narHash": "sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD+/cTUzzgVFoaHrkqY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "6faeb062ee4cf4f105989d490831713cc5a43ee1", "rev": "8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "id": "nixpkgs",
"ref": "nixos-25.05", "ref": "nixos-25.11",
"type": "indirect" "type": "indirect"
} }
}, },
"root": { "root": {
"inputs": { "inputs": {
"declarative-jellyfin": "declarative-jellyfin", "declarative-jellyfin": "declarative-jellyfin",
"deploy-rs": "deploy-rs",
"disko": "disko",
"nid": "nid", "nid": "nid",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"sops-nix": "sops-nix", "sops-nix": "sops-nix",
@ -100,6 +160,21 @@
"type": "indirect" "type": "indirect"
} }
}, },
"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"
}
},
"treefmt-nix": { "treefmt-nix": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -135,6 +210,24 @@
"ref": "nixos-unstable", "ref": "nixos-unstable",
"type": "indirect" "type": "indirect"
} }
},
"utils": {
"inputs": {
"systems": "systems_2"
},
"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", "root": "root",

View file

@ -1,7 +1,7 @@
{ {
description = "Nixos config flake"; description = "Nixos config flake";
inputs = { inputs = {
nixpkgs.url = "nixpkgs/nixos-25.05"; nixpkgs.url = "nixpkgs/nixos-25.11";
unstable.url = "nixpkgs/nixos-unstable"; unstable.url = "nixpkgs/nixos-unstable";
nid.url = "github:nix-community/nix-index-database"; nid.url = "github:nix-community/nix-index-database";
@ -12,18 +12,26 @@
declarative-jellyfin.url = "github:Sveske-Juice/declarative-jellyfin"; declarative-jellyfin.url = "github:Sveske-Juice/declarative-jellyfin";
declarative-jellyfin.inputs.nixpkgs.follows = "nixpkgs"; declarative-jellyfin.inputs.nixpkgs.follows = "nixpkgs";
deploy-rs.url = "github:serokell/deploy-rs";
deploy-rs.inputs.nixpkgs.follows = "nixpkgs";
disko.url = "github:nix-community/disko";
disko.inputs.nixpkgs.follows = "nixpkgs";
}; };
outputs = { self, nixpkgs, unstable, ... }@inputs: let outputs = { self, nixpkgs, unstable, ... }@inputs: let
base = [ base = [
# I've put these all here so that it's easier to see what's being # I've put these all here so that it's easier to see what's being
# imported by default # imported by default
./modules/os.nix ./modules/os.nix
./modules/server.nix
./modules/ssh.nix ./modules/ssh.nix
./modules/time.nix ./modules/time.nix
./modules/pkgs.nix ./modules/pkgs.nix
./modules/unstable.nix ./modules/unstable.nix
./modules/zmotd.nix ./modules/zmotd.nix
./modules/sops.nix ./modules/sops.nix
./modules/wireguard.nix
./modules/users/admin.nix ./modules/users/admin.nix
./overlays ./overlays
@ -33,6 +41,8 @@
# use comma just in case I need to do some sysadmin stuff # use comma just in case I need to do some sysadmin stuff
inputs.nid.nixosModules.nix-index inputs.nid.nixosModules.nix-index
{ programs.nix-index-database.comma.enable = true; } { programs.nix-index-database.comma.enable = true; }
# disko for completly declarative machines
inputs.disko.nixosModules.disko
]; ];
# ts so DRY it makes me wanna cry # ts so DRY it makes me wanna cry
@ -46,11 +56,35 @@
] ++ modules; ] ++ modules;
} }
)) <| hosts; )) <| hosts;
mkNodes = nodes:
(builtins.mapAttrs (name: options:
nixpkgs.lib.attrsets.recursiveUpdate {
hostname = name;
profiles.system = {
user = "root";
sshUser = "crown";
path = inputs.deploy-rs.lib."x86_64-linux".activate.nixos self.nixosConfigurations.${name};
};
} options
)) <| nodes;
in { in {
# define all of my machines # define all of my machines
nixosConfigurations = mkHosts { nixosConfigurations = mkHosts {
blobercraft = []; blob = [];
crayon = []; crayon = [];
}; };
# and where they get deployed to
deploy.nodes = mkNodes {
crayon = { hostname = "squi.bid"; };
};
# dev shell to deploy this flake
devShells."x86_64-linux".default = builtins.import ./shell.nix {
pkgs = nixpkgs.legacyPackages."x86_64-linux";
};
checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) inputs.deploy-rs.lib;
}; };
} }

27
hosts/blob/default.nix Normal file
View file

@ -0,0 +1,27 @@
{ modulesPath, ... }:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
(modulesPath + "/profiles/qemu-guest.nix")
./disko.nix
./hardware-configuration.nix # Include the results of the hardware scan.
./jellyfin.nix
./minecraft.nix
./gatus.nix
./ai.nix
];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# ai.enable = true;
jellyfin.enable = true;
minecraft.enable = true;
# This value determines the NixOS release with which your system is to be
# compatible, in order to avoid breaking some software such as database
# servers. You should change this only after NixOS release notes say you
# should.
system.stateVersion = "25.05"; # Did you read the comment?
}

36
hosts/blob/disko.nix Normal file
View file

@ -0,0 +1,36 @@
{ lib, ... }:
{
disko.devices = {
disk.main = {
device = lib.mkDefault "/dev/sda";
type = "disk";
content = {
type = "gpt";
partitions = {
boot = {
size = "1M";
type = "EF02"; # for grub MBR
};
ESP = {
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
};
}

View file

@ -8,24 +8,11 @@
[ (modulesPath + "/installer/scan/not-detected.nix") [ (modulesPath + "/installer/scan/not-detected.nix")
]; ];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ]; boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ ]; boot.initrd.kernelModules = [ ];
boot.kernelModules = [ ]; boot.kernelModules = [ ];
boot.extraModulePackages = [ ]; boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/59b4c37b-b8c6-4b95-96af-e343161381bb";
fsType = "ext4";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/E8A3-780D";
fsType = "vfat";
options = [ "fmask=0077" "dmask=0077" ];
};
swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking # 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 # (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 # still possible to use this option, but it's recommended to use it in conjunction

View file

@ -1,17 +0,0 @@
{ ... }:
{
imports = [
./hardware-configuration.nix # Include the results of the hardware scan.
./jellyfin.nix
./minecraft.nix
./gatus.nix
./ai.nix
];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# ai.enable = true;
jellyfin.enable = true;
minecraft.enable = true;
}

View file

@ -1,4 +1,4 @@
{ ... }: { config, ... }:
{ {
imports = [ imports = [
./hardware-configuration.nix # Include the results of the hardware scan. ./hardware-configuration.nix # Include the results of the hardware scan.
@ -9,4 +9,17 @@
boot.loader.grub.enable = true; boot.loader.grub.enable = true;
boot.loader.grub.device = "/dev/vda"; boot.loader.grub.device = "/dev/vda";
wireguard = {
enable = true;
# pub: gq0/fX4EF/3jUNJSW5C3ythZjMVAWYqQdAVRw1eUC1Y=
privateKeyFile = config.sops.secrets."wireguard/crayon".path;
externalInterface = "enp1s0";
};
# This value determines the NixOS release with which your system is to be
# compatible, in order to avoid breaking some software such as database
# servers. You should change this only after NixOS release notes say you
# should.
system.stateVersion = "25.05"; # Did you read the comment?
} }

View file

@ -4,13 +4,14 @@
# working :( # working :(
imports = [ imports = [
(builtins.fetchTarball { (builtins.fetchTarball {
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-25.05/nixos-mailserver-nixos-25.05.tar.gz"; url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-25.11/nixos-mailserver-nixos-25.11.tar.gz";
sha256 = "0la8v8d9vzhwrnxmmyz3xnb6vm76kihccjyidhfg6qfi3143fiwq"; sha256 = "16kanlk74xnj7xgmjsj7pahy31hlxqcbv76xnsg8qbh54b0hwxgq";
}) })
]; ];
mailserver = { mailserver = {
enable = true; enable = true;
stateVersion = 3;
fqdn = "mail.zacharyscheiman.com"; fqdn = "mail.zacharyscheiman.com";
domains = [ "zacharyscheiman.com" "squi.bid" ]; domains = [ "zacharyscheiman.com" "squi.bid" ];
messageSizeLimit = 2500000000; # 2.5GB messageSizeLimit = 2500000000; # 2.5GB

View file

@ -4,6 +4,7 @@
settings = { settings = {
experimental-features = [ "nix-command" "flakes" "pipe-operators" ]; experimental-features = [ "nix-command" "flakes" "pipe-operators" ];
auto-optimise-store = true; auto-optimise-store = true;
trusted-users = [ "@wheel" ];
}; };
gc = { gc = {
dates = "weekly"; dates = "weekly";
@ -18,10 +19,4 @@
enable = true; enable = true;
dates = "weekly"; dates = "weekly";
}; };
# This value determines the NixOS release with which your system is to be
# compatible, in order to avoid breaking some software such as database
# servers. You should change this only after NixOS release notes say you
# should.
system.stateVersion = "25.05"; # Did you read the comment?
} }

View file

@ -11,6 +11,12 @@
tree tree
unzip unzip
zmotd zmotd
# mmmm terminfo
foot.terminfo
ghostty.terminfo
kitty.terminfo
termite.terminfo
]; ];
security.sudo.execWheelOnly = true; security.sudo.execWheelOnly = true;

20
modules/server.nix Normal file
View file

@ -0,0 +1,20 @@
# Most of this has been yoinked from nix-community/srvos, the only reason I'm
# not using it is because I want absolute control over my nix settings and using
# it would mean I would have to disable options that they enabled
{
# Given that our systems are headless, emergency mode is useless.
# We prefer the system to attempt to continue booting so
# that we can hopefully still access it remotely.
systemd.enableEmergencyMode = false;
# No need for fonts on a server
fonts.fontconfig.enable = false;
# Ensure that basic bugs in systemd services are caught.
systemd.enableStrictShellChecks = true;
# Make builds to be more likely killed than important services.
# 100 is the default for user slices and 500 is systemd-coredumpd@
# We rather want a build to be killed than our precious user sessions as builds can be easily restarted.
systemd.services.nix-daemon.serviceConfig.OOMScoreAdjust = 250;
}

View file

@ -16,6 +16,7 @@
secrets = { secrets = {
"mail/me" = {}; "mail/me" = {};
"jellyfin/zachary" = {}; "jellyfin/zachary" = {};
"wireguard/crayon" = {};
}; };
}; };
} }

View file

@ -20,7 +20,12 @@
services.sshguard.enable = true; services.sshguard.enable = true;
services.openssh = { services.openssh = {
enable = true; enable = true;
settings.PasswordAuthentication = false; settings = {
KbdInteractiveAuthentication = false;
PasswordAuthentication = false;
UseDns = false;
X11Forwarding = false;
};
}; };
users.users.root.openssh.authorizedKeys.keys = config.ssh.keys; users.users.root.openssh.authorizedKeys.keys = config.ssh.keys;

60
modules/wireguard.nix Normal file
View file

@ -0,0 +1,60 @@
{ pkgs, lib, config, ... }:
{
options.wireguard = {
enable = lib.mkEnableOption "wireguard";
port = lib.mkOption {
default = 51820;
description = "The port for wireguard to use.";
type = lib.types.int;
};
externalInterface = lib.mkOption {
description = "The external networking interface for wireguard to use.";
type = lib.types.str;
};
internalInterface = lib.mkOption {
default = "wg0";
description = "The networking interface for wireguard to use.";
type = lib.types.str;
};
privateKeyFile = lib.mkOption {
description = "The path to the private key of the wireguard server.";
type = lib.types.path;
};
};
config = lib.mkIf config.wireguard.enable {
networking.nat.enable = true;
networking.nat.externalInterface = config.wireguard.externalInterface;
networking.nat.internalInterfaces = [ config.wireguard.internalInterface ];
networking.firewall.allowedUDPPorts = [ config.wireguard.port ];
networking.wireguard.interfaces = {
${config.wireguard.internalInterface} = {
# Determines the IP address and subnet of the server's end of the tunnel interface.
ips = [ "10.100.0.1/24" ];
listenPort = config.wireguard.port;
# This allows the wireguard server to route your traffic to the internet and hence be like a VPN
# For this to work you have to set the dnsserver IP of your router (or dnsserver of choice) in your clients
postSetup = ''
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o eth0 -j MASQUERADE
'';
# This undoes the above command
postShutdown = ''
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o eth0 -j MASQUERADE
'';
# Path to the servers private key file.
privateKeyFile = config.wireguard.privateKeyFile;
# TODO: add config option?
peers = [
{
publicKey = "L+NlTn0E9pgCoEoTYs4aDewZSMmyeyC1Os9DCdwYTjY=";
allowedIPs = [ "10.100.0.2/32" ];
}
];
};
};
};
}

View file

@ -4,6 +4,8 @@ jellyfin:
zachary: ENC[AES256_GCM,data:GIDgfsxhU4fZVjP/cTmTvIA1aeP4lbd3Fz6tbPLdyL37KD+IKERgkxJmGwtt9GNwnJBsHE/xpH8ZAvloS1DykZZtEaqB0H6wuA==,iv:FM0d4tiQPzyoEiqEQF5YvNeClHXOhP+q+TaKGeyg/TE=,tag:v+sYDwQiCX7o+g7plcnQFg==,type:str] zachary: ENC[AES256_GCM,data:GIDgfsxhU4fZVjP/cTmTvIA1aeP4lbd3Fz6tbPLdyL37KD+IKERgkxJmGwtt9GNwnJBsHE/xpH8ZAvloS1DykZZtEaqB0H6wuA==,iv:FM0d4tiQPzyoEiqEQF5YvNeClHXOhP+q+TaKGeyg/TE=,tag:v+sYDwQiCX7o+g7plcnQFg==,type:str]
users: users:
crown: ENC[AES256_GCM,data:6UAYcafxflvbsTXC1N3Ff0hAlWGjveYDUzbcXPSGfPX0uXg++bfjRwYo3JFgfJpJ/KN4MODPSxgjFAFnoZOnkyxk0UDSppDagQ==,iv:PWmxuj2caqRLASjftbl0tovNq2t1WoDoviJXs/OO8yI=,tag:EwJhROsHfj5cPkpxUCy+uw==,type:str] crown: ENC[AES256_GCM,data:6UAYcafxflvbsTXC1N3Ff0hAlWGjveYDUzbcXPSGfPX0uXg++bfjRwYo3JFgfJpJ/KN4MODPSxgjFAFnoZOnkyxk0UDSppDagQ==,iv:PWmxuj2caqRLASjftbl0tovNq2t1WoDoviJXs/OO8yI=,tag:EwJhROsHfj5cPkpxUCy+uw==,type:str]
wireguard:
crayon: ENC[AES256_GCM,data:pQ4nOzcON+yCqgisBQO8LIdfi9GmXE9YcPzBRgu9Fdzx0R6p4dEK+DVBuDg=,iv:vq0uDgZlLwXVZMwE3xTWZDP20uaAcT4I0D7qLS61ApI=,tag:btVyZREPAgfcC694/Wusmg==,type:str]
sops: sops:
kms: [] kms: []
gcp_kms: [] gcp_kms: []
@ -13,41 +15,41 @@ sops:
- recipient: age14d55nfxlzm8t2yzplxpprygxmt99javafz9a8dh5llu87aww4qlswf6g0c - recipient: age14d55nfxlzm8t2yzplxpprygxmt99javafz9a8dh5llu87aww4qlswf6g0c
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNT0IxYjhWWkZadnVmcGpz YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaZVRGTEpIWW1qRWhPOTR5
VXB5U2VvTFllYWhJTkNwQmxsWkxEL2drRHcwCksrMGs4SVZoL1pJNU00TUZBeU5V STdwVzZzeU1QS2l0TlN2NFNLY1VNZjVCdEhFCmxhejBDSjF5Vk1UQjdEYmpRRFRw
UFBRcnRFdTlxUjgvcVpSelZIU0NyVWsKLS0tICtnZm8rYnB5cWhIUVBmQzQxSWIr allpajVzcUFpc1h0TVBlUFdaUERPZ3cKLS0tIHc3S0FRbkgwc3BwYUYrWGUrUjZX
M29ZRHIwNGZSdi9LYmp5d2xyTWdmRDgKhs6COQa3Vmosiwv7I/IjvYr10Mx83V6z QjBLcFY5NnFBZXBJenFYUS8yMXBML0EKkuoDfnc0MnZ0bRQ4Op8GnxC0Mpld9nRE
W2d8PPTHBlRMqPcghpG2UOFsygzP8Y6UlMpCgt25vnFLUwCPlo7ERA== 5tn6why12mT65jDHuaU3+bX2Rg5+NU90KpdA3S88M4tiCD3WSo70eg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1rjtqzmywfr3zuzz0cn8eqnwp3x8ypzya9gcv6kvtplhudar5eayqq83ey4 - recipient: age1rjtqzmywfr3zuzz0cn8eqnwp3x8ypzya9gcv6kvtplhudar5eayqq83ey4
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXMUFJY2RjSHcrS2Foa2Fo YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyVEx6VzRNOFBickVjcGFj
dUJMSmpEL0NEN1BLYlZDNlA3aUQyQUNkYWxnCnNmV0ZpWTA0ZHUrUEtBV3MyZ3U1 UkpGNUpTeTVVUVRGRHJrRTI3UzhrRjIvcXdrCkFSWGE4YS91dEpJbFZEcFNGUmdP
SitYaVFBZklaZ282K2plYUhlVjRVWGMKLS0tIGlOZENMbURDMWR5VEFIVEdyV3k5 UFJDc0hpTEVvaHZjY2k3Vk5jdTk4NjgKLS0tIDFpU0srRzBMTDFPVGVVblpEMTZk
S3hQemRLNFd6eDlQY3pvUlkzUVhRUlUKHvdPyCCb0I825u9Hx+Fz+W9ESM2Gxy+N SEtxQnN6T2lNbkRGWmUwSFdMVUw0dlEKKYe2xCYLQ8Q21p6f3NIIwRMrQHTicSp3
lUsxP/ngAnG52MSrxxU33PG4TXSvaaYzuGP7gOQF6hB9U79inWzFzg== BSIG0SmRGcSrzPlg8agUi4aWQ7du9EECXanQSu98sGhCWkIc/QHWnQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1pnu4tkdxfcnefntdw262k4m8wuv3qe2894s4e6w5j8yshg8vlu6q9uq5tv - recipient: age1pnu4tkdxfcnefntdw262k4m8wuv3qe2894s4e6w5j8yshg8vlu6q9uq5tv
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtYTkvaldVWUk1TC94REEr YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvaVZxYTFMZDFCYnVTYWM4
OHNiUHlqN0l3QWFJbjZ6anZpVTN5OGtibGtNCm9DcVJ6SktQeEFWU2REU0dpRjZu QS9Oa1dLa3dVNzArZ0hkKy8yR1Z3UVpRQzJVClo5dzU3dythWGU0NkoySUpYRUQv
WnBBaDMrbnRNaVhtR3BqdjVkc2tpZEEKLS0tIHRVdW8yL1JmcDVrVkNaa2lNN2h5 MTlQYmJSVG5RNWkzWnlEaDh0YjFxL3MKLS0tIDdySlB3cGxoM09BZWdhN3RwNGtZ
Y0gxSjYrY3gydnBseEVlQTBSSEtJSVEKH4v1Q9kKQaj5vdV9mW2Rsl/GUbq1h/m9 Y1ZUb1Y3ais0dlZrclQyUUZxWkNSVHcKv1Q0VBHE9Y9bU6XyQ84WNf+JTIQq/mPI
iy6BPmjC9GNtTBJ8VuvkQSvPLD+dsMwYqhmSbTQgDpRP3sQ4a6rWkA== tOD6uiS46KgnO5p8oM9rqvBmOPJKoS6bgSLUuEnqjLTtZE3QO0eKzA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age167gn88rldpmqmjhm9nl0gv05ms4tn37jx2nxwklfvs3xymfp9y7sa8vurh - recipient: age1kardawqarv498rwayadsmnlx62kvjgduvhhg3drx39xacn9u3ajq5d0qra
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYcWVDbmhhc1FHRG5WOTEz YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwTFR1UU1PaTl0NWZ1dEVk
emp4Rm9YMlA3aXUvMnpDWElqRElzQjdlMzNRCjducWdqQzliZjkzaWtGdEdUbk9u WTZMUEtGWFFyNm9aTzNmZHh3RkZHOGsvRWowCnYzZ3JlRGlqN2tHbmtIMFFHUVBD
MlBCL0lqdWs4TVo0RW9ham5mTExTSzQKLS0tICtJWk15NG9yMWwyVjF6SE1weWFF dWNNc2ZqL1UwdlBmMERlNVZGK1ZhdVkKLS0tIGV1RHh5Z0Z3MlNMZHB0K1liTFdr
NmlybmxKYlJESGxJbFdCazZUKzVjYmMK56j3+CuRfZsbVeYfmESlD2z6GYzIFQYz NTUrY2pDQXJuTnREakRWQkFqckN2M2MKSonhOJsqcY/HDY+d25rEPwKSl3FSOpkW
f/jpI+8CteDlxbGuUvW10hD7lB8az2+Z+MQX2+koy3PZBkGChPh/Yg== EJFXcKKTiJB96Ms5yDGRAtUvbqw/oSBbdGTqe7bE7pQhfj3Y8ECz4w==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2025-11-09T02:00:10Z" lastmodified: "2025-11-26T18:38:21Z"
mac: ENC[AES256_GCM,data:9Jg3aXMMe8Yhf3CycD+UPqlTg0E619dmOJENRe2sfwROdKxOXhiFqnuI4t262XW3IMpJdCbv3RIblklF6vPaqqJWkPqj4Jt2niF4Bq0oR+cRM+rAElYAZ6vviCWnjTjOhTD/UB2RYPFH77Ce7RQmR4c5H4D6uLaw1g3+9TLJPTE=,iv:p4mF2S1n+mTV+ny3hKbQ+tYqh+4HGURyUP9hiSdMZjs=,tag:dWCa87XTwH3mBHshUMxjiQ==,type:str] mac: ENC[AES256_GCM,data:V3lKQj0ZWIPl2RPpnv7tRBG8sH6W9+rfnPy0z6g+3SZGmKtwhcgqVBG/VPMKhuyseNZ4vxE23lD7Ol44PchMgd/OCJqJF6TUl3A4LIqkK8Ji0m0cPcC3hsFaI8rChkWcLse30qcoQov4NbP7yElpf76Bh/NqBFgOqCjDD0Pp/NU=,iv:897reifxaub96UDCKCsWNxabVCSzYLmsIrrkXCxBgoM=,tag:0d4iQhLA/YxR7wrtUVxXqA==,type:str]
pgp: [] pgp: []
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.9.1 version: 3.9.1

92
shell.nix Normal file
View file

@ -0,0 +1,92 @@
{
pkgs ?
# If pkgs is not defined, instantiate nixpkgs from locked commit
# yoinked from (github.com/EmergentMind/nix-config)
let
lock = (builtins.fromJSON (builtins.readFile ./flake.lock)).nodes.nixpkgs.locked;
nixpkgs = builtins.fetchTarball {
url = "https://github.com/${lock.owner}/${lock.repo}/archive/${lock.rev}.tar.gz";
sha256 = lock.narHash;
};
in
builtins.import nixpkgs { overlays = [ ]; },
...
}:
pkgs.mkShell {
nativeBuildInputs = with pkgs.buildPackages; [
git
openssh
ssh-to-age
nixos-anywhere
(pkgs.writeShellScriptBin "-commit" ''
# there shall be no impurity
if [ -n "$(git diff)" ]; then
git add .
git commit -m "auto commit on build" -m "`PAGER=cat git diff --name-only --cached`"
fi
'')
(pkgs.writeShellScriptBin "-sops" "sops updatekeys secrets.yaml")
(pkgs.writeShellScriptBin "-init" ''
USER="root"
if [ -z "$1" ] || [ -z "$2" ]; then
echo "the 1st argument must be the ip address"
echo "the 2nd argument must be the new hostname (the nix flake host)"
echo "the 3rd argument may be the user to ssh with if unset the default is root"
exit 0
fi
IP=$1
HOST=$2
if [ -n "$3" ]; then
USER=$3
fi
# get the remote systems ssh key
key=$(ssh $(USER)@$(IP) 'cat /etc/ssh/ssh_host_ed25519_key.pub' | ssh-to-age)
if [ -z "$key" ]; then
echo "failed to get the remote systems ssh pubkey"
exit 1
fi
# add the new sops key to the .sops.yaml
sed -i '/# new-host marker/i\ - &$(HOST) $(key)' .sops.yaml
sed -i '/# new-host ptr marker/i\ - *$(HOST)' .sops.yaml
# update the keys
sops updatekeys secrets.yaml
-commit
# push the flake to the remote system
nixos-anywhere\
--flake .#$HOST\
--build-on remote\
--copy-host-keys\
--generate-hardware-config nixos-generate-config ./hosts/$HOST/hardware-configuration.nix\
--target-host $USER@$IP
'')
(pkgs.writeShellScriptBin "-deploy" ''
-commit
# push flake config to a remote server(s)
nix run github:serokell/deploy-rs . # this needs to be the same version that the flake is using
'')
];
shellHook = ''
cat << EOF
# This is my tiny nix shell to create new machines and update existing ones
# it requires you to have nix and sops installed to correctly setup a new
# system and nix to deploy to an existing one.
#
# Available commands:
# '-sops' -> updates your sops secret file
# '-init' -> initializes a new system with nix-anywhere
# '-deploy' -> deploys the existing flake to all nodes using deploy-rs
EOF
'';
}