Modernize bootstrap: fix bugs, idempotent reruns, OS/arch detection

Security / correctness:
- Remove embedded basic-auth credential in scripts/bootstrap.sh (was fetching
  zsh-setup.sh via a credentialed URL when the binary was already installed
  by strap.sh into /usr/local/sbin/zsh-setup; the .profile dance + curl was
  dead code).
- Drop pre-install eval of `sentry-cli bash-hook` (sentry-cli was never
  installed by this repo, so the call halted under `set -e`).
- Fix /root/.ssh order-of-operations: mkdir + chmod before writing
  authorized_keys, and append-if-missing instead of clobbering existing keys.
- Replace `defaults-bootstrap|*` wildcard in strap.sh with an explicit error
  arm so typos no longer silently run defaults.
- Pass `nosalt` (the actual recognized token) as the salt arg to bootstrap.sh
  instead of `nogluster`, which fell through to the help branch.

Modernization:
- Drop docker-compose v1 binary download; rely on docker-compose-plugin only.
- CTOP install detects arch (amd64/arm64) via `dpkg --print-architecture`.
- Salt repo URLs detect Ubuntu codename + version + arch from /etc/os-release
  instead of hardcoding jammy/22.04/amd64.
- Drop deprecated `apt-get --force-yes`.
- Remove obsolete `version: '3.7'` from docker-compose.yml.
- Add `--no-install-recommends` to apt installs.

Robustness / idempotency:
- `set -euo pipefail` across all three scripts.
- `append_unique` helper guards every `.zshrc` edit so reruns no longer
  duplicate `SENTRY_DSN`, `DOCKER_BUILDKIT`, plugin block, etc.
- Replace `USRDIR=$(echo ~)` with `$HOME` / explicit defaults.
- chsh now skipped if zsh is already the user's shell, and the trailing
  `exec zsh` only runs on an interactive TTY (no more hanging non-interactive
  bootstraps).
- zsh-setup.sh's old .profile cleanup sed actually matches the line written
  by bootstrap.sh.

Architecture:
- Environment overrides: STRAP_BASE_URL, STRAP_AUTHORIZED_KEYS,
  STRAP_SENTRY_DSN, STRAP_SALT_MASTER. Built-in defaults preserve existing
  behavior on a no-env-var invocation.

Default flow (strap.sh / strap.sh defaults-bootstrap → `bootstrap none nosalt`
+ docker + ctop + oh-my-zsh + defaultkey SSH key + SENTRY_DSN) is unchanged.

Shellcheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leopere 2026-05-12 10:11:51 -04:00
parent c0838e5a23
commit 7ea275f7e6
Signed by: colin
SSH Key Fingerprint: SHA256:nRPCQTeMFLdGytxRQmPVK9VXY3/ePKQ5lGRyJhT5DY8
5 changed files with 227 additions and 123 deletions

View File

