diff --git a/.memory/worklog.json b/.memory/worklog.json index 75759eb..1225dd6 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -20,6 +20,13 @@ "message": "auto-save 2026-04-18 16:07 (~1)", "hash": "ddafce5", "files_changed": 1 + }, + { + "ts": "2026-04-18T16:12:48+08:00", + "type": "commit", + "message": "auto-save 2026-04-18 16:12 (~1)", + "hash": "380dc95", + "files_changed": 1 } ] } diff --git a/scripts/host-init.sh b/scripts/host-init.sh new file mode 100644 index 0000000..5d94c1b --- /dev/null +++ b/scripts/host-init.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# Sandbox host initialization. +# Idempotent: safe to run multiple times. +# +# Prereqs (must already be on VPS): +# - Incus >= 6.0 +# - btrfs-progs +# - netfilter-persistent + iptables-persistent +# +# Creates: +# - btrfs storage pool: lobe-sandbox-pool (200GiB file-backed) +# - Incus project: lobe-sandbox (shares networks from default) +# - Incus profile: sandbox-default (2GB RAM / 2 CPU / 10GiB disk) +# - iptables rules: ACCEPT DHCP/DNS/FORWARD on incusbr0 +# (workaround for UFW dropping incusbr0 broadcast) + +set -euo pipefail + +POOL="lobe-sandbox-pool" +POOL_SIZE="200GiB" +PROJECT="lobe-sandbox" +PROFILE="sandbox-default" +NETWORK="incusbr0" + +log() { echo "==> $*"; } + +log "1/4 btrfs storage pool" +if ! incus storage list --format csv | cut -d, -f1 | grep -qx "$POOL"; then + incus storage create "$POOL" btrfs size="$POOL_SIZE" +else + echo " (exists)" +fi + +log "2/4 Incus project" +if ! incus project list --format csv | cut -d, -f1 | grep -qx "$PROJECT"; then + incus project create "$PROJECT" -c features.networks=false +else + echo " (exists)" +fi + +log "3/4 Sandbox profile" +if ! incus profile list --project "$PROJECT" --format csv | cut -d, -f1 | grep -qx "$PROFILE"; then + incus profile create "$PROFILE" --project "$PROJECT" + incus profile set "$PROFILE" --project "$PROJECT" \ + limits.memory=2GiB \ + limits.cpu=2 \ + security.nesting=false \ + security.privileged=false + incus profile device add "$PROFILE" root disk path=/ pool="$POOL" size=10GiB --project "$PROJECT" + incus profile device add "$PROFILE" eth0 nic network="$NETWORK" --project "$PROJECT" +else + echo " (exists)" +fi + +log "4/4 iptables rules for incusbr0 (UFW drops incus DHCP/DNS by default)" +add_rule() { + # $1 = chain, $2... = rule args + local chain="$1"; shift + if ! iptables -C "$chain" "$@" 2>/dev/null; then + iptables -I "$chain" "$@" + fi +} +add_rule INPUT -i "$NETWORK" -p udp --dport 67 -j ACCEPT -m comment --comment "incus-dhcp" +add_rule INPUT -i "$NETWORK" -p udp --dport 53 -j ACCEPT -m comment --comment "incus-dns" +add_rule INPUT -i "$NETWORK" -p tcp --dport 53 -j ACCEPT -m comment --comment "incus-dns-tcp" +add_rule FORWARD -i "$NETWORK" -j ACCEPT -m comment --comment "incus-fwd-in" +add_rule FORWARD -o "$NETWORK" -j ACCEPT -m comment --comment "incus-fwd-out" +netfilter-persistent save >/dev/null + +log "DONE"