Lab

erectus.sh

Script
Linux
Debian
Bootstrap
Bash
Script

A Debian-first bootstrap script for fresh Linux machines, with package installs, fake apt theater, a progress bar, and a name that did not survive contact with adulthood.

Published
April 28, 2026
Updated
April 28, 2026

Usage Notes

Practical commands, script details, and implementation notes.

Another one for Lab.

Not a polished framework. Not a serious provisioning system. Just a small bootstrap script for getting a fresh Debian-ish machine into a usable dev shape without manually installing the same pile of tools every single time.

It is called erectus.sh, which is obviously a mature and dignified name chosen by a responsible adult.

What it is

A Debian-first setup script that:

  • updates package metadata
  • installs a basic stack of dev and admin tools
  • checks whether packages are already present
  • prints a progress bar so the whole thing feels slightly more alive
  • ends with a small summary of installed versions and system info

Why it exists

Because I got tired of repeating the same setup dance on fresh machines:

  • curl
  • git
  • node
  • npm
  • java
  • caddy
  • fish
  • jq
  • htop
  • ufw
  • fail2ban

Could this become something more structured later? Probably.

Is this currently just a useful script with fake apt drama and a spinner? Also yes.

Scope

This version is intentionally narrowed to Debian / Ubuntu / Mint style systems.

I use Debian. That is the environment I actually care about here.

I had some multi-distro logic in earlier versions, but if something is not tested, I would rather not pretend it is portable.

Script

Save it as:

sudo nano /usr/local/bin/erectus.sh

Paste:

#!/bin/bash

GREEN="\033[0;32m"
YELLOW="\033[1;33m"
CYAN="\033[0;36m"
RESET="\033[0m"

spinner='|/-\\'

progress_bar() {
    local cur=$1
    local total=$2
    local msg="$3"
    local cols
    local percent
    local pct_text
    local bar_width
    local fill
    local empty

    cols=$(tput cols 2>/dev/null || echo 80)
    percent=$(( cur * 100 / total ))
    printf -v pct_text "%03d%%" "$percent"

    bar_width=$(( cols - 12 ))
    (( bar_width < 20 )) && bar_width=20

    fill=$(( percent * bar_width / 100 ))
    empty=$(( bar_width - fill ))

    printf "\r\033[K"
    printf "%s [" "${spinner:cur%4:1}"
    printf "%0.s#" $(seq 1 "$fill")
    printf "%0.s " $(seq 1 "$empty")
    printf "] %s\n%s" "$pct_text" "$msg"
    printf "\033[A"
}

fake_apt_intro() {
    echo -e "${CYAN}Reading package lists... Done"
    sleep 0.2
    echo -e "Building dependency tree... Done"
    sleep 0.2
    echo -e "Reading state information... Done${RESET}"
    sleep 0.2
}

if [[ $EUID -ne 0 ]]; then
    echo -e "${YELLOW}Please run as root (sudo ./erectus.sh)${RESET}"
    exit 1
fi

. /etc/os-release 2>/dev/null || {
    echo "Could not detect distro"
    exit 1
}

case "${ID:-}" in
    debian|ubuntu|linuxmint)
        ;;
    *)
        echo -e "${YELLOW}This script is meant for Debian, Ubuntu, or Mint style systems.${RESET}"
        exit 1
        ;;
esac

echo -e "${GREEN}Detected Linux distribution: ${ID}${RESET}"

PKG_UPDATE="apt -qq update"
PKG_INSTALL="apt -qq install -y"
PKG_CHECK="dpkg -s"

echo -e "${GREEN}Updating package lists...${RESET}"
$PKG_UPDATE >/dev/null 2>&1

pkgs=( curl git nodejs npm yarn openjdk-21-jdk caddy fish jq htop ufw fail2ban )
total=${#pkgs[@]}

echo -e "${GREEN}Installing required tools...${RESET}"
fake_apt_intro

for i in "${!pkgs[@]}"; do
    pkg=${pkgs[$i]}
    step=$((i + 1))

    if $PKG_CHECK "$pkg" &>/dev/null; then
        progress_bar "$step" "$total" "already installed: $pkg"
    else
        progress_bar "$step" "$total" "installing: $pkg"
        $PKG_INSTALL "$pkg" >/dev/null 2>&1
        progress_bar "$step" "$total" "installed: $pkg"
    fi

    sleep 0.4
done

progress_bar "$total" "$total" "setup complete"
echo -e "\n${GREEN}All tools are installed and verified.${RESET}\n"

echo -e "${CYAN}──────────────────────────────"
echo -e " Installed tool versions"
echo -e "──────────────────────────────${RESET}"

printf "%-12s → %s\n" "curl" "$(curl --version | head -n1 | awk '{print $2}')"
printf "%-12s → %s\n" "git" "$(git --version | awk '{print $3}')"
printf "%-12s → %s\n" "node" "$(node -v)"
printf "%-12s → %s\n" "npm" "$(npm -v)"

if command -v yarn >/dev/null 2>&1; then
    YARN_VER=$(yarn --version 2>/dev/null || yarn -v 2>/dev/null || yarnpkg --version 2>/dev/null)
    [[ -n "$YARN_VER" ]] && printf "%-12s → %s\n" "yarn" "$YARN_VER"
fi

printf "%-12s → %s\n" "java" "$(java -version 2>&1 | awk -F\\\" '/version/ {print $2}')"
printf "%-12s → %s\n" "caddy" "$(caddy version 2>/dev/null)"
printf "%-12s → %s\n" "fish" "$(fish --version | awk '{print $3}')"
printf "%-12s → %s\n" "jq" "$(jq --version)"
printf "%-12s → %s\n" "htop" "$(htop --version | head -n1 | awk '{print $2}')"
printf "%-12s → %s\n" "ufw" "$(ufw version | awk '/ufw/ {print $2}')"
printf "%-12s → %s\n" "fail2ban" "$(fail2ban-server -V 2>&1 | head -n1 | awk '{print $NF}')"

echo -e "\n${CYAN}──────────────────────────────"
echo -e " System information"
echo -e "──────────────────────────────${RESET}"

CPU_MODEL=$(lscpu | awk -F: '/Model name/ {gsub(/^ +/, "", $2); print $2; exit}')
RAM_TOTAL=$(free -h | awk '/Mem:/ {print $2}')
DISK_USAGE=$(df -h / | awk 'NR==2 {print $3 " / " $2 " used"}')
LOCAL_IP=$(hostname -I | awk '{print $1}')
PUBLIC_IP=$(curl -s https://api.ipify.org)

printf "%-12s → %s\n" "CPU" "$CPU_MODEL"
printf "%-12s → %s\n" "RAM" "$RAM_TOTAL"
printf "%-12s → %s\n" "Disk" "$DISK_USAGE"
printf "%-12s → %s\n" "Local IP" "$LOCAL_IP"
printf "%-12s → %s\n" "Public IP" "$PUBLIC_IP"

echo -e "\n${GREEN}System ready for action, commander 🚀${RESET}"

Make it executable:

sudo chmod +x /usr/local/bin/erectus.sh

Run it:

sudo /usr/local/bin/erectus.sh

Notes

  • This is a draft utility script, not a serious provisioning system.
  • It is intentionally Debian-first now.
  • openjdk-21-jdk, ufw, fail2ban, and even yarn may deserve a second pass depending on the machine.
  • The fake apt intro serves no real purpose except making the whole thing feel a little more theatrical.

Things I would probably improve later

  • make the package list configurable
  • split desktop bootstrap from server bootstrap
  • decide whether yarn should stay at all
  • make the summary more defensive when a tool installs but reports version info differently
  • maybe eventually give it a less stupid name, although that would be just stupid