@ -1,34 +1,45 @@
## Bootstrap Script Documentation ## Bootstrap Script Documentation
### Scope ### Scope
This document details the usage of a server bootstrap script aimed at installing essential utilities and configurations for server setups. It supports the installation of ZSH, Docker, along with various optimizations and support tools. A server bootstrap script that installs essential utilities and configurations: ZSH (with Oh My Zsh and plugins), Docker (with the Compose v2 plugin), system tooling (htop, glances, iftop, ctop), and optional provider / Salt configuration. Targets Debian/Ubuntu hosts (`apt-get`) on `amd64` or `arm64`. Re-runs are safe — edits to `.zshrc` and SSH keys are idempotent.
### Usage ### Usage
To initiate the bootstrap process with the default configuration, embed the following command in your server's post-installation scripts: To run the bootstrap with the default configuration on a fresh host (as root):
```bash ```bash
#!/usr/bin/env bash source <(curl -fsSL https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main/strap.sh) defaults-bootstrap
## source <(curl -s https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main/strap.sh) defaults-bootstrap
``` ```
This line fetches and executes the bootstrap script, setting up the server with a standard suite of tools and settings. This fetches and executes the bootstrap script, applying a standard suite of tools and settings.
### Advanced Usage and Provider Specific Deploys ### Advanced Usage and Provider-specific Deploys
The bootstrap script accommodates deployments specific to different providers, allowing for the inclusion or exclusion of selected features based on requirements. The bootstrap supports per-provider configuration and selective feature toggles via positional args.
#### Example for OVH Deployment: #### Example for OVH deployment
For deploying on an OVH server with tailored settings, use the example below:
```bash ```bash
#!/usr/bin/env bash source <(curl -fsSL https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main/strap.sh) bootstrap ovh nosalt
source <(curl -s https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main/strap.sh) bootstrap ovh nosalt
``` ```
This example demonstrates how to configure a server specifically for OVH, omitting Salt configuration management. #### Argument reference
- `strap.sh defaults-bootstrap` — provider=`none`, salt=`nosalt`. Also the default when no args are given.
- `strap.sh bootstrap PROVIDER SALT` where:
- `PROVIDER` ∈ {`none`, `ovh`, `digitalocean`}
- `SALT` ∈ {`salt`, `nosalt`}
#### Deployment Customization: ### Environment overrides
- The first argument after `bootstrap` indicates the target cloud provider or environment (e.g., `ovh`, `digitalocean`).
- The second argument allows for specifying configuration preferences, such as excluding Salt stack installation (`nosalt`).
Adjust these parameters to customize the bootstrap process according to your deployment environment and preferences. | Variable | Default | Purpose |
| --- | --- | --- |
| `STRAP_BASE_URL` | `https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main` | Base URL for fetching `bootstrap.sh` / `zsh-setup.sh` |
| `STRAP_AUTHORIZED_KEYS` | built-in `defaultkey_key` | SSH public key appended to `/root/.ssh/authorized_keys` |
| `STRAP_SENTRY_DSN` | `https://...@sentry.aenow.com/3` | Sentry DSN exported in `.zshrc` |
| `STRAP_SALT_MASTER` | `aerence.aenow.fun` | Salt master address (only used when `SALT=salt`) |
Example:
```bash
STRAP_AUTHORIZED_KEYS="$(cat ~/.ssh/id_ed25519.pub)" \
source <(curl -fsSL https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main/strap.sh) defaults-bootstrap
```

View File

@ -1,4 +1,3 @@
version: '3.7'
services: services:
bootstrap-scripts: bootstrap-scripts:
build: build:

View File

