Commit 9b8a3c191ad2
Changed files (4)
imperative/aomi/bootstrap.sh
@@ -0,0 +1,161 @@
+#!/usr/bin/env bash
+
+# Aomi (Fedora CSB) Bootstrap Script
+# Description: Installs Nix (Determinate) and deploys system-manager config
+#
+# Prerequisites: Fedora CSB installed, user has sudo access
+# Usage: ./bootstrap.sh
+# Or remotely: ssh vincent@aomi.home 'bash -s' < imperative/aomi/bootstrap.sh
+
+set -euo pipefail
+
+readonly GREEN='\033[0;32m'
+readonly YELLOW='\033[1;33m'
+readonly RED='\033[0;31m'
+readonly NC='\033[0m'
+
+REPO_URL="${REPO_URL:-https://git.sbr.pm/home.git}"
+REPO_PATH="${REPO_PATH:-$HOME/src/home}"
+SYSTEM_CONFIG="${SYSTEM_CONFIG:-aomi}"
+
+log_info() { echo -e "${GREEN}[INFO]${NC} $*"; }
+log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
+log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
+
+check_root() {
+ if [[ $EUID -eq 0 ]]; then
+ log_error "Run as your regular user, not root (sudo is used when needed)"
+ exit 1
+ fi
+}
+
+# --- Phase 1: Nix ---
+
+install_nix() {
+ if command -v nix &>/dev/null; then
+ log_info "Nix already installed: $(nix --version)"
+ return 0
+ fi
+
+ log_info "Installing Nix (Determinate Systems installer)..."
+ curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
+
+ # Source nix for this session
+ if [[ -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]]; then
+ # shellcheck disable=SC1091
+ . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
+ fi
+
+ log_info "Nix installed: $(nix --version)"
+}
+
+configure_nix() {
+ local nix_conf="${XDG_CONFIG_HOME:-$HOME/.config}/nix/nix.conf"
+ mkdir -p "$(dirname "$nix_conf")"
+
+ # Determinate installer enables flakes by default, but ensure our preferences
+ if [[ ! -f "$nix_conf" ]] || ! grep -q 'use-xdg-base-directories' "$nix_conf" 2>/dev/null; then
+ cat > "$nix_conf" <<-'EOF'
+ experimental-features = nix-command flakes
+ use-xdg-base-directories = true
+ EOF
+ log_info "Nix config written to $nix_conf"
+ else
+ log_info "Nix config already exists"
+ fi
+}
+
+# --- Phase 2: Repository ---
+
+clone_repo() {
+ if [[ -d "$REPO_PATH/.git" ]]; then
+ log_info "Repository exists at $REPO_PATH, pulling..."
+ git -C "$REPO_PATH" pull --ff-only || log_warn "Pull failed, continuing with existing"
+ return 0
+ fi
+
+ log_info "Cloning $REPO_URL → $REPO_PATH"
+ mkdir -p "$(dirname "$REPO_PATH")"
+ git clone "$REPO_URL" "$REPO_PATH"
+}
+
+# --- Phase 3: System-manager ---
+
+build_and_activate() {
+ log_info "Building system-manager config: $SYSTEM_CONFIG"
+
+ # Ensure nix is in PATH
+ if ! command -v nix &>/dev/null; then
+ # shellcheck disable=SC1091
+ . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
+ fi
+
+ cd "$REPO_PATH"
+
+ local system_path
+ system_path=$(nix build ".#systemConfigs.${SYSTEM_CONFIG}" --no-link --print-out-paths)
+
+ log_info "Built: $system_path"
+ log_info "Activating system-manager..."
+ sudo "${system_path}/bin/activate"
+
+ log_info "System-manager activated!"
+}
+
+# --- Phase 4: WireGuard key ---
+
+setup_wireguard_key() {
+ if [[ -f /etc/wireguard/private.key ]]; then
+ log_info "WireGuard private key already exists"
+ return 0
+ fi
+
+ log_warn "WireGuard private key not found at /etc/wireguard/private.key"
+ log_warn ""
+ log_warn "To set up WireGuard, either:"
+ log_warn " 1. Copy existing key: sudo cp /path/to/backup/private.key /etc/wireguard/"
+ log_warn " 2. Generate new key: wg genkey | sudo tee /etc/wireguard/private.key"
+ log_warn " Then update globals.nix with new pubkey: sudo cat /etc/wireguard/private.key | wg pubkey"
+ log_warn ""
+ log_warn "After placing the key: sudo chmod 600 /etc/wireguard/private.key"
+ log_warn "Then re-run: sudo systemctl restart wireguard-wg0"
+}
+
+# --- Main ---
+
+print_summary() {
+ log_info ""
+ log_info "╔══════════════════════════════════════════╗"
+ log_info "║ Aomi (Fedora CSB) Bootstrap Done ║"
+ log_info "╠══════════════════════════════════════════╣"
+ log_info "║ Nix: ✓ installed ║"
+ log_info "║ Repository: ✓ $REPO_PATH"
+ log_info "║ System-manager: ✓ activated ║"
+ log_info "╠══════════════════════════════════════════╣"
+ log_info "║ To rebuild: ║"
+ log_info "║ cd $REPO_PATH"
+ log_info "║ nix build .#systemConfigs.aomi ║"
+ log_info "║ sudo ./result/bin/activate ║"
+ log_info "╠══════════════════════════════════════════╣"
+ log_info "║ Next: home-manager for dev tools ║"
+ log_info "║ nix run home-manager -- switch \\ ║"
+ log_info "║ --flake .#vincent@aomi ║"
+ log_info "╚══════════════════════════════════════════╝"
+}
+
+main() {
+ log_info "Bootstrapping aomi (Fedora CSB)..."
+ log_info " Repo: $REPO_URL → $REPO_PATH"
+ log_info " Config: $SYSTEM_CONFIG"
+ echo
+
+ check_root
+ install_nix
+ configure_nix
+ clone_repo
+ build_and_activate
+ setup_wireguard_key
+ print_summary
+}
+
+main "$@"
imperative/aomi/README.md
@@ -0,0 +1,68 @@
+# Aomi — Fedora CSB + Nix
+
+ThinkPad P1 Gen 3 running Red Hat CSB (Fedora), managed with Nix
+system-manager and home-manager.
+
+## Architecture
+
+```
+Fedora CSB (base OS, IT-managed)
+ └── Nix (Determinate installer)
+ ├── system-manager → WireGuard, Syncthing, system services
+ └── home-manager → shell, editors, dev tools
+```
+
+## Bootstrap
+
+From another machine with SSH access to aomi:
+
+```bash
+ssh vincent@192.168.1.39 'bash -s' < imperative/aomi/bootstrap.sh
+```
+
+Or on aomi directly:
+
+```bash
+curl -sL https://git.sbr.pm/home/raw/branch/main/imperative/aomi/bootstrap.sh | bash
+```
+
+## Rebuilding
+
+```bash
+cd ~/src/home
+
+# System-manager (WireGuard, Syncthing)
+nix build .#systemConfigs.aomi && sudo ./result/bin/activate
+
+# Home-manager (dev tools, shell) — TODO: not yet configured
+# nix run home-manager -- switch --flake .#vincent@aomi
+```
+
+## WireGuard
+
+The system-manager config writes `/etc/wireguard/wg0.conf` but uses a
+placeholder for the private key. After first activation:
+
+```bash
+# Option 1: Restore backed-up key
+sudo cp /path/to/backup/private.key /etc/wireguard/
+sudo chmod 600 /etc/wireguard/private.key
+
+# Option 2: Generate new keypair (update globals.nix with new pubkey)
+wg genkey | sudo tee /etc/wireguard/private.key
+sudo cat /etc/wireguard/private.key | wg pubkey
+# → update globals.nix machines.aomi.net.vpn.pubkey
+
+sudo systemctl restart wireguard-wg0
+```
+
+## Syncthing
+
+After activation, Syncthing runs as a system service under the
+`vincent` user. It will generate a new device ID — update
+`globals.nix` and accept the device on other nodes.
+
+```bash
+# Get new device ID
+curl -s http://localhost:8384/rest/system/status | jq -r .myID
+```
systems/aomi/system.nix
@@ -0,0 +1,83 @@
+{
+ pkgs,
+ globals,
+ ...
+}:
+let
+ machine = globals.machines.aomi;
+ vpnServer = globals.machines.carthage;
+in
+{
+ config = {
+ # Platform
+ nixpkgs.hostPlatform = "x86_64-linux";
+
+ # Required for non-NixOS (Fedora CSB)
+ system-manager.allowAnyDistro = true;
+
+ # System packages
+ environment.systemPackages = with pkgs; [
+ wireguard-tools
+ syncthing
+ vim
+ htop
+ curl
+ git
+ ];
+
+ # WireGuard wg0 service
+ systemd.services.wireguard-wg0 = {
+ description = "WireGuard VPN (wg0)";
+ wants = [ "network-online.target" ];
+ after = [ "network-online.target" ];
+ wantedBy = [ "system-manager.target" ];
+ serviceConfig = {
+ Type = "oneshot";
+ RemainAfterExit = true;
+ ExecStart = "${pkgs.wireguard-tools}/bin/wg-quick up wg0";
+ ExecStop = "${pkgs.wireguard-tools}/bin/wg-quick down wg0";
+ };
+ };
+
+ # WireGuard configuration file
+ # NOTE: Private key must be added manually to /etc/wireguard/private.key
+ environment.etc."wireguard/wg0.conf" = {
+ text = ''
+ [Interface]
+ PrivateKey = PLACEHOLDER_REPLACE_MANUALLY
+ Address = ${builtins.head machine.net.vpn.ips}/24
+
+ [Peer]
+ PublicKey = ${vpnServer.net.vpn.pubkey}
+ AllowedIPs = 10.100.0.0/24
+ Endpoint = ${globals.net.vpn.endpoint}:51820
+ PersistentKeepalive = 25
+ '';
+ mode = "0600";
+ };
+
+ # Syncthing user service for vincent
+ systemd.services.syncthing = {
+ description = "Syncthing - Open Source Continuous File Synchronization";
+ wants = [ "network-online.target" ];
+ after = [ "network-online.target" ];
+ wantedBy = [ "system-manager.target" ];
+ serviceConfig = {
+ Type = "simple";
+ User = "vincent";
+ Group = "vincent";
+ ExecStart = "${pkgs.syncthing}/bin/syncthing serve --no-browser --no-restart";
+ Restart = "on-failure";
+ RestartSec = "10";
+ SuccessExitStatus = "3 4";
+ RestartForceExitStatus = "3 4";
+ # Hardening
+ ProtectSystem = "full";
+ PrivateTmp = true;
+ SystemCallArchitectures = "native";
+ MemoryDenyWriteExecute = true;
+ NoNewPrivileges = true;
+ };
+ };
+ };
+}
flake.nix
@@ -157,6 +157,10 @@
hostname = "aion";
system = "aarch64-linux";
};
+ aomi = libx.mkSystemManager {
+ hostname = "aomi";
+ system = "x86_64-linux";
+ };
nagoya = libx.mkSystemManager {
hostname = "nagoya";
system = "aarch64-linux";