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
### 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
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
#!/usr/bin/env bash
## source <(curl -s https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main/strap.sh) defaults-bootstrap
source <(curl -fsSL 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:
For deploying on an OVH server with tailored settings, use the example below:
#### Example for OVH deployment
```bash
#!/usr/bin/env bash
source <(curl -s https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main/strap.sh) bootstrap ovh nosalt
source <(curl -fsSL 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:
- 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`).
### Environment overrides
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:
bootstrap-scripts:
build:

View File

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

View File

@ -1,68 +1,108 @@
#!/usr/bin/env bash
set -euo pipefail
USRDIR=$(echo ~)
: "${STRAP_SENTRY_DSN:=https://4d089076433c4a7aa31bbb2741f053fe@sentry.aenow.com/3}"
# Simplify installation command
curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh | sh -s -- --unattended
USR_HOME="${HOME:-/root}"
ZSHRC="$USR_HOME/.zshrc"
# Update ZSH theme directly
sed -i'' -e 's@ZSH_THEME="robbyrussell"@ZSH_THEME="pygmalion"@' "$USRDIR/.zshrc"
append_unique() {
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() {
echo 'export SENTRY_DSN=https://4d089076433c4a7aa31bbb2741f053fe@sentry.aenow.com/3' >> "$USRDIR/.zshrc"
append_unique "export SENTRY_DSN=$STRAP_SENTRY_DSN" "$ZSHRC"
}
digitalocean() {
echo 'export PUBLIC_IPV4=$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address)' >> "$USRDIR/.zshrc"
echo 'export PUBLIC_IPV6=$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv6/address)' >> "$USRDIR/.zshrc"
# shellcheck disable=SC2016
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() {
echo "Nothing to see here at the moment."
echo "No OVH-specific zsh configuration."
}
configure_plugins() {
# Clone only if directory does not exist to prevent errors on rerun
[ ! -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"
[ ! -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"
[ ! -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"
[ ! -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"
cat <<EOF >> "$USRDIR/.zshrc"
ZSH_COMMAND_TIME_MIN_SECONDS=3
ZSH_COMMAND_TIME_MSG="Execution time: %s"
ZSH_COMMAND_TIME_COLOR="cyan"
ZSH_COMMAND_TIME_EXCLUDE=(vim mcedit nano ctop ssh)
EOF
local custom="${ZSH_CUSTOM:-$USR_HOME/.oh-my-zsh/custom}"
clone_plugin https://github.com/zsh-users/zsh-autosuggestions "$custom/plugins/zsh-autosuggestions"
clone_plugin https://github.com/zsh-users/zsh-syntax-highlighting.git "$custom/plugins/zsh-syntax-highlighting"
clone_plugin https://github.com/zsh-users/zsh-history-substring-search "$custom/plugins/zsh-history-substring-search"
clone_plugin https://github.com/popstas/zsh-command-time.git "$custom/plugins/command-time"
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"
append_unique 'ZSH_COMMAND_TIME_MIN_SECONDS=3' "$ZSHRC"
append_unique 'ZSH_COMMAND_TIME_MSG="Execution time: %s"' "$ZSHRC"
append_unique 'ZSH_COMMAND_TIME_COLOR="cyan"' "$ZSHRC"
append_unique 'ZSH_COMMAND_TIME_EXCLUDE=(vim mcedit nano ctop ssh)' "$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
case $1 in
clean_profile_remnants() {
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 ;;
ovh) ovh ;;
*) echo "Usage: zsh-setup.sh [digitalocean|ovh|none]" ;;
ovh) ovh ;;
none) ;;
*) usage ;;
esac
case $2 in
case "${2:-none}" in
ae-sentry) ae_sentry ;;
none) echo "No Sentry server added." ;;
*) echo "Usage: zsh-setup.sh hosting-provider [ae-sentry|my-sentry|none]" ;;
none) ;;
*) usage ;;
esac
echo "export DOCKER_BUILDKIT=1" >> "$USRDIR/.zshrc"
echo "export COMPOSE_DOCKER_CLI_BUILD=1" >> "$USRDIR/.zshrc"
append_unique 'export DOCKER_BUILDKIT=1' "$ZSHRC"
append_unique 'export COMPOSE_DOCKER_CLI_BUILD=1' "$ZSHRC"
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
# rm -f "$USRDIR/zsh-setup.sh"
echo "Bootstrap complete. Relog to start zsh."
echo "Relog into terminal finished bootstrapping server"
chsh -s "$(which zsh)"
zsh
source "$USRDIR/.zshrc"
if [ -n "$ZSH_BIN" ] && [ -t 0 ] && [ -t 1 ]; then
exec "$ZSH_BIN"
fi

View File

@ -1,27 +1,59 @@
#!/usr/bin/env bash
set -e
set -euo pipefail
# Basic dependencies installation
DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y curl wget
: "${STRAP_BASE_URL:=https://git.nixc.us/colin/bootstrap-scripts/raw/branch/main}"
: "${STRAP_AUTHORIZED_KEYS:=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICxoakgL0Tq4mAv+UMnFc3PZptPCXz8ObCsyVmBtiB2P defaultkey_key}"
# Downloading bootstrap scripts
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
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() {
cat <<USAGE
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
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICxoakgL0Tq4mAv+UMnFc3PZptPCXz8ObCsyVmBtiB2P defaultkey_key" > /root/.ssh/authorized_keys
Environment overrides:
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
chmod 700 /root/.ssh
touch /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 in
case "${1:-defaults-bootstrap}" in
bootstrap)
/usr/local/sbin/bootstrap "$2" "$3" "$4"
/usr/local/sbin/bootstrap "${2:-none}" "${3:-nosalt}"
;;
defaults-bootstrap|*)
/usr/local/sbin/bootstrap none nogluster nosalt
defaults-bootstrap)
/usr/local/sbin/bootstrap none nosalt
;;
-h|--help|help)
usage
;;
*)
echo "Unknown command: ${1:-}" >&2
usage >&2
exit 1
;;
esac