@ -1,74 +1,96 @@
#!/bin/bash #!/usr/bin/env bash
set -e set -euo pipefail
# Sentry setup : "${STRAP_SENTRY_DSN:=https://4d089076433c4a7aa31bbb2741f053fe@sentry.aenow.com/3}"
echo 'export SENTRY_DSN=https://4d089076433c4a7aa31bbb2741f053fe@sentry.aenow.com/3' >> ~/.zshrc : "${STRAP_SALT_MASTER:=aerence.aenow.fun}"
eval "$(sentry-cli bash-hook)"
PROVIDER="${1:-none}"
SALT_MODE="${2:-nosalt}"
# shellcheck disable=SC1091
. /etc/os-release
CODENAME="${UBUNTU_CODENAME:-${VERSION_CODENAME:-jammy}}"
VERSION_ID_SHORT="${VERSION_ID:-22.04}"
ARCH="$(dpkg --print-architecture)"
HOME_DIR="${HOME:-/root}"
ZSHRC="$HOME_DIR/.zshrc"
append_unique() {
local line="$1" file="$2"
touch "$file"
grep -qxF "$line" "$file" || echo "$line" >> "$file"
}
append_unique "export SENTRY_DSN=$STRAP_SENTRY_DSN" "$ZSHRC"
# Functions for provider-specific configurations
digitalocean() { digitalocean() {
export HOSTNAME=$(curl -s http://169.254.169.254/metadata/v1/hostname) local md_base=http://169.254.169.254/metadata/v1
hostnamectl set-hostname "$HOSTNAME" local hostname
export PUBLIC_IPV4=$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address) hostname=$(curl -fsS "$md_base/hostname" || true)
export PUBLIC_IPV6=$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv6/address) if [ -n "$hostname" ]; then
hostnamectl set-hostname "$hostname"
fi
} }
ovh() { ovh() {
echo "Nothing special for OVH at this stage." echo "No OVH-specific configuration needed."
} }
# Provider setup case "$PROVIDER" in
case $1 in
digitalocean) digitalocean ;; digitalocean) digitalocean ;;
ovh) ovh ;; ovh) ovh ;;
none) echo "Nothing special going to be done here." ;; none) echo "No provider-specific configuration." ;;
*) echo "bootstrap options are:" *)
echo "bootstrap ovh [salt/nosalt]" echo "Unknown provider '$PROVIDER'. Options: none, ovh, digitalocean" >&2
echo "bootstrap digitalocean [salt/nosalt]" exit 1
echo "bootstrap none [salt/nosalt]" ;; ;;
esac esac
# Salt installation
install_salt() { install_salt() {
sudo curl -fsSL -o /usr/share/keyrings/salt-archive-keyring.gpg https://repo.saltproject.io/salt/py3/ubuntu/22.04/amd64/latest/salt-archive-keyring.gpg curl -fsSL -o /usr/share/keyrings/salt-archive-keyring.gpg \
echo "deb [signed-by=/usr/share/keyrings/salt-archive-keyring.gpg arch=amd64] https://repo.saltproject.io/salt/py3/ubuntu/22.04/amd64/latest jammy main" | sudo tee /etc/apt/sources.list.d/salt.list "https://repo.saltproject.io/salt/py3/ubuntu/${VERSION_ID_SHORT}/${ARCH}/latest/salt-archive-keyring.gpg"
echo "deb [signed-by=/usr/share/keyrings/salt-archive-keyring.gpg arch=${ARCH}] https://repo.saltproject.io/salt/py3/ubuntu/${VERSION_ID_SHORT}/${ARCH}/latest ${CODENAME} main" \
> /etc/apt/sources.list.d/salt.list
mkdir -p /etc/salt/minion.d/ mkdir -p /etc/salt/minion.d/
echo 'master: aerence.aenow.fun' > /etc/salt/minion.d/99-master-address.conf echo "master: $STRAP_SALT_MASTER" > /etc/salt/minion.d/99-master-address.conf
apt-get update DEBIAN_FRONTEND=noninteractive apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y salt-minion DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends salt-minion
} }
# Salt installation based on user selection case "$SALT_MODE" in
case $2 in
salt) install_salt ;; salt) install_salt ;;
nosalt) echo "Not installing salt." ;; nosalt) echo "Skipping salt-minion install." ;;
*) echo "No salt instructions received." *)
echo "Options are:" echo "Unknown salt mode '$SALT_MODE'. Options: salt, nosalt" >&2
echo "bootstrap [hostingProvider] salt" exit 1
echo "bootstrap [hostingProvider] nosalt" ;; ;;
esac esac
# Apt package installations echo "Installing apt packages"
echo "Installing Apt Packages" DEBIAN_FRONTEND=noninteractive apt-get update
apt-get update DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::='--force-confold' -y dist-upgrade
DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::='--force-confold' --force-yes -fuy dist-upgrade DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
DEBIAN_FRONTEND=noninteractive apt-get install -y asciinema ca-certificates gnupg git glances htop iftop zsh asciinema ca-certificates gnupg git glances htop iftop zsh
apt-get update
# Docker and docker-compose installation echo "Installing Docker and compose plugin"
echo "Install docker-compose and docker via convenience scripts" if ! command -v docker >/dev/null 2>&1; then
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose curl -fsSL https://get.docker.com -o /tmp/get-docker.sh
chmod +x /usr/local/bin/docker-compose sh /tmp/get-docker.sh
curl -fsSL https://get.docker.com -o get-docker.sh rm -f /tmp/get-docker.sh
sh get-docker.sh fi
DEBIAN_FRONTEND=noninteractive apt-get install -y docker-compose-plugin DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends docker-compose-plugin
# CTOP installation
echo "Installing CTOP" echo "Installing CTOP"
wget https://github.com/bcicen/ctop/releases/download/v0.7.7/ctop-0.7.7-linux-amd64 -O /usr/local/bin/ctop case "$ARCH" in
amd64|arm64)
curl -fsSL "https://github.com/bcicen/ctop/releases/download/v0.7.7/ctop-0.7.7-linux-${ARCH}" \
-o /usr/local/bin/ctop
chmod +x /usr/local/bin/ctop chmod +x /usr/local/bin/ctop
;;
*)
echo "Skipping CTOP (unsupported arch: $ARCH)" >&2
;;
esac
# Setup Oh My Zsh on first login echo "Running zsh setup"
curl -o /root/zsh-setup.sh https://bootstrap:sHEG3NTC6og8pCJDTF6EPYb8jLmbskx5Ns@git.nixc.us/colin/bootstrap-scripts/raw/branch/main/scripts/zsh-setup.sh STRAP_SENTRY_DSN="$STRAP_SENTRY_DSN" /usr/local/sbin/zsh-setup "$PROVIDER" ae-sentry
echo "zsh-setup" >> ~/.profile
source ~/.profile

