feat(tools): ansipa-proxmox-lxc.sh — pre-configured full-stack ansipa Proxmox LXC

Generate everything needed to run the complete ansipa stack (FreeIPA + CheckMK
+ Keycloak + PostgreSQL + nginx gateway) inside a single Proxmox LXC container.
Unlike freeipa-image.sh's proxmox-lxc target (which exports a FreeIPA-only CT
rootfs), this runs the tested docker-compose stack inside a privileged,
nesting-enabled CT ("Docker-in-LXC"), so it is the whole management plane in
one container.

Prompts for domain/realm/VMID/resources, generates all service secrets, and
emits: pct-create-<vmid>.sh, ansipa-<vmid>.conf (nesting=1,keyctl=1,fuse=1 +
the cgroup/apparmor allowances FreeIPA's systemd and Docker overlay2 need), a
first-boot provisioner that installs Docker and brings the stack up via run.sh,
a filled-in .env (mode 600), and a DEPLOY guide. Verified the generator emits
correct, syntactically-valid artifacts. Documented in the ansipa Setup Guide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
feat/astal-menu
Amir Alexander Abdelbaki 2026-07-02 13:13:02 +02:00
parent a73bc7cb93
commit baf5e73cc1
3 changed files with 272 additions and 1 deletions

View File

@ -192,6 +192,35 @@ container-internal `172.30.0.12`.
--- ---
## Deploying as a Proxmox LXC container
To run the whole stack as a single Proxmox container, use the generator:
```bash
bash setup/tools/ansipa-proxmox-lxc.sh [OUT_DIR] # default ~/ansipa-lxc-out
```
It prompts for domain/realm/VMID/resources, generates all secrets, and writes:
| File | Purpose |
|------|---------|
| `pct-create-<vmid>.sh` | `pct create` command — run on the Proxmox host |
| `ansipa-<vmid>.conf` | LXC options to append to `/etc/pve/lxc/<vmid>.conf` |
| `ansipa-provision.sh` | first-boot provisioner (installs Docker, brings the stack up) |
| `.env` | filled-in stack environment (generated passwords — mode 600) |
| `DEPLOY-<vmid>.md` | step-by-step guide |
The container is **privileged** with `nesting=1,keyctl=1,fuse=1` — required for
FreeIPA's systemd + Kerberos keyrings and Docker's overlay2. It runs the same
tested docker-compose stack inside the CT ("Docker-in-LXC"), so it is the full
ansipa deployment in one Proxmox container. Size it ≥6 GB RAM.
> `setup/tools/freeipa-image.sh` has a separate `proxmox-lxc` target that
> exports a **FreeIPA-only** CT rootfs (no CheckMK/Keycloak/nginx) — use that if
> you want just the identity server; use `ansipa-proxmox-lxc.sh` for the full stack.
---
## Client enrollment ## Client enrollment
```bash ```bash

View File

@ -71,7 +71,8 @@ Dotfiles/
│ │ ├── wds-deploy.sh # package netboot artifacts for WDS/PXE │ │ ├── wds-deploy.sh # package netboot artifacts for WDS/PXE
│ │ ├── write-usb.sh # write the ISO to a USB stick │ │ ├── write-usb.sh # write the ISO to a USB stick
│ │ ├── generate-answerfile.sh # dry-run to produce answerfile.json │ │ ├── generate-answerfile.sh # dry-run to produce answerfile.json
│ │ ├── proxmox-lxc-gen.sh # Proxmox LXC container generator (TUI) │ │ ├── proxmox-lxc-gen.sh # generic Proxmox LXC container generator (TUI)
│ │ ├── ansipa-proxmox-lxc.sh # pre-configured full ansipa stack as a Proxmox LXC
│ │ └── freeipa-image.sh # build the ansipa FreeIPA container image │ │ └── freeipa-image.sh # build the ansipa FreeIPA container image
│ └── modules/ # Modular install scripts │ └── modules/ # Modular install scripts
├── desktopenvs/hyprlua/ # HyprLua (Lua-based Hyprland) configs ├── desktopenvs/hyprlua/ # HyprLua (Lua-based Hyprland) configs

241
setup/tools/ansipa-proxmox-lxc.sh Executable file
View File

@ -0,0 +1,241 @@
#!/usr/bin/env bash
# =============================================================================
# ansipa-proxmox-lxc.sh — generate a pre-configured ansipa Proxmox LXC container
#
# Produces everything needed to stand up the FULL ansipa stack (FreeIPA +
# CheckMK + Keycloak + PostgreSQL + nginx gateway) inside a single Proxmox LXC
# container, using the tested docker-compose deployment run inside the CT
# ("Docker-in-LXC"). This is the whole management plane in one container, unlike
# freeipa-image.sh's proxmox-lxc target which exports a FreeIPA-only rootfs.
#
# Why Docker-in-LXC instead of native install:
# FreeIPA + CheckMK + Keycloak are already packaged and wired together as a
# compose stack that this repo tests end-to-end. Running that stack inside a
# privileged, nesting-enabled LXC reuses all of it verbatim and keeps the
# Proxmox container reproducible.
#
# OUTPUT (written to an output dir, default ~/ansipa-lxc-out):
# pct-create-<vmid>.sh runnable pct create command (run on the Proxmox host)
# ansipa-<vmid>.conf LXC options to append to /etc/pve/lxc/<vmid>.conf
# ansipa-provision.sh first-boot provisioner (installs Docker + brings the
# stack up); copied into the CT and run once
# .env filled-in ansipa stack environment (secrets!)
# DEPLOY-<vmid>.md step-by-step deployment guide
#
# Requirements on the workstation running THIS script: bash, openssl (for
# password generation). The Proxmox host needs a Debian 12 CT template.
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOTFILES_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
IMAGE_SRC="$DOTFILES_DIR/setup/modules/FreeipaAnsible/image"
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; MAGENTA='\033[0;35m'; NC='\033[0m'
log() { echo -e "${GREEN}[+]${NC} $*"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
error() { echo -e "${RED}[✗]${NC} $*" >&2; }
info() { echo -e "${CYAN}[i]${NC} $*"; }
section() { echo -e "\n${BLUE}━━━ $* ━━━${NC}"; }
ask() { printf "${MAGENTA}[?]${NC} %s " "$*"; }
[[ $EUID -eq 0 ]] && { error "Run as your normal user (not root)."; exit 1; }
gen_pw() { openssl rand -base64 18 2>/dev/null | tr -d '/+=' | cut -c1-20; }
# ─── Gather configuration ─────────────────────────────────────────────────────
section "ansipa Proxmox LXC generator"
info "Generates a pre-configured full-stack ansipa container for Proxmox."
echo
ask "IPA domain (e.g. corp.example.com):"; read -r IPA_DOMAIN
[[ -z "$IPA_DOMAIN" ]] && { error "IPA domain is required."; exit 1; }
ask "IPA server FQDN [ipa.$IPA_DOMAIN]:"; read -r I; IPA_HOSTNAME="${I:-ipa.$IPA_DOMAIN}"
ask "Kerberos realm [${IPA_DOMAIN^^}]:"; read -r I; IPA_REALM="${I:-${IPA_DOMAIN^^}}"
ask "Proxmox VMID [910]:"; read -r I; VMID="${I:-910}"
ask "CT hostname [ansipa]:"; read -r I; CT_HOSTNAME="${I:-ansipa}"
ask "Proxmox storage [local-lvm]:"; read -r I; PVE_STORAGE="${I:-local-lvm}"
ask "Template storage [local]:"; read -r I; TPL_STORAGE="${I:-local}"
ask "Debian CT template [debian-12-standard_12.7-1_amd64.tar.zst]:"; read -r I
CT_TEMPLATE="${I:-debian-12-standard_12.7-1_amd64.tar.zst}"
# FreeIPA alone wants ~2 GB; the full stack (CheckMK/Keycloak/Postgres) needs headroom.
ask "RAM MB [6144]:"; read -r I; CT_RAM="${I:-6144}"
ask "Cores [4]:"; read -r I; CT_CORES="${I:-4}"
ask "Disk GB [20]:"; read -r I; CT_DISK="${I:-20}"
ask "Bridge [vmbr0]:"; read -r I; CT_BRIDGE="${I:-vmbr0}"
ask "Static IP CIDR or 'dhcp' [dhcp]:"; read -r I; CT_IP="${I:-dhcp}"
ask "Advertised CheckMK URL for clients (e.g. http://ansipa.$IPA_DOMAIN:8090) [blank=set later]:"
read -r CMK_ADVERTISED_URL
OUT_DIR="${1:-$HOME/ansipa-lxc-out}"
mkdir -p "$OUT_DIR"
# ─── Generate secrets ─────────────────────────────────────────────────────────
section "Generating secrets"
IPA_ADMIN_PASSWORD=$(gen_pw); IPA_DM_PASSWORD=$(gen_pw)
CMK_ADMIN_PASSWORD=$(gen_pw); KC_ADMIN_PASSWORD=$(gen_pw); KC_DB_PASSWORD=$(gen_pw)
SMB_SCAN_PASSWORD=$(gen_pw); LUKS_KEY_UPLOAD_PASSWORD=$(gen_pw)
log "Generated admin/service passwords (saved in $OUT_DIR/.env — keep it safe)."
# ─── .env for the ansipa stack ────────────────────────────────────────────────
cat > "$OUT_DIR/.env" <<EOF
# ansipa stack environment — generated by ansipa-proxmox-lxc.sh
IPA_HOSTNAME=$IPA_HOSTNAME
IPA_DOMAIN=$IPA_DOMAIN
IPA_REALM=$IPA_REALM
IPA_ADMIN_PASSWORD=$IPA_ADMIN_PASSWORD
IPA_DM_PASSWORD=$IPA_DM_PASSWORD
IPA_SETUP_DNS=false
IPA_SETUP_KRA=false
SMB_SCAN_PASSWORD=$SMB_SCAN_PASSWORD
LUKS_KEY_UPLOAD_PASSWORD=$LUKS_KEY_UPLOAD_PASSWORD
CMK_ADMIN_PASSWORD=$CMK_ADMIN_PASSWORD
CMK_SITE_ID=cmk
CMK_ADVERTISED_URL=$CMK_ADVERTISED_URL
KC_HOSTNAME=${IPA_HOSTNAME/ipa./sso.}
KC_ADMIN=admin
KC_ADMIN_PASSWORD=$KC_ADMIN_PASSWORD
KC_DB_PASSWORD=$KC_DB_PASSWORD
ANSIPA_HTTP_PORT=8088
EOF
chmod 600 "$OUT_DIR/.env"
# ─── pct create script ────────────────────────────────────────────────────────
# Privileged + nesting + keyctl + fuse: FreeIPA runs systemd and Docker needs
# nesting/overlay; keyctl is required by Kerberos/SSSD keyrings inside the CT.
NET_LINE="name=eth0,bridge=$CT_BRIDGE,ip=dhcp"
[[ "$CT_IP" != "dhcp" ]] && NET_LINE="name=eth0,bridge=$CT_BRIDGE,ip=$CT_IP"
cat > "$OUT_DIR/pct-create-$VMID.sh" <<EOF
#!/usr/bin/env bash
# Run on the Proxmox host. Creates the ansipa LXC container.
set -euo pipefail
pct create $VMID $TPL_STORAGE:vztmpl/$CT_TEMPLATE \\
--hostname $CT_HOSTNAME \\
--cores $CT_CORES \\
--memory $CT_RAM \\
--swap 2048 \\
--rootfs $PVE_STORAGE:$CT_DISK \\
--net0 $NET_LINE \\
--features nesting=1,keyctl=1,fuse=1 \\
--unprivileged 0 \\
--onboot 1 \\
--start 0
echo "Created CT $VMID. Now append the extra options and start it:"
echo " cat ansipa-$VMID.conf >> /etc/pve/lxc/$VMID.conf"
echo " pct start $VMID"
echo " pct push $VMID ansipa-provision.sh /root/ansipa-provision.sh"
echo " pct push $VMID .env /root/.env"
echo " pct exec $VMID -- bash /root/ansipa-provision.sh"
EOF
chmod +x "$OUT_DIR/pct-create-$VMID.sh"
# ─── LXC config extras ────────────────────────────────────────────────────────
# Docker overlay2 + FreeIPA need these cgroup/device allowances in a CT.
cat > "$OUT_DIR/ansipa-$VMID.conf" <<EOF
# Append to /etc/pve/lxc/$VMID.conf — enables Docker + FreeIPA inside the CT.
lxc.apparmor.profile: unconfined
lxc.cgroup2.devices.allow: a
lxc.cap.drop:
lxc.mount.auto: proc:rw sys:rw
EOF
# ─── First-boot provisioner (runs INSIDE the container) ───────────────────────
cat > "$OUT_DIR/ansipa-provision.sh" <<'PROVEOF'
#!/usr/bin/env bash
# ansipa-provision.sh — runs once inside the LXC to bring up the ansipa stack.
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
echo "[ansipa] Installing Docker + git..."
apt-get update -qq
apt-get install -y -qq ca-certificates curl git >/dev/null
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release; echo $VERSION_CODENAME) stable" \
> /etc/apt/sources.list.d/docker.list
apt-get update -qq
apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-compose-plugin >/dev/null
systemctl enable --now docker
echo "[ansipa] Fetching the ansipa stack..."
git clone --depth 1 https://git.abdelbaki.eu/The_miro/Dotfiles.git /opt/ansipa-src 2>/dev/null \
|| { cd /opt/ansipa-src && git pull; }
STACK=/opt/ansipa
mkdir -p "$STACK"
cp -r /opt/ansipa-src/setup/modules/FreeipaAnsible/image/. "$STACK/"
cp /root/.env "$STACK/.env"
echo "[ansipa] Starting the full stack (this builds the FreeIPA image + first-boot ~10 min)..."
cd "$STACK"
# cgroup v2 hosts need run.sh (compose can't express --cgroupns host for FreeIPA).
if [ "$(stat -fc %T /sys/fs/cgroup 2>/dev/null)" = "cgroup2fs" ]; then
bash ./run.sh all
else
docker compose up -d
fi
echo "[ansipa] Stack starting. Watch first-boot with:"
echo " docker logs -f freeipa"
echo "[ansipa] Once healthy, wire Keycloak↔FreeIPA LDAP: cd $STACK && ./keycloak-configure.sh"
PROVEOF
chmod +x "$OUT_DIR/ansipa-provision.sh"
# ─── Deployment guide ─────────────────────────────────────────────────────────
cat > "$OUT_DIR/DEPLOY-$VMID.md" <<EOF
# ansipa Proxmox LXC — deployment ($CT_HOSTNAME, VMID $VMID)
Generated by \`ansipa-proxmox-lxc.sh\`. Runs the full ansipa stack
(FreeIPA + CheckMK + Keycloak + PostgreSQL + nginx) as Docker containers
inside a privileged, nesting-enabled Proxmox LXC.
## 1. Copy these files to the Proxmox host
\`\`\`
scp pct-create-$VMID.sh ansipa-$VMID.conf ansipa-provision.sh .env root@PROXMOX:/root/ansipa/
\`\`\`
## 2. Create and provision the container (on the Proxmox host)
\`\`\`
cd /root/ansipa
# Ensure the Debian template exists: pveam update && pveam download $TPL_STORAGE $CT_TEMPLATE
bash pct-create-$VMID.sh
cat ansipa-$VMID.conf >> /etc/pve/lxc/$VMID.conf
pct start $VMID
pct push $VMID .env /root/.env
pct push $VMID ansipa-provision.sh /root/ansipa-provision.sh
pct exec $VMID -- bash /root/ansipa-provision.sh
\`\`\`
## 3. Access
- Portal / all UIs: \`http://<CT-IP>:8088/\` (put your reverse proxy in front — see docs/md/ansipa-setup.md)
- FreeIPA: \`/ipa/ui/\` · CheckMK: \`/cmk/\` · Keycloak: \`/auth/\`
- Admin passwords are in \`.env\` (IPA_ADMIN_PASSWORD, CMK_ADMIN_PASSWORD, KC_ADMIN_PASSWORD).
## Notes
- The CT is **privileged** with nesting/keyctl/fuse — required for FreeIPA's
systemd + Kerberos keyrings and Docker's overlay2. Do not run untrusted
workloads in it.
- RAM: ${CT_RAM} MB. FreeIPA + CheckMK + Keycloak together need ~46 GB.
- Firewall: open the ansipa ports (see docs/md/ansipa-setup.md → Ports).
EOF
# ─── Summary ──────────────────────────────────────────────────────────────────
section "Done"
log "Artifacts written to: $OUT_DIR"
info " pct-create-$VMID.sh — create the CT (run on Proxmox host)"
info " ansipa-$VMID.conf — append to /etc/pve/lxc/$VMID.conf"
info " ansipa-provision.sh — first-boot provisioner (run inside CT)"
info " .env — stack secrets (mode 600 — keep safe)"
info " DEPLOY-$VMID.md — full deployment guide"
echo
warn "The .env contains generated admin passwords in plain text. Store it securely."