From 091f11f0369153f25deccc74bd3b6d03974374c3 Mon Sep 17 00:00:00 2001 From: "Artemis (Iron Legion)" Date: Sat, 23 May 2026 18:50:08 -0400 Subject: [PATCH] Add minimal autoinstall + first-boot.sh (fleet baseline, Docker, NFS, Tailscale) --- autoinstall/first-boot.sh | 88 +++++++++++++++++ .../ubuntu-autoinstall-fleet-minimal.yaml | 95 +++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 autoinstall/first-boot.sh create mode 100644 autoinstall/ubuntu-autoinstall-fleet-minimal.yaml diff --git a/autoinstall/first-boot.sh b/autoinstall/first-boot.sh new file mode 100644 index 0000000..82ec34d --- /dev/null +++ b/autoinstall/first-boot.sh @@ -0,0 +1,88 @@ +#!/bin/bash +# first-boot.sh — Iron Legion Fleet Node Post-Install Bootstrap +# Run manually AFTER confirming autoinstall boots successfully +# Date: May 23, 2026 + +set -euo pipefail + +# ========== CONFIG ========== +TRUENAS_IP="192.168.16.254" +NFS_SHARE="/mnt/Ice/Backup/swarm-data" +LOCAL_MOUNT="/mnt/swarm-data" +ANSIBLE_REPO="https://gitea.nb.bobbysh.me/Iron-Legion/ansible-pull-deploy.git" +ANSIBLE_DIR="/var/lib/ansible/local" +TAILSCALE_API_KEY="${TAILSCALE_API_KEY:-}" # Set before running, or hardcode for unattended + +# ========== DOCKER ========== +echo "[1/6] Installing Docker CE..." +if ! command -v docker >/dev/null 2>&1; then + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker.gpg + echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable" > /etc/apt/sources.list.d/docker.list + apt-get update + apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + systemctl enable docker + systemctl start docker + usermod -aG docker jarvis + echo "Docker installed." +else + echo "Docker already present." +fi + +# ========== NFS AUTOMOUNT ========== +echo "[2/6] Configuring NFS automount for TrueNAS..." +mkdir -p "$LOCAL_MOUNT" +if ! grep -q "$TRUENAS_IP:$NFS_SHARE" /etc/fstab; then + echo "$TRUENAS_IP:$NFS_SHARE $LOCAL_MOUNT nfs defaults,_netdev 0 0" >> /etc/fstab + mount "$LOCAL_MOUNT" + echo "NFS mount added to fstab and mounted." +else + echo "NFS fstab entry already exists." +fi + +# ========== ANSIBLE-PULL REPO ========== +echo "[3/6] Cloning ansible-pull repo..." +mkdir -p "$ANSIBLE_DIR" +if [ ! -d "$ANSIBLE_DIR/.git" ]; then + cd "$ANSIBLE_DIR" + git clone "$ANSIBLE_REPO" . + echo "Ansible repo cloned." +else + echo "Ansible repo already present." +fi + +# ========== TAILSCALE ========== +echo "[4/6] Installing Tailscale..." +if ! command -v tailscale >/dev/null 2>&1; then + curl -fsSL https://tailscale.com/install.sh | sh + echo "Tailscale installed." +else + echo "Tailscale already present." +fi + +if [ -n "$TAILSCALE_API_KEY" ]; then + echo "[5/6] Joining Tailnet..." + tailscale up --auth-key="$TAILSCALE_API_KEY" --ssh --accept-routes + echo "Tailscale joined." +else + echo "[5/6] TAILSCALE_API_KEY not set. Run manually:" + echo " export TAILSCALE_API_KEY=tskey-..." + echo " tailscale up --auth-key=\$TAILSCALE_API_KEY --ssh --accept-routes" +fi + +# ========== ENABLE SERVICES ========== +echo "[6/6] Enabling services..." +systemctl enable ssh docker +systemctl restart ssh docker + +# ========== DONE ========== +echo "" +echo "========================================" +echo " Fleet node bootstrap complete" +echo "========================================" +echo "Docker: $(docker --version)" +echo "Tailscale: $(tailscale version 2>/dev/null | head -1 || echo 'not joined')" +echo "NFS mount: $(df -h | grep swarm-data || echo 'not mounted')" +echo "Ansible: $(ansible --version | head -1 || echo 'not checked')" +echo "" +echo "Next: run ansible-pull from $ANSIBLE_DIR" +echo " cd $ANSIBLE_DIR && ansible-pull -d . -U $ANSIBLE_REPO" diff --git a/autoinstall/ubuntu-autoinstall-fleet-minimal.yaml b/autoinstall/ubuntu-autoinstall-fleet-minimal.yaml new file mode 100644 index 0000000..dbcf60d --- /dev/null +++ b/autoinstall/ubuntu-autoinstall-fleet-minimal.yaml @@ -0,0 +1,95 @@ +# Ubuntu Autoinstall — Iron Legion Fleet Standard (MINIMAL) +# Targets: GMKtec G9 N150, 1TB NVMe (/dev/nvme0n1) +# Date: May 23, 2026 +# Role: Bare-metal bootable fleet node — manual post-install via first-boot.sh + +version: 1 +reporting: + builtin: + type: print + +autoinstall: + identity: + hostname: fleet-node + username: jarvis + password: "$6$0DL8vh2WMWRpPiOt$xP1XyKFbX8J0hGSwd9GD6RsPAM5Ajdkrd8PYW2KJAv64YBJC3NAHgGr4BNYORodCVf1hkv3D2KhbezFoIlVsL1" + + ssh: + install-server: true + authorized-keys: + - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPSBrRCROUHOiZX9IB3teEK89VFfghbdu7OF5NoJ1Y6g Generated By Termius + allow-pw: true + + network: + version: 2 + ethernets: + enp4s0: + dhcp4: true + optional: true + enp5s0: + dhcp4: true + optional: true + enp6s0: + dhcp4: true + optional: true + + storage: + config: + - type: disk + id: nvme0n1 + path: /dev/nvme0n1 + ptable: gpt + wipe: superblock-recursive + - type: partition + id: boot-part + device: nvme0n1 + size: 1GiB + flag: boot + - type: partition + id: root-part + device: nvme0n1 + size: -1 + - type: format + id: boot-format + volume: boot-part + fstype: ext4 + - type: format + id: root-format + volume: root-part + fstype: ext4 + - type: mount + id: boot-mount + device: boot-format + path: /boot + - type: mount + id: root-mount + device: root-format + path: / + swap: + size: 0 + + packages: + - openssh-server + - curl + - nfs-common + - cifs-utils + - net-tools + - ca-certificates + - gnupg + - ansible + - git + + late-commands: + # Prevent cloud-init from stomping hostname on first boot + - echo 'preserve_hostname: true' > /target/etc/cloud/cloud.cfg.d/99_preserve_hostname.cfg + + # Add jarvis to sudoers with NOPASSWD + - echo 'jarvis ALL=(ALL) NOPASSWD: ALL' > /target/etc/sudoers.d/jarvis + - chmod 440 /target/etc/sudoers.d/jarvis + + # Ensure SSH key has correct permissions + - chmod 600 /target/home/jarvis/.ssh/authorized_keys + - chown -R 1000:1000 /target/home/jarvis/.ssh + + # Auto-reboot after install completes + shutdown: reboot