View File

@ -1,68 +1,108 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail
USRDIR=$(echo ~) : "${STRAP_SENTRY_DSN:=https://4d089076433c4a7aa31bbb2741f053fe@sentry.aenow.com/3}"
# Simplify installation command USR_HOME="${HOME:-/root}"
curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | sh -s -- --unattended ZSHRC="$USR_HOME/.zshrc"
# Update ZSH theme directly append_unique() {
sed -i'' -e 's@ZSH_THEME="robbyrussell"@ZSH_THEME="pygmalion"@' "$USRDIR/.zshrc" local line="$1" file="$2"
touch "$file"
grep -qxF "$line" "$file" || echo "$line" >> "$file"
}
clone_plugin() {
local repo="$1" dest="$2"
[ -d "$dest" ] || git clone --depth=1 "$repo" "$dest"
}
usage() {
echo "Usage: zsh-setup [digitalocean|ovh|none] [ae-sentry|none]" >&2
}
install_omz() {
if [ ! -d "$USR_HOME/.oh-my-zsh" ]; then
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended
fi
if [ -f "$ZSHRC" ]; then
sed -i -e 's@ZSH_THEME="robbyrussell"@ZSH_THEME="pygmalion"@' "$ZSHRC"
fi
}
ae_sentry() { ae_sentry() {
echo 'export SENTRY_DSN=https://4d089076433c4a7aa31bbb2741f053fe@sentry.aenow.com/3' >> "$USRDIR/.zshrc" append_unique "export SENTRY_DSN=$STRAP_SENTRY_DSN" "$ZSHRC"
} }
digitalocean() { digitalocean() {
echo 'export PUBLIC_IPV4=$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address)' >> "$USRDIR/.zshrc" # shellcheck disable=SC2016
echo 'export PUBLIC_IPV6=$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv6/address)' >> "$USRDIR/.zshrc" append_unique 'export PUBLIC_IPV4=$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address)' "$ZSHRC"
# shellcheck disable=SC2016
append_unique 'export PUBLIC_IPV6=$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv6/address)' "$ZSHRC"
} }
ovh() { ovh() {
echo "Nothing to see here at the moment." echo "No OVH-specific zsh configuration."
} }
configure_plugins() { configure_plugins() {
# Clone only if directory does not exist to prevent errors on rerun local custom="${ZSH_CUSTOM:-$USR_HOME/.oh-my-zsh/custom}"
[ ! -d "${ZSH_CUSTOM:-$USRDIR/.oh-my-zsh/custom}/plugins/zsh-autosuggestions" ] && git clone https://github.com/zsh-users/zsh-autosuggestions "${ZSH_CUSTOM:-$USRDIR/.oh-my-zsh/custom}/plugins/zsh-autosuggestions" clone_plugin https://github.com/zsh-users/zsh-autosuggestions "$custom/plugins/zsh-autosuggestions"
[ ! -d "${ZSH_CUSTOM:-$USRDIR/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting" ] && git clone https://github.com/zsh-users/zsh-syntax-highlighting.git "${ZSH_CUSTOM:-$USRDIR/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting" clone_plugin https://github.com/zsh-users/zsh-syntax-highlighting.git "$custom/plugins/zsh-syntax-highlighting"
[ ! -d "${ZSH_CUSTOM:-$USRDIR/.oh-my-zsh/custom}/plugins/zsh-history-substring-search" ] && git clone https://github.com/zsh-users/zsh-history-substring-search "${ZSH_CUSTOM:-$USRDIR/.oh-my-zsh/custom}/plugins/zsh-history-substring-search" clone_plugin https://github.com/zsh-users/zsh-history-substring-search "$custom/plugins/zsh-history-substring-search"
[ ! -d "${ZSH_CUSTOM:-$USRDIR/.oh-my-zsh/custom}/plugins/command-time" ] && git clone https://github.com/popstas/zsh-command-time.git "${ZSH_CUSTOM:-$USRDIR/.oh-my-zsh/custom}/plugins/command-time" clone_plugin https://github.com/popstas/zsh-command-time.git "$custom/plugins/command-time"
cat <<EOF >> "$USRDIR/.zshrc" append_unique 'ZSH_COMMAND_TIME_MIN_SECONDS=3' "$ZSHRC"
ZSH_COMMAND_TIME_MIN_SECONDS=3 append_unique 'ZSH_COMMAND_TIME_MSG="Execution time: %s"' "$ZSHRC"
ZSH_COMMAND_TIME_MSG="Execution time: %s" append_unique 'ZSH_COMMAND_TIME_COLOR="cyan"' "$ZSHRC"
ZSH_COMMAND_TIME_COLOR="cyan" append_unique 'ZSH_COMMAND_TIME_EXCLUDE=(vim mcedit nano ctop ssh)' "$ZSHRC"
ZSH_COMMAND_TIME_EXCLUDE=(vim mcedit nano ctop ssh)
EOF
sed -i'' -e 's@plugins=(git)@plugins=(git cp colored-man-pages docker docker-compose extract iterm2 python rsync safe-paste transfer ubuntu zsh-navigation-tools zsh-autosuggestions zsh-syntax-highlighting zsh-history-substring-search command-time universalarchive)@' "$USRDIR/.zshrc" local plugin_line='plugins=(git cp colored-man-pages docker docker-compose extract iterm2 python rsync safe-paste transfer ubuntu zsh-navigation-tools zsh-autosuggestions zsh-syntax-highlighting zsh-history-substring-search command-time universalarchive)'
if grep -q '^plugins=(git)$' "$ZSHRC"; then
sed -i -e "s@^plugins=(git)\$@$plugin_line@" "$ZSHRC"
elif ! grep -qxF "$plugin_line" "$ZSHRC"; then
echo "$plugin_line" >> "$ZSHRC"
fi
} }
# Process options clean_profile_remnants() {
case $1 in if [ -f "$USR_HOME/.profile" ]; then
sed -i -e '/^zsh-setup$/d' -e '/zsh-setup\.sh/d' "$USR_HOME/.profile"
fi
}
install_omz
case "${1:-none}" in
digitalocean) digitalocean ;; digitalocean) digitalocean ;;
ovh) ovh ;; ovh) ovh ;;
*) echo "Usage: zsh-setup.sh [digitalocean|ovh|none]" ;; none) ;;
*) usage ;;
esac esac
case $2 in case "${2:-none}" in
ae-sentry) ae_sentry ;; ae-sentry) ae_sentry ;;
none) echo "No Sentry server added." ;; none) ;;
*) echo "Usage: zsh-setup.sh hosting-provider [ae-sentry|my-sentry|none]" ;; *) usage ;;
esac esac
echo "export DOCKER_BUILDKIT=1" >> "$USRDIR/.zshrc" append_unique 'export DOCKER_BUILDKIT=1' "$ZSHRC"
echo "export COMPOSE_DOCKER_CLI_BUILD=1" >> "$USRDIR/.zshrc" append_unique 'export COMPOSE_DOCKER_CLI_BUILD=1' "$ZSHRC"
configure_plugins configure_plugins
clean_profile_remnants
sed -i'' -e "/bash \$USRDIR\/zsh-setup.sh/d" "$USRDIR/.profile" ZSH_BIN="$(command -v zsh || true)"
if [ -n "$ZSH_BIN" ]; then
USER_NAME="$(id -un)"
CURRENT_SHELL="$(getent passwd "$USER_NAME" | cut -d: -f7 || true)"
if [ "$CURRENT_SHELL" != "$ZSH_BIN" ]; then
chsh -s "$ZSH_BIN" "$USER_NAME" || true
fi
fi
# Consider not removing the script automatically for debugging or rerun echo "Bootstrap complete. Relog to start zsh."
# rm -f "$USRDIR/zsh-setup.sh"
echo "Relog into terminal finished bootstrapping server" if [ -n "$ZSH_BIN" ] && [ -t 0 ] && [ -t 1 ]; then
exec "$ZSH_BIN"
chsh -s "$(which zsh)" fi
zsh
source "$USRDIR/.zshrc"

