- source build.func (script was unrunnable without it) - validate DB_NAME/DB_USER/DB_PORT/NEXUS_APP_IP before SQL/pg_hba use - rotate password when role exists but credentials file is missing
96 lines
3.8 KiB
Bash
Executable File
96 lines
3.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# nexus-db — PostgreSQL 16 (+pgvector) for nexus (Family Knowledge Hub)
|
|
#
|
|
# Creates an unprivileged Debian 12 LXC that:
|
|
# - runs PostgreSQL 16 from the PGDG repo with the pgvector extension
|
|
# - hosts database `nexus` owned by a least-privilege role `nexus`
|
|
# - accepts connections ONLY from the nexus app LXC (pg_hba allowlist);
|
|
# every other host is rejected
|
|
#
|
|
# Companion card: nexus-hub K-102. Run on a Proxmox VE host:
|
|
# bash -c "$(curl -fsSL https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/ct/nexus-db.sh)"
|
|
|
|
set -euo pipefail
|
|
|
|
APP="nexus-db"
|
|
APP_DESCRIPTION="PostgreSQL 16 + pgvector for nexus (access restricted to the nexus LXC)"
|
|
|
|
LIB_URL="${LIB_URL:-https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/lib}"
|
|
INSTALL_SCRIPT_URL="${INSTALL_SCRIPT_URL:-https://gitea.luki-net.org/luki-net/proxmox-scripts/raw/branch/main/install/nexus-db-install.sh}"
|
|
|
|
# LXC defaults (DB only: small CPU, RAM matters for shared_buffers/cache)
|
|
DEFAULT_HOSTNAME="nexus-db"
|
|
DEFAULT_DISK="16"
|
|
DEFAULT_CORES="2"
|
|
DEFAULT_RAM="4096"
|
|
|
|
DEFAULT_DB_NAME="nexus"
|
|
DEFAULT_DB_USER="nexus"
|
|
DEFAULT_DB_PORT="5432"
|
|
|
|
source <(curl -fsSL "$LIB_URL/build.func")
|
|
|
|
# ── app-specific prompts (host TTY; each skipped if the var is preset) ───────
|
|
prompt_app_config() {
|
|
echo
|
|
echo "── nexus-db configuration ───────────────────────────────────"
|
|
# The ONLY host that may connect (pg_hba allowlist) — the nexus app LXC.
|
|
if [[ -z "${NEXUS_APP_IP:-}" ]]; then
|
|
read -rp "IP of the nexus app LXC (sole allowed client): " NEXUS_APP_IP
|
|
fi
|
|
[[ -n "${NEXUS_APP_IP:-}" ]] || { msg_err "NEXUS_APP_IP is required (pg_hba allowlist)"; exit 1; }
|
|
|
|
DB_NAME="${DB_NAME:-$DEFAULT_DB_NAME}"
|
|
DB_USER="${DB_USER:-$DEFAULT_DB_USER}"
|
|
DB_PORT="${DB_PORT:-$DEFAULT_DB_PORT}"
|
|
|
|
echo " → database: $DB_NAME role: $DB_USER port: $DB_PORT"
|
|
echo " → allowed client: $NEXUS_APP_IP/32 (everything else is rejected)"
|
|
}
|
|
|
|
# ── push gathered config into the container for the installer to consume ─────
|
|
push_app_config() {
|
|
msg_info "Pushing db config into container..."
|
|
local tmpf; tmpf=$(mktemp)
|
|
cat >"$tmpf" <<EOF
|
|
NEXUS_APP_IP='$NEXUS_APP_IP'
|
|
DB_NAME='$DB_NAME'
|
|
DB_USER='$DB_USER'
|
|
DB_PORT='$DB_PORT'
|
|
EOF
|
|
pct push "$CTID" "$tmpf" /root/nexus-db.deploy.env --perms 600
|
|
rm -f "$tmpf"
|
|
}
|
|
|
|
# ── trailing summary ─────────────────────────────────────────────────────────
|
|
print_app_summary() {
|
|
local pg_state
|
|
pg_state=$(pct exec "$CTID" -- systemctl is-active postgresql 2>/dev/null | tr -d '\r\n')
|
|
cat <<EOF
|
|
PostgreSQL 16: $IP_CT:$DB_PORT — $pg_state
|
|
Database: $DB_NAME (owner: $DB_USER, extension: vector)
|
|
Allowed client: $NEXUS_APP_IP/32 — all other hosts are rejected
|
|
Credentials + DSN: /root/nexus-db.credentials (inside the LXC)
|
|
|
|
Smoke test FROM THE NEXUS LXC (uses the DSN from the credentials file):
|
|
psql "postgresql://$DB_USER:<password>@$IP_CT:$DB_PORT/$DB_NAME" -c "SELECT extname FROM pg_extension;"
|
|
|
|
Negative test from any OTHER host (must fail):
|
|
psql "postgresql://$DB_USER:<password>@$IP_CT:$DB_PORT/$DB_NAME" -c "SELECT 1;"
|
|
|
|
Logs: pct exec $CTID -- journalctl -u postgresql -f
|
|
EOF
|
|
}
|
|
|
|
# ── orchestrate ───────────────────────────────────────────────────────────────
|
|
trap _on_error ERR
|
|
preflight_pve
|
|
show_header "$APP" "$APP_DESCRIPTION"
|
|
prompt_lxc_config
|
|
prompt_app_config
|
|
resolve_debian_template
|
|
create_lxc
|
|
push_app_config
|
|
bootstrap_install_script "$INSTALL_SCRIPT_URL"
|
|
print_summary
|