#!/bin/bash # bootstrap.sh — One-shot OS prep for MukenVault Entry partners. # # Installs the minimum apt packages the preflight checker expects # (nginx, curl, openssl, gdb) on a fresh Ubuntu 22.04 / 24.04 box, then # enables nginx so the partner can move straight to preflight + setup. # # Intended flow: # curl -fsSL https://install.mukenvault.com/bootstrap.sh | sudo bash # curl -fsSL https://install.mukenvault.com/preflight.sh | sudo bash # curl -fsSL https://install.mukenvault.com/setup.sh | \ # sudo bash -s -- --license YOUR-KEY-HERE # # Why a separate script (vs rolling into setup.sh): bootstrap.sh writes # to /etc/apt and installs packages — partners on a host with stricter # change-control may want to apt install by hand, review the package # list, or skip nginx (already installed via PPA, custom build, etc.). # Splitting keeps setup.sh focused on MukenVault itself and bootstrap # focused on "make the OS ready." set -euo pipefail IFS=$'\n\t' red() { printf '\033[1;31m%s\033[0m' "$1"; } green() { printf '\033[1;32m%s\033[0m' "$1"; } log() { printf '\033[1;36m[bootstrap]\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[bootstrap WARN]\033[0m %s\n' "$*" >&2; } fail() { printf '\033[1;31m[bootstrap FAIL]\033[0m %s\n' "$*" >&2; exit 1; } if [[ "$(id -u)" -ne 0 ]]; then fail "must run as root (re-run with sudo)" fi # ── Refuse on unexpected distros ─────────────────────────────────── # Founding 50 only supports Ubuntu 22.04 / 24.04. Bootstrapping on # RHEL or Debian would need different package names; we'd rather stop # loudly than apt-install something that looks right and breaks later. if [[ -r /etc/os-release ]]; then . /etc/os-release case "$ID:$VERSION_ID" in ubuntu:22.04|ubuntu:24.04) log "OS: ${PRETTY_NAME:-$ID $VERSION_ID} (supported)";; ubuntu:*) warn "OS: ${PRETTY_NAME:-$ID $VERSION_ID} — Founding 50 tested on 22.04/24.04 only." warn "Continuing, but apt package versions may differ. Press Ctrl-C in 5s to abort." sleep 5;; *) fail "OS: ${PRETTY_NAME:-$ID $VERSION_ID} — bootstrap.sh only handles Ubuntu (use 'apt install' equivalents on your distro)";; esac else fail "cannot read /etc/os-release — refusing to guess the distro" fi # ── Package list ─────────────────────────────────────────────────── # nginx — primary protection target (Founding 50 protects nginx only) # curl — heartbeat + setup.sh + preflight use libcurl # openssl — libkeyless hooks OpenSSL 3.x; the binary is also useful for cert ops # gdb — provides `gcore` used by the optional verify.sh # apache2-utils — provides `ab` used by `verify.sh --proc-a` (Day 2-3 of T1-3, # errata D-8). Tiny package; if a partner declines it, --proc-a # cleanly returns verdict=skip with an install hint instead of # blocking install.sh. # ca-certificates — ensure TLS trust store is current (handles fresh VPS images) # libbpf1 — BPF runtime loaded by keyless-daemon for process monitoring # and detection pipeline. Not present on fresh Ubuntu 24.04 VPS # images; without it, installer Phase A fails with # 'libbpf runtime missing'. PACKAGES=(nginx curl openssl gdb apache2-utils ca-certificates libbpf1) # ── apt update + install ─────────────────────────────────────────── # Wait up to 180s for any in-flight apt operation to release the dpkg # lock. Fresh Ubuntu VPS images almost always have unattended-upgrades # running for the first few minutes after boot, which would otherwise # make bootstrap.sh die immediately with the opaque # "E: Could not get lock /var/lib/dpkg/lock-frontend" # and force the partner to figure out why and retry by hand. APT_LOCK_OPTS=(-o "DPkg::Lock::Timeout=180") log "apt update (this may take ~30s, or up to ~3 min if unattended-upgrades is running)" DEBIAN_FRONTEND=noninteractive apt-get "${APT_LOCK_OPTS[@]}" update -qq # Print space-separated for readability — IFS=$'\n\t' above means # ${PACKAGES[*]} would otherwise show one package per line. log "apt install -y $(IFS=' '; printf '%s' "${PACKAGES[*]}")" DEBIAN_FRONTEND=noninteractive apt-get "${APT_LOCK_OPTS[@]}" install -y -qq "${PACKAGES[@]}" # ── nginx baseline ───────────────────────────────────────────────── # `enable --now` covers the common "fresh VPS, nginx not yet started" # case without disrupting an already-running nginx (systemctl is # idempotent: enabled + active stays that way). log "systemctl enable --now nginx" systemctl enable --now nginx >/dev/null # Sanity probe: nginx should now serve the default Welcome page on :80. # We don't make this fatal — the partner may have a firewall in front # or a custom config that already replaced the default. if curl -fsS -m 5 -o /dev/null http://127.0.0.1/; then log "$(green '✓') nginx is serving HTTP on 127.0.0.1:80" else warn "could not GET http://127.0.0.1/ — nginx may need manual configuration" fi # ── Versions for the log ─────────────────────────────────────────── log "installed:" printf ' nginx: %s\n' "$(nginx -v 2>&1 | grep -oP 'nginx/\K[0-9.]+' || echo unknown)" printf ' curl: %s\n' "$(curl --version 2>/dev/null | head -1 | awk '{print $2}' || echo unknown)" printf ' openssl: %s\n' "$(openssl version 2>/dev/null | awk '{print $2}' || echo unknown)" printf ' gdb: %s\n' "$(gdb --version 2>/dev/null | head -1 | awk '{print $NF}' || echo unknown)" cat <