- Removed ansible, compose, docs, scripts, tasks, templates - Simplified bootstrap.sh for all major distros - Works on Ubuntu, Debian, Fedora, Rocky, Arch, openSUSE - Installs Docker, Tailscale, essential tools - Configures firewall automatically Co-authored-by: openhands <openhands@all-hands.dev>
325 lines
10 KiB
Bash
Executable File
325 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
# =============================================================================
|
|
# Server Bootstrap Script
|
|
# =============================================================================
|
|
# Prepares a fresh server with Docker, Tailscale, and essential tools.
|
|
# Zero intervention required - just run and go.
|
|
#
|
|
# Supported: Ubuntu, Debian, Fedora, Rocky/Alma/RHEL, Arch, openSUSE
|
|
#
|
|
# Usage:
|
|
# curl -fsSL <url>/bootstrap.sh | sudo bash
|
|
#
|
|
# Options:
|
|
# --no-tailscale Skip Tailscale installation
|
|
# --no-firewall Skip firewall configuration
|
|
# =============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
log() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
error() { echo -e "${RED}[ERROR]${NC} $1" >&2; exit 1; }
|
|
|
|
# Configuration
|
|
SKIP_TAILSCALE=false
|
|
SKIP_FIREWALL=false
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--no-tailscale) SKIP_TAILSCALE=true; shift ;;
|
|
--no-firewall) SKIP_FIREWALL=true; shift ;;
|
|
--help|-h)
|
|
echo "Usage: bootstrap.sh [--no-tailscale] [--no-firewall]"
|
|
exit 0
|
|
;;
|
|
*) shift ;;
|
|
esac
|
|
done
|
|
|
|
# Check root
|
|
[[ $EUID -ne 0 ]] && error "Run as root: sudo bash bootstrap.sh"
|
|
|
|
# Detect OS
|
|
detect_os() {
|
|
if [[ -f /etc/os-release ]]; then
|
|
. /etc/os-release
|
|
OS=$ID
|
|
OS_VERSION=${VERSION_ID:-}
|
|
OS_NAME=$NAME
|
|
else
|
|
error "Cannot detect OS"
|
|
fi
|
|
log "Detected: $OS_NAME $OS_VERSION"
|
|
}
|
|
|
|
# Install essential packages
|
|
install_essentials() {
|
|
log "Installing essential packages..."
|
|
|
|
case $OS in
|
|
ubuntu|debian|linuxmint|pop)
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update -qq
|
|
apt-get install -y -qq \
|
|
curl wget git unzip htop nano vim \
|
|
ca-certificates gnupg lsb-release \
|
|
jq tree ncdu lsof net-tools
|
|
;;
|
|
fedora)
|
|
dnf install -y -q \
|
|
curl wget git unzip htop nano vim \
|
|
ca-certificates gnupg \
|
|
jq tree ncdu lsof net-tools
|
|
;;
|
|
rocky|almalinux|rhel|centos)
|
|
dnf install -y -q epel-release 2>/dev/null || true
|
|
dnf install -y -q \
|
|
curl wget git unzip htop nano vim \
|
|
ca-certificates gnupg \
|
|
jq tree ncdu lsof net-tools
|
|
;;
|
|
arch|manjaro|endeavouros)
|
|
pacman -Sy --noconfirm \
|
|
curl wget git unzip htop nano vim \
|
|
ca-certificates gnupg \
|
|
jq tree ncdu lsof net-tools
|
|
;;
|
|
opensuse*|sles)
|
|
zypper install -y \
|
|
curl wget git unzip htop nano vim \
|
|
ca-certificates \
|
|
jq tree ncdu lsof net-tools
|
|
;;
|
|
*)
|
|
warn "Unknown OS: $OS - skipping package installation"
|
|
;;
|
|
esac
|
|
success "Essential packages installed"
|
|
}
|
|
|
|
# Install Docker
|
|
install_docker() {
|
|
if command -v docker &>/dev/null; then
|
|
success "Docker already installed"
|
|
return
|
|
fi
|
|
|
|
log "Installing Docker..."
|
|
|
|
case $OS in
|
|
ubuntu|debian|linuxmint|pop)
|
|
# Remove old versions
|
|
apt-get remove -y -qq docker docker-engine docker.io containerd runc 2>/dev/null || true
|
|
|
|
install -m 0755 -d /etc/apt/keyrings
|
|
|
|
# Determine base OS for Docker repo
|
|
DOCKER_OS=$OS
|
|
if [[ "$OS" == "linuxmint" || "$OS" == "pop" ]]; then
|
|
DOCKER_OS="ubuntu"
|
|
fi
|
|
|
|
curl -fsSL https://download.docker.com/linux/$DOCKER_OS/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg 2>/dev/null
|
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
|
|
|
# Get codename
|
|
if [[ -n "${VERSION_CODENAME:-}" ]]; then
|
|
CODENAME=$VERSION_CODENAME
|
|
else
|
|
CODENAME=$(lsb_release -cs 2>/dev/null || echo "jammy")
|
|
fi
|
|
|
|
# Map derivative codenames to Ubuntu
|
|
case $OS in
|
|
linuxmint|pop)
|
|
case $OS_VERSION in
|
|
20*|21.0|21.1) CODENAME="focal" ;;
|
|
21.2|21.3|22*) CODENAME="jammy" ;;
|
|
*) CODENAME="jammy" ;;
|
|
esac
|
|
;;
|
|
esac
|
|
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$DOCKER_OS $CODENAME stable" > /etc/apt/sources.list.d/docker.list
|
|
|
|
apt-get update -qq
|
|
apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
;;
|
|
|
|
fedora)
|
|
dnf remove -y -q docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 2>/dev/null || true
|
|
dnf install -y -q dnf-plugins-core
|
|
dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
|
|
dnf install -y -q docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
;;
|
|
|
|
rocky|almalinux|rhel|centos)
|
|
dnf remove -y -q docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine 2>/dev/null || true
|
|
dnf install -y -q dnf-plugins-core
|
|
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
|
dnf install -y -q docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
;;
|
|
|
|
arch|manjaro|endeavouros)
|
|
pacman -Sy --noconfirm docker docker-compose
|
|
;;
|
|
|
|
opensuse*|sles)
|
|
zypper install -y docker docker-compose
|
|
;;
|
|
|
|
*)
|
|
error "Unsupported OS for Docker: $OS"
|
|
;;
|
|
esac
|
|
|
|
systemctl enable --now docker
|
|
success "Docker installed"
|
|
}
|
|
|
|
# Install Tailscale
|
|
install_tailscale() {
|
|
$SKIP_TAILSCALE && return
|
|
|
|
if command -v tailscale &>/dev/null; then
|
|
success "Tailscale already installed"
|
|
return
|
|
fi
|
|
|
|
log "Installing Tailscale..."
|
|
curl -fsSL https://tailscale.com/install.sh | sh
|
|
success "Tailscale installed - run 'sudo tailscale up' to connect"
|
|
}
|
|
|
|
# Configure firewall
|
|
configure_firewall() {
|
|
$SKIP_FIREWALL && return
|
|
|
|
log "Configuring firewall..."
|
|
|
|
case $OS in
|
|
ubuntu|debian|linuxmint|pop)
|
|
if ! command -v ufw &>/dev/null; then
|
|
apt-get install -y -qq ufw
|
|
fi
|
|
|
|
ufw --force reset >/dev/null 2>&1
|
|
ufw default deny incoming >/dev/null
|
|
ufw default allow outgoing >/dev/null
|
|
ufw allow ssh >/dev/null
|
|
ufw allow 32400/tcp >/dev/null # Plex
|
|
ufw allow 8096/tcp >/dev/null # Jellyfin
|
|
ufw --force enable >/dev/null
|
|
success "UFW firewall configured"
|
|
;;
|
|
|
|
fedora|rocky|almalinux|rhel|centos)
|
|
if command -v firewall-cmd &>/dev/null; then
|
|
firewall-cmd --permanent --add-service=ssh >/dev/null 2>&1
|
|
firewall-cmd --permanent --add-port=32400/tcp >/dev/null 2>&1 # Plex
|
|
firewall-cmd --permanent --add-port=8096/tcp >/dev/null 2>&1 # Jellyfin
|
|
firewall-cmd --reload >/dev/null 2>&1
|
|
success "firewalld configured"
|
|
fi
|
|
;;
|
|
|
|
*)
|
|
warn "Firewall configuration skipped for $OS"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Create helpful aliases
|
|
create_aliases() {
|
|
log "Creating helpful aliases..."
|
|
|
|
cat > /etc/profile.d/server-aliases.sh << 'EOF'
|
|
# Server management aliases
|
|
alias dps='docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"'
|
|
alias dlogs='docker compose logs -f'
|
|
alias dstop='docker compose stop'
|
|
alias dstart='docker compose up -d'
|
|
alias drestart='docker compose restart'
|
|
alias dupdate='docker compose pull && docker compose up -d'
|
|
|
|
# System info
|
|
alias sysinfo='echo "=== System ===" && uname -a && echo && free -h && echo && df -h /'
|
|
alias myip='curl -s ifconfig.me'
|
|
alias ports='ss -tulpn | grep LISTEN'
|
|
EOF
|
|
|
|
chmod +x /etc/profile.d/server-aliases.sh
|
|
success "Aliases created (reload shell to use)"
|
|
}
|
|
|
|
# Show completion message
|
|
show_complete() {
|
|
local IP=$(curl -s --max-time 5 ifconfig.me 2>/dev/null || hostname -I | awk '{print $1}')
|
|
|
|
echo ""
|
|
echo "========================================"
|
|
echo " Server Bootstrap Complete!"
|
|
echo "========================================"
|
|
echo ""
|
|
echo "Installed:"
|
|
echo " ✅ Docker & Docker Compose"
|
|
if ! $SKIP_TAILSCALE; then
|
|
echo " ✅ Tailscale (run 'sudo tailscale up' to connect)"
|
|
fi
|
|
if ! $SKIP_FIREWALL; then
|
|
echo " ✅ Firewall (SSH, Plex, Jellyfin allowed)"
|
|
fi
|
|
echo " ✅ Essential tools (htop, git, curl, etc.)"
|
|
echo ""
|
|
echo "Server IP: $IP"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " 1. Connect Tailscale: sudo tailscale up"
|
|
echo " 2. Install arr-suite:"
|
|
echo ""
|
|
echo " # Plex version:"
|
|
echo " curl -fsSL -H \"Authorization: token YOUR_TOKEN\" \\"
|
|
echo " \"https://git.vish.gg/Vish/arr-suite/raw/branch/main/install.sh\" | sudo bash"
|
|
echo ""
|
|
echo " # Jellyfin version:"
|
|
echo " curl -fsSL -H \"Authorization: token YOUR_TOKEN\" \\"
|
|
echo " \"https://git.vish.gg/Vish/arr-suite-jellyfin/raw/branch/main/install.sh\" | sudo bash"
|
|
echo ""
|
|
echo "Helpful commands:"
|
|
echo " dps - Show running containers"
|
|
echo " dlogs - View container logs"
|
|
echo " dupdate - Update all containers"
|
|
echo " sysinfo - System information"
|
|
echo " myip - Show public IP"
|
|
echo ""
|
|
}
|
|
|
|
# Main
|
|
main() {
|
|
echo ""
|
|
echo "========================================"
|
|
echo " Server Bootstrap"
|
|
echo "========================================"
|
|
echo ""
|
|
|
|
detect_os
|
|
install_essentials
|
|
install_docker
|
|
install_tailscale
|
|
configure_firewall
|
|
create_aliases
|
|
show_complete
|
|
}
|
|
|
|
main
|