Files
ServerKit/scripts/install.sh
T
Juan Denis f9c31aec32 feat(installer): guided install/update flow with health-checked rollback
- install.sh: staged installer with pre-flight checks (disk/memory/root),
  apt/dnf lock handling, low-RAM safe mode + swap, source-or-release install
  modes, generated secrets/.env, self-signed cert bootstrap, nginx + systemd
  wiring, a post-install health probe with automatic rollback, and optional
  Let's Encrypt issuance for the panel domain.
- scripts/update.sh: in-place updater with release self-refresh, pre-update
  database + tree backups, release/source paths, health-checked rollback,
  and backup pruning.
- scripts/build-release.sh: builds a portable release tarball (pre-built
  venv + frontend) at the repo root.
- serverkit CLI: 'update' delegates to scripts/update.sh and accepts
  --release [vX.Y.Z].
- Harden the serverkit-agent unit (kernel/namespace protections, MemoryMax,
  LimitNOFILE) and ignore release tarball artifacts.
2026-06-19 01:33:17 -04:00

377 lines
10 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
#
# ServerKit Agent Installation Script
#
# Usage:
# curl -fsSL https://your-serverkit.com/install.sh | sudo bash -s -- --token "TOKEN" --server "URL"
#
# Options:
# --token, -t Registration token (required)
# --server, -s ServerKit server URL (required)
# --name, -n Display name for this server (optional)
# --version, -v Specific agent version to install (optional, defaults to latest)
# --help, -h Show this help message
#
set -e
# Palette (truecolor violet gradient)
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ] && [ "${TERM:-dumb}" != "dumb" ]; then
NC=$'\033[0m'; BOLD=$'\033[1m'
fg() { printf '\033[38;2;%s;%s;%sm' "$1" "$2" "$3"; }
else
NC=''; BOLD=''
fg() { :; }
fi
V1="$(fg 196 181 253)"; V2="$(fg 167 139 250)"; V3="$(fg 139 92 246)"
V4="$(fg 124 58 237)"; V5="$(fg 109 40 217)"
WHITE="$(fg 237 233 254)"; MUTED="$(fg 165 160 190)"; FAINT="$(fg 113 108 140)"
GREEN="$(fg 52 211 153)"; RED="$(fg 248 113 113)"; YELLOW="$(fg 250 204 21)"
CYAN="$(fg 103 232 249)"
# Configuration
INSTALL_DIR="/usr/local/bin"
CONFIG_DIR="/etc/serverkit-agent"
LOG_DIR="/var/log/serverkit-agent"
SERVICE_USER="serverkit-agent"
GITHUB_REPO="jhd3197/ServerKit"
AGENT_BINARY="serverkit-agent"
# Arguments
TOKEN=""
SERVER_URL=""
SERVER_NAME=""
VERSION="latest"
print_banner() {
echo
printf " ${V1}${BOLD}╔═╗┌─┐┌─┐┌┬┐┌─┐┬┌─┐${NC}\n"
printf " ${V2}${BOLD}╚═╗│ ││ │ ├┤ │├┤ ${NC} ${WHITE}${BOLD}ServerKit Agent${NC}\n"
printf " ${V3}${BOLD}╚═╝└─┘└─┘ ┴ └─┘┴└──┘${NC} ${FAINT}v%s${NC}\n" "$VERSION"
echo
}
log_info() {
echo -e " ${CYAN}›${NC} $1"
}
log_success() {
echo -e " ${GREEN}●${NC} $1"
}
log_warn() {
echo -e " ${YELLOW}▲${NC} $1"
}
log_error() {
echo -e " ${RED}■${NC} $1"
exit 1
}
show_help() {
echo "ServerKit Agent Installation Script"
echo ""
echo "Usage: install.sh [OPTIONS]"
echo ""
echo "Options:"
echo " --token, -t Registration token (required)"
echo " --server, -s ServerKit server URL (required)"
echo " --name, -n Display name for this server (optional)"
echo " --version, -v Specific agent version (optional, defaults to latest)"
echo " --help, -h Show this help message"
echo ""
echo "Example:"
echo " curl -fsSL https://your-serverkit.com/install.sh | sudo bash -s -- \\"
echo " --token 'sk_reg_xxx' \\"
echo " --server 'https://your-serverkit.com'"
exit 0
}
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
--token|-t)
TOKEN="$2"
shift 2
;;
--server|-s)
SERVER_URL="$2"
shift 2
;;
--name|-n)
SERVER_NAME="$2"
shift 2
;;
--version|-v)
VERSION="$2"
shift 2
;;
--help|-h)
show_help
;;
*)
log_error "Unknown option: $1"
;;
esac
done
# Validate required arguments
if [[ -z "$TOKEN" ]]; then
log_error "Registration token is required. Use --token or -t"
fi
if [[ -z "$SERVER_URL" ]]; then
log_error "Server URL is required. Use --server or -s"
fi
}
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root (use sudo)"
fi
}
detect_platform() {
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
case "$ARCH" in
x86_64|amd64)
ARCH="amd64"
;;
aarch64|arm64)
ARCH="arm64"
;;
*)
log_error "Unsupported architecture: $ARCH"
;;
esac
if [[ "$OS" != "linux" ]]; then
log_error "This script only supports Linux. For Windows, use install.ps1"
fi
log_info "Detected platform: ${OS}-${ARCH}"
}
check_dependencies() {
log_info "Checking dependencies..."
# Check for required tools
for cmd in curl tar; do
if ! command -v "$cmd" &> /dev/null; then
log_error "$cmd is required but not installed"
fi
done
# Check for systemd
if ! command -v systemctl &> /dev/null; then
log_warn "systemd not found. You will need to start the agent manually."
fi
}
get_latest_version() {
if [[ "$VERSION" == "latest" ]]; then
log_info "Fetching latest version..."
VERSION=$(curl -fsSL "https://api.github.com/repos/${GITHUB_REPO}/releases" | \
grep -oP '"tag_name": "agent-v\K[^"]+' | head -1)
if [[ -z "$VERSION" ]]; then
log_error "Failed to fetch latest version"
fi
log_info "Latest version: v${VERSION}"
fi
}
download_agent() {
log_info "Downloading ServerKit Agent v${VERSION}..."
DOWNLOAD_URL="https://github.com/${GITHUB_REPO}/releases/download/agent-v${VERSION}/serverkit-agent-${VERSION}-linux-${ARCH}.tar.gz"
TMP_DIR=$(mktemp -d)
ARCHIVE="${TMP_DIR}/serverkit-agent.tar.gz"
if ! curl -fsSL "$DOWNLOAD_URL" -o "$ARCHIVE"; then
rm -rf "$TMP_DIR"
log_error "Failed to download agent from: $DOWNLOAD_URL"
fi
# Extract binary
log_info "Extracting agent..."
tar -xzf "$ARCHIVE" -C "$TMP_DIR"
# Install binary
mv "${TMP_DIR}/serverkit-agent-linux-${ARCH}" "${INSTALL_DIR}/${AGENT_BINARY}"
chmod +x "${INSTALL_DIR}/${AGENT_BINARY}"
# Cleanup
rm -rf "$TMP_DIR"
log_success "Agent installed to ${INSTALL_DIR}/${AGENT_BINARY}"
}
create_user() {
if id "$SERVICE_USER" &>/dev/null; then
log_info "User $SERVICE_USER already exists"
else
log_info "Creating service user: $SERVICE_USER"
useradd -r -s /bin/false -d /nonexistent "$SERVICE_USER"
fi
# Add to docker group if it exists
if getent group docker > /dev/null 2>&1; then
usermod -aG docker "$SERVICE_USER"
log_info "Added $SERVICE_USER to docker group"
fi
}
create_config_dir() {
log_info "Creating configuration and log directories..."
mkdir -p "$CONFIG_DIR" "$LOG_DIR"
chown "$SERVICE_USER:$SERVICE_USER" "$CONFIG_DIR" "$LOG_DIR"
chmod 750 "$CONFIG_DIR" "$LOG_DIR"
}
register_agent() {
log_info "Registering agent with ServerKit..."
REGISTER_CMD=(
"${INSTALL_DIR}/${AGENT_BINARY}"
--config "${CONFIG_DIR}/config.yaml"
register
--token "${TOKEN}"
--server "${SERVER_URL}"
)
if [[ -n "$SERVER_NAME" ]]; then
REGISTER_CMD+=(--name "${SERVER_NAME}")
fi
if ! "${REGISTER_CMD[@]}"; then
log_error "Agent registration failed"
fi
# Fix permissions on config files
chown -R "$SERVICE_USER:$SERVICE_USER" "$CONFIG_DIR" "$LOG_DIR"
[[ -f "${CONFIG_DIR}/config.yaml" ]] && chmod 600 "${CONFIG_DIR}/config.yaml"
[[ -f "${CONFIG_DIR}/agent.key" ]] && chmod 600 "${CONFIG_DIR}/agent.key"
log_success "Agent registered successfully"
}
install_systemd_service() {
if ! command -v systemctl &> /dev/null; then
log_warn "Skipping systemd service installation (systemd not found)"
return
fi
log_info "Installing systemd service..."
cat > /etc/systemd/system/serverkit-agent.service << EOF
[Unit]
Description=ServerKit Agent
Documentation=https://github.com/${GITHUB_REPO}
After=network-online.target docker.service
Wants=network-online.target
[Service]
Type=simple
User=${SERVICE_USER}
Group=${SERVICE_USER}
ExecStart=${INSTALL_DIR}/${AGENT_BINARY} --config ${CONFIG_DIR}/config.yaml start
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=serverkit-agent
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=${CONFIG_DIR} ${LOG_DIR}
PrivateTmp=true
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
ProtectClock=yes
ProtectHostname=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
LockPersonality=yes
MemoryMax=512M
LimitNOFILE=65535
# Environment
Environment=HOME=/nonexistent
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable serverkit-agent
log_success "Systemd service installed"
}
start_service() {
if ! command -v systemctl &> /dev/null; then
log_warn "Cannot auto-start without systemd"
echo ""
echo "To start the agent manually:"
echo " ${INSTALL_DIR}/${AGENT_BINARY} --config ${CONFIG_DIR}/config.yaml start"
return
fi
log_info "Starting ServerKit Agent..."
systemctl start serverkit-agent
sleep 2
if systemctl is-active --quiet serverkit-agent; then
log_success "Agent is running"
else
log_error "Failed to start agent. Check logs with: journalctl -u serverkit-agent"
fi
}
print_success() {
echo ""
echo -e "${GREEN}╔═══════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ Installation completed successfully! ║${NC}"
echo -e "${GREEN}╚═══════════════════════════════════════════════════════════╝${NC}"
echo ""
echo "Agent Status:"
echo " Binary: ${INSTALL_DIR}/${AGENT_BINARY}"
echo " Config: ${CONFIG_DIR}/config.yaml"
echo " Service: serverkit-agent"
echo ""
echo "Useful commands:"
echo " Check status: systemctl status serverkit-agent"
echo " View logs: journalctl -u serverkit-agent -f"
echo " Restart agent: systemctl restart serverkit-agent"
echo " Stop agent: systemctl stop serverkit-agent"
echo ""
}
# Main execution
main() {
print_banner
parse_args "$@"
check_root
detect_platform
check_dependencies
get_latest_version
download_agent
create_user
create_config_dir
register_agent
install_systemd_service
start_service
print_success
}
main "$@"