#!/usr/bin/env bash # # Install the BookStack MCP server into a Debian/Ubuntu LXC container. # Run as root, from inside the container, in the directory containing pyproject.toml: # # bash deploy/lxc/install.sh # set -euo pipefail APP_DIR=/opt/bookstack-mcp CONF_DIR=/etc/bookstack-mcp SVC_USER=bookstack-mcp SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; } die() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; exit 1; } # Find the project root. Normally this script lives at deploy/lxc/install.sh so # the root is two levels up, but people often copy the tree around flat, so # check the obvious candidates rather than assuming. find_src() { local candidate for candidate in "$SCRIPT_DIR/../.." "$SCRIPT_DIR/.." "$SCRIPT_DIR" "$PWD"; do if [[ -f "$candidate/pyproject.toml" && -d "$candidate/bookstack_mcp" ]]; then (cd "$candidate" && pwd) return 0 fi done return 1 } if ! SRC_DIR="$(find_src)"; then die "Can't find the project source (needs pyproject.toml and a bookstack_mcp/ directory). Looked in: $SCRIPT_DIR/../.. , $SCRIPT_DIR/.. , $SCRIPT_DIR , $PWD Get the whole project into the container, then run the script from its root: git clone /opt/src/bookstack-mcp cd /opt/src/bookstack-mcp bash deploy/lxc/install.sh" fi [[ $EUID -eq 0 ]] || die "Run this as root (or with sudo)." # The script copies SRC_DIR into APP_DIR, so they must not be the same place. if [[ "$SRC_DIR" == "$APP_DIR" ]]; then die "The source is $APP_DIR, which is also the install target. Keep the source somewhere else and let the installer copy it in: mkdir -p /opt/src && mv $APP_DIR /opt/src/bookstack-mcp cd /opt/src/bookstack-mcp && bash deploy/lxc/install.sh" fi log "Installing from $SRC_DIR" # --- Python version check ------------------------------------------------- # Needs 3.11+. Debian 12/13 and Ubuntu 24.04 are fine; Debian 11 and # Ubuntu 22.04 ship something older and need a newer python installed first. log "Checking Python version" if ! command -v python3 >/dev/null; then die "python3 not installed. Try: apt install -y python3 python3-venv" fi PY_OK=$(python3 -c 'import sys; print(1 if sys.version_info >= (3,11) else 0)') if [[ "$PY_OK" != "1" ]]; then die "Python $(python3 -V | cut -d' ' -f2) found, but 3.11+ is required. Debian 12+/Ubuntu 24.04+ work out of the box. On older releases install a newer python3 first (e.g. via deadsnakes) and re-run." fi # --- Dependencies --------------------------------------------------------- log "Installing system packages" export DEBIAN_FRONTEND=noninteractive # A single broken third-party repo shouldn't abort the whole install, so the # update is advisory; only the install itself is allowed to fail the script. apt-get update -qq || log "apt update reported errors, continuing" apt-get install -y -qq python3-venv python3-pip ca-certificates >/dev/null # --- Service user --------------------------------------------------------- if ! id -u "$SVC_USER" >/dev/null 2>&1; then log "Creating service user $SVC_USER" useradd --system --home-dir "$APP_DIR" --shell /usr/sbin/nologin "$SVC_USER" fi # --- Application ---------------------------------------------------------- log "Installing application to $APP_DIR" mkdir -p "$APP_DIR" rm -rf "$APP_DIR/bookstack_mcp" cp -r "$SRC_DIR/bookstack_mcp" "$APP_DIR/" cp "$SRC_DIR/pyproject.toml" "$APP_DIR/" if [[ ! -d "$APP_DIR/venv" ]]; then log "Creating virtualenv" python3 -m venv "$APP_DIR/venv" fi log "Installing Python dependencies (this takes a minute)" "$APP_DIR/venv/bin/pip" install --quiet --upgrade pip "$APP_DIR/venv/bin/pip" install --quiet "$APP_DIR" chown -R "$SVC_USER:$SVC_USER" "$APP_DIR" # --- Configuration -------------------------------------------------------- mkdir -p "$CONF_DIR" if [[ ! -f "$CONF_DIR/env" ]]; then log "Creating $CONF_DIR/env from the template" # systemd EnvironmentFile does not understand quotes or inline comments the # way a shell does, so strip comments and blank lines out of the example. grep -vE '^\s*(#|$)' "$SRC_DIR/.env.example" > "$CONF_DIR/env" NEW_CONFIG=1 else log "Keeping existing $CONF_DIR/env" NEW_CONFIG=0 fi chown root:"$SVC_USER" "$CONF_DIR/env" chmod 640 "$CONF_DIR/env" # --- systemd -------------------------------------------------------------- log "Installing systemd unit" UNIT_SRC="" for candidate in "$SRC_DIR/deploy/lxc/bookstack-mcp.service" "$SCRIPT_DIR/bookstack-mcp.service"; do [[ -f "$candidate" ]] && { UNIT_SRC="$candidate"; break; } done [[ -n "$UNIT_SRC" ]] || die "Can't find bookstack-mcp.service" install -m 644 "$UNIT_SRC" /etc/systemd/system/bookstack-mcp.service systemctl daemon-reload systemctl enable bookstack-mcp >/dev/null echo log "Install complete." echo if [[ "$NEW_CONFIG" == "1" ]]; then cat <