View File

@ -1,27 +1,59 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -euo pipefail
# Basic dependencies installation : "${STRAP_BASE_URL:=https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main}"
DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y curl wget : "${STRAP_AUTHORIZED_KEYS:=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICxoakgL0Tq4mAv+UMnFc3PZptPCXz8ObCsyVmBtiB2P defaultkey_key}"
# Downloading bootstrap scripts usage() {
curl -o /usr/local/sbin/zsh-setup https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main/scripts/zsh-setup.sh && chmod +x /usr/local/sbin/zsh-setup cat <<USAGE
curl -o /usr/local/sbin/bootstrap https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main/scripts/bootstrap.sh && chmod +x /usr/local/sbin/bootstrap Usage:
strap.sh run defaults (provider=none, no salt)
strap.sh defaults-bootstrap run defaults explicitly
strap.sh bootstrap PROVIDER SALT PROVIDER in {none, ovh, digitalocean}; SALT in {salt, nosalt}
# Update Dewitt SSH key Environment overrides:
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICxoakgL0Tq4mAv+UMnFc3PZptPCXz8ObCsyVmBtiB2P defaultkey_key" > /root/.ssh/authorized_keys STRAP_BASE_URL base URL for fetching scripts
STRAP_AUTHORIZED_KEYS ssh public key(s) to install (default: built-in defaultkey)
USAGE
}
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
echo "strap.sh must be run as root" >&2
exit 1
fi
if ! command -v apt-get >/dev/null 2>&1; then
echo "strap.sh requires a Debian/Ubuntu host (apt-get not found)" >&2
exit 1
fi
DEBIAN_FRONTEND=noninteractive apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends curl wget ca-certificates
curl -fsSL -o /usr/local/sbin/zsh-setup "$STRAP_BASE_URL/scripts/zsh-setup.sh"
curl -fsSL -o /usr/local/sbin/bootstrap "$STRAP_BASE_URL/scripts/bootstrap.sh"
chmod +x /usr/local/sbin/zsh-setup /usr/local/sbin/bootstrap
# Ensure .ssh directory exists and proper permissions are set
mkdir -p /root/.ssh mkdir -p /root/.ssh
chmod 700 /root/.ssh chmod 700 /root/.ssh
touch /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys
grep -qxF "$STRAP_AUTHORIZED_KEYS" /root/.ssh/authorized_keys \
|| echo "$STRAP_AUTHORIZED_KEYS" >> /root/.ssh/authorized_keys
# Run bootstrap based on input parameters or default action case "${1:-defaults-bootstrap}" in
case $1 in
bootstrap) bootstrap)
/usr/local/sbin/bootstrap "$2" "$3" "$4" /usr/local/sbin/bootstrap "${2:-none}" "${3:-nosalt}"
;; ;;
defaults-bootstrap|*) defaults-bootstrap)
/usr/local/sbin/bootstrap none nogluster nosalt /usr/local/sbin/bootstrap none nosalt
;;
-h|--help|help)
usage
;;
*)
echo "Unknown command: ${1:-}" >&2
usage >&2
exit 1
;; ;;
esac esac