noisebridge-wiki/flake.nix
Jet 642869ce9b
Some checks failed
CI / check (push) Has been cancelled
CI / deploy (push) Has been cancelled
init
2026-03-21 02:27:44 -07:00

318 lines
10 KiB
Nix

{
description = "Basic MediaWiki primary + replica deployment";
nixConfig = {
max-jobs = "auto";
cores = 0;
};
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs";
};
deploy-rs = {
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 =
{
self,
nixpkgs,
agenix,
deploy-rs,
disko,
nixos-anywhere,
...
}:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
lib = nixpkgs.lib;
siteConfig = rec {
wikiName = "Noisebridge";
baseDomain = "noisebridge.net";
replicaSubdomain = "replica";
sshUser = "root";
primaryHostName = "main-wiki";
replicaHostName = "replica-wiki";
database = {
name = "noisebridge_mediawiki";
mediawikiUser = "wiki";
replicationUser = "repl";
};
hosts = {
primary = {
nixosName = primaryHostName;
tailscaleName = primaryHostName;
};
replica = {
nixosName = replicaHostName;
tailscaleName = replicaHostName;
};
};
};
mkPublicDomain =
role:
if role == "primary" then
siteConfig.baseDomain
else
"${siteConfig.replicaSubdomain}.${siteConfig.baseDomain}";
mkHostMeta =
role:
siteConfig.hosts.${role}
// {
inherit role;
publicDomain = mkPublicDomain role;
};
mkHost =
{
hostMeta,
hostModule,
roleModules,
}:
lib.nixosSystem {
inherit system;
specialArgs = {
inherit agenix siteConfig hostMeta;
};
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;
};
primaryMeta = mkHostMeta "primary";
replicaMeta = mkHostMeta "replica";
in
{
nixosConfigurations = {
main-wiki = mkHost {
hostMeta = primaryMeta;
hostModule = ./hosts/main-wiki;
roleModules = [
./modules/wiki-primary/mysql.nix
./modules/wiki-primary/mediawiki.nix
];
};
replica-wiki = mkHost {
hostMeta = replicaMeta;
hostModule = ./hosts/replica-wiki;
roleModules = [
./modules/wiki-replica/mysql.nix
./modules/wiki-replica/mediawiki.nix
];
};
};
deploy.nodes = {
main-wiki = {
hostname = primaryMeta.tailscaleName;
profiles.system = {
user = siteConfig.sshUser;
sshUser = siteConfig.sshUser;
path = deploy-rs.lib.${system}.activate.nixos self.nixosConfigurations.main-wiki;
};
};
replica-wiki = {
hostname = replicaMeta.tailscaleName;
profiles.system = {
user = siteConfig.sshUser;
sshUser = siteConfig.sshUser;
path = deploy-rs.lib.${system}.activate.nixos self.nixosConfigurations.replica-wiki;
};
};
};
checks = builtins.mapAttrs (_: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
apps.${system} = {
deploy = {
type = "app";
program = "${pkgs.writeShellScript "deploy-noisebridge" ''
if [ "$#" -eq 0 ] || [ "''${1#-}" != "$1" ]; then
exec ${deploy-rs.packages.${system}.default}/bin/deploy \
--auto-rollback true \
--magic-rollback true \
path:.# \
"$@"
fi
exec ${deploy-rs.packages.${system}.default}/bin/deploy \
--auto-rollback true \
--magic-rollback true \
"$@"
''}";
meta.description = "Deploy all Noisebridge wiki hosts by default";
};
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";
};
};
devShells.${system}.default = pkgs.mkShell {
packages = with pkgs; [
agenix.packages.${system}.default
deploy-rs.packages.${system}.default
nixos-anywhere.packages.${system}.default
mariadb.client
rsync
curl
jq
age
openssl
];
};
};
}