This commit is contained in:
2025-11-15 09:07:04 +01:00
commit d5834de32e
26 changed files with 2170 additions and 0 deletions

192
install.sh Normal file
View File

@@ -0,0 +1,192 @@
#!/usr/bin/env bash
set -euo pipefail
C_RESET="\033[0m"; C_DIM="\033[2m"; C_BOLD="\033[1m"
C_RED="\033[31m"; C_GRN="\033[32m"; C_BLU="\033[34m"; C_YEL="\033[33m"
info(){ echo -e "${C_BLU}${C_RESET} $*"; }
ok(){ echo -e "${C_GRN}${C_RESET} $*"; }
warn(){ echo -e "${C_YEL}!${C_RESET} $*"; }
fail(){ echo -e "${C_RED}${C_RESET} $*"; }
if [[ $EUID -ne 0 ]]; then fail "Run as root (sudo)."; exit 1; fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PANEL_ROOT="/var/www/snowpanel"
PANEL_PUBLIC="$PANEL_ROOT/public"
STATE_DIR="/var/lib/snowpanel"
LOG_DIR="/var/log/snowpanel"
ETC_APP="/etc/snowpanel"
NGX_SITE_AVAIL="/etc/nginx/sites-available/snowpanel"
NGX_SITE_ENABL="/etc/nginx/sites-enabled/snowpanel"
SUDOERS_FILE="/etc/sudoers.d/snowpanel"
COLLECTOR_SRC="$SCRIPT_DIR/bin/snowpanel-collect.py"
COLLECTOR_BIN="/usr/local/bin/snowpanel-collect.py"
LOGDUMP_SRC="$SCRIPT_DIR/bin/snowpanel-logdump"
LOGDUMP_BIN="/usr/local/bin/snowpanel-logdump"
SHAPER_SRC="$SCRIPT_DIR/bin/snowpanel-shaper"
SHAPER_BIN="/usr/local/bin/snowpanel-shaper"
SHAPER_SVC="/etc/systemd/system/snowpanel-shaper.service"
SHAPER_PATH="/etc/systemd/system/snowpanel-shaper.path"
SVC="/etc/systemd/system/snowpanel-collector.service"
TIMER="/etc/systemd/system/snowpanel-collector.timer"
SF_DROPIN_DIR="/etc/systemd/system/snowflake-proxy.service.d"
SF_ACCOUNTING="$SF_DROPIN_DIR/10-accounting.conf"
export DEBIAN_FRONTEND=noninteractive
echo -e "${C_BOLD}Installing SnowPanel...${C_RESET}"
info "Updating apt and installing packages"
apt-get update -y >/dev/null
apt-get install -y --no-install-recommends snowflake-proxy nginx rsync php-fpm php-cli php-json php-curl php-zip php-common php-opcache python3 iproute2 iptables >/dev/null
ok "Packages installed"
PHPV=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;' 2>/dev/null || echo "8.2")
PHP_FPM_SVC="php${PHPV}-fpm"
PHP_SOCK="/run/php/php${PHPV}-fpm.sock"
ln -sf "$PHP_SOCK" /run/php/php-fpm.sock || true
info "Preparing directories"
install -d "$PANEL_PUBLIC" "$STATE_DIR" "$LOG_DIR" "$ETC_APP"
install -d -m 0755 /usr/local/bin
chown -R www-data:www-data "$PANEL_ROOT" || true
chown -R www-data:www-data "$STATE_DIR" "$LOG_DIR" || true
chmod 750 "$PANEL_ROOT" "$STATE_DIR" "$LOG_DIR"
ok "Directories ready"
info "Deploying web"
rsync -a --delete "$SCRIPT_DIR/web/" "$PANEL_PUBLIC/"
chown -R www-data:www-data "$PANEL_PUBLIC"
ok "Web deployed"
info "Seeding state"
echo -n '{"data":[]}' > "$STATE_DIR/stats.json"
chown www-data:www-data "$STATE_DIR/stats.json"
chmod 640 "$STATE_DIR/stats.json"
ok "State seeded"
info "Writing Nginx site"
cat > "$NGX_SITE_AVAIL" <<'NGINX'
server {
listen 80 default_server;
server_name _;
root /var/www/snowpanel/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
location ~ /\. {
deny all;
}
}
NGINX
rm -f /etc/nginx/sites-enabled/default || true
ln -sf "$NGX_SITE_AVAIL" "$NGX_SITE_ENABL"
ok "Nginx site enabled"
info "Installing helpers"
install -m 0755 "$COLLECTOR_SRC" "$COLLECTOR_BIN"
install -m 0755 "$LOGDUMP_SRC" "$LOGDUMP_BIN"
install -m 0755 "$SHAPER_SRC" "$SHAPER_BIN"
install -d -m 0750 -o www-data -g www-data "$STATE_DIR"
ok "Helpers installed"
info "Granting sudoers"
cat > "$SUDOERS_FILE" <<SUD
www-data ALL=NOPASSWD:/usr/local/bin/snowpanel-logdump
www-data ALL=NOPASSWD:/bin/systemctl start snowflake-proxy, /bin/systemctl stop snowflake-proxy, /bin/systemctl restart snowflake-proxy
www-data ALL=NOPASSWD:/bin/systemctl restart snowpanel-shaper
SUD
chmod 440 "$SUDOERS_FILE"
ok "Sudoers set"
info "Enabling systemd IP accounting"
mkdir -p "$SF_DROPIN_DIR"
cat > "$SF_ACCOUNTING" <<EOF
[Service]
IPAccounting=yes
EOF
ok "Accounting drop-in written"
info "Creating collector units"
cat > "$SVC" <<'UNIT'
[Unit]
Description=SnowPanel minute collector
After=snowflake-proxy.service
[Service]
Type=oneshot
User=www-data
Group=www-data
ExecStart=/usr/bin/env python3 /usr/local/bin/snowpanel-collect.py
UNIT
cat > "$TIMER" <<'TIMER'
[Unit]
Description=Run SnowPanel collector every minute
[Timer]
OnCalendar=*-*-* *:*:00
Persistent=true
Unit=snowpanel-collector.service
[Install]
WantedBy=timers.target
TIMER
ok "Collector units created"
info "Creating shaper units"
cat > "$SHAPER_SVC" <<'UNIT'
[Unit]
Description=SnowPanel traffic shaper for snowflake-proxy
After=network-online.target snowflake-proxy.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/snowpanel-shaper apply
ExecStop=/usr/local/bin/snowpanel-shaper clear
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
UNIT
cat > "$SHAPER_PATH" <<'PATHUNIT'
[Unit]
Description=Watch SnowPanel limits and reapply shaper
[Path]
PathChanged=/var/lib/snowpanel/app.json
PathChanged=/etc/snowpanel/app.json
PathChanged=/etc/snowpanel/limits.json
PathChanged=/var/lib/snowpanel/limits.json
[Install]
WantedBy=multi-user.target
PATHUNIT
ok "Shaper units created"
info "Restarting services"
systemctl daemon-reload
systemctl enable "$PHP_FPM_SVC" nginx >/dev/null 2>&1 || true
systemctl restart "$PHP_FPM_SVC" || true
systemctl restart nginx
systemctl enable --now snowflake-proxy >/dev/null 2>&1 || true
systemctl restart snowflake-proxy || true
systemctl enable --now snowpanel-collector.timer
systemctl start snowpanel-collector.service || true
systemctl enable --now snowpanel-shaper.service snowpanel-shaper.path
systemctl restart snowpanel-shaper.service || true
ok "Services running"
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
echo
echo -e "${C_BOLD}All set!${C_RESET}"
echo -e "URL: ${C_GRN}http://$IP/${C_RESET}"
echo -e " First run: you'll see a setup page to create the admin user."