Adds --force-confold to prevent interactive dpkg prompts (e.g. sshd_config) that would block unattended installation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
228 lines
7.8 KiB
Bash
Executable File
228 lines
7.8 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
|
|
|
|
echo ""
|
|
echo "═══════════════════════════════════════════════════════════"
|
|
echo " WebsiteBox Installer"
|
|
echo "═══════════════════════════════════════════════════════════"
|
|
echo ""
|
|
|
|
# --- Check for root/sudo ---
|
|
|
|
if [ "$(id -u)" -eq 0 ]; then
|
|
SUDO=""
|
|
ACTUAL_USER="${SUDO_USER:-root}"
|
|
else
|
|
if ! command -v sudo &>/dev/null; then
|
|
echo "ERROR: 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
|
|
echo "ERROR: Cannot detect OS. /etc/os-release not found."
|
|
echo "WebsiteBox supports Ubuntu 20.04+ and Debian 11+."
|
|
exit 1
|
|
fi
|
|
|
|
case "$OS_ID" in
|
|
ubuntu)
|
|
if [ "${OS_VERSION%%.*}" -lt 20 ]; then
|
|
echo "ERROR: Ubuntu 20.04 or later is required (detected: ${OS_VERSION})."
|
|
exit 1
|
|
fi
|
|
;;
|
|
debian)
|
|
if [ "${OS_VERSION%%.*}" -lt 11 ]; then
|
|
echo "ERROR: Debian 11 or later is required (detected: ${OS_VERSION})."
|
|
exit 1
|
|
fi
|
|
;;
|
|
*)
|
|
echo "WARNING: Unsupported OS detected (${OS_ID} ${OS_VERSION})."
|
|
echo "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
|
|
|
|
echo "Detected: ${OS_ID} ${OS_VERSION}"
|
|
|
|
# --- Secure the Server ---
|
|
|
|
echo ""
|
|
echo "───────────────────────────────────────────────────────────"
|
|
echo " Securing your server..."
|
|
echo "───────────────────────────────────────────────────────────"
|
|
|
|
# Update system packages
|
|
echo "Updating system packages..."
|
|
echo " Downloading the latest security patches for your operating system."
|
|
echo " On a fresh server this can take 2-10 minutes. Sit tight."
|
|
$SUDO apt-get update -qq
|
|
$SUDO apt-get upgrade -y -qq -o Dpkg::Options::="--force-confold"
|
|
echo "System packages updated."
|
|
|
|
# Install firewall, fail2ban, and automatic updates
|
|
echo "Installing security tools (firewall, fail2ban, auto-updates)..."
|
|
echo " These protect your server from common attacks. Usually under a minute."
|
|
$SUDO apt-get install -y -qq ufw fail2ban unattended-upgrades
|
|
|
|
# Configure firewall — allow SSH first to avoid lockout
|
|
if ! $SUDO ufw status | grep -q "Status: active"; then
|
|
echo "Configuring firewall..."
|
|
$SUDO ufw allow OpenSSH
|
|
$SUDO ufw allow 80/tcp
|
|
$SUDO ufw allow 443/tcp
|
|
$SUDO ufw --force enable
|
|
echo "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
|
|
echo "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
|
|
echo "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
|
|
echo "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
|
|
echo "Docker log rotation configured (10MB max per log, 3 files per container)."
|
|
else
|
|
echo "Docker daemon.json already exists. Skipping log rotation config."
|
|
fi
|
|
|
|
echo ""
|
|
echo " Server secured:"
|
|
echo " Firewall: active (SSH, HTTP, HTTPS only)"
|
|
echo " Fail2ban: active (SSH brute-force protection)"
|
|
echo " Auto-updates: enabled (daily security patches)"
|
|
echo " Docker log limits: configured (30MB max per container)"
|
|
echo ""
|
|
|
|
# --- Install Docker if needed ---
|
|
|
|
DOCKER_JUST_INSTALLED=false
|
|
|
|
if command -v docker &>/dev/null; then
|
|
echo "Docker is already installed."
|
|
else
|
|
echo "Installing Docker..."
|
|
echo " Docker packages and runs your website in isolated containers."
|
|
echo " This is the largest download — usually takes 1-3 minutes."
|
|
|
|
# Install prerequisites
|
|
$SUDO apt-get update -qq
|
|
$SUDO apt-get install -y -qq ca-certificates curl gnupg lsb-release
|
|
|
|
# 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
|
|
$SUDO apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
|
|
|
# Add user to docker group
|
|
if [ "$ACTUAL_USER" != "root" ]; then
|
|
$SUDO usermod -aG docker "$ACTUAL_USER"
|
|
DOCKER_JUST_INSTALLED=true
|
|
echo "Docker installed. User '${ACTUAL_USER}' added to docker group."
|
|
fi
|
|
|
|
# Start and enable Docker
|
|
$SUDO systemctl start docker
|
|
$SUDO systemctl enable docker
|
|
|
|
echo "Docker installation complete."
|
|
else
|
|
# Docker exists — 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
|
|
fi
|
|
|
|
# --- Clone Repository ---
|
|
|
|
INSTALL_DIR="${HOME}/websitebox"
|
|
|
|
if [ -d "$INSTALL_DIR" ]; then
|
|
echo "WebsiteBox directory already exists at ${INSTALL_DIR}"
|
|
echo "Pulling latest changes..."
|
|
cd "$INSTALL_DIR"
|
|
git pull || true
|
|
else
|
|
echo "Cloning WebsiteBox..."
|
|
echo " Downloading the project files from GitHub. Just a few seconds."
|
|
git clone https://github.com/websitebox/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
|
|
echo "Activating Docker permissions for current session..."
|
|
sg docker -c "./setup.sh"
|
|
else
|
|
./setup.sh
|
|
fi
|
|
|
|
echo ""
|
|
echo "If 'docker compose' commands fail later, log out and back in"
|
|
echo "to permanently activate Docker permissions, then try again."
|
|
echo ""
|