Private
Public Access
1
0
Files
websitebox/install.sh
constantprojects eca351057b Add colored output to install.sh, update all URLs to Gitea
Color system: green checkmarks for success, orange bold for info/hints,
cyan section headers, bold white title headers, yellow warnings, red
errors. Rolling progress preview lines shown in dim. UFW "Rules updated"
noise suppressed.

Updated all repository URLs from github.com/websitebox/websitebox to
git.constantprojects.xyz/tankadmin/websitebox across install.sh,
guide.md, and README.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 08:49:13 -07:00

262 lines
9.5 KiB
Bash
Executable File

#!/bin/bash
set -eo pipefail
# WebsiteBox Install Script
# Bootstrap script: installs Docker, clones repo, runs setup wizard
# Usage: curl -fsSL <url>/install.sh | bash
# --- Colors and formatting ---
BOLD='\033[1m'
DIM='\033[2m'
RESET='\033[0m'
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
ORANGE='\033[1;38;5;208m'
CYAN='\033[1;36m'
WHITE='\033[1;37m'
header() { printf "\n${WHITE}═══════════════════════════════════════════════════════════${RESET}\n ${BOLD}%s${RESET}\n${WHITE}═══════════════════════════════════════════════════════════${RESET}\n\n" "$1"; }
section() { printf "\n${CYAN}───────────────────────────────────────────────────────────${RESET}\n ${BOLD}%s${RESET}\n${CYAN}───────────────────────────────────────────────────────────${RESET}\n" "$1"; }
step() { printf "${GREEN}${RESET} ${BOLD}%s${RESET}\n" "$1"; }
info() { printf "${ORANGE} %s${RESET}\n" "$1"; }
ok() { printf "${GREEN} ✓ %s${RESET}\n" "$1"; }
warn() { printf "${YELLOW} ⚠ %s${RESET}\n" "$1"; }
err() { printf "${RED} ✗ %s${RESET}\n" "$1"; }
# --- Rolling preview helper ---
# Shows last 4 lines of output in-place, then clears when done.
# Keeps the terminal clean while still showing live progress.
show_progress() {
local n=4 buffer=() count=0
while IFS= read -r line; do
buffer+=("$line")
(( count++ )) || true
if [ ${#buffer[@]} -gt $n ]; then
buffer=("${buffer[@]:1}")
fi
if [ $count -gt 1 ]; then
printf '\033[%dA' "${#buffer[@]}" 2>/dev/null || true
fi
for l in "${buffer[@]}"; do
printf "\033[2K${DIM} %.60s${RESET}\n" "$l"
done
done
# clear preview lines when done
if [ ${#buffer[@]} -gt 0 ]; then
printf '\033[%dA' "${#buffer[@]}" 2>/dev/null || true
for _ in "${buffer[@]}"; do printf '\033[2K\n'; done
printf '\033[%dA' "${#buffer[@]}" 2>/dev/null || true
fi
}
header "WebsiteBox Installer"
# --- Check for root/sudo ---
if [ "$(id -u)" -eq 0 ]; then
SUDO=""
ACTUAL_USER="${SUDO_USER:-root}"
else
if ! command -v sudo &>/dev/null; then
err "This script requires root or sudo access."
exit 1
fi
SUDO="sudo"
ACTUAL_USER="$(whoami)"
fi
# --- Detect OS ---
if [ -f /etc/os-release ]; then
# shellcheck disable=SC1091
. /etc/os-release
OS_ID="$ID"
OS_VERSION="$VERSION_ID"
else
err "Cannot detect OS. /etc/os-release not found."
err "WebsiteBox supports Ubuntu 20.04+ and Debian 11+."
exit 1
fi
case "$OS_ID" in
ubuntu)
if [ "${OS_VERSION%%.*}" -lt 20 ]; then
err "Ubuntu 20.04 or later is required (detected: ${OS_VERSION})."
exit 1
fi
;;
debian)
if [ "${OS_VERSION%%.*}" -lt 11 ]; then
err "Debian 11 or later is required (detected: ${OS_VERSION})."
exit 1
fi
;;
*)
warn "Unsupported OS detected (${OS_ID} ${OS_VERSION})."
warn "WebsiteBox is tested on Ubuntu 20.04+ and Debian 11+."
read -rp "Continue anyway? (y/N) " cont
if [ "$cont" != "y" ] && [ "$cont" != "Y" ]; then
exit 1
fi
;;
esac
ok "Detected: ${OS_ID} ${OS_VERSION}"
# --- Secure the Server ---
section "Securing your server"
step "Updating system packages..."
info "Downloading the latest security patches for your operating system."
info "On a fresh server this can take 2-10 minutes. Sit tight."
$SUDO apt-get update -qq
DEBIAN_FRONTEND=noninteractive $SUDO apt-get upgrade -y -o Dpkg::Options::="--force-confold" 2>&1 | show_progress
ok "System packages updated."
step "Installing security tools (firewall, fail2ban, auto-updates)..."
info "These protect your server from common attacks. Usually under a minute."
DEBIAN_FRONTEND=noninteractive $SUDO apt-get install -y ufw fail2ban unattended-upgrades 2>&1 | show_progress
# Configure firewall — allow SSH first to avoid lockout
if ! $SUDO ufw status | grep -q "Status: active"; then
step "Configuring firewall..."
$SUDO ufw allow OpenSSH > /dev/null 2>&1
$SUDO ufw allow 80/tcp > /dev/null 2>&1
$SUDO ufw allow 443/tcp > /dev/null 2>&1
$SUDO ufw --force enable > /dev/null 2>&1
ok "Firewall enabled: SSH, HTTP, and HTTPS allowed. All other ports blocked."
else
# Firewall already active — just make sure our ports are open
$SUDO ufw allow OpenSSH 2>/dev/null || true
$SUDO ufw allow 80/tcp 2>/dev/null || true
$SUDO ufw allow 443/tcp 2>/dev/null || true
ok "Firewall already active. Verified SSH, HTTP, and HTTPS are allowed."
fi
# Enable fail2ban
$SUDO systemctl enable fail2ban --quiet 2>/dev/null || true
$SUDO systemctl start fail2ban 2>/dev/null || true
ok "Fail2ban enabled: brute-force SSH protection active."
# Enable automatic security updates (non-interactive)
echo 'Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";' | $SUDO tee /etc/apt/apt.conf.d/50unattended-upgrades-websitebox > /dev/null
echo 'APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";' | $SUDO tee /etc/apt/apt.conf.d/20auto-upgrades > /dev/null
ok "Automatic security updates enabled."
# Configure Docker log rotation (create config before Docker install)
$SUDO mkdir -p /etc/docker
if [ ! -f /etc/docker/daemon.json ]; then
echo '{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}' | $SUDO tee /etc/docker/daemon.json > /dev/null
ok "Docker log rotation configured (10MB max per log, 3 files per container)."
else
ok "Docker daemon.json already exists. Skipping log rotation config."
fi
printf "\n${GREEN} Server secured:${RESET}\n"
printf " ${BOLD}Firewall:${RESET} active (SSH, HTTP, HTTPS only)\n"
printf " ${BOLD}Fail2ban:${RESET} active (SSH brute-force protection)\n"
printf " ${BOLD}Auto-updates:${RESET} enabled (daily security patches)\n"
printf " ${BOLD}Docker log limits:${RESET} configured (30MB max per container)\n\n"
# --- Install Docker if needed ---
DOCKER_JUST_INSTALLED=false
if command -v docker &>/dev/null; then
ok "Docker is already installed."
# Restart to pick up daemon.json if it was just created
if [ -f /etc/docker/daemon.json ]; then
$SUDO systemctl restart docker 2>/dev/null || true
fi
else
section "Installing Docker"
step "Installing Docker..."
info "Docker packages and runs your website in isolated containers."
info "This is the largest download — usually takes 1-3 minutes."
# Install prerequisites
$SUDO apt-get update -qq
DEBIAN_FRONTEND=noninteractive $SUDO apt-get install -y ca-certificates curl gnupg lsb-release 2>&1 | show_progress
# Add Docker's GPG key
$SUDO install -m 0755 -d /etc/apt/keyrings
curl -fsSL "https://download.docker.com/linux/${OS_ID}/gpg" | $SUDO gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$SUDO chmod a+r /etc/apt/keyrings/docker.gpg
# Add Docker repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${OS_ID} \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
$SUDO tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
$SUDO apt-get update -qq
DEBIAN_FRONTEND=noninteractive $SUDO apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin 2>&1 | show_progress
# Add user to docker group
if [ "$ACTUAL_USER" != "root" ]; then
$SUDO usermod -aG docker "$ACTUAL_USER"
DOCKER_JUST_INSTALLED=true
ok "Docker installed. User '${ACTUAL_USER}' added to docker group."
fi
# Start and enable Docker
$SUDO systemctl start docker
$SUDO systemctl enable docker
ok "Docker installation complete."
fi
# --- Clone Repository ---
INSTALL_DIR="${HOME}/websitebox"
if [ -d "$INSTALL_DIR" ]; then
ok "WebsiteBox directory already exists at ${INSTALL_DIR}"
info "Pulling latest changes..."
cd "$INSTALL_DIR"
git pull || true
else
step "Cloning WebsiteBox..."
info "Downloading the project files. Just a few seconds."
git clone https://git.constantprojects.xyz/tankadmin/websitebox.git "$INSTALL_DIR"
cd "$INSTALL_DIR"
fi
# Make scripts executable
chmod +x setup.sh install.sh scripts/*.sh
# --- Run Setup Wizard ---
echo ""
if [ "$DOCKER_JUST_INSTALLED" = true ] && [ "$ACTUAL_USER" != "root" ]; then
# Activate docker group for this session without requiring logout/login
info "Activating Docker permissions for current session..."
sg docker -c "./setup.sh"
else
./setup.sh
fi
echo ""
warn "If 'docker compose' commands fail later, log out and back in"
warn "to permanently activate Docker permissions, then try again."
echo ""