feat: get to a solid bootstrap on public ssh

This commit is contained in:
Jet 2026-03-21 16:05:47 -07:00
parent 642869ce9b
commit 3850948f71
No known key found for this signature in database
27 changed files with 262 additions and 865 deletions

211
flake.nix
View file

@ -16,14 +16,6 @@
url = "github:serokell/deploy-rs";
inputs.nixpkgs.follows = "nixpkgs";
};
disko = {
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
};
nixos-anywhere = {
url = "github:nix-community/nixos-anywhere";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
@ -32,8 +24,6 @@
nixpkgs,
agenix,
deploy-rs,
disko,
nixos-anywhere,
...
}:
let
@ -45,7 +35,14 @@
wikiName = "Noisebridge";
baseDomain = "noisebridge.net";
replicaSubdomain = "replica";
sshUser = "root";
sshUser = "jet";
adminUsers = {
jet = {
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE40ISu3ydCqfdpb26JYD5cIN0Fu0id/FDS+xjB5zpqu jetthomaspham@gmail.com"
];
};
};
primaryHostName = "main-wiki";
replicaHostName = "replica-wiki";
@ -58,11 +55,11 @@
hosts = {
primary = {
nixosName = primaryHostName;
tailscaleName = primaryHostName;
publicIpv4 = "134.199.221.52";
};
replica = {
nixosName = replicaHostName;
tailscaleName = replicaHostName;
publicIpv4 = "167.99.174.109";
};
};
};
@ -82,12 +79,8 @@
publicDomain = mkPublicDomain role;
};
mkHost =
{
hostMeta,
hostModule,
roleModules,
}:
mkDeployHost =
hostModule: hostMeta:
lib.nixosSystem {
inherit system;
specialArgs = {
@ -95,16 +88,11 @@
};
modules = [
agenix.nixosModules.default
disko.nixosModules.disko
hostModule
./disk-config.nix
./modules/common.nix
./modules/security.nix
./modules/tailscale.nix
./modules/caddy.nix
./modules/mediawiki-base.nix
]
++ roleModules;
./modules/admin-users.nix
./modules/deploy-ssh.nix
];
};
primaryMeta = mkHostMeta "primary";
@ -112,40 +100,28 @@
in
{
nixosConfigurations = {
main-wiki = mkHost {
hostMeta = primaryMeta;
hostModule = ./hosts/main-wiki;
roleModules = [
./modules/wiki-primary/mysql.nix
./modules/wiki-primary/mediawiki.nix
];
};
main-wiki = mkDeployHost ./hosts/main-wiki.nix primaryMeta;
replica-wiki = mkHost {
hostMeta = replicaMeta;
hostModule = ./hosts/replica-wiki;
roleModules = [
./modules/wiki-replica/mysql.nix
./modules/wiki-replica/mediawiki.nix
];
};
replica-wiki = mkDeployHost ./hosts/replica-wiki.nix replicaMeta;
};
deploy.nodes = {
main-wiki = {
hostname = primaryMeta.tailscaleName;
hostname = primaryMeta.publicIpv4;
remoteBuild = true;
sshUser = siteConfig.sshUser;
profiles.system = {
user = siteConfig.sshUser;
sshUser = siteConfig.sshUser;
user = "root";
path = deploy-rs.lib.${system}.activate.nixos self.nixosConfigurations.main-wiki;
};
};
replica-wiki = {
hostname = replicaMeta.tailscaleName;
hostname = replicaMeta.publicIpv4;
remoteBuild = true;
sshUser = siteConfig.sshUser;
profiles.system = {
user = siteConfig.sshUser;
sshUser = siteConfig.sshUser;
user = "root";
path = deploy-rs.lib.${system}.activate.nixos self.nixosConfigurations.replica-wiki;
};
};
@ -175,129 +151,19 @@
bootstrap-host = {
type = "app";
program = "${pkgs.writeShellScript "bootstrap-host" ''
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
nix run .#bootstrap-host -- <main-wiki|replica-wiki> <target-host> [ssh-identity-file]
nix run .#bootstrap-host -- <main-target-host> <replica-target-host> [ssh-identity-file]
Examples:
nix run .#bootstrap-host -- main-wiki root@203.0.113.10 ~/.ssh/do-bootstrap
nix run .#bootstrap-host -- root@203.0.113.10 root@203.0.113.11 ~/.ssh/do-bootstrap
EOF
}
if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
usage
exit 1
fi
repo_root="$(pwd)"
if [ ! -f "$repo_root/flake.nix" ]; then
printf 'Run bootstrap-host from the repo root\n' >&2
exit 1
fi
ssh_identity_file=""
main_target=""
replica_target=""
selected_host=""
case "$1" in
main-wiki|replica-wiki)
selected_host="$1"
if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
usage
exit 1
fi
if [ "$selected_host" = "main-wiki" ]; then
main_target="$2"
else
replica_target="$2"
fi
ssh_identity_file="''${3:-}"
;;
*)
main_target="$1"
replica_target="$2"
ssh_identity_file="''${3:-}"
;;
esac
install_root="$(mktemp -d)"
cleanup() {
rm -rf "$install_root"
}
trap cleanup EXIT
ensure_host_key() {
local host_name="$1"
local private_key_file="$repo_root/.bootstrap/$host_name/host.age"
local public_key_file="$repo_root/secrets/hosts/$host_name.age.pub"
local public_key
mkdir -p "$(dirname "$private_key_file")" "$(dirname "$public_key_file")"
if [ ! -s "$private_key_file" ]; then
public_key="$(${pkgs.age}/bin/age-keygen -o "$private_key_file" | sed 's/^Public key: //')"
chmod 600 "$private_key_file"
printf 'Generated host age key for %s\n' "$host_name"
else
public_key="$(${pkgs.age}/bin/age-keygen -y "$private_key_file")"
printf 'Reused existing host age key for %s\n' "$host_name"
fi
printf '%s\n' "$public_key" > "$public_key_file"
}
run_bootstrap() {
local host_name="$1"
local target_host="$2"
local private_key_file="$repo_root/.bootstrap/$host_name/host.age"
local -a nixos_anywhere_args
mkdir -p "$install_root/var/lib/agenix"
${pkgs.coreutils}/bin/install -m 0400 "$private_key_file" "$install_root/var/lib/agenix/host.age"
nixos_anywhere_args=(
--extra-files "$install_root"
--flake "path:$repo_root#$host_name"
)
if [ -n "$ssh_identity_file" ]; then
nixos_anywhere_args+=( -i "$ssh_identity_file" )
fi
printf 'Bootstrapping %s onto %s\n' "$host_name" "$target_host"
${
nixos-anywhere.packages.${system}.default
}/bin/nixos-anywhere "''${nixos_anywhere_args[@]}" "$target_host"
rm -f "$install_root/var/lib/agenix/host.age"
}
if [ -n "$main_target" ]; then
ensure_host_key main-wiki
fi
if [ -n "$replica_target" ]; then
ensure_host_key replica-wiki
fi
printf 'Rekeying agenix secrets\n'
${agenix.packages.${system}.default}/bin/agenix -r
if [ -n "$main_target" ]; then
run_bootstrap main-wiki "$main_target"
fi
if [ -n "$replica_target" ]; then
run_bootstrap replica-wiki "$replica_target"
fi
printf '\nBootstrap complete. The hosts should now join Tailscale using their configured hostnames.\n'
''}";
meta.description = "Install NixOS on one or both raw hosts and seed agenix identities";
program = "${pkgs.writeShellScript "bootstrap-host" (
builtins.replaceStrings
[ "@ADMIN_KEYS@" ]
[
(lib.concatMapStringsSep "\n" (key: " \"${key}\"") (
lib.flatten (
lib.mapAttrsToList (_: userCfg: userCfg.openssh.authorizedKeys.keys or [ ]) siteConfig.adminUsers
)
))
]
(builtins.readFile ./scripts/bootstrap-host.sh)
)}";
meta.description = "Convert one or both Ubuntu DigitalOcean hosts into a minimal NixOS bootstrap config with nixos-infect";
};
};
@ -305,7 +171,6 @@
packages = with pkgs; [
agenix.packages.${system}.default
deploy-rs.packages.${system}.default
nixos-anywhere.packages.${system}.default
mariadb.client
rsync
curl