mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-04-21 13:37:48 +00:00
2529 lines
97 KiB
Bash
2529 lines
97 KiB
Bash
#!/bin/bash
|
|
|
|
# BunkerWeb Easy Install Script
|
|
# Automatically installs BunkerWeb on supported Linux distributions
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Default values
|
|
# Hardcoded default version (immutable reference)
|
|
DEFAULT_BUNKERWEB_VERSION="1.6.9"
|
|
# Mutable effective version (can be overridden by --version)
|
|
BUNKERWEB_VERSION="$DEFAULT_BUNKERWEB_VERSION"
|
|
NGINX_VERSION=""
|
|
ENABLE_WIZARD=""
|
|
FORCE_INSTALL="no"
|
|
INTERACTIVE_MODE="yes"
|
|
CROWDSEC_INSTALL="no"
|
|
CROWDSEC_APPSEC_INSTALL="no"
|
|
CROWDSEC_API_KEY=""
|
|
REDIS_INSTALL="no"
|
|
REDIS_HOST_INPUT=""
|
|
REDIS_PORT_INPUT=""
|
|
REDIS_DATABASE_INPUT=""
|
|
REDIS_USERNAME_INPUT=""
|
|
REDIS_PASSWORD_INPUT=""
|
|
REDIS_SSL_INPUT=""
|
|
REDIS_SSL_VERIFY_INPUT=""
|
|
INSTALL_TYPE=""
|
|
BUNKERWEB_INSTANCES_INPUT=""
|
|
MANAGER_IP_INPUT=""
|
|
DNS_RESOLVERS_INPUT=""
|
|
API_LISTEN_HTTPS_INPUT=""
|
|
UPGRADE_SCENARIO="no"
|
|
BACKUP_DIRECTORY=""
|
|
AUTO_BACKUP="yes"
|
|
SYSTEM_ARCH=""
|
|
INSTALL_EPEL="auto"
|
|
|
|
# Function to print colored output
|
|
print_status() {
|
|
echo -e "${GREEN}[INFO]${NC} $1"
|
|
}
|
|
|
|
print_warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
}
|
|
|
|
print_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
print_step() {
|
|
echo -e "${BLUE}[STEP]${NC} $1"
|
|
}
|
|
|
|
# Function to run command with error checking
|
|
run_cmd() {
|
|
echo -e "${BLUE}[CMD]${NC} $*"
|
|
if ! "$@"; then
|
|
print_error "Command failed: $*"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
set_config_kv() {
|
|
local config_file="$1"
|
|
local key="$2"
|
|
local value="$3"
|
|
|
|
if grep -q "^${key}=" "$config_file"; then
|
|
sed -i "s|^${key}=.*|${key}=${value}|" "$config_file"
|
|
else
|
|
echo "${key}=${value}" >> "$config_file"
|
|
fi
|
|
}
|
|
|
|
ensure_config_file() {
|
|
local config_file="$1"
|
|
|
|
if [ ! -d /etc/bunkerweb ]; then
|
|
mkdir -p /etc/bunkerweb
|
|
fi
|
|
|
|
if [ ! -f "$config_file" ]; then
|
|
touch "$config_file"
|
|
fi
|
|
|
|
chown root:nginx "$config_file" 2>/dev/null || true
|
|
chmod 660 "$config_file" 2>/dev/null || true
|
|
}
|
|
|
|
# Function to check if running as root
|
|
check_root() {
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
print_error "This script must be run as root. Please use sudo or run as root."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Function to detect operating system
|
|
detect_os() {
|
|
DISTRO_ID=""
|
|
DISTRO_VERSION=""
|
|
DISTRO_CODENAME=""
|
|
|
|
# Check for FreeBSD first
|
|
if [ "$(uname)" = "FreeBSD" ]; then
|
|
DISTRO_ID="freebsd"
|
|
DISTRO_VERSION=$(freebsd-version -u 2>/dev/null | cut -d'-' -f1 || uname -r | cut -d'-' -f1)
|
|
DISTRO_CODENAME=""
|
|
print_status "Detected OS: FreeBSD $DISTRO_VERSION"
|
|
return
|
|
fi
|
|
|
|
if [ -f /etc/os-release ]; then
|
|
# shellcheck disable=SC1091
|
|
. /etc/os-release
|
|
DISTRO_ID=$(echo "$ID" | tr '[:upper:]' '[:lower:]')
|
|
DISTRO_VERSION="$VERSION_ID"
|
|
DISTRO_CODENAME="$VERSION_CODENAME"
|
|
elif [ -f /etc/redhat-release ]; then
|
|
DISTRO_ID="redhat"
|
|
DISTRO_VERSION=$(grep -oE '[0-9]+\.[0-9]+' /etc/redhat-release | head -1)
|
|
elif command -v lsb_release >/dev/null 2>&1; then
|
|
DISTRO_ID=$(lsb_release -is 2>/dev/null | tr '[:upper:]' '[:lower:]')
|
|
DISTRO_VERSION=$(lsb_release -rs 2>/dev/null)
|
|
DISTRO_CODENAME=$(lsb_release -cs 2>/dev/null)
|
|
else
|
|
print_error "Unable to detect operating system"
|
|
exit 1
|
|
fi
|
|
|
|
print_status "Detected OS: $DISTRO_ID $DISTRO_VERSION"
|
|
}
|
|
|
|
# Function to detect system architecture and warn for unsupported combinations
|
|
detect_architecture() {
|
|
SYSTEM_ARCH=$(uname -m 2>/dev/null || echo "unknown")
|
|
NORMALIZED_ARCH="$SYSTEM_ARCH"
|
|
case "$SYSTEM_ARCH" in
|
|
x86_64|amd64)
|
|
NORMALIZED_ARCH="amd64"
|
|
;;
|
|
aarch64|arm64)
|
|
NORMALIZED_ARCH="arm64"
|
|
;;
|
|
armv7l|armhf)
|
|
NORMALIZED_ARCH="armhf"
|
|
;;
|
|
unknown)
|
|
print_warning "Unable to detect system architecture."
|
|
;;
|
|
*)
|
|
print_warning "Architecture $SYSTEM_ARCH has not been validated with the easy install script."
|
|
if [ "$FORCE_INSTALL" != "yes" ] && [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
read -p "Continue anyway? (y/N): " -r
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
;;
|
|
esac
|
|
export NORMALIZED_ARCH
|
|
}
|
|
|
|
# Function to ask user preferences
|
|
ask_user_preferences() {
|
|
if [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
echo
|
|
print_step "Configuration Options"
|
|
echo
|
|
|
|
# Ask about installation type
|
|
if [ -z "$INSTALL_TYPE" ]; then
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}📦 Installation Type${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "Choose the type of installation based on your needs:"
|
|
echo " 1) Full Stack (default): All-in-one installation (BunkerWeb, Scheduler, UI)."
|
|
echo " 2) Manager: Installs Scheduler and UI to manage remote BunkerWeb workers."
|
|
echo " 3) Worker: Installs only the BunkerWeb instance, to be managed remotely."
|
|
echo " 4) Scheduler Only: Installs only the Scheduler component."
|
|
echo " 5) Web UI Only: Installs only the Web UI component."
|
|
echo " 6) API Only: Installs only the API service component."
|
|
echo
|
|
while true; do
|
|
echo -e "${YELLOW}Select installation type (1-6) [1]:${NC} "
|
|
read -p "" -r
|
|
REPLY=${REPLY:-1}
|
|
case $REPLY in
|
|
1) INSTALL_TYPE="full"; break ;;
|
|
2) INSTALL_TYPE="manager"; break ;;
|
|
3) INSTALL_TYPE="worker"; break ;;
|
|
4) INSTALL_TYPE="scheduler"; break ;;
|
|
5) INSTALL_TYPE="ui"; break ;;
|
|
6) INSTALL_TYPE="api"; break ;;
|
|
*) echo "Invalid option. Please choose a number between 1 and 6." ;;
|
|
esac
|
|
done
|
|
fi
|
|
|
|
if [[ "$INSTALL_TYPE" = "manager" || "$INSTALL_TYPE" = "scheduler" ]]; then
|
|
if [ -z "$BUNKERWEB_INSTANCES_INPUT" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🔗 BunkerWeb Instances Configuration${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "Please provide the list of BunkerWeb instances (workers) to manage."
|
|
echo "Format: a space-separated list of IP addresses or hostnames."
|
|
echo "Example: 192.168.1.10 192.168.1.11"
|
|
echo "Leave empty to add workers later."
|
|
echo
|
|
echo -e "${YELLOW}Enter BunkerWeb instances (or press Enter to skip):${NC} "
|
|
read -p "" -r BUNKERWEB_INSTANCES_INPUT
|
|
if [ -z "$BUNKERWEB_INSTANCES_INPUT" ]; then
|
|
print_warning "No instances configured. You can add workers later."
|
|
print_status "See: https://docs.bunkerweb.io/latest/advanced/#3-manage-workers"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ "$INSTALL_TYPE" = "manager" ] && [ -z "$MANAGER_IP_INPUT" ]; then
|
|
local detected_ip=""
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🌐 Manager API Binding${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "The manager listens on 0.0.0.0 but only whitelists explicit local IPs for API access."
|
|
echo "We'll detect the best local IPv4 to whitelist, or you can provide one manually."
|
|
echo
|
|
detected_ip=$(get_primary_ipv4)
|
|
if [ -n "$detected_ip" ]; then
|
|
while true; do
|
|
echo -e "${YELLOW}Whitelist detected IP $detected_ip for API access? (Y/n):${NC}"
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*|"")
|
|
MANAGER_IP_INPUT="$detected_ip"
|
|
break
|
|
;;
|
|
[Nn]*)
|
|
echo
|
|
echo -e "${BLUE}----------------------------------------${NC}"
|
|
echo -e "${BLUE}✍️ Manual Manager IP Entry${NC}"
|
|
echo -e "${BLUE}----------------------------------------${NC}"
|
|
echo "Enter the IPv4 address you want to whitelist for manager API access."
|
|
prompt_for_local_ipv4 MANAGER_IP_INPUT
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
else
|
|
print_warning "Unable to detect a local IPv4 automatically."
|
|
echo -e "${BLUE}----------------------------------------${NC}"
|
|
echo -e "${BLUE}✍️ Manual Manager IP Entry${NC}"
|
|
echo -e "${BLUE}----------------------------------------${NC}"
|
|
echo "Enter the IPv4 address you want to whitelist for manager API access."
|
|
prompt_for_local_ipv4 MANAGER_IP_INPUT
|
|
fi
|
|
fi
|
|
|
|
if [ "$INSTALL_TYPE" = "worker" ] && [ -z "$MANAGER_IP_INPUT" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🛡️ Manager API Access${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "Provide the IP address (or space-separated list) of the manager/scheduler that will control this worker."
|
|
echo "The worker API listens on 0.0.0.0, and these IPs will be whitelisted automatically."
|
|
echo
|
|
while true; do
|
|
echo -e "${YELLOW}Enter manager IP address(es):${NC} "
|
|
read -p "" -r MANAGER_IP_INPUT
|
|
if [ -n "$MANAGER_IP_INPUT" ]; then
|
|
break
|
|
else
|
|
print_warning "This field cannot be empty for Worker installations."
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Ask about custom DNS resolvers for full, manager, or worker installations
|
|
if [[ "$INSTALL_TYPE" = "full" || "$INSTALL_TYPE" = "manager" || "$INSTALL_TYPE" = "worker" ]] && [ -z "$DNS_RESOLVERS_INPUT" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🔍 DNS Resolvers Configuration${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "BunkerWeb needs DNS resolvers for domain resolution."
|
|
echo "Default: 9.9.9.9 149.112.112.112 8.8.8.8 8.8.4.4 (Quad9 and Google DNS)"
|
|
echo
|
|
while true; do
|
|
echo -e "${YELLOW}Use custom DNS resolvers? (y/N):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*)
|
|
echo -e "${YELLOW}Enter space-separated DNS resolver IPs:${NC} "
|
|
read -p "" -r DNS_RESOLVERS_INPUT
|
|
if [ -n "$DNS_RESOLVERS_INPUT" ]; then
|
|
break
|
|
else
|
|
print_warning "DNS resolvers cannot be empty. Please enter at least one resolver."
|
|
fi
|
|
;;
|
|
[Nn]*|"")
|
|
DNS_RESOLVERS_INPUT="9.9.9.9 149.112.112.112 8.8.8.8 8.8.4.4"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
fi
|
|
|
|
# Ask about internal API HTTPS communication for full, manager, or worker installations
|
|
if [[ "$INSTALL_TYPE" = "full" || "$INSTALL_TYPE" = "manager" || "$INSTALL_TYPE" = "worker" ]] && [ -z "$API_LISTEN_HTTPS_INPUT" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🔒 Internal API HTTPS Communication${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "The scheduler/manager can communicate with BunkerWeb/worker instances via HTTPS"
|
|
echo "for internal API communication (not the public API service)."
|
|
echo "Default: HTTP only (no HTTPS)"
|
|
echo
|
|
while true; do
|
|
echo -e "${YELLOW}Enable HTTPS for internal API communication? (y/N):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*)
|
|
API_LISTEN_HTTPS_INPUT="yes"
|
|
break
|
|
;;
|
|
[Nn]*|"")
|
|
API_LISTEN_HTTPS_INPUT="no"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
fi
|
|
|
|
# Ask about setup wizard
|
|
if [ "$INSTALL_TYPE" = "manager" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🧙 Setup Wizard Not Available${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
if [ "$ENABLE_WIZARD" = "yes" ]; then
|
|
print_warning "Setup wizard cannot be enabled for manager mode; it will be disabled."
|
|
fi
|
|
echo "Manager installations are not compatible with the setup wizard."
|
|
echo "The UI can still be started normally without the wizard."
|
|
ENABLE_WIZARD="no"
|
|
elif [ -z "$ENABLE_WIZARD" ]; then
|
|
if [ "$INSTALL_TYPE" = "worker" ] || [ "$INSTALL_TYPE" = "scheduler" ] || [ "$INSTALL_TYPE" = "api" ]; then
|
|
ENABLE_WIZARD="no"
|
|
else
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🧙 BunkerWeb Setup Wizard${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "The BunkerWeb setup wizard provides a web-based interface to:"
|
|
echo " • Complete initial configuration easily"
|
|
echo " • Set up your first protected service"
|
|
echo " • Configure SSL/TLS certificates"
|
|
echo " • Access the management interface"
|
|
echo
|
|
while true; do
|
|
echo -e "${YELLOW}Would you like to enable the setup wizard? (Y/n):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*|"")
|
|
ENABLE_WIZARD="yes"
|
|
break
|
|
;;
|
|
[Nn]*)
|
|
ENABLE_WIZARD="no"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
fi
|
|
fi
|
|
|
|
if [ "$INSTALL_TYPE" = "manager" ] && [ -z "$SERVICE_UI" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🖥 Manager Web UI${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "The setup wizard is disabled, but you can still start the Web UI service."
|
|
echo "Do you want the Web UI to run after installation?"
|
|
while true; do
|
|
echo -e "${YELLOW}Start the Web UI service? (Y/n):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Nn]*)
|
|
export SERVICE_UI="no"
|
|
break
|
|
;;
|
|
[Yy]*|"")
|
|
export SERVICE_UI="yes"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
fi
|
|
|
|
# Ask about CrowdSec installation
|
|
if [[ "$INSTALL_TYPE" != "worker" && "$INSTALL_TYPE" != "scheduler" && "$INSTALL_TYPE" != "ui" && "$INSTALL_TYPE" != "manager" && "$INSTALL_TYPE" != "api" ]]; then
|
|
if [ -z "$CROWDSEC_INSTALL" ] || [ "$CROWDSEC_INSTALL" = "no" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🦙 CrowdSec Intrusion Prevention${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "CrowdSec is a community-powered, open-source intrusion prevention engine that analyzes logs in real time to detect, block and share intelligence on malicious IPs."
|
|
echo "It seamlessly integrates with BunkerWeb for automated threat remediation."
|
|
echo
|
|
while true; do
|
|
echo -e "${YELLOW}Would you like to automatically install and configure CrowdSec? (Y/n):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*|"")
|
|
CROWDSEC_INSTALL="yes"
|
|
break
|
|
;;
|
|
[Nn]*)
|
|
CROWDSEC_INSTALL="no"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
fi
|
|
else
|
|
# CrowdSec not applicable for manager, worker, scheduler-only, ui-only, or api-only installations
|
|
CROWDSEC_INSTALL="no"
|
|
fi
|
|
|
|
# Ask about API service enablement (not applicable for worker, scheduler-only, ui-only, or api-only)
|
|
if [[ "$INSTALL_TYPE" != "worker" && "$INSTALL_TYPE" != "scheduler" && "$INSTALL_TYPE" != "ui" && "$INSTALL_TYPE" != "api" ]] && [ -z "$SERVICE_API" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🧩 BunkerWeb API Service${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "The BunkerWeb API provides a programmatic interface (FastAPI) to manage instances,"
|
|
echo "perform actions (reload/stop), and integrate with external systems."
|
|
echo "It is optional and disabled by default on Linux installations."
|
|
echo
|
|
while true; do
|
|
echo -e "${YELLOW}Enable the API service? (y/N):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*) SERVICE_API=yes; break ;;
|
|
""|[Nn]*) SERVICE_API=no; break ;;
|
|
*) echo "Please answer yes (y) or no (n)." ;;
|
|
esac
|
|
done
|
|
elif [[ "$INSTALL_TYPE" = "worker" || "$INSTALL_TYPE" = "scheduler" || "$INSTALL_TYPE" = "ui" || "$INSTALL_TYPE" = "api" ]]; then
|
|
# API service not applicable for these installation types
|
|
SERVICE_API=no
|
|
fi
|
|
|
|
# Ask about AppSec installation if CrowdSec is chosen
|
|
if [ "$CROWDSEC_INSTALL" = "yes" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🛡️ CrowdSec Application Security (AppSec)${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "CrowdSec Application Security Component (AppSec) adds advanced application security, turning CrowdSec into a full WAF."
|
|
echo "It's optional, installs alongside CrowdSec, and integrates seamlessly with the engine."
|
|
echo
|
|
while true; do
|
|
echo -e "${YELLOW}Would you like to install and configure the CrowdSec AppSec Component? (Y/n):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*|"")
|
|
CROWDSEC_APPSEC_INSTALL="yes"
|
|
break
|
|
;;
|
|
[Nn]*)
|
|
CROWDSEC_APPSEC_INSTALL="no"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
fi
|
|
|
|
# Ask about Redis configuration
|
|
if [[ "$INSTALL_TYPE" = "full" || "$INSTALL_TYPE" = "manager" || -z "$INSTALL_TYPE" ]]; then
|
|
if [ -z "$REDIS_INSTALL" ] || [ "$REDIS_INSTALL" = "no" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}🧠 Redis Cache (Sessions/Cluster Storage)${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "Redis/Valkey enables shared caching and fast data retrieval across BunkerWeb nodes."
|
|
echo "It stores session data, metrics, and security data centrally so clustering and load balancing work seamlessly."
|
|
echo "For HA, you can also use Redis Sentinel for automatic failover."
|
|
echo "You can install Redis locally or point to an existing Redis server."
|
|
echo
|
|
while true; do
|
|
echo -e "${YELLOW}Enable Redis integration? (y/N):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*)
|
|
REDIS_INSTALL="yes"
|
|
break
|
|
;;
|
|
[Nn]*|"")
|
|
REDIS_INSTALL="no"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
fi
|
|
|
|
if [ "$REDIS_INSTALL" = "yes" ]; then
|
|
echo
|
|
echo -e "${BLUE}----------------------------------------${NC}"
|
|
echo -e "${BLUE}🗄️ Redis Instance${NC}"
|
|
echo -e "${BLUE}----------------------------------------${NC}"
|
|
while true; do
|
|
echo -e "${YELLOW}Install Redis locally on this host? (Y/n):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Nn]*)
|
|
REDIS_INSTALL="no"
|
|
break
|
|
;;
|
|
[Yy]*|"")
|
|
REDIS_INSTALL="yes"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [ "$REDIS_INSTALL" = "no" ]; then
|
|
echo
|
|
echo -e "${BLUE}----------------------------------------${NC}"
|
|
echo -e "${BLUE}✍️ Existing Redis Configuration${NC}"
|
|
echo -e "${BLUE}----------------------------------------${NC}"
|
|
echo "Provide connection details for your existing Redis server."
|
|
echo
|
|
echo -e "${YELLOW}Redis host [127.0.0.1]:${NC} "
|
|
read -p "" -r REDIS_HOST_INPUT
|
|
REDIS_HOST_INPUT=${REDIS_HOST_INPUT:-127.0.0.1}
|
|
echo -e "${YELLOW}Redis port [6379]:${NC} "
|
|
read -p "" -r REDIS_PORT_INPUT
|
|
REDIS_PORT_INPUT=${REDIS_PORT_INPUT:-6379}
|
|
echo -e "${YELLOW}Redis database [0]:${NC} "
|
|
read -p "" -r REDIS_DATABASE_INPUT
|
|
REDIS_DATABASE_INPUT=${REDIS_DATABASE_INPUT:-0}
|
|
echo -e "${YELLOW}Redis username (optional):${NC} "
|
|
read -p "" -r REDIS_USERNAME_INPUT
|
|
echo -e "${YELLOW}Redis password (optional):${NC} "
|
|
read -p "" -r REDIS_PASSWORD_INPUT
|
|
while true; do
|
|
echo -e "${YELLOW}Use SSL/TLS for Redis connection? (y/N):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*)
|
|
REDIS_SSL_INPUT="yes"
|
|
break
|
|
;;
|
|
[Nn]*|"")
|
|
REDIS_SSL_INPUT="no"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
if [ "$REDIS_SSL_INPUT" = "yes" ]; then
|
|
while true; do
|
|
echo -e "${YELLOW}Verify Redis SSL certificate? (Y/n):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Nn]*)
|
|
REDIS_SSL_VERIFY_INPUT="no"
|
|
break
|
|
;;
|
|
[Yy]*|"")
|
|
REDIS_SSL_VERIFY_INPUT="yes"
|
|
break
|
|
;;
|
|
*)
|
|
echo "Please answer yes (y) or no (n)."
|
|
;;
|
|
esac
|
|
done
|
|
fi
|
|
fi
|
|
fi
|
|
else
|
|
# Redis only applicable for full or manager installations
|
|
REDIS_INSTALL="no"
|
|
fi
|
|
|
|
echo
|
|
print_status "Configuration summary:"
|
|
echo " 🛡 BunkerWeb version: $BUNKERWEB_VERSION"
|
|
case "$INSTALL_TYPE" in
|
|
"full"|"") echo " 📦 Installation type: Full Stack" ;;
|
|
"manager") echo " 📦 Installation type: Manager" ;;
|
|
"worker") echo " 📦 Installation type: Worker" ;;
|
|
"scheduler") echo " 📦 Installation type: Scheduler Only" ;;
|
|
"ui") echo " 📦 Installation type: Web UI Only" ;;
|
|
"api") echo " 📦 Installation type: API Only" ;;
|
|
esac
|
|
if [ -n "$BUNKERWEB_INSTANCES_INPUT" ]; then
|
|
echo " 🔗 BunkerWeb instances: $BUNKERWEB_INSTANCES_INPUT"
|
|
fi
|
|
if [ -n "$MANAGER_IP_INPUT" ]; then
|
|
echo " 📡 Manager API whitelist: $MANAGER_IP_INPUT"
|
|
fi
|
|
if [ -n "$DNS_RESOLVERS_INPUT" ]; then
|
|
echo " 🔍 DNS resolvers: $DNS_RESOLVERS_INPUT"
|
|
fi
|
|
if [ -n "$API_LISTEN_HTTPS_INPUT" ] && [ "$API_LISTEN_HTTPS_INPUT" = "yes" ]; then
|
|
echo " 🔒 Internal API HTTPS: Enabled"
|
|
fi
|
|
if [ "$INSTALL_TYPE" = "manager" ]; then
|
|
echo " 🖥 Web UI service: $([ "${SERVICE_UI:-yes}" = "no" ] && echo "Disabled" || echo "Enabled")"
|
|
echo " 🧙 Setup wizard: Disabled (not supported in manager mode)"
|
|
else
|
|
echo " 🧙 Setup wizard: $([ "$ENABLE_WIZARD" = "yes" ] && echo "Enabled" || echo "Disabled")"
|
|
fi
|
|
if [[ "$INSTALL_TYPE" = "worker" || "$INSTALL_TYPE" = "scheduler" || "$INSTALL_TYPE" = "ui" ]]; then
|
|
echo " 🔌 API service: Not available for this mode"
|
|
elif [ "${SERVICE_API:-no}" = "yes" ]; then
|
|
echo " 🔌 API service: Enabled"
|
|
else
|
|
echo " 🔌 API service: Disabled"
|
|
fi
|
|
echo " 🖥 Operating system: $DISTRO_ID $DISTRO_VERSION"
|
|
echo " ⚙️ Architecture: ${SYSTEM_ARCH:-unknown}"
|
|
echo " 🟢 NGINX version: $NGINX_VERSION"
|
|
if [ "$INSTALL_TYPE" = "manager" ] || [ "$INSTALL_TYPE" = "worker" ] || [ "$INSTALL_TYPE" = "api" ]; then
|
|
echo " 🦙 CrowdSec: Not available for this mode"
|
|
else
|
|
if [ "$CROWDSEC_INSTALL" = "yes" ]; then
|
|
if [ "$CROWDSEC_APPSEC_INSTALL" = "yes" ]; then
|
|
echo " 🦙 CrowdSec: Will be installed (with AppSec Component)"
|
|
else
|
|
echo " 🦙 CrowdSec: Will be installed (without AppSec Component)"
|
|
fi
|
|
else
|
|
echo " 🦙 CrowdSec: Not installed"
|
|
fi
|
|
fi
|
|
if [[ "$INSTALL_TYPE" != "full" && "$INSTALL_TYPE" != "manager" && -n "$INSTALL_TYPE" ]]; then
|
|
echo " 🧠 Redis: Not available for this mode"
|
|
else
|
|
if [ "$REDIS_INSTALL" = "yes" ]; then
|
|
echo " 🧠 Redis: Will be installed and configured locally"
|
|
elif [ -n "$REDIS_HOST_INPUT" ]; then
|
|
echo " 🧠 Redis: Will use existing server at $REDIS_HOST_INPUT:${REDIS_PORT_INPUT:-6379}"
|
|
else
|
|
echo " 🧠 Redis: Not installed"
|
|
fi
|
|
fi
|
|
echo
|
|
fi
|
|
}
|
|
|
|
# Function to show RHEL database warning
|
|
show_rhel_database_warning() {
|
|
if [[ "$DISTRO_ID" =~ ^(rhel|centos|fedora|rocky|almalinux|redhat)$ ]]; then
|
|
echo
|
|
print_warning "Important information for RHEL-based systems:"
|
|
echo
|
|
echo "If you plan to use an external database (recommended for production),"
|
|
echo "you'll need to install the appropriate database client:"
|
|
echo
|
|
echo " For MariaDB: dnf install mariadb"
|
|
echo " For MySQL: dnf install mysql"
|
|
echo " For PostgreSQL: dnf install postgresql"
|
|
echo
|
|
echo "This is required for the BunkerWeb Scheduler to connect to your database."
|
|
echo
|
|
read -p "Press Enter to continue..." -r
|
|
fi
|
|
}
|
|
|
|
check_supported_os() {
|
|
case "$DISTRO_ID" in
|
|
"freebsd")
|
|
major_version=$(echo "$DISTRO_VERSION" | cut -d. -f1)
|
|
if [[ "$major_version" != "13" && "$major_version" != "14" ]]; then
|
|
print_warning "Only FreeBSD 13 and 14 are officially supported"
|
|
if [ "$FORCE_INSTALL" != "yes" ] && [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
read -p "Continue anyway? (y/N): " -r
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
NGINX_VERSION="1.28.0"
|
|
;;
|
|
"debian")
|
|
if [[ "$DISTRO_VERSION" != "12" && "$DISTRO_VERSION" != "13" ]]; then
|
|
print_warning "Only Debian 12 (Bookworm) and 13 (Trixie) are officially supported"
|
|
if [ "$FORCE_INSTALL" != "yes" ] && [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
read -p "Continue anyway? (y/N): " -r
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
NGINX_VERSION="1.28.2-1~$DISTRO_CODENAME"
|
|
;;
|
|
"ubuntu")
|
|
if [[ "$DISTRO_VERSION" != "22.04" && "$DISTRO_VERSION" != "24.04" ]]; then
|
|
print_warning "Only Ubuntu 22.04 (Jammy) and 24.04 (Noble) are officially supported"
|
|
if [ "$FORCE_INSTALL" != "yes" ] && [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
read -p "Continue anyway? (y/N): " -r
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
NGINX_VERSION="1.28.2-1~$DISTRO_CODENAME"
|
|
;;
|
|
"fedora")
|
|
if [[ "$DISTRO_VERSION" != "42" && "$DISTRO_VERSION" != "43" ]]; then
|
|
print_warning "Only Fedora 42 and 43 are officially supported"
|
|
if [ "$FORCE_INSTALL" != "yes" ] && [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
read -p "Continue anyway? (y/N): " -r
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
NGINX_VERSION="1.28.2"
|
|
;;
|
|
"rhel"|"rocky"|"almalinux")
|
|
major_version=$(echo "$DISTRO_VERSION" | cut -d. -f1)
|
|
if [[ "$major_version" != "8" && "$major_version" != "9" && "$major_version" != "10" ]]; then
|
|
print_warning "Only RHEL 8, 9, and 10 are officially supported"
|
|
if [ "$FORCE_INSTALL" != "yes" ] && [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
read -p "Continue anyway? (y/N): " -r
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
NGINX_VERSION="1.28.2"
|
|
;;
|
|
*)
|
|
print_error "Unsupported operating system: $DISTRO_ID"
|
|
print_error "Supported distributions: Debian 12/13, Ubuntu 22.04/24.04, Fedora 42/43, RHEL 8/9/10, FreeBSD 13/14"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Function to check for port conflicts
|
|
check_ports() {
|
|
if [[ "$INSTALL_TYPE" == "full" || "$INSTALL_TYPE" == "worker" || -z "$INSTALL_TYPE" ]]; then
|
|
if command -v ss >/dev/null 2>&1; then
|
|
if ss -tulpn | grep -E ":(80|443)\s" >/dev/null 2>&1; then
|
|
print_warning "Port 80 or 443 appears to be in use."
|
|
print_warning "Common conflict: Apache/httpd running."
|
|
print_warning "Please stop conflicting services before proceeding."
|
|
if [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
read -p "Continue anyway? (y/N): " -r
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Check if provided IPv4 belongs to a private (LAN) range
|
|
is_private_ipv4() {
|
|
local ip="$1"
|
|
local o1 o2 _o3 _o4
|
|
|
|
if [[ ! $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
|
|
return 1
|
|
fi
|
|
|
|
IFS='.' read -r o1 o2 _o3 _o4 <<< "$ip"
|
|
|
|
if [ "$o1" -eq 10 ]; then
|
|
return 0
|
|
elif [ "$o1" -eq 172 ] && [ "$o2" -ge 16 ] && [ "$o2" -le 31 ]; then
|
|
return 0
|
|
elif [ "$o1" -eq 192 ] && [ "$o2" -eq 168 ]; then
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# Extract the first IPv4 address from a whitespace-separated list
|
|
extract_first_ipv4() {
|
|
local input="$1"
|
|
local token
|
|
|
|
for token in $input; do
|
|
if [[ $token =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
|
|
echo "$token"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
return 1
|
|
}
|
|
|
|
# Prompt interactively for a local IPv4 address
|
|
prompt_for_local_ipv4() {
|
|
local -n __target_var="$1"
|
|
local answer=""
|
|
local ip=""
|
|
|
|
while true; do
|
|
echo -e "${YELLOW}Enter the local IPv4 address to use:${NC} "
|
|
read -p "" -r answer
|
|
ip=$(extract_first_ipv4 "$answer")
|
|
if [ -n "$ip" ]; then
|
|
__target_var="$ip"
|
|
return 0
|
|
fi
|
|
print_warning "Invalid IPv4 address. Please try again."
|
|
done
|
|
}
|
|
|
|
# Function to determine the primary IPv4 address of the current host using only
|
|
# locally available routing/interface information (no external queries)
|
|
get_primary_ipv4() {
|
|
local primary_ip=""
|
|
local route_output=""
|
|
local host_output=""
|
|
local addr_output=""
|
|
local prev=""
|
|
local token=""
|
|
local line=""
|
|
local candidate=""
|
|
|
|
if command -v ip >/dev/null 2>&1; then
|
|
route_output=$(ip -4 route show default 2>/dev/null || true)
|
|
if [ -z "$route_output" ]; then
|
|
route_output=$(ip route show default 2>/dev/null || true)
|
|
fi
|
|
if [ -n "$route_output" ]; then
|
|
for token in $route_output; do
|
|
if [ "$prev" = "src" ]; then
|
|
candidate="$token"
|
|
if is_private_ipv4 "$candidate"; then
|
|
primary_ip="$candidate"
|
|
break
|
|
fi
|
|
fi
|
|
prev="$token"
|
|
done
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$primary_ip" ] && command -v hostname >/dev/null 2>&1; then
|
|
host_output=$(hostname -I 2>/dev/null || true)
|
|
if [ -n "$host_output" ]; then
|
|
for token in $host_output; do
|
|
if [[ $token =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && is_private_ipv4 "$token"; then
|
|
primary_ip="$token"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$primary_ip" ] && command -v ip >/dev/null 2>&1; then
|
|
addr_output=$(ip -4 addr show scope global 2>/dev/null || true)
|
|
if [ -n "$addr_output" ]; then
|
|
while IFS= read -r line; do
|
|
case "$line" in
|
|
*inet\ *)
|
|
line=${line#*inet }
|
|
candidate=${line%%/*}
|
|
if [[ $candidate =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && is_private_ipv4 "$candidate"; then
|
|
primary_ip="$candidate"
|
|
break
|
|
fi
|
|
;;
|
|
esac
|
|
done <<< "$addr_output"
|
|
fi
|
|
fi
|
|
|
|
echo "$primary_ip"
|
|
}
|
|
|
|
should_apply_redis_config() {
|
|
if [ "$REDIS_INSTALL" = "yes" ] || [ -n "$REDIS_HOST_INPUT" ] || [ -n "$REDIS_PORT_INPUT" ] || [ -n "$REDIS_DATABASE_INPUT" ] || [ -n "$REDIS_USERNAME_INPUT" ] || [ -n "$REDIS_PASSWORD_INPUT" ] || [ -n "$REDIS_SSL_INPUT" ] || [ -n "$REDIS_SSL_VERIFY_INPUT" ]; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
apply_redis_config() {
|
|
local config_file="$1"
|
|
local redis_host="${REDIS_HOST_INPUT:-}"
|
|
local redis_port="${REDIS_PORT_INPUT:-6379}"
|
|
local redis_db="${REDIS_DATABASE_INPUT:-0}"
|
|
|
|
if [ -z "$redis_host" ]; then
|
|
redis_host="127.0.0.1"
|
|
fi
|
|
|
|
set_config_kv "$config_file" "USE_REDIS" "yes"
|
|
set_config_kv "$config_file" "REDIS_HOST" "$redis_host"
|
|
set_config_kv "$config_file" "REDIS_PORT" "$redis_port"
|
|
set_config_kv "$config_file" "REDIS_DATABASE" "$redis_db"
|
|
if [ -n "$REDIS_USERNAME_INPUT" ]; then
|
|
set_config_kv "$config_file" "REDIS_USERNAME" "$REDIS_USERNAME_INPUT"
|
|
fi
|
|
if [ -n "$REDIS_PASSWORD_INPUT" ]; then
|
|
set_config_kv "$config_file" "REDIS_PASSWORD" "$REDIS_PASSWORD_INPUT"
|
|
fi
|
|
if [ -n "$REDIS_SSL_INPUT" ]; then
|
|
set_config_kv "$config_file" "REDIS_SSL" "$REDIS_SSL_INPUT"
|
|
fi
|
|
if [ -n "$REDIS_SSL_VERIFY_INPUT" ]; then
|
|
set_config_kv "$config_file" "REDIS_SSL_VERIFY" "$REDIS_SSL_VERIFY_INPUT"
|
|
fi
|
|
}
|
|
|
|
should_apply_crowdsec_config() {
|
|
if [ "$CROWDSEC_INSTALL" = "yes" ]; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
apply_crowdsec_config() {
|
|
local config_file="$1"
|
|
|
|
set_config_kv "$config_file" "USE_CROWDSEC" "yes"
|
|
set_config_kv "$config_file" "CROWDSEC_API" "http://127.0.0.1:8080"
|
|
if [ -n "$CROWDSEC_API_KEY" ]; then
|
|
set_config_kv "$config_file" "CROWDSEC_API_KEY" "$CROWDSEC_API_KEY"
|
|
fi
|
|
if [ "$CROWDSEC_APPSEC_INSTALL" = "yes" ]; then
|
|
set_config_kv "$config_file" "CROWDSEC_APPSEC_URL" "http://127.0.0.1:7422"
|
|
fi
|
|
}
|
|
|
|
apply_optional_integrations() {
|
|
local config_file="$1"
|
|
local needs_reload_var="$2"
|
|
local needs_reload=false
|
|
|
|
if should_apply_redis_config; then
|
|
print_status "Applying Redis configuration"
|
|
apply_redis_config "$config_file"
|
|
needs_reload=true
|
|
fi
|
|
|
|
if should_apply_crowdsec_config; then
|
|
print_status "Applying CrowdSec configuration"
|
|
apply_crowdsec_config "$config_file"
|
|
needs_reload=true
|
|
fi
|
|
|
|
if [ -n "$needs_reload_var" ]; then
|
|
if [ "$needs_reload" = true ]; then
|
|
eval "$needs_reload_var=true"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Ensure manager installations expose the API and only whitelist the local host IP
|
|
configure_manager_api_defaults() {
|
|
local config_file="/etc/bunkerweb/variables.env"
|
|
local whitelist_ip
|
|
local provided_ip
|
|
|
|
provided_ip=$(extract_first_ipv4 "$MANAGER_IP_INPUT")
|
|
|
|
if [ -n "$provided_ip" ]; then
|
|
whitelist_ip="$provided_ip"
|
|
else
|
|
whitelist_ip=$(get_primary_ipv4)
|
|
fi
|
|
|
|
if [ -z "$whitelist_ip" ]; then
|
|
if [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
print_warning "Unable to detect a local network IP automatically."
|
|
prompt_for_local_ipv4 whitelist_ip
|
|
MANAGER_IP_INPUT="$whitelist_ip"
|
|
else
|
|
print_error "Unable to detect a local network IP. Provide it with --manager-ip <IP>."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
whitelist_ip="127.0.0.0/8 $whitelist_ip"
|
|
whitelist_ip=$(printf '%s\n' "$whitelist_ip" | xargs)
|
|
|
|
if [ -z "$provided_ip" ]; then
|
|
MANAGER_IP_INPUT="$whitelist_ip"
|
|
fi
|
|
|
|
print_status "Applying manager API defaults (listen on 0.0.0.0, whitelist local IP $whitelist_ip)"
|
|
|
|
ensure_config_file "$config_file"
|
|
|
|
{
|
|
echo "SERVER_NAME="
|
|
if [ -n "$BUNKERWEB_INSTANCES_INPUT" ]; then
|
|
echo "BUNKERWEB_INSTANCES=$BUNKERWEB_INSTANCES_INPUT"
|
|
else
|
|
echo "BUNKERWEB_INSTANCES="
|
|
fi
|
|
# Use custom DNS resolvers if provided, otherwise use defaults
|
|
if [ -n "$DNS_RESOLVERS_INPUT" ]; then
|
|
echo "DNS_RESOLVERS=$DNS_RESOLVERS_INPUT"
|
|
else
|
|
echo "DNS_RESOLVERS=9.9.9.9 149.112.112.112 8.8.8.8 8.8.4.4" # Quad9, Google
|
|
fi
|
|
echo "HTTP_PORT=80"
|
|
echo "HTTPS_PORT=443"
|
|
echo "API_LISTEN_IP=0.0.0.0"
|
|
echo "API_WHITELIST_IP=$whitelist_ip"
|
|
if [ -n "$API_LISTEN_HTTPS_INPUT" ] && [ "$API_LISTEN_HTTPS_INPUT" = "yes" ]; then
|
|
echo "API_LISTEN_HTTPS=yes"
|
|
fi
|
|
echo "API_TOKEN="
|
|
# Enable multisite mode when UI service is used
|
|
if [ "${SERVICE_UI:-yes}" != "no" ]; then
|
|
echo "MULTISITE=yes"
|
|
fi
|
|
} > "$config_file"
|
|
apply_optional_integrations "$config_file"
|
|
|
|
print_status "Enabling and starting BunkerWeb Scheduler with configured settings..."
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
sysrc bunkerweb_scheduler_enable=YES >/dev/null 2>&1
|
|
service bunkerweb_scheduler start
|
|
sleep 2
|
|
service bunkerweb_scheduler status || print_warning "BunkerWeb Scheduler may not be running"
|
|
else
|
|
run_cmd systemctl enable --now bunkerweb-scheduler
|
|
sleep 2
|
|
systemctl status bunkerweb-scheduler --no-pager -l || print_warning "BunkerWeb Scheduler may not be running"
|
|
fi
|
|
}
|
|
|
|
# Ensure worker installations whitelist the selected manager/scheduler IPs
|
|
configure_worker_api_whitelist() {
|
|
local config_file="/etc/bunkerweb/variables.env"
|
|
local whitelist_value
|
|
|
|
if [ -z "$MANAGER_IP_INPUT" ]; then
|
|
print_warning "Manager IP not provided; please whitelist it manually in $config_file."
|
|
return
|
|
fi
|
|
|
|
whitelist_value="127.0.0.0/8 $MANAGER_IP_INPUT"
|
|
whitelist_value=$(printf '%s\n' "$whitelist_value" | xargs)
|
|
|
|
print_status "Applying worker API whitelist: $whitelist_value"
|
|
|
|
ensure_config_file "$config_file"
|
|
|
|
if grep -q "^API_LISTEN_IP=" "$config_file"; then
|
|
sed -i 's|^API_LISTEN_IP=.*|API_LISTEN_IP=0.0.0.0|' "$config_file"
|
|
else
|
|
echo "API_LISTEN_IP=0.0.0.0" >> "$config_file"
|
|
fi
|
|
|
|
if grep -q "^API_WHITELIST_IP=" "$config_file"; then
|
|
sed -i "s|^API_WHITELIST_IP=.*|API_WHITELIST_IP=$whitelist_value|" "$config_file"
|
|
else
|
|
echo "API_WHITELIST_IP=$whitelist_value" >> "$config_file"
|
|
fi
|
|
|
|
# Configure custom DNS resolvers if provided
|
|
if [ -n "$DNS_RESOLVERS_INPUT" ]; then
|
|
print_status "Configuring custom DNS resolvers: $DNS_RESOLVERS_INPUT"
|
|
if grep -q "^DNS_RESOLVERS=" "$config_file"; then
|
|
sed -i "s|^DNS_RESOLVERS=.*|DNS_RESOLVERS=$DNS_RESOLVERS_INPUT|" "$config_file"
|
|
else
|
|
echo "DNS_RESOLVERS=$DNS_RESOLVERS_INPUT" >> "$config_file"
|
|
fi
|
|
fi
|
|
|
|
# Configure internal API HTTPS if enabled
|
|
if [ -n "$API_LISTEN_HTTPS_INPUT" ] && [ "$API_LISTEN_HTTPS_INPUT" = "yes" ]; then
|
|
print_status "Configuring internal API HTTPS communication"
|
|
if grep -q "^API_LISTEN_HTTPS=" "$config_file"; then
|
|
sed -i "s|^API_LISTEN_HTTPS=.*|API_LISTEN_HTTPS=yes|" "$config_file"
|
|
else
|
|
echo "API_LISTEN_HTTPS=yes" >> "$config_file"
|
|
fi
|
|
fi
|
|
|
|
print_status "Enabling and starting BunkerWeb with configured settings..."
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
sysrc bunkerweb_enable=YES >/dev/null 2>&1
|
|
service bunkerweb start
|
|
sleep 2
|
|
service bunkerweb status || print_warning "BunkerWeb may not be running"
|
|
else
|
|
run_cmd systemctl enable --now bunkerweb
|
|
sleep 2
|
|
systemctl status bunkerweb --no-pager -l || print_warning "BunkerWeb may not be running"
|
|
fi
|
|
}
|
|
|
|
# Configure full installation settings (DNS resolvers, API HTTPS, multisite)
|
|
configure_full_config() {
|
|
local config_file="/etc/bunkerweb/variables.env"
|
|
local needs_reload=false
|
|
|
|
ensure_config_file "$config_file"
|
|
|
|
# Configure custom DNS resolvers if provided
|
|
if [ -n "$DNS_RESOLVERS_INPUT" ]; then
|
|
print_status "Configuring custom DNS resolvers: $DNS_RESOLVERS_INPUT"
|
|
if grep -q "^DNS_RESOLVERS=" "$config_file"; then
|
|
sed -i "s|^DNS_RESOLVERS=.*|DNS_RESOLVERS=$DNS_RESOLVERS_INPUT|" "$config_file"
|
|
else
|
|
echo "DNS_RESOLVERS=$DNS_RESOLVERS_INPUT" >> "$config_file"
|
|
fi
|
|
needs_reload=true
|
|
fi
|
|
|
|
# Configure internal API HTTPS if enabled
|
|
if [ -n "$API_LISTEN_HTTPS_INPUT" ] && [ "$API_LISTEN_HTTPS_INPUT" = "yes" ]; then
|
|
print_status "Configuring internal API HTTPS communication"
|
|
if grep -q "^API_LISTEN_HTTPS=" "$config_file"; then
|
|
sed -i "s|^API_LISTEN_HTTPS=.*|API_LISTEN_HTTPS=yes|" "$config_file"
|
|
else
|
|
echo "API_LISTEN_HTTPS=yes" >> "$config_file"
|
|
fi
|
|
needs_reload=true
|
|
fi
|
|
|
|
# Enable multisite mode when UI service is used
|
|
if [ "$ENABLE_WIZARD" = "yes" ] || [ "${SERVICE_UI:-no}" = "yes" ]; then
|
|
if grep -q "^MULTISITE=" "$config_file"; then
|
|
sed -i "s|^MULTISITE=.*|MULTISITE=yes|" "$config_file"
|
|
else
|
|
echo "MULTISITE=yes" >> "$config_file"
|
|
fi
|
|
needs_reload=true
|
|
fi
|
|
|
|
apply_optional_integrations "$config_file" "needs_reload"
|
|
|
|
# Start bunkerweb and the scheduler if any changes were made
|
|
if [ "$needs_reload" = true ]; then
|
|
print_status "Enabling and starting services with configured settings..."
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
sysrc bunkerweb_enable=YES >/dev/null 2>&1
|
|
sysrc bunkerweb_scheduler_enable=YES >/dev/null 2>&1
|
|
service bunkerweb start || true
|
|
service bunkerweb_scheduler start || true
|
|
else
|
|
run_cmd systemctl enable --now bunkerweb
|
|
run_cmd systemctl enable --now bunkerweb-scheduler
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Function to install NGINX on Debian/Ubuntu
|
|
install_nginx_debian() {
|
|
print_step "Installing NGINX on Debian/Ubuntu"
|
|
|
|
# Install prerequisites
|
|
run_cmd apt update
|
|
run_cmd apt install -y curl gnupg2 ca-certificates lsb-release
|
|
|
|
if [ "$DISTRO_ID" = "debian" ]; then
|
|
run_cmd apt install -y debian-archive-keyring
|
|
elif [ "$DISTRO_ID" = "ubuntu" ]; then
|
|
run_cmd apt install -y ubuntu-keyring
|
|
fi
|
|
|
|
# Add NGINX repository
|
|
curl -fsSL https://nginx.org/keys/nginx_signing.key | gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
|
|
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/$DISTRO_ID $DISTRO_CODENAME nginx" | tee /etc/apt/sources.list.d/nginx.list
|
|
|
|
# Update and install NGINX
|
|
run_cmd apt update
|
|
run_cmd apt install -y "nginx=$NGINX_VERSION"
|
|
|
|
# Hold NGINX package to prevent upgrades
|
|
run_cmd apt-mark hold nginx
|
|
|
|
print_status "NGINX $NGINX_VERSION installed successfully"
|
|
}
|
|
|
|
# Function to install NGINX on Fedora
|
|
install_nginx_fedora() {
|
|
print_step "Installing NGINX on Fedora"
|
|
|
|
# Install versionlock plugin
|
|
run_cmd dnf install -y 'dnf-command(versionlock)'
|
|
|
|
# Enable testing repository if needed
|
|
if ! dnf info "nginx-$NGINX_VERSION" >/dev/null 2>&1; then
|
|
print_status "Enabling updates-testing repository"
|
|
run_cmd dnf config-manager setopt updates-testing.enabled=1
|
|
fi
|
|
|
|
# Install NGINX
|
|
run_cmd dnf install -y "nginx-$NGINX_VERSION"
|
|
|
|
# Lock NGINX version
|
|
run_cmd dnf versionlock add nginx
|
|
|
|
print_status "NGINX $NGINX_VERSION installed successfully"
|
|
}
|
|
|
|
# Function to install NGINX on RHEL
|
|
install_nginx_rhel() {
|
|
print_step "Installing NGINX on RHEL"
|
|
|
|
# Install versionlock plugin
|
|
run_cmd dnf install -y 'dnf-command(versionlock)'
|
|
|
|
# Create NGINX repository file
|
|
cat > /etc/yum.repos.d/nginx.repo << EOF
|
|
[nginx-stable]
|
|
name=nginx stable repo
|
|
baseurl=http://nginx.org/packages/centos/\$releasever/\$basearch/
|
|
gpgcheck=1
|
|
enabled=1
|
|
gpgkey=https://nginx.org/keys/nginx_signing.key
|
|
module_hotfixes=true
|
|
|
|
[nginx-mainline]
|
|
name=nginx mainline repo
|
|
baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/
|
|
gpgcheck=1
|
|
enabled=0
|
|
gpgkey=https://nginx.org/keys/nginx_signing.key
|
|
module_hotfixes=true
|
|
EOF
|
|
|
|
# Install NGINX
|
|
run_cmd dnf install -y "nginx-$NGINX_VERSION"
|
|
|
|
# Lock NGINX version
|
|
run_cmd dnf versionlock add nginx
|
|
|
|
print_status "NGINX $NGINX_VERSION installed successfully"
|
|
}
|
|
|
|
# Function to install NGINX on FreeBSD
|
|
install_nginx_freebsd() {
|
|
print_step "Installing NGINX on FreeBSD"
|
|
|
|
# Update pkg database
|
|
run_cmd pkg update -f
|
|
|
|
# Install NGINX from packages
|
|
run_cmd pkg install -y nginx
|
|
|
|
# Lock NGINX package version
|
|
run_cmd pkg lock -y nginx
|
|
|
|
print_status "NGINX installed successfully"
|
|
}
|
|
|
|
# Function to install BunkerWeb on Debian/Ubuntu
|
|
install_bunkerweb_debian() {
|
|
print_step "Installing BunkerWeb on Debian/Ubuntu"
|
|
|
|
# Handle testing/dev version
|
|
if [[ "$BUNKERWEB_VERSION" =~ (testing|dev) ]]; then
|
|
print_status "Adding force-bad-version directive for testing/dev version"
|
|
echo "force-bad-version" >> /etc/dpkg/dpkg.cfg
|
|
fi
|
|
|
|
# Set environment variables
|
|
if [ "$ENABLE_WIZARD" = "no" ]; then
|
|
export UI_WIZARD=no
|
|
fi
|
|
|
|
# Download and add BunkerWeb repository
|
|
run_cmd curl -fsSL https://repo.bunkerweb.io/install/script.deb.sh -o /tmp/bunkerweb-repo.sh
|
|
run_cmd bash /tmp/bunkerweb-repo.sh
|
|
run_cmd rm -f /tmp/bunkerweb-repo.sh
|
|
|
|
run_cmd apt update
|
|
run_cmd apt install -y --allow-downgrades "bunkerweb=$BUNKERWEB_VERSION"
|
|
|
|
# Hold BunkerWeb package to prevent upgrades
|
|
run_cmd apt-mark hold bunkerweb
|
|
|
|
print_status "BunkerWeb $BUNKERWEB_VERSION installed successfully"
|
|
}
|
|
|
|
# Function to install BunkerWeb on Fedora/RHEL
|
|
install_bunkerweb_rpm() {
|
|
print_step "Installing BunkerWeb on $DISTRO_ID"
|
|
|
|
# Offer to install EPEL on RHEL-family distros before installing BunkerWeb
|
|
if [[ "$DISTRO_ID" =~ ^(rhel|centos|fedora|rocky|almalinux|redhat)$ ]] && ! rpm -q epel-release >/dev/null 2>&1; then
|
|
if [ "$INSTALL_EPEL" = "yes" ]; then
|
|
print_step "Installing EPEL repository (epel-release)"
|
|
run_cmd dnf install -y epel-release
|
|
elif [ "$INSTALL_EPEL" = "no" ]; then
|
|
print_warning "EPEL repository not installed; continuing without epel-release."
|
|
elif [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
print_warning "EPEL repository is not installed."
|
|
read -p "Install epel-release? (y/N): " -r
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
INSTALL_EPEL="yes"
|
|
print_step "Installing EPEL repository (epel-release)"
|
|
run_cmd dnf install -y epel-release
|
|
else
|
|
INSTALL_EPEL="no"
|
|
fi
|
|
else
|
|
INSTALL_EPEL="no"
|
|
print_warning "EPEL repository not installed; skipping epel-release in non-interactive mode."
|
|
fi
|
|
fi
|
|
|
|
# Set environment variables
|
|
if [ "$ENABLE_WIZARD" = "no" ]; then
|
|
export UI_WIZARD=no
|
|
fi
|
|
|
|
# Add BunkerWeb repository and install
|
|
run_cmd curl -fsSL https://repo.bunkerweb.io/install/script.rpm.sh -o /tmp/bunkerweb-repo.sh
|
|
run_cmd bash /tmp/bunkerweb-repo.sh
|
|
run_cmd rm -f /tmp/bunkerweb-repo.sh
|
|
|
|
run_cmd dnf makecache
|
|
run_cmd dnf install -y "bunkerweb-$BUNKERWEB_VERSION"
|
|
|
|
# Lock BunkerWeb version
|
|
run_cmd dnf versionlock add bunkerweb
|
|
|
|
print_status "BunkerWeb $BUNKERWEB_VERSION installed successfully"
|
|
}
|
|
|
|
# Function to install BunkerWeb on FreeBSD
|
|
install_bunkerweb_freebsd() {
|
|
print_step "Installing BunkerWeb on FreeBSD"
|
|
|
|
# Install required dependencies
|
|
run_cmd pkg install -y bash python311 py311-pip curl libxml2 yajl gd sudo \
|
|
lsof libmaxminddb postgresql16-client mariadb1011-client sqlite3 \
|
|
openssl pcre2 lmdb ssdeep unzip gtar
|
|
|
|
# Create nginx user and group if they don't exist
|
|
if ! pw groupshow nginx >/dev/null 2>&1; then
|
|
print_status "Creating nginx group..."
|
|
pw groupadd nginx
|
|
fi
|
|
|
|
if ! pw usershow nginx >/dev/null 2>&1; then
|
|
print_status "Creating nginx user..."
|
|
pw useradd nginx -g nginx -d /nonexistent -s /usr/sbin/nologin -c "nginx user"
|
|
fi
|
|
|
|
# Set environment variables
|
|
if [ "$ENABLE_WIZARD" = "no" ]; then
|
|
export UI_WIZARD=no
|
|
fi
|
|
|
|
# Download and install BunkerWeb package from GitHub releases or custom repo
|
|
print_status "Installing BunkerWeb..."
|
|
|
|
# For FreeBSD, we provide instructions for manual installation until packages are available
|
|
print_warning "FreeBSD packages are currently built from source."
|
|
print_status "Downloading BunkerWeb source..."
|
|
|
|
BUNKERWEB_INSTALL_DIR="/usr/share/bunkerweb"
|
|
|
|
# Create required directories
|
|
mkdir -p "$BUNKERWEB_INSTALL_DIR"
|
|
mkdir -p /etc/bunkerweb/configs /etc/bunkerweb/plugins
|
|
mkdir -p /var/cache/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb
|
|
mkdir -p /var/log/bunkerweb /var/lib/bunkerweb /var/www/html
|
|
|
|
# Clone and setup BunkerWeb (or download release tarball)
|
|
if [ -n "$BUNKERWEB_TARBALL_URL" ]; then
|
|
run_cmd curl -fsSL "$BUNKERWEB_TARBALL_URL" -o /tmp/bunkerweb.tar.gz
|
|
run_cmd tar -xzf /tmp/bunkerweb.tar.gz -C "$BUNKERWEB_INSTALL_DIR" --strip-components=1
|
|
rm -f /tmp/bunkerweb.tar.gz
|
|
else
|
|
print_warning "Please download BunkerWeb from https://github.com/bunkerity/bunkerweb/releases"
|
|
print_status "Then run the FreeBSD postinstall script: /usr/share/bunkerweb/scripts/postinstall-freebsd.sh"
|
|
fi
|
|
|
|
# Install Python dependencies
|
|
if [ -d "$BUNKERWEB_INSTALL_DIR/deps" ]; then
|
|
print_status "Python dependencies already bundled"
|
|
else
|
|
print_status "Installing Python dependencies..."
|
|
mkdir -p "$BUNKERWEB_INSTALL_DIR/deps/python"
|
|
python3.11 -m pip install --target "$BUNKERWEB_INSTALL_DIR/deps/python" \
|
|
-r "$BUNKERWEB_INSTALL_DIR/requirements.txt" 2>/dev/null || true
|
|
fi
|
|
|
|
# Install rc.d scripts
|
|
print_status "Installing rc.d service scripts..."
|
|
if [ -d "$BUNKERWEB_INSTALL_DIR/rc.d" ]; then
|
|
for script in bunkerweb bunkerweb_scheduler bunkerweb_ui bunkerweb_api; do
|
|
if [ -f "$BUNKERWEB_INSTALL_DIR/rc.d/${script}" ]; then
|
|
cp "$BUNKERWEB_INSTALL_DIR/rc.d/${script}" "/usr/local/etc/rc.d/${script}"
|
|
chmod 555 "/usr/local/etc/rc.d/${script}"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Set permissions
|
|
chown -R root:nginx "$BUNKERWEB_INSTALL_DIR"
|
|
chown -R nginx:nginx /var/cache/bunkerweb /var/lib/bunkerweb /etc/bunkerweb \
|
|
/var/tmp/bunkerweb /var/run/bunkerweb /var/log/bunkerweb
|
|
chmod 755 /var/log/bunkerweb
|
|
chmod 770 /var/cache/bunkerweb /var/tmp/bunkerweb /var/run/bunkerweb
|
|
chmod 2770 /var/tmp/bunkerweb
|
|
|
|
# Install CLI
|
|
if [ -f "$BUNKERWEB_INSTALL_DIR/helpers/bwcli" ]; then
|
|
install -m 755 "$BUNKERWEB_INSTALL_DIR/helpers/bwcli" /usr/bin/bwcli
|
|
fi
|
|
|
|
# Write integration marker
|
|
echo "FreeBSD" > "$BUNKERWEB_INSTALL_DIR/INTEGRATION"
|
|
|
|
# Lock BunkerWeb package
|
|
pkg lock -y bunkerweb 2>/dev/null || true
|
|
|
|
print_status "BunkerWeb installed successfully on FreeBSD"
|
|
}
|
|
|
|
# Function to install CrowdSec
|
|
install_crowdsec() {
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}CrowdSec Security Engine Installation${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo
|
|
print_step "Installing CrowdSec security engine"
|
|
|
|
# Ensure required dependencies
|
|
for dep in curl gnupg2 ca-certificates; do
|
|
if ! command -v $dep >/dev/null 2>&1; then
|
|
print_status "Installing missing dependency: $dep"
|
|
case "$DISTRO_ID" in
|
|
"debian"|"ubuntu")
|
|
run_cmd apt update
|
|
run_cmd apt install -y "$dep"
|
|
;;
|
|
"fedora"|"rhel"|"rocky"|"almalinux")
|
|
run_cmd dnf install -y $dep
|
|
;;
|
|
"freebsd")
|
|
run_cmd pkg install -y $dep
|
|
;;
|
|
*)
|
|
print_warning "Automatic install not supported on $DISTRO_ID"
|
|
;;
|
|
esac
|
|
fi
|
|
done
|
|
|
|
echo -e "${YELLOW}--- Step 1: Add CrowdSec repository and install engine ---${NC}"
|
|
print_step "Adding CrowdSec repository and installing engine"
|
|
run_cmd curl -s https://install.crowdsec.net | sh
|
|
case "$DISTRO_ID" in
|
|
"debian"|"ubuntu")
|
|
run_cmd apt install -y crowdsec
|
|
;;
|
|
"fedora"|"rhel"|"rocky"|"almalinux")
|
|
run_cmd dnf install -y crowdsec
|
|
;;
|
|
"freebsd")
|
|
run_cmd pkg install -y crowdsec
|
|
;;
|
|
*)
|
|
print_error "Unsupported distribution: $DISTRO_ID"
|
|
return
|
|
;;
|
|
esac
|
|
print_status "CrowdSec engine installed"
|
|
|
|
echo -e "${YELLOW}--- Step 2: Configure log acquisition for BunkerWeb ---${NC}"
|
|
print_step "Configuring CrowdSec to parse BunkerWeb logs"
|
|
ACQ_FILE="/etc/crowdsec/acquis.yaml"
|
|
ACQ_CONTENT="filenames:
|
|
- /var/log/bunkerweb/access.log
|
|
- /var/log/bunkerweb/error.log
|
|
- /var/log/bunkerweb/modsec_audit.log
|
|
labels:
|
|
type: bunkerweb
|
|
"
|
|
if [ -f "$ACQ_FILE" ]; then
|
|
cp "$ACQ_FILE" "${ACQ_FILE}.bak"
|
|
echo "$ACQ_CONTENT" >> "$ACQ_FILE"
|
|
print_status "Appended BunkerWeb acquisition config to: $ACQ_FILE"
|
|
else
|
|
echo "$ACQ_CONTENT" > "$ACQ_FILE"
|
|
print_status "Created acquisition file: $ACQ_FILE"
|
|
fi
|
|
|
|
echo -e "${YELLOW}--- Step 3: Update hub and install core collections/parsers ---${NC}"
|
|
print_step "Updating hub and installing detection collections/parsers"
|
|
cscli hub update
|
|
cscli collections install bunkerity/bunkerweb
|
|
cscli parsers install crowdsecurity/geoip-enrich
|
|
|
|
# AppSec installation if chosen
|
|
if [ "$CROWDSEC_APPSEC_INSTALL" = "yes" ]; then
|
|
echo -e "${YELLOW}--- Step 4: Install and configure CrowdSec AppSec Component ---${NC}"
|
|
print_step "Installing and configuring CrowdSec AppSec Component"
|
|
APPSEC_ACQ_FILE="/etc/crowdsec/acquis.d/appsec.yaml"
|
|
APPSEC_ACQ_CONTENT="appsec_config: crowdsecurity/appsec-default
|
|
labels:
|
|
type: appsec
|
|
listen_addr: 127.0.0.1:7422
|
|
source: appsec
|
|
"
|
|
mkdir -p /etc/crowdsec/acquis.d
|
|
echo "$APPSEC_ACQ_CONTENT" > "$APPSEC_ACQ_FILE"
|
|
print_status "Created AppSec acquisition file: $APPSEC_ACQ_FILE"
|
|
cscli collections install crowdsecurity/appsec-virtual-patching
|
|
cscli collections install crowdsecurity/appsec-generic-rules
|
|
print_status "Installed AppSec collections"
|
|
fi
|
|
|
|
echo -e "${YELLOW}--- Step 5: Register BunkerWeb bouncer(s) and retrieve API key ---${NC}"
|
|
print_step "Registering BunkerWeb bouncer with CrowdSec"
|
|
BOUNCER_KEY=$(cscli bouncers add crowdsec-bunkerweb-bouncer/v1.6 --output raw)
|
|
if [ -z "$BOUNCER_KEY" ]; then
|
|
print_warning "Failed to retrieve API key; please register manually: cscli bouncers add crowdsec-bunkerweb-bouncer/v1.6"
|
|
else
|
|
print_status "Bouncer Successfully registered"
|
|
fi
|
|
|
|
if [ -n "$BOUNCER_KEY" ]; then
|
|
CROWDSEC_API_KEY="$BOUNCER_KEY"
|
|
fi
|
|
|
|
echo
|
|
echo -e "${GREEN}CrowdSec installed successfully${NC}"
|
|
echo "See BunkerWeb docs for more: https://docs.bunkerweb.io/latest/features/#crowdsec"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
}
|
|
|
|
# Function to install Redis
|
|
install_redis() {
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}Redis Installation${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo
|
|
print_step "Installing Redis"
|
|
|
|
case "$DISTRO_ID" in
|
|
"debian"|"ubuntu")
|
|
run_cmd apt update
|
|
run_cmd apt install -y redis-server
|
|
;;
|
|
"fedora"|"rhel"|"rocky"|"almalinux")
|
|
run_cmd dnf install -y redis
|
|
;;
|
|
"freebsd")
|
|
run_cmd pkg install -y redis
|
|
;;
|
|
*)
|
|
print_error "Unsupported distribution: $DISTRO_ID"
|
|
return
|
|
;;
|
|
esac
|
|
|
|
# Cross-platform service detection and enablement
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
# FreeBSD uses rc.d
|
|
sysrc redis_enable=YES >/dev/null 2>&1
|
|
service redis start || true
|
|
print_status "Redis service enabled and started"
|
|
else
|
|
REDIS_SERVICE=""
|
|
for candidate in redis-server redis; do
|
|
if systemctl list-unit-files --type=service --all 2>/dev/null | grep -q "^${candidate}\.service"; then
|
|
REDIS_SERVICE="$candidate"
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [ -n "$REDIS_SERVICE" ]; then
|
|
run_cmd systemctl enable --now "$REDIS_SERVICE"
|
|
print_status "Redis service enabled and started ($REDIS_SERVICE)"
|
|
else
|
|
print_warning "Redis service name not found; start it manually if needed."
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$REDIS_HOST_INPUT" ]; then
|
|
REDIS_HOST_INPUT="127.0.0.1"
|
|
fi
|
|
|
|
echo
|
|
echo -e "${GREEN}Redis installed and configured successfully${NC}"
|
|
echo "See BunkerWeb docs for more: https://docs.bunkerweb.io/latest/features/#redis"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
}
|
|
|
|
# Function to show final information
|
|
show_final_info() {
|
|
echo
|
|
echo "========================================="
|
|
echo -e "${GREEN}BunkerWeb Installation Complete!${NC}"
|
|
echo "========================================="
|
|
echo
|
|
echo "Services status:"
|
|
|
|
# Cross-platform service status display
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
service bunkerweb status 2>/dev/null || true
|
|
service bunkerweb_scheduler status 2>/dev/null || true
|
|
if [ -f /usr/local/etc/rc.d/bunkerweb_api ]; then
|
|
service bunkerweb_api status 2>/dev/null || true
|
|
fi
|
|
if [ "$ENABLE_WIZARD" = "yes" ]; then
|
|
service bunkerweb_ui status 2>/dev/null || true
|
|
fi
|
|
else
|
|
systemctl status bunkerweb --no-pager -l || true
|
|
systemctl status bunkerweb-scheduler --no-pager -l || true
|
|
# Show API service status if present on this system
|
|
if systemctl list-units --type=service --all | grep -q '^bunkerweb-api.service'; then
|
|
systemctl status bunkerweb-api --no-pager -l || true
|
|
fi
|
|
if [ "$ENABLE_WIZARD" = "yes" ]; then
|
|
systemctl status bunkerweb-ui --no-pager -l || true
|
|
fi
|
|
fi
|
|
|
|
echo
|
|
echo "Configuration:"
|
|
echo " - Main config: /etc/bunkerweb/variables.env"
|
|
|
|
if [ "$ENABLE_WIZARD" = "yes" ]; then
|
|
echo " - UI config: /etc/bunkerweb/ui.env"
|
|
fi
|
|
|
|
echo " - Scheduler config: /etc/bunkerweb/scheduler.env"
|
|
|
|
# Cross-platform API service detection
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
if [ "${SERVICE_API:-no}" = "yes" ] || [ -f /usr/local/etc/rc.d/bunkerweb_api ]; then
|
|
echo " - API config: /etc/bunkerweb/api.env"
|
|
fi
|
|
else
|
|
if [ "${SERVICE_API:-no}" = "yes" ] || systemctl list-units --type=service --all | grep -q '^bunkerweb-api.service'; then
|
|
echo " - API config: /etc/bunkerweb/api.env"
|
|
fi
|
|
fi
|
|
echo " - Logs: /var/log/bunkerweb/"
|
|
echo
|
|
|
|
# FreeBSD-specific instructions
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
echo "FreeBSD Notes:"
|
|
echo " - Services are managed via rc.d: service bunkerweb start|stop|restart"
|
|
echo " - Enable services in /etc/rc.conf: sysrc bunkerweb_enable=YES"
|
|
echo " - View logs: tail -f /var/log/bunkerweb/*.log"
|
|
echo
|
|
fi
|
|
|
|
# Display next steps based on installation type and wizard status
|
|
case "$INSTALL_TYPE" in
|
|
"manager")
|
|
echo "Next steps:"
|
|
echo " 1. Configure database connection in /etc/bunkerweb/scheduler.env"
|
|
echo " Set DATABASE_URI (e.g., sqlite:///var/lib/bunkerweb/db.sqlite3)"
|
|
echo " 2. Verify BUNKERWEB_INSTANCES is set to: $BUNKERWEB_INSTANCES_INPUT"
|
|
if [ "${SERVICE_UI:-yes}" != "no" ]; then
|
|
echo " 3. Access the Web UI at: http://your-server-ip:7000"
|
|
echo " 4. Use the UI to manage your BunkerWeb workers"
|
|
else
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
echo " 3. Start the Web UI: service bunkerweb_ui start"
|
|
else
|
|
echo " 3. Start the Web UI: systemctl start bunkerweb-ui"
|
|
fi
|
|
echo " 4. Access the UI at: http://your-server-ip:7000"
|
|
fi
|
|
echo
|
|
echo "📝 Manager mode information:"
|
|
echo " • The scheduler orchestrates configuration across all workers"
|
|
echo " • Workers must have their API accessible on port 5000 (default)"
|
|
echo " • Ensure workers whitelist this manager's IP: $MANAGER_IP_INPUT"
|
|
echo " • Use multisite mode: MULTISITE=yes for multiple services"
|
|
;;
|
|
"worker")
|
|
echo "Next steps:"
|
|
echo " 1. Verify this worker's API is accessible from the manager"
|
|
echo " Default API port: 5000 (configured via API_HTTP_PORT)"
|
|
echo " 2. Ensure firewall allows connections from: $MANAGER_IP_INPUT"
|
|
echo " 3. Configuration will be pushed automatically from the manager"
|
|
echo
|
|
echo "📝 Worker mode information:"
|
|
echo " • This instance is managed remotely by the scheduler"
|
|
echo " • API_WHITELIST_IP is configured to allow: $MANAGER_IP_INPUT"
|
|
echo " • API listens on: 0.0.0.0:5000 (whitelisting enforces access control)"
|
|
echo " • Local config changes in /etc/bunkerweb/variables.env may be overwritten"
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
echo " • Check logs: tail -f /var/log/bunkerweb/*.log"
|
|
else
|
|
echo " • Check logs: journalctl -u bunkerweb -f"
|
|
fi
|
|
;;
|
|
"scheduler")
|
|
echo "Next steps:"
|
|
echo " 1. Configure database connection in /etc/bunkerweb/scheduler.env"
|
|
echo " Set DATABASE_URI for shared configuration storage"
|
|
echo " 2. Verify BUNKERWEB_INSTANCES is set to: $BUNKERWEB_INSTANCES_INPUT"
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
echo " 3. Restart scheduler: service bunkerweb_scheduler restart"
|
|
else
|
|
echo " 3. Restart scheduler: systemctl restart bunkerweb-scheduler"
|
|
fi
|
|
echo " 4. Use 'bwcli' commands to manage the cluster"
|
|
echo
|
|
echo "📝 Scheduler-only mode information:"
|
|
echo " • Workers communicate via their API (port 5000 by default)"
|
|
echo " • Install the Web UI separately for graphical management"
|
|
echo " • All instances must share the same database backend"
|
|
;;
|
|
"ui")
|
|
echo "Next steps:"
|
|
echo " 1. Configure database connection in /etc/bunkerweb/ui.env"
|
|
echo " Set DATABASE_URI to the same database as your scheduler"
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
echo " 2. Restart the UI: service bunkerweb_ui restart"
|
|
else
|
|
echo " 2. Restart the UI: systemctl restart bunkerweb-ui"
|
|
fi
|
|
echo " 3. Access the Web UI at: http://your-server-ip:7000"
|
|
echo
|
|
echo "📝 UI-only mode information:"
|
|
echo " • The UI must connect to the same database as the scheduler"
|
|
echo " • Requires an existing scheduler instance managing workers"
|
|
echo " • Default UI port: 7000"
|
|
;;
|
|
"api")
|
|
echo "Next steps:"
|
|
echo " 1. Configure API settings in /etc/bunkerweb/api.env"
|
|
echo " Set API_LISTEN_IP and API_HTTP_PORT as needed"
|
|
echo " 2. Configure database connection: DATABASE_URI"
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
echo " 3. Restart the API: service bunkerweb_api restart"
|
|
else
|
|
echo " 3. Restart the API: systemctl restart bunkerweb-api"
|
|
fi
|
|
echo " 4. The API will be available at: http://your-server-ip:8000"
|
|
echo
|
|
echo "📝 API-only mode information:"
|
|
echo " • The API service provides programmatic access to BunkerWeb"
|
|
echo " • Must connect to the same database as scheduler/UI"
|
|
echo " • Default API port: 8000 (FastAPI service, not internal API)"
|
|
echo " • Configure API_KEY for authentication if needed"
|
|
;;
|
|
"full"|*)
|
|
if [ "$ENABLE_WIZARD" = "yes" ]; then
|
|
echo "Next steps:"
|
|
echo " 1. Access the setup wizard at: https://your-server-ip/setup"
|
|
echo " 2. Follow the configuration wizard to complete setup"
|
|
echo
|
|
echo "📝 Setup wizard information:"
|
|
echo " • The wizard guides you through initial configuration"
|
|
echo " • Configure your first protected service"
|
|
echo " • Set up SSL/TLS certificates automatically"
|
|
echo " • Access the management UI after completion"
|
|
else
|
|
echo "Next steps:"
|
|
echo " 1. Edit /etc/bunkerweb/variables.env to configure BunkerWeb"
|
|
echo " 2. Add your server settings and protected services"
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
echo " 3. Restart services: service bunkerweb restart && service bunkerweb_scheduler restart"
|
|
else
|
|
echo " 3. Restart services: systemctl restart bunkerweb bunkerweb-scheduler"
|
|
fi
|
|
echo
|
|
echo "📝 Manual configuration:"
|
|
echo " • Default database: SQLite (upgrade to MariaDB/PostgreSQL for production)"
|
|
echo " • Use 'bwcli' for command-line management"
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
echo " • Check logs: tail -f /var/log/bunkerweb/*.log"
|
|
else
|
|
echo " • Check logs: journalctl -u bunkerweb -f"
|
|
fi
|
|
echo " • Access Web UI (if enabled): http://your-server-ip:7000"
|
|
fi
|
|
;;
|
|
esac
|
|
echo
|
|
|
|
# Show RHEL database information if applicable
|
|
if [[ "$DISTRO_ID" =~ ^(rhel|centos|fedora|rocky|almalinux|redhat)$ ]]; then
|
|
echo "💾 Database clients for external databases:"
|
|
echo " • MariaDB: dnf install mariadb"
|
|
echo " • MySQL: dnf install mysql"
|
|
echo " • PostgreSQL: dnf install postgresql"
|
|
echo
|
|
fi
|
|
|
|
echo "📚 Resources:"
|
|
echo " • Documentation: https://docs.bunkerweb.io"
|
|
echo " • Community support: https://discord.bunkerity.com"
|
|
echo " • Commercial support: https://panel.bunkerweb.io/store/support"
|
|
echo "========================================="
|
|
}
|
|
|
|
# Function to show usage
|
|
usage() {
|
|
echo "BunkerWeb Easy Install Script"
|
|
echo
|
|
echo "Usage: $0 [OPTIONS]"
|
|
echo
|
|
echo "Options:"
|
|
echo " -v, --version VERSION BunkerWeb version to install (default: ${DEFAULT_BUNKERWEB_VERSION})"
|
|
echo " -w, --enable-wizard Enable the setup wizard (default in interactive mode)"
|
|
echo " -n, --no-wizard Disable the setup wizard"
|
|
echo " -y, --yes Non-interactive mode, use defaults"
|
|
echo " --api, --enable-api Enable the API service (disabled by default on Linux)"
|
|
echo " --no-api Explicitly disable the API service"
|
|
echo " -f, --force Force installation on unsupported OS versions"
|
|
echo " -q, --quiet Silent installation (suppress output)"
|
|
echo " -h, --help Show this help message"
|
|
echo " --dry-run Show what would be installed without doing it"
|
|
echo
|
|
echo "Installation types:"
|
|
echo " --full Full stack installation (default)"
|
|
echo " --manager Manager installation (Scheduler + UI)"
|
|
echo " --worker Worker installation (BunkerWeb only)"
|
|
echo " --scheduler-only Scheduler only installation"
|
|
echo " --ui-only Web UI only installation"
|
|
echo " --api-only API service only installation"
|
|
echo
|
|
echo "Security integrations:"
|
|
echo " --crowdsec Install and configure CrowdSec"
|
|
echo " --no-crowdsec Skip CrowdSec installation"
|
|
echo " --crowdsec-appsec Install CrowdSec with AppSec component"
|
|
echo " --redis Install and configure Redis"
|
|
echo " --no-redis Skip Redis installation"
|
|
echo
|
|
echo "Advanced options:"
|
|
echo " --instances \"IP1 IP2\" Space-separated list of BunkerWeb instances"
|
|
echo " (optional for --manager and --scheduler-only)"
|
|
echo " --manager-ip IPs Manager/Scheduler IPs to whitelist (required for --worker in non-interactive mode, overrides auto-detect for --manager)"
|
|
echo " --dns-resolvers \"IP1 IP2\" Custom DNS resolver IPs (for --full, --manager, --worker)"
|
|
echo " --api-https Enable HTTPS for internal API communication (default: HTTP only)"
|
|
echo " --backup-dir PATH Directory to store automatic backup before upgrade"
|
|
echo " --no-auto-backup Skip automatic backup (you MUST have done it manually)"
|
|
echo " --redis-host HOST Redis host for existing server"
|
|
echo " --redis-port PORT Redis port for existing server"
|
|
echo " --redis-database DB Redis database number"
|
|
echo " --redis-username USER Redis username"
|
|
echo " --redis-password PASS Redis password"
|
|
echo " --redis-ssl Enable SSL/TLS for Redis connection"
|
|
echo " --redis-no-ssl Disable SSL/TLS for Redis connection"
|
|
echo " --redis-ssl-verify Verify Redis SSL certificate"
|
|
echo " --redis-no-ssl-verify Do not verify Redis SSL certificate"
|
|
echo " --epel Install epel-release on RHEL-family distros if missing"
|
|
echo " --no-epel Do not install epel-release on RHEL-family distros"
|
|
echo
|
|
echo "Examples:"
|
|
echo " $0 # Interactive installation"
|
|
echo " $0 --no-wizard # Install without setup wizard"
|
|
echo " $0 --version 1.6.0 # Install specific version"
|
|
echo " $0 --yes # Non-interactive with defaults"
|
|
echo " $0 --force # Force install on unsupported OS"
|
|
echo " $0 --manager --instances \"192.168.1.10 192.168.1.11\""
|
|
echo " # Manager setup with worker instances"
|
|
echo " $0 --worker --manager-ip 10.20.30.40"
|
|
echo " # Worker installation with manager IP"
|
|
echo " $0 --dns-resolvers \"1.1.1.1 1.0.0.1\""
|
|
echo " # Use Cloudflare DNS resolvers"
|
|
echo " $0 --manager --instances \"192.168.1.10 192.168.1.11\" --api-https"
|
|
echo " # Manager with workers over HTTPS"
|
|
echo " $0 --crowdsec-appsec # Full installation with CrowdSec AppSec"
|
|
echo " $0 --quiet --yes # Silent non-interactive installation"
|
|
echo " $0 --dry-run # Preview installation without executing"
|
|
echo
|
|
}
|
|
|
|
# Parse command line arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-v|--version)
|
|
# Fix: actually use provided argument for version
|
|
if [ -z "$2" ] || [[ "$2" == -* ]]; then
|
|
print_error "Missing version after $1"
|
|
exit 1
|
|
fi
|
|
BUNKERWEB_VERSION="$2"
|
|
shift 2
|
|
;;
|
|
-w|--enable-wizard)
|
|
ENABLE_WIZARD="yes"
|
|
shift
|
|
;;
|
|
-n|--no-wizard)
|
|
ENABLE_WIZARD="no"
|
|
shift
|
|
;;
|
|
-y|--yes)
|
|
INTERACTIVE_MODE="no"
|
|
ENABLE_WIZARD="yes" # Default to wizard in non-interactive mode
|
|
shift
|
|
;;
|
|
-f|--force)
|
|
FORCE_INSTALL="yes"
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
--full)
|
|
INSTALL_TYPE="full"
|
|
shift
|
|
;;
|
|
--manager)
|
|
INSTALL_TYPE="manager"
|
|
shift
|
|
;;
|
|
--worker)
|
|
INSTALL_TYPE="worker"
|
|
shift
|
|
;;
|
|
--scheduler-only)
|
|
INSTALL_TYPE="scheduler"
|
|
shift
|
|
;;
|
|
--ui-only)
|
|
INSTALL_TYPE="ui"
|
|
shift
|
|
;;
|
|
--api-only)
|
|
INSTALL_TYPE="api"
|
|
shift
|
|
;;
|
|
--crowdsec)
|
|
CROWDSEC_INSTALL="yes"
|
|
shift
|
|
;;
|
|
--no-crowdsec)
|
|
CROWDSEC_INSTALL="no"
|
|
shift
|
|
;;
|
|
--crowdsec-appsec)
|
|
CROWDSEC_INSTALL="yes"
|
|
CROWDSEC_APPSEC_INSTALL="yes"
|
|
shift
|
|
;;
|
|
--redis)
|
|
REDIS_INSTALL="yes"
|
|
shift
|
|
;;
|
|
--no-redis)
|
|
REDIS_INSTALL="no"
|
|
shift
|
|
;;
|
|
--redis-host)
|
|
REDIS_HOST_INPUT="$2"
|
|
REDIS_INSTALL="no"
|
|
shift 2
|
|
;;
|
|
--redis-port)
|
|
REDIS_PORT_INPUT="$2"
|
|
REDIS_INSTALL="no"
|
|
shift 2
|
|
;;
|
|
--redis-database)
|
|
REDIS_DATABASE_INPUT="$2"
|
|
REDIS_INSTALL="no"
|
|
shift 2
|
|
;;
|
|
--redis-username)
|
|
REDIS_USERNAME_INPUT="$2"
|
|
REDIS_INSTALL="no"
|
|
shift 2
|
|
;;
|
|
--redis-password)
|
|
REDIS_PASSWORD_INPUT="$2"
|
|
REDIS_INSTALL="no"
|
|
shift 2
|
|
;;
|
|
--redis-ssl)
|
|
REDIS_SSL_INPUT="yes"
|
|
REDIS_INSTALL="no"
|
|
shift
|
|
;;
|
|
--redis-no-ssl)
|
|
REDIS_SSL_INPUT="no"
|
|
REDIS_INSTALL="no"
|
|
shift
|
|
;;
|
|
--redis-ssl-verify)
|
|
REDIS_SSL_VERIFY_INPUT="yes"
|
|
REDIS_INSTALL="no"
|
|
shift
|
|
;;
|
|
--redis-no-ssl-verify)
|
|
REDIS_SSL_VERIFY_INPUT="no"
|
|
REDIS_INSTALL="no"
|
|
shift
|
|
;;
|
|
--instances)
|
|
BUNKERWEB_INSTANCES_INPUT="$2"
|
|
shift 2
|
|
;;
|
|
--manager-ip)
|
|
MANAGER_IP_INPUT="$2"
|
|
shift 2
|
|
;;
|
|
--dns-resolvers)
|
|
DNS_RESOLVERS_INPUT="$2"
|
|
shift 2
|
|
;;
|
|
--api-https)
|
|
API_LISTEN_HTTPS_INPUT="yes"
|
|
shift
|
|
;;
|
|
--api|--enable-api)
|
|
SERVICE_API=yes
|
|
shift
|
|
;;
|
|
--no-api)
|
|
SERVICE_API=no
|
|
shift
|
|
;;
|
|
--backup-dir)
|
|
BACKUP_DIRECTORY="$2"; shift 2 ;;
|
|
--no-auto-backup)
|
|
AUTO_BACKUP="no"; shift ;;
|
|
--epel)
|
|
INSTALL_EPEL="yes"
|
|
shift
|
|
;;
|
|
--no-epel)
|
|
INSTALL_EPEL="no"
|
|
shift
|
|
;;
|
|
-q|--quiet)
|
|
exec >/dev/null 2>&1
|
|
shift
|
|
;;
|
|
--dry-run)
|
|
echo "Dry run mode - would install BunkerWeb $BUNKERWEB_VERSION"
|
|
detect_os
|
|
check_supported_os
|
|
echo "Installation type: ${INSTALL_TYPE:-full}"
|
|
echo "Setup wizard: ${ENABLE_WIZARD:-auto}"
|
|
echo "CrowdSec: ${CROWDSEC_INSTALL:-no}"
|
|
if [ "$REDIS_INSTALL" = "yes" ]; then
|
|
echo "Redis: yes (local install)"
|
|
elif [ -n "$REDIS_HOST_INPUT" ]; then
|
|
echo "Redis: yes (existing server)"
|
|
else
|
|
echo "Redis: no"
|
|
fi
|
|
if [ -n "$REDIS_HOST_INPUT" ]; then
|
|
echo "Redis host: $REDIS_HOST_INPUT"
|
|
fi
|
|
if [ -n "$BUNKERWEB_INSTANCES_INPUT" ]; then
|
|
echo "BunkerWeb instances: $BUNKERWEB_INSTANCES_INPUT"
|
|
fi
|
|
if [ -n "$MANAGER_IP_INPUT" ]; then
|
|
echo "Manager IP: $MANAGER_IP_INPUT"
|
|
fi
|
|
if [ -n "$DNS_RESOLVERS_INPUT" ]; then
|
|
echo "DNS resolvers: $DNS_RESOLVERS_INPUT"
|
|
fi
|
|
if [ -n "$API_LISTEN_HTTPS_INPUT" ]; then
|
|
echo "API HTTPS: $API_LISTEN_HTTPS_INPUT"
|
|
fi
|
|
exit 0
|
|
;;
|
|
*)
|
|
print_error "Unknown option: $1"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Force wizard off for manager installations
|
|
if [ "$INSTALL_TYPE" = "manager" ]; then
|
|
if [ "$ENABLE_WIZARD" = "yes" ]; then
|
|
print_warning "Setup wizard cannot run in manager mode; disabling it."
|
|
fi
|
|
ENABLE_WIZARD="no"
|
|
fi
|
|
|
|
# Validate instances option usage
|
|
if [ -n "$BUNKERWEB_INSTANCES_INPUT" ] && [[ "$INSTALL_TYPE" != "manager" && "$INSTALL_TYPE" != "scheduler" ]]; then
|
|
print_error "The --instances option can only be used with --manager or --scheduler-only installation types"
|
|
exit 1
|
|
fi
|
|
|
|
# Inform about missing instances for manager/scheduler in non-interactive mode
|
|
if [ "$INTERACTIVE_MODE" = "no" ] && [[ "$INSTALL_TYPE" = "manager" || "$INSTALL_TYPE" = "scheduler" ]] && [ -z "$BUNKERWEB_INSTANCES_INPUT" ]; then
|
|
print_warning "No BunkerWeb instances configured. You can add workers later."
|
|
print_status "See: https://docs.bunkerweb.io/latest/integrations/#linux"
|
|
fi
|
|
|
|
if [ "$INTERACTIVE_MODE" = "no" ] && [ "$INSTALL_TYPE" = "worker" ] && [ -z "$MANAGER_IP_INPUT" ]; then
|
|
print_error "The --manager-ip option is required when using --worker in non-interactive mode"
|
|
print_error "Example: --worker --manager-ip 10.20.30.40"
|
|
exit 1
|
|
fi
|
|
|
|
# Validate CrowdSec options usage
|
|
if [[ "$CROWDSEC_INSTALL" = "yes" || "$CROWDSEC_APPSEC_INSTALL" = "yes" ]] && [[ "$INSTALL_TYPE" = "worker" || "$INSTALL_TYPE" = "scheduler" || "$INSTALL_TYPE" = "ui" || "$INSTALL_TYPE" = "api" ]]; then
|
|
print_error "CrowdSec options (--crowdsec, --crowdsec-appsec) can only be used with --full or --manager installation types"
|
|
exit 1
|
|
fi
|
|
|
|
if { [ "$REDIS_INSTALL" = "yes" ] || [ -n "$REDIS_HOST_INPUT" ] || [ -n "$REDIS_PORT_INPUT" ] || [ -n "$REDIS_DATABASE_INPUT" ] || [ -n "$REDIS_USERNAME_INPUT" ] || [ -n "$REDIS_PASSWORD_INPUT" ] || [ -n "$REDIS_SSL_INPUT" ] || [ -n "$REDIS_SSL_VERIFY_INPUT" ]; } \
|
|
&& [[ "$INSTALL_TYPE" != "full" && "$INSTALL_TYPE" != "manager" && -n "$INSTALL_TYPE" ]]; then
|
|
print_error "Redis options (--redis, --redis-*) can only be used with --full or --manager installation types"
|
|
exit 1
|
|
fi
|
|
|
|
# Detect existing installation and handle reinstall/upgrade
|
|
check_existing_installation() {
|
|
if [ -f /usr/share/bunkerweb/VERSION ]; then
|
|
INSTALLED_VERSION=$(cat /usr/share/bunkerweb/VERSION 2>/dev/null || echo "unknown")
|
|
print_status "Detected existing BunkerWeb installation (version ${INSTALLED_VERSION})"
|
|
if [ "$INSTALLED_VERSION" = "$BUNKERWEB_VERSION" ]; then
|
|
if [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
echo
|
|
read -p "BunkerWeb ${INSTALLED_VERSION} already installed. Show status and exit? (Y/n): " -r
|
|
case $REPLY in
|
|
[Nn]*) print_status "Nothing to do."; exit 0 ;;
|
|
*) show_final_info; exit 0 ;;
|
|
esac
|
|
else
|
|
print_status "BunkerWeb ${INSTALLED_VERSION} already installed. Nothing to do."; exit 0
|
|
fi
|
|
else
|
|
print_warning "Requested version ${BUNKERWEB_VERSION} differs from installed version ${INSTALLED_VERSION}. Upgrade will be attempted."
|
|
if [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
read -p "Proceed with upgrade? (Y/n): " -r
|
|
case $REPLY in
|
|
[Nn]*) print_status "Upgrade cancelled."; exit 0 ;;
|
|
esac
|
|
fi
|
|
UPGRADE_SCENARIO="yes"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
perform_upgrade_backup() {
|
|
[ "$UPGRADE_SCENARIO" != "yes" ] && return 0
|
|
if should_skip_upgrade_backup; then
|
|
return 0
|
|
fi
|
|
if [ "$AUTO_BACKUP" != "yes" ]; then
|
|
print_warning "Automatic backup disabled. Ensure you already performed a manual backup (see https://docs.bunkerweb.io/latest/upgrading)."
|
|
return 0
|
|
fi
|
|
if ! command -v bwcli >/dev/null 2>&1; then
|
|
print_warning "bwcli not found, cannot run automatic backup. Perform manual backup per documentation."
|
|
return 0
|
|
fi
|
|
# Check if scheduler service is running using cross-platform helper
|
|
local scheduler_running="no"
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
if service bunkerweb_scheduler status >/dev/null 2>&1; then
|
|
scheduler_running="yes"
|
|
fi
|
|
else
|
|
if systemctl is-active --quiet bunkerweb-scheduler 2>/dev/null; then
|
|
scheduler_running="yes"
|
|
fi
|
|
fi
|
|
if [ "$scheduler_running" = "no" ]; then
|
|
print_warning "Scheduler service not active; starting temporarily for backup."
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
service bunkerweb_scheduler onestart || print_warning "Failed to start scheduler; backup may fail."
|
|
else
|
|
systemctl start bunkerweb-scheduler || print_warning "Failed to start scheduler; backup may fail."
|
|
fi
|
|
TEMP_STARTED="yes"
|
|
fi
|
|
if [ -z "$BACKUP_DIRECTORY" ]; then
|
|
BACKUP_DIRECTORY="/var/tmp/bunkerweb-backup-$(date +%Y%m%d-%H%M%S)"
|
|
fi
|
|
mkdir -p "$BACKUP_DIRECTORY" || {
|
|
print_warning "Unable to create backup directory $BACKUP_DIRECTORY. Skipping automatic backup."; return 0; }
|
|
print_step "Creating pre-upgrade backup in $BACKUP_DIRECTORY"
|
|
if BACKUP_DIRECTORY="$BACKUP_DIRECTORY" bwcli plugin backup save; then
|
|
print_status "Backup completed: $BACKUP_DIRECTORY"
|
|
else
|
|
print_warning "Automatic backup failed. Verify manually before continuing."
|
|
fi
|
|
if [ "$TEMP_STARTED" = "yes" ]; then
|
|
if [ "$DISTRO_ID" = "freebsd" ]; then
|
|
service bunkerweb_scheduler onestop || print_warning "Failed to stop bunkerweb_scheduler after temporary start."
|
|
else
|
|
systemctl stop bunkerweb-scheduler || print_warning "Failed to stop bunkerweb-scheduler after temporary start."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
should_skip_upgrade_backup() {
|
|
if [[ "$INSTALL_TYPE" = "worker" || "$INSTALL_TYPE" = "ui" || "$INSTALL_TYPE" = "api" ]]; then
|
|
return 0
|
|
fi
|
|
if ! systemctl list-unit-files --type=service 2>/dev/null | grep -q "^bunkerweb-scheduler.service"; then
|
|
return 0
|
|
fi
|
|
if ! systemctl is-enabled --quiet bunkerweb-scheduler 2>/dev/null && ! systemctl is-active --quiet bunkerweb-scheduler 2>/dev/null; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
upgrade_only() {
|
|
if should_skip_upgrade_backup; then
|
|
print_status "Skipping pre-upgrade backup (scheduler not enabled; worker/ui/api install)."
|
|
else
|
|
# Interactive confirmation about backup (optional, enabled by default)
|
|
if [ "$INTERACTIVE_MODE" = "yes" ]; then
|
|
if [ "$AUTO_BACKUP" = "yes" ]; then
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}💾 Pre-upgrade Backup${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "A pre-upgrade backup is recommended to preserve configuration and database."
|
|
echo "You can change the destination directory or accept the default."
|
|
DEFAULT_BACKUP_DIR="/var/tmp/bunkerweb-backup-$(date +%Y%m%d-%H%M%S)"
|
|
echo
|
|
echo -e "${YELLOW}Create automatic backup before upgrade? (Y/n):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Nn]*) AUTO_BACKUP="no" ;;
|
|
*)
|
|
echo -e "${YELLOW}Backup directory [${DEFAULT_BACKUP_DIR}]:${NC} "
|
|
read -p "" -r BACKUP_DIRECTORY_INPUT
|
|
if [ -n "$BACKUP_DIRECTORY_INPUT" ]; then
|
|
BACKUP_DIRECTORY="$BACKUP_DIRECTORY_INPUT"
|
|
else
|
|
BACKUP_DIRECTORY="${BACKUP_DIRECTORY:-$DEFAULT_BACKUP_DIR}"
|
|
fi
|
|
;;
|
|
esac
|
|
else
|
|
echo
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo -e "${BLUE}⚠️ Backup Confirmation${NC}"
|
|
echo -e "${BLUE}========================================${NC}"
|
|
echo "Automatic backup is disabled. Make sure you already performed a manual backup as described in the documentation."
|
|
echo
|
|
echo -e "${YELLOW}Confirm manual backup was performed? (y/N):${NC} "
|
|
read -p "" -r
|
|
case $REPLY in
|
|
[Yy]*) ;; * ) print_error "Upgrade aborted until backup is confirmed."; exit 1 ;;
|
|
esac
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
print_status "Upgrade mode: $INSTALLED_VERSION -> $BUNKERWEB_VERSION"
|
|
perform_upgrade_backup
|
|
# Remove holds/version locks
|
|
case "$DISTRO_ID" in
|
|
debian|ubuntu)
|
|
if command -v apt-mark >/dev/null 2>&1; then
|
|
print_status "Removing holds (bunkerweb, nginx)"
|
|
apt-mark unhold bunkerweb nginx >/dev/null 2>&1 || true
|
|
fi
|
|
;;
|
|
fedora|rhel|rocky|almalinux)
|
|
if command -v dnf >/dev/null 2>&1; then
|
|
print_status "Removing versionlock (bunkerweb, nginx)"
|
|
dnf versionlock delete bunkerweb nginx >/dev/null 2>&1 || true
|
|
fi
|
|
;;
|
|
esac
|
|
# Stop services (best effort)
|
|
print_step "Stopping services prior to upgrade"
|
|
for svc in bunkerweb-ui bunkerweb-scheduler bunkerweb; do
|
|
if systemctl list-units --type=service --all | grep -q "^${svc}.service"; then
|
|
if systemctl is-active --quiet "$svc"; then
|
|
run_cmd systemctl stop "$svc"
|
|
fi
|
|
fi
|
|
done
|
|
# Install new version only (do NOT reinstall nginx)
|
|
print_step "Upgrading BunkerWeb package"
|
|
case "$DISTRO_ID" in
|
|
debian|ubuntu)
|
|
run_cmd apt update
|
|
run_cmd apt install -y --allow-downgrades "bunkerweb=$BUNKERWEB_VERSION"
|
|
run_cmd apt-mark hold bunkerweb nginx
|
|
;;
|
|
fedora|rhel|rocky|almalinux)
|
|
if [ "$DISTRO_ID" = "fedora" ]; then
|
|
run_cmd dnf makecache || true
|
|
else
|
|
dnf check-update || true
|
|
fi
|
|
run_cmd dnf install -y --allowerasing "bunkerweb-$BUNKERWEB_VERSION"
|
|
run_cmd dnf versionlock add bunkerweb nginx
|
|
;;
|
|
esac
|
|
show_final_info
|
|
exit 0
|
|
}
|
|
|
|
# Main installation function
|
|
main() {
|
|
echo "========================================="
|
|
echo " BunkerWeb Easy Install Script"
|
|
echo "========================================="
|
|
echo
|
|
|
|
# Preliminary checks
|
|
check_root
|
|
detect_os
|
|
detect_architecture
|
|
check_supported_os
|
|
# New: check if already installed (after OS detection)
|
|
check_existing_installation
|
|
|
|
# If upgrade scenario, skip prompts & ancillary installs
|
|
if [ "$UPGRADE_SCENARIO" = "yes" ]; then
|
|
upgrade_only
|
|
fi
|
|
|
|
# Show RHEL database warning early
|
|
show_rhel_database_warning
|
|
|
|
# Ask user preferences in interactive mode
|
|
ask_user_preferences
|
|
|
|
# Check for port conflicts after knowing the install type
|
|
check_ports
|
|
|
|
# Set environment variables based on installation type
|
|
case "$INSTALL_TYPE" in
|
|
"manager")
|
|
export MANAGER_MODE=yes
|
|
export ENABLE_WIZARD=no
|
|
;;
|
|
"worker")
|
|
export WORKER_MODE=yes
|
|
export ENABLE_WIZARD=no
|
|
;;
|
|
"scheduler")
|
|
export SERVICE_BUNKERWEB=no
|
|
export SERVICE_SCHEDULER=yes
|
|
export SERVICE_UI=no
|
|
;;
|
|
"ui")
|
|
export SERVICE_BUNKERWEB=no
|
|
export SERVICE_SCHEDULER=no
|
|
export SERVICE_UI=yes
|
|
;;
|
|
"api")
|
|
export SERVICE_BUNKERWEB=no
|
|
export SERVICE_SCHEDULER=no
|
|
export SERVICE_UI=no
|
|
export SERVICE_API=yes
|
|
;;
|
|
"full"|"")
|
|
;;
|
|
esac
|
|
|
|
# Pass UI_WIZARD to postinstall script
|
|
if [ "$ENABLE_WIZARD" = "no" ]; then
|
|
export UI_WIZARD=no
|
|
fi
|
|
|
|
print_status "Installing BunkerWeb $BUNKERWEB_VERSION"
|
|
echo
|
|
|
|
# Confirmation prompt in interactive mode
|
|
if [ "$INTERACTIVE_MODE" = "yes" ] && [ "$FORCE_INSTALL" != "yes" ]; then
|
|
read -p "Continue with installation? (Y/n): " -r
|
|
case $REPLY in
|
|
[Nn]*)
|
|
print_status "Installation cancelled"
|
|
exit 0
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
# If upgrading, remove holds/versionlocks so upgrade can proceed
|
|
if [ "$UPGRADE_SCENARIO" = "yes" ]; then
|
|
case "$DISTRO_ID" in
|
|
debian|ubuntu)
|
|
if command -v apt-mark >/dev/null 2>&1; then
|
|
print_status "Removing holds on bunkerweb & nginx (upgrade scenario)"
|
|
apt-mark unhold bunkerweb nginx >/dev/null 2>&1 || true
|
|
fi
|
|
;;
|
|
fedora|rhel|rocky|almalinux)
|
|
if command -v dnf >/dev/null 2>&1; then
|
|
print_status "Removing versionlock on bunkerweb & nginx (upgrade scenario)"
|
|
dnf versionlock delete bunkerweb nginx >/dev/null 2>&1 || true
|
|
fi
|
|
;;
|
|
esac
|
|
# Stop services before upgrading (per upgrading.md procedure)
|
|
print_step "Stopping BunkerWeb services before upgrade"
|
|
for svc in bunkerweb bunkerweb-ui bunkerweb-scheduler; do
|
|
if systemctl list-units --type=service --all | grep -q "^${svc}.service"; then
|
|
if systemctl is-active --quiet "$svc"; then
|
|
run_cmd systemctl stop "$svc"
|
|
else
|
|
print_status "Service $svc not active, skipping stop"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Install NGINX based on distribution
|
|
case "$DISTRO_ID" in
|
|
"debian"|"ubuntu")
|
|
install_nginx_debian
|
|
;;
|
|
"fedora")
|
|
install_nginx_fedora
|
|
;;
|
|
"rhel"|"rocky"|"almalinux")
|
|
install_nginx_rhel
|
|
;;
|
|
"freebsd")
|
|
install_nginx_freebsd
|
|
;;
|
|
esac
|
|
|
|
# Install CrowdSec if chosen
|
|
if [ "$CROWDSEC_INSTALL" = "yes" ]; then
|
|
install_crowdsec
|
|
fi
|
|
|
|
# Install Redis if chosen (configuration applied later)
|
|
if [ "$REDIS_INSTALL" = "yes" ]; then
|
|
install_redis
|
|
fi
|
|
|
|
# Install BunkerWeb based on distribution
|
|
# Set environment variables to prevent postinstall from starting services we'll configure
|
|
if [ "$INSTALL_TYPE" = "manager" ]; then
|
|
export SERVICE_SCHEDULER=no
|
|
elif [ "$INSTALL_TYPE" = "worker" ]; then
|
|
export SERVICE_BUNKERWEB=no
|
|
elif [ "$INSTALL_TYPE" = "full" ] || [ -z "$INSTALL_TYPE" ]; then
|
|
# Only prevent start if we have configuration to apply
|
|
if [ -n "$DNS_RESOLVERS_INPUT" ] || [ -n "$API_LISTEN_HTTPS_INPUT" ] || [ -n "$REDIS_HOST_INPUT" ] || [ "$REDIS_INSTALL" = "yes" ] || [ -n "$REDIS_PORT_INPUT" ] || [ -n "$REDIS_DATABASE_INPUT" ] || [ -n "$REDIS_USERNAME_INPUT" ] || [ -n "$REDIS_PASSWORD_INPUT" ] || [ -n "$REDIS_SSL_INPUT" ] || [ -n "$REDIS_SSL_VERIFY_INPUT" ] || [ "$CROWDSEC_INSTALL" = "yes" ] || [ "$CROWDSEC_APPSEC_INSTALL" = "yes" ]; then
|
|
export SERVICE_BUNKERWEB=no
|
|
export SERVICE_SCHEDULER=no
|
|
fi
|
|
fi
|
|
|
|
case "$DISTRO_ID" in
|
|
"debian"|"ubuntu")
|
|
install_bunkerweb_debian
|
|
;;
|
|
"fedora")
|
|
install_bunkerweb_rpm
|
|
;;
|
|
"rhel"|"rocky"|"almalinux")
|
|
install_bunkerweb_rpm
|
|
;;
|
|
"freebsd")
|
|
install_bunkerweb_freebsd
|
|
;;
|
|
esac
|
|
|
|
if [ "$INSTALL_TYPE" = "manager" ]; then
|
|
configure_manager_api_defaults
|
|
elif [ "$INSTALL_TYPE" = "worker" ]; then
|
|
configure_worker_api_whitelist
|
|
elif [ "$INSTALL_TYPE" = "full" ] || [ -z "$INSTALL_TYPE" ]; then
|
|
configure_full_config
|
|
fi
|
|
|
|
if [ "$CROWDSEC_INSTALL" = "yes" ]; then
|
|
run_cmd systemctl restart crowdsec
|
|
sleep 2
|
|
systemctl status crowdsec --no-pager -l || print_warning "CrowdSec may not be running"
|
|
fi
|
|
|
|
# Show final information
|
|
show_final_info
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|