Download src/supplemental/scripts/install-agent.sh from cacodex/beszel: direct link, hf CLI and curl.
- Browser
- Download file 33 kB
-
https://huggingface.co/spaces/cacodex/beszel/resolve/main/src/supplemental/scripts/install-agent.sh
- Command line
-
hf download hf://spaces/cacodex/beszel/src/supplemental/scripts/install-agent.sh
-
curl -L -o install-agent.sh https://huggingface.co/spaces/cacodex/beszel/resolve/main/src/supplemental/scripts/install-agent.sh
33 kB
| is_alpine() { | |
| [ -f /etc/alpine-release ] | |
| } | |
| is_openwrt() { | |
| grep -qi "OpenWrt" /etc/os-release | |
| } | |
| is_freebsd() { | |
| [ "$(uname -s)" = "FreeBSD" ] | |
| } | |
| is_opnsense() { | |
| [ -f /usr/local/sbin/opnsense-version ] || [ -f /usr/local/etc/opnsense-version ] || [ -f /etc/opnsense-release ] | |
| } | |
| is_glibc() { | |
| # Prefer glibc-enabled agent (NVML via purego) on linux/amd64 glibc systems. | |
| # Check common dynamic loader paths first (fast + reliable). | |
| for p in \ | |
| /lib64/ld-linux-x86-64.so.2 \ | |
| /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 \ | |
| /lib/ld-linux-x86-64.so.2; do | |
| [ -e "$p" ] && return 0 | |
| done | |
| # Fallback to ldd output if available. | |
| if command -v ldd >/dev/null 2>&1; then | |
| ldd --version 2>&1 | grep -qiE 'gnu libc|glibc' && return 0 | |
| fi | |
| return 1 | |
| } | |
| # If SELinux is enabled, set the context of the binary | |
| set_selinux_context() { | |
| # Check if SELinux is enabled and in enforcing or permissive mode | |
| if command -v getenforce >/dev/null 2>&1; then | |
| SELINUX_MODE=$(getenforce) | |
| if [ "$SELINUX_MODE" != "Disabled" ]; then | |
| echo "SELinux is enabled (${SELINUX_MODE} mode). Setting appropriate context..." | |
| # First try to set persistent context if semanage is available | |
| if command -v semanage >/dev/null 2>&1; then | |
| echo "Attempting to set persistent SELinux context..." | |
| if semanage fcontext -a -t bin_t "$BIN_PATH" >/dev/null 2>&1; then | |
| restorecon -v "$BIN_PATH" >/dev/null 2>&1 | |
| else | |
| echo "Warning: Failed to set persistent context, falling back to temporary context." | |
| fi | |
| fi | |
| # Fall back to chcon if semanage failed or isn't available | |
| if command -v chcon >/dev/null 2>&1; then | |
| # Set context for both the directory and binary | |
| chcon -t bin_t "$BIN_PATH" || echo "Warning: Failed to set SELinux context for binary." | |
| chcon -R -t bin_t "$AGENT_DIR" || echo "Warning: Failed to set SELinux context for directory." | |
| else | |
| if [ "$SELINUX_MODE" = "Enforcing" ]; then | |
| echo "Warning: SELinux is in enforcing mode but chcon command not found. The service may fail to start." | |
| echo "Consider installing the policycoreutils package or temporarily setting SELinux to permissive mode." | |
| else | |
| echo "Warning: SELinux is in permissive mode but chcon command not found." | |
| fi | |
| fi | |
| fi | |
| fi | |
| } | |
| # Clean up SELinux contexts if they were set | |
| cleanup_selinux_context() { | |
| if command -v getenforce >/dev/null 2>&1 && [ "$(getenforce)" != "Disabled" ]; then | |
| echo "Cleaning up SELinux contexts..." | |
| # Remove persistent context if semanage is available | |
| if command -v semanage >/dev/null 2>&1; then | |
| semanage fcontext -d "$BIN_PATH" 2>/dev/null || true | |
| fi | |
| fi | |
| } | |
| # Ensure the proxy URL ends with a / | |
| ensure_trailing_slash() { | |
| if [ -n "$1" ]; then | |
| case "$1" in | |
| */) echo "$1" ;; | |
| *) echo "$1/" ;; | |
| esac | |
| else | |
| echo "$1" | |
| fi | |
| } | |
| # Generate FreeBSD rc service content | |
| generate_freebsd_rc_service() { | |
| cat <<'EOF' | |
| #!/bin/sh | |
| # PROVIDE: beszel_agent | |
| # REQUIRE: DAEMON NETWORKING | |
| # BEFORE: LOGIN | |
| # KEYWORD: shutdown | |
| # Add the following lines to /etc/rc.conf to configure Beszel Agent: | |
| # | |
| # beszel_agent_enable (bool): Set to YES to enable Beszel Agent | |
| # Default: YES | |
| # beszel_agent_env_file (str): Beszel Agent env configuration file | |
| # Default: /usr/local/etc/beszel-agent/env | |
| # beszel_agent_user (str): Beszel Agent daemon user | |
| # Default: beszel | |
| # beszel_agent_bin (str): Path to the beszel-agent binary | |
| # Default: /usr/local/sbin/beszel-agent | |
| # beszel_agent_flags (str): Extra flags passed to beszel-agent command invocation | |
| # Default: | |
| . /etc/rc.subr | |
| name="beszel_agent" | |
| rcvar=beszel_agent_enable | |
| load_rc_config $name | |
| : ${beszel_agent_enable:="YES"} | |
| : ${beszel_agent_user:="beszel"} | |
| : ${beszel_agent_flags:=""} | |
| : ${beszel_agent_env_file:="/usr/local/etc/beszel-agent/env"} | |
| : ${beszel_agent_bin:="/usr/local/sbin/beszel-agent"} | |
| logfile="/var/log/${name}.log" | |
| pidfile="/var/run/${name}.pid" | |
| procname="/usr/sbin/daemon" | |
| start_precmd="${name}_prestart" | |
| start_cmd="${name}_start" | |
| stop_cmd="${name}_stop" | |
| extra_commands="upgrade" | |
| upgrade_cmd="beszel_agent_upgrade" | |
| beszel_agent_prestart() | |
| { | |
| if [ ! -f "${beszel_agent_env_file}" ]; then | |
| echo WARNING: missing "${beszel_agent_env_file}" env file. Start aborted. | |
| exit 1 | |
| fi | |
| } | |
| beszel_agent_start() | |
| { | |
| echo "Starting ${name}" | |
| /usr/sbin/daemon -fc \ | |
| -P "${pidfile}" \ | |
| -o "${logfile}" \ | |
| -u "${beszel_agent_user}" \ | |
| "${beszel_agent_bin}" ${beszel_agent_flags} | |
| } | |
| beszel_agent_stop() | |
| { | |
| pid="$(check_pidfile "${pidfile}" "${procname}")" | |
| if [ -n "${pid}" ]; then | |
| echo "Stopping ${name} (pid=${pid})" | |
| kill -- "-${pid}" | |
| wait_for_pids "${pid}" | |
| else | |
| echo "${name} isn't running" | |
| fi | |
| } | |
| beszel_agent_upgrade() | |
| { | |
| echo "Upgrading ${name}" | |
| if command -v sudo >/dev/null; then | |
| sudo -u "${beszel_agent_user}" -- "${beszel_agent_bin}" update | |
| else | |
| su -m "${beszel_agent_user}" -c "${beszel_agent_bin} update" | |
| fi | |
| } | |
| run_rc_command "$1" | |
| EOF | |
| } | |
| # Detect system architecture | |
| detect_architecture() { | |
| local arch=$(uname -m) | |
| if [ "$arch" = "mips" ]; then | |
| detect_mips_endianness | |
| return $? | |
| fi | |
| case "$arch" in | |
| x86_64) | |
| arch="amd64" | |
| ;; | |
| armv6l|armv7l) | |
| arch="arm" | |
| ;; | |
| aarch64) | |
| arch="arm64" | |
| ;; | |
| esac | |
| echo "$arch" | |
| } | |
| # Detect MIPS endianness using ELF header | |
| detect_mips_endianness() { | |
| local bins="/bin/sh /bin/ls /usr/bin/env" | |
| local bin_to_check endian | |
| for bin_to_check in $bins; do | |
| if [ -f "$bin_to_check" ]; then | |
| # The 6th byte in ELF header: 01 = little, 02 = big | |
| endian=$(hexdump -n 1 -s 5 -e '1/1 "%02x"' "$bin_to_check" 2>/dev/null) | |
| if [ "$endian" = "01" ]; then | |
| echo "mipsle" | |
| return | |
| elif [ "$endian" = "02" ]; then | |
| echo "mips" | |
| return | |
| fi | |
| fi | |
| done | |
| # Final fallback | |
| echo "mips" | |
| } | |
| # Default values | |
| PORT=45876 | |
| UNINSTALL=false | |
| GITHUB_URL="https://github.com" | |
| GITHUB_PROXY_URL="" | |
| KEY="" | |
| TOKEN="" | |
| HUB_URL="" | |
| AUTO_UPDATE_FLAG="" # empty string means prompt, "true" means auto-enable, "false" means skip | |
| VERSION="latest" | |
| # Check for help flag | |
| case "$1" in | |
| -h | --help) | |
| printf "Beszel Agent installation script\n\n" | |
| printf "Usage: ./install-agent.sh [options]\n\n" | |
| printf "Options: \n" | |
| printf " -k : SSH key (required, or interactive if not provided)\n" | |
| printf " -p : Port (default: $PORT)\n" | |
| printf " -t : Token (optional for backwards compatibility)\n" | |
| printf " -url : Hub URL (optional for backwards compatibility)\n" | |
| printf " -v, --version : Version to install (default: latest)\n" | |
| printf " -u : Uninstall Beszel Agent\n" | |
| printf " --auto-update [VALUE] : Control automatic daily updates\n" | |
| printf " VALUE can be true (enable) or false (disable). If not specified, will prompt.\n" | |
| printf " --mirror [URL] : Use GitHub proxy to resolve network timeout issues in mainland China\n" | |
| printf " URL: optional custom proxy URL (default: https://gh.beszel.dev)\n" | |
| printf " -h, --help : Display this help message\n" | |
| exit 0 | |
| ;; | |
| esac | |
| # Build sudo args by properly quoting everything | |
| build_sudo_args() { | |
| QUOTED_ARGS="" | |
| while [ $# -gt 0 ]; do | |
| if [ -n "$QUOTED_ARGS" ]; then | |
| QUOTED_ARGS="$QUOTED_ARGS " | |
| fi | |
| QUOTED_ARGS="$QUOTED_ARGS'$(echo "$1" | sed "s/'/'\\\\''/g")'" | |
| shift | |
| done | |
| echo "$QUOTED_ARGS" | |
| } | |
| # Check if running as root and re-execute with sudo if needed | |
| if [ "$(id -u)" != "0" ]; then | |
| if command -v sudo >/dev/null 2>&1; then | |
| SUDO_ARGS=$(build_sudo_args "$@") | |
| eval "exec sudo $0 $SUDO_ARGS" | |
| else | |
| echo "This script must be run as root. Please either:" | |
| echo "1. Run this script as root (su root)" | |
| echo "2. Install sudo and run with sudo" | |
| exit 1 | |
| fi | |
| fi | |
| # Parse arguments | |
| while [ $# -gt 0 ]; do | |
| case "$1" in | |
| -k) | |
| shift | |
| KEY="$1" | |
| ;; | |
| -p) | |
| shift | |
| PORT="$1" | |
| ;; | |
| -t) | |
| shift | |
| TOKEN="$1" | |
| ;; | |
| -url) | |
| shift | |
| HUB_URL="$1" | |
| ;; | |
| -v | --version) | |
| shift | |
| VERSION="$1" | |
| ;; | |
| -u) | |
| UNINSTALL=true | |
| ;; | |
| --mirror* | --china-mirrors*) | |
| # Check if there's a value after the = sign | |
| if echo "$1" | grep -q "="; then | |
| # Extract the value after = | |
| CUSTOM_PROXY=$(echo "$1" | cut -d'=' -f2) | |
| if [ -n "$CUSTOM_PROXY" ]; then | |
| GITHUB_PROXY_URL="$CUSTOM_PROXY" | |
| GITHUB_URL="$(ensure_trailing_slash "$CUSTOM_PROXY")https://github.com" | |
| else | |
| GITHUB_PROXY_URL="https://gh.beszel.dev" | |
| GITHUB_URL="$GITHUB_PROXY_URL" | |
| fi | |
| elif [ "$2" != "" ] && ! echo "$2" | grep -q '^-'; then | |
| # use custom proxy URL provided as next argument | |
| GITHUB_PROXY_URL="$2" | |
| GITHUB_URL="$(ensure_trailing_slash "$2")https://github.com" | |
| shift | |
| else | |
| # No value specified, use default | |
| GITHUB_PROXY_URL="https://gh.beszel.dev" | |
| GITHUB_URL="$GITHUB_PROXY_URL" | |
| fi | |
| ;; | |
| --auto-update*) | |
| # Check if there's a value after the = sign | |
| if echo "$1" | grep -q "="; then | |
| # Extract the value after = | |
| AUTO_UPDATE_VALUE=$(echo "$1" | cut -d'=' -f2) | |
| if [ "$AUTO_UPDATE_VALUE" = "true" ]; then | |
| AUTO_UPDATE_FLAG="true" | |
| elif [ "$AUTO_UPDATE_VALUE" = "false" ]; then | |
| AUTO_UPDATE_FLAG="false" | |
| else | |
| echo "Invalid value for --auto-update flag: $AUTO_UPDATE_VALUE. Using default (prompt)." | |
| fi | |
| elif [ "$2" = "true" ] || [ "$2" = "false" ]; then | |
| # Value provided as next argument | |
| AUTO_UPDATE_FLAG="$2" | |
| shift | |
| else | |
| # No value specified, use true | |
| AUTO_UPDATE_FLAG="true" | |
| fi | |
| ;; | |
| *) | |
| echo "Invalid option: $1" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| shift | |
| done | |
| # Set paths based on operating system | |
| if is_freebsd; then | |
| AGENT_DIR="/usr/local/etc/beszel-agent" | |
| BIN_DIR="/usr/local/sbin" | |
| BIN_PATH="/usr/local/sbin/beszel-agent" | |
| else | |
| AGENT_DIR="/opt/beszel-agent" | |
| BIN_DIR="/opt/beszel-agent" | |
| BIN_PATH="/opt/beszel-agent/beszel-agent" | |
| fi | |
| # Stop existing service if it exists (for upgrades) | |
| if [ "$UNINSTALL" != true ] && [ -f "$BIN_PATH" ]; then | |
| echo "Existing installation detected. Stopping service for upgrade..." | |
| if is_alpine; then | |
| rc-service beszel-agent stop 2>/dev/null || true | |
| elif is_openwrt; then | |
| /etc/init.d/beszel-agent stop 2>/dev/null || true | |
| elif is_freebsd; then | |
| service beszel-agent stop 2>/dev/null || true | |
| else | |
| systemctl stop beszel-agent.service 2>/dev/null || true | |
| fi | |
| fi | |
| # Uninstall process | |
| if [ "$UNINSTALL" = true ]; then | |
| # Clean up SELinux contexts before removing files | |
| cleanup_selinux_context | |
| if is_alpine; then | |
| echo "Stopping and disabling the agent service..." | |
| rc-service beszel-agent stop | |
| rc-update del beszel-agent default | |
| echo "Removing the OpenRC service files..." | |
| rm -f /etc/init.d/beszel-agent | |
| # Remove the daily update cron job if it exists | |
| echo "Removing the daily update cron job..." | |
| if crontab -u root -l 2>/dev/null | grep -q "beszel-agent.*update"; then | |
| crontab -u root -l 2>/dev/null | grep -v "beszel-agent.*update" | crontab -u root - | |
| fi | |
| # Remove log files | |
| echo "Removing log files..." | |
| rm -f /var/log/beszel-agent.log /var/log/beszel-agent.err | |
| elif is_openwrt; then | |
| echo "Stopping and disabling the agent service..." | |
| /etc/init.d/beszel-agent stop | |
| /etc/init.d/beszel-agent disable | |
| echo "Removing the OpenWRT service files..." | |
| rm -f /etc/init.d/beszel-agent | |
| # Remove the update service if it exists | |
| echo "Removing the daily update service..." | |
| # Remove legacy beszel account based crontab file | |
| rm -f /etc/crontabs/beszel | |
| # Install root crontab job | |
| if crontab -u root -l 2>/dev/null | grep -q "beszel-agent.*update"; then | |
| crontab -u root -l 2>/dev/null | grep -v "beszel-agent.*update" | crontab -u root - | |
| fi | |
| elif is_freebsd; then | |
| echo "Stopping and disabling the agent service..." | |
| service beszel-agent stop | |
| sysrc beszel_agent_enable="NO" | |
| echo "Removing the FreeBSD service files..." | |
| rm -f /usr/local/etc/rc.d/beszel-agent | |
| # Remove the daily update cron job if it exists | |
| echo "Removing the daily update cron job..." | |
| rm -f /etc/cron.d/beszel-agent | |
| # Remove log files | |
| echo "Removing log files..." | |
| rm -f /var/log/beszel-agent.log | |
| # Remove env file and directories | |
| echo "Removing environment configuration file..." | |
| rm -f "$AGENT_DIR/env" | |
| rm -f "$BIN_PATH" | |
| rmdir "$AGENT_DIR" 2>/dev/null || true | |
| else | |
| echo "Stopping and disabling the agent service..." | |
| systemctl stop beszel-agent.service | |
| systemctl disable beszel-agent.service >/dev/null 2>&1 | |
| echo "Removing the systemd service file..." | |
| rm /etc/systemd/system/beszel-agent.service | |
| # Remove the update timer and service if they exist | |
| echo "Removing the daily update service and timer..." | |
| systemctl stop beszel-agent-update.timer 2>/dev/null | |
| systemctl disable beszel-agent-update.timer >/dev/null 2>&1 | |
| rm -f /etc/systemd/system/beszel-agent-update.service | |
| rm -f /etc/systemd/system/beszel-agent-update.timer | |
| systemctl daemon-reload | |
| fi | |
| echo "Removing the Beszel Agent directory..." | |
| rm -rf "$AGENT_DIR" | |
| echo "Removing the dedicated user for the agent service..." | |
| killall beszel-agent 2>/dev/null | |
| if is_alpine || is_openwrt; then | |
| deluser beszel 2>/dev/null | |
| elif is_freebsd; then | |
| pw user del beszel 2>/dev/null | |
| else | |
| userdel beszel 2>/dev/null | |
| fi | |
| echo "Beszel Agent has been uninstalled successfully!" | |
| exit 0 | |
| fi | |
| # Check if a package is installed | |
| package_installed() { | |
| command -v "$1" >/dev/null 2>&1 | |
| } | |
| # Check for package manager and install necessary packages if not installed | |
| if package_installed apk; then | |
| if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then | |
| apk update | |
| apk add tar curl coreutils shadow | |
| fi | |
| elif package_installed opkg; then | |
| if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then | |
| opkg update | |
| opkg install tar curl coreutils | |
| fi | |
| elif package_installed pkg && is_freebsd; then | |
| if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then | |
| pkg update | |
| pkg install -y gtar curl coreutils | |
| fi | |
| elif package_installed apt-get; then | |
| if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then | |
| apt-get update | |
| apt-get install -y tar curl coreutils | |
| fi | |
| elif package_installed yum; then | |
| if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then | |
| yum install -y tar curl coreutils | |
| fi | |
| elif package_installed pacman; then | |
| if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then | |
| pacman -Sy --noconfirm tar curl coreutils | |
| fi | |
| else | |
| echo "Warning: Please ensure 'tar' and 'curl' and 'sha256sum (coreutils)' are installed." | |
| fi | |
| # If no SSH key is provided, ask for the SSH key interactively (skip if upgrading) | |
| if [ -z "$KEY" ]; then | |
| if [ -f "$BIN_PATH" ]; then | |
| echo "Upgrading existing installation. Using existing service configuration." | |
| else | |
| printf "Enter your SSH key: " | |
| read KEY | |
| fi | |
| fi | |
| # Remove newlines from KEY | |
| KEY=$(echo "$KEY" | tr -d '\n') | |
| # TOKEN and HUB_URL are optional for backwards compatibility - no interactive prompts | |
| # They will be set as empty environment variables if not provided | |
| # Verify checksum | |
| if command -v sha256sum >/dev/null; then | |
| CHECK_CMD="sha256sum" | |
| elif command -v sha256 >/dev/null; then | |
| # FreeBSD uses 'sha256' instead of 'sha256sum', with different output format | |
| CHECK_CMD="sha256 -q" | |
| else | |
| echo "No SHA256 checksum utility found" | |
| exit 1 | |
| fi | |
| # Create a dedicated user for the service if it doesn't exist | |
| AGENT_USER="beszel" | |
| echo "Configuring the dedicated user for the Beszel Agent service..." | |
| if is_alpine; then | |
| if ! id -u beszel >/dev/null 2>&1; then | |
| addgroup beszel | |
| adduser -S -D -H -s /sbin/nologin -G beszel beszel | |
| fi | |
| # Add the user to the docker group to allow access to the Docker socket if group docker exists | |
| if getent group docker >/dev/null 2>&1; then | |
| echo "Adding beszel to docker group" | |
| addgroup beszel docker | |
| fi | |
| elif is_openwrt; then | |
| # Create beszel group first if it doesn't exist (check /etc/group directly) | |
| if ! grep -q "^beszel:" /etc/group >/dev/null 2>&1; then | |
| echo "beszel:x:999:" >> /etc/group | |
| fi | |
| # Create beszel user if it doesn't exist (double-check to prevent duplicates) | |
| if ! id -u beszel >/dev/null 2>&1 && ! grep -q "^beszel:" /etc/passwd >/dev/null 2>&1; then | |
| echo "beszel:x:999:999::/nonexistent:/bin/false" >> /etc/passwd | |
| fi | |
| # Add the user to the docker group if docker group exists and user is not already in it | |
| if grep -q "^docker:" /etc/group >/dev/null 2>&1; then | |
| echo "Adding beszel to docker group" | |
| # Check if beszel is already in docker group | |
| if ! grep "^docker:" /etc/group | grep -q "beszel"; then | |
| # Add beszel to docker group by modifying /etc/group | |
| # Handle both cases: group with existing members and group without members | |
| if grep "^docker:" /etc/group | grep -q ":.*:.*$"; then | |
| # Group has existing members, append with comma | |
| sed -i 's/^docker:\([^:]*:[^:]*:\)\(.*\)$/docker:\1\2,beszel/' /etc/group | |
| else | |
| # Group has no members, just append | |
| sed -i 's/^docker:\([^:]*:[^:]*:\)$/docker:\1beszel/' /etc/group | |
| fi | |
| fi | |
| fi | |
| elif is_freebsd; then | |
| if is_opnsense; then | |
| echo "OPNsense detected: skipping user creation (using daemon user instead)" | |
| AGENT_USER="daemon" | |
| else | |
| if ! id -u beszel >/dev/null 2>&1; then | |
| pw user add beszel -d /nonexistent -s /usr/sbin/nologin -c "beszel user" | |
| fi | |
| # Add the user to the wheel group to allow self-updates | |
| if pw group show wheel >/dev/null 2>&1; then | |
| echo "Adding beszel to wheel group for self-updates" | |
| pw group mod wheel -m beszel | |
| fi | |
| fi | |
| else | |
| if ! id -u beszel >/dev/null 2>&1; then | |
| useradd --system --home-dir /nonexistent --shell /bin/false beszel | |
| fi | |
| # Add the user to the docker group to allow access to the Docker socket if group docker exists | |
| if getent group docker >/dev/null 2>&1; then | |
| echo "Adding beszel to docker group" | |
| usermod -aG docker beszel | |
| fi | |
| # Add the user to the disk group to allow access to disk devices if group disk exists | |
| if getent group disk >/dev/null 2>&1; then | |
| echo "Adding beszel to disk group" | |
| usermod -aG disk beszel | |
| fi | |
| fi | |
| # Create the directory for the Beszel Agent | |
| if [ ! -d "$AGENT_DIR" ]; then | |
| echo "Creating the directory for the Beszel Agent..." | |
| mkdir -p "$AGENT_DIR" | |
| chown "${AGENT_USER}:${AGENT_USER}" "$AGENT_DIR" | |
| chmod 755 "$AGENT_DIR" | |
| fi | |
| if [ ! -d "$BIN_DIR" ]; then | |
| mkdir -p "$BIN_DIR" | |
| fi | |
| # Download and install the Beszel Agent | |
| OS=$(uname -s | sed -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/') | |
| ARCH=$(detect_architecture) | |
| FILE_NAME="beszel-agent_${OS}_${ARCH}.tar.gz" | |
| if [ "$OS" = "linux" ] && [ "$ARCH" = "amd64" ] && is_glibc; then | |
| FILE_NAME="beszel-agent_${OS}_${ARCH}_glibc.tar.gz" | |
| fi | |
| # Determine version to install | |
| if [ "$VERSION" = "latest" ]; then | |
| INSTALL_VERSION=$(curl -s "https://get.beszel.dev/latest-version") | |
| if [ -z "$INSTALL_VERSION" ]; then | |
| # Fallback to GitHub API | |
| API_RELEASE_URL="https://api.github.com/repos/henrygd/beszel/releases/latest" | |
| INSTALL_VERSION=$(curl -s "$API_RELEASE_URL" | grep -o '"tag_name": "v[^"]*"' | cut -d'"' -f4 | tr -d 'v') | |
| fi | |
| if [ -z "$INSTALL_VERSION" ]; then | |
| echo "Failed to get latest version" | |
| exit 1 | |
| fi | |
| else | |
| INSTALL_VERSION="$VERSION" | |
| # Remove 'v' prefix if present | |
| INSTALL_VERSION=$(echo "$INSTALL_VERSION" | sed 's/^v//') | |
| fi | |
| echo "Downloading beszel-agent v${INSTALL_VERSION}..." | |
| # Download checksums file | |
| TEMP_DIR=$(mktemp -d) | |
| cd "$TEMP_DIR" || exit 1 | |
| CHECKSUM=$(curl -fsSL "$GITHUB_URL/henrygd/beszel/releases/download/v${INSTALL_VERSION}/beszel_${INSTALL_VERSION}_checksums.txt" | grep "$FILE_NAME" | cut -d' ' -f1) | |
| if [ -z "$CHECKSUM" ] || ! echo "$CHECKSUM" | grep -qE "^[a-fA-F0-9]{64}$"; then | |
| echo "Failed to get checksum or invalid checksum format" | |
| echo "Try again with --mirror (or --mirror <url>) if GitHub is not reachable." | |
| rm -rf "$TEMP_DIR" | |
| exit 1 | |
| fi | |
| if ! curl -fL# --retry 3 --retry-delay 2 --connect-timeout 10 "$GITHUB_URL/henrygd/beszel/releases/download/v${INSTALL_VERSION}/$FILE_NAME" -o "$FILE_NAME"; then | |
| echo "Failed to download the agent from $GITHUB_URL/henrygd/beszel/releases/download/v${INSTALL_VERSION}/$FILE_NAME" | |
| echo "Try again with --mirror (or --mirror <url>) if GitHub is not reachable." | |
| rm -rf "$TEMP_DIR" | |
| exit 1 | |
| fi | |
| if ! tar -tzf "$FILE_NAME" >/dev/null 2>&1; then | |
| echo "Downloaded archive is invalid or incomplete (possible network/proxy issue)." | |
| echo "Try again with --mirror (or --mirror <url>) if the download path is unstable." | |
| rm -rf "$TEMP_DIR" | |
| exit 1 | |
| fi | |
| if [ "$($CHECK_CMD "$FILE_NAME" | cut -d' ' -f1)" != "$CHECKSUM" ]; then | |
| echo "Checksum verification failed: $($CHECK_CMD "$FILE_NAME" | cut -d' ' -f1) & $CHECKSUM" | |
| rm -rf "$TEMP_DIR" | |
| exit 1 | |
| fi | |
| if ! tar -xzf "$FILE_NAME" beszel-agent; then | |
| echo "Failed to extract the agent" | |
| rm -rf "$TEMP_DIR" | |
| exit 1 | |
| fi | |
| if [ ! -s "$TEMP_DIR/beszel-agent" ]; then | |
| echo "Downloaded binary is missing or empty." | |
| rm -rf "$TEMP_DIR" | |
| exit 1 | |
| fi | |
| if [ -f "$BIN_PATH" ]; then | |
| echo "Backing up existing binary..." | |
| cp "$BIN_PATH" "$BIN_PATH.bak" | |
| fi | |
| mv beszel-agent "$BIN_PATH" | |
| chown beszel:beszel "$BIN_PATH" | |
| chmod 755 "$BIN_PATH" | |
| # Set SELinux context if needed | |
| set_selinux_context | |
| # Cleanup | |
| rm -rf "$TEMP_DIR" | |
| # Make sure /etc/machine-id exists for persistent fingerprint | |
| if [ ! -f /etc/machine-id ]; then | |
| cat /proc/sys/kernel/random/uuid | tr -d '-' > /etc/machine-id | |
| fi | |
| # Check for NVIDIA GPUs and grant device permissions for systemd service | |
| detect_nvidia_devices() { | |
| local devices="" | |
| for i in /dev/nvidia*; do | |
| if [ -e "$i" ]; then | |
| devices="${devices}DeviceAllow=$i rw\n" | |
| fi | |
| done | |
| echo "$devices" | |
| } | |
| # Modify service installation part, add Alpine check before systemd service creation | |
| if is_alpine; then | |
| if [ ! -f /etc/init.d/beszel-agent ]; then | |
| echo "Creating OpenRC service for Alpine Linux..." | |
| cat >/etc/init.d/beszel-agent <<EOF | |
| #!/sbin/openrc-run | |
| name="beszel-agent" | |
| description="Beszel Agent Service" | |
| command="$BIN_PATH" | |
| command_user="beszel" | |
| command_background="yes" | |
| pidfile="/run/\${RC_SVCNAME}.pid" | |
| output_log="/var/log/beszel-agent.log" | |
| error_log="/var/log/beszel-agent.err" | |
| start_pre() { | |
| checkpath -f -m 0644 -o beszel:beszel "\$output_log" "\$error_log" | |
| } | |
| export PORT="$PORT" | |
| export KEY="$KEY" | |
| export TOKEN="$TOKEN" | |
| export HUB_URL="$HUB_URL" | |
| depend() { | |
| need net | |
| after firewall | |
| } | |
| EOF | |
| chmod +x /etc/init.d/beszel-agent | |
| rc-update add beszel-agent default | |
| else | |
| echo "Alpine OpenRC service file already exists. Skipping creation." | |
| fi | |
| # Create log files with proper permissions | |
| touch /var/log/beszel-agent.log /var/log/beszel-agent.err | |
| chown beszel:beszel /var/log/beszel-agent.log /var/log/beszel-agent.err | |
| # Start the service | |
| rc-service beszel-agent restart | |
| # Check if service started successfully | |
| sleep 2 | |
| if ! rc-service beszel-agent status | grep -q "started"; then | |
| echo "Error: The Beszel Agent service failed to start. Checking logs..." | |
| tail -n 20 /var/log/beszel-agent.err | |
| exit 1 | |
| fi | |
| # Auto-update service for Alpine | |
| if [ "$AUTO_UPDATE_FLAG" = "true" ]; then | |
| AUTO_UPDATE="y" | |
| elif [ "$AUTO_UPDATE_FLAG" = "false" ]; then | |
| AUTO_UPDATE="n" | |
| else | |
| printf "\nEnable automatic daily updates for beszel-agent? (y/n): " | |
| read AUTO_UPDATE | |
| fi | |
| case "$AUTO_UPDATE" in | |
| [Yy]*) | |
| echo "Setting up daily automatic updates for beszel-agent..." | |
| # Create cron job to run beszel-agent update command daily at midnight | |
| if ! crontab -u root -l 2>/dev/null | grep -q "beszel-agent.*update"; then | |
| (crontab -u root -l 2>/dev/null; echo "12 0 * * * $BIN_PATH update >/dev/null 2>&1") | crontab -u root - | |
| fi | |
| printf "\nDaily updates have been enabled via cron job.\n" | |
| ;; | |
| esac | |
| # Check service status | |
| if ! rc-service beszel-agent status >/dev/null 2>&1; then | |
| echo "Error: The Beszel Agent service is not running." | |
| rc-service beszel-agent status | |
| exit 1 | |
| fi | |
| elif is_openwrt; then | |
| if [ ! -f /etc/init.d/beszel-agent ]; then | |
| echo "Creating procd init script service for OpenWRT..." | |
| cat >/etc/init.d/beszel-agent <<EOF | |
| #!/bin/sh /etc/rc.common | |
| USE_PROCD=1 | |
| START=99 | |
| start_service() { | |
| procd_open_instance | |
| procd_set_param command $BIN_PATH | |
| procd_set_param user beszel | |
| procd_set_param pidfile /var/run/beszel-agent.pid | |
| procd_set_param env PORT="$PORT" KEY="$KEY" TOKEN="$TOKEN" HUB_URL="$HUB_URL" | |
| procd_set_param respawn | |
| procd_set_param stdout 1 | |
| procd_set_param stderr 1 | |
| procd_close_instance | |
| } | |
| # Extra command to trigger agent update | |
| EXTRA_COMMANDS="update restart" | |
| EXTRA_HELP=" update Update the Beszel agent | |
| restart Restart the Beszel agent" | |
| update() { | |
| $BIN_PATH update | |
| } | |
| EOF | |
| # Enable the service | |
| chmod +x /etc/init.d/beszel-agent | |
| /etc/init.d/beszel-agent enable | |
| else | |
| echo "OpenWRT init script already exists. Skipping creation." | |
| fi | |
| # Start the service | |
| /etc/init.d/beszel-agent restart | |
| # Auto-update service for OpenWRT using a crontab job | |
| if [ "$AUTO_UPDATE_FLAG" = "true" ]; then | |
| AUTO_UPDATE="y" | |
| sleep 1 # give time for the service to start | |
| elif [ "$AUTO_UPDATE_FLAG" = "false" ]; then | |
| AUTO_UPDATE="n" | |
| sleep 1 # give time for the service to start | |
| else | |
| printf "\nEnable automatic daily updates for beszel-agent? (y/n): " | |
| read AUTO_UPDATE | |
| fi | |
| case "$AUTO_UPDATE" in | |
| [Yy]*) | |
| echo "Setting up daily automatic updates for beszel-agent..." | |
| if ! crontab -u root -l 2>/dev/null | grep -q "beszel-agent.*update"; then | |
| (crontab -u root -l 2>/dev/null; echo "12 0 * * * /etc/init.d/beszel-agent update") | crontab -u root - | |
| fi | |
| /etc/init.d/cron restart | |
| printf "\nDaily updates have been enabled.\n" | |
| ;; | |
| esac | |
| # Check service status | |
| if ! /etc/init.d/beszel-agent running >/dev/null 2>&1; then | |
| echo "Error: The Beszel Agent service is not running." | |
| /etc/init.d/beszel-agent status | |
| exit 1 | |
| fi | |
| elif is_freebsd; then | |
| echo "Checking for existing FreeBSD service configuration..." | |
| # Ensure rc.d directory exists on minimal FreeBSD installs | |
| mkdir -p /usr/local/etc/rc.d | |
| # Create environment configuration file with proper permissions if it doesn't exist | |
| if [ ! -f "$AGENT_DIR/env" ]; then | |
| echo "Creating environment configuration file..." | |
| cat >"$AGENT_DIR/env" <<EOF | |
| LISTEN=$PORT | |
| KEY="$KEY" | |
| TOKEN=$TOKEN | |
| HUB_URL=$HUB_URL | |
| EOF | |
| chmod 640 "$AGENT_DIR/env" | |
| chown "root:${AGENT_USER}" "$AGENT_DIR/env" | |
| else | |
| echo "FreeBSD environment file already exists. Skipping creation." | |
| fi | |
| # Create the rc service file if it doesn't exist | |
| if [ ! -f /usr/local/etc/rc.d/beszel-agent ]; then | |
| echo "Creating FreeBSD rc service..." | |
| generate_freebsd_rc_service > /usr/local/etc/rc.d/beszel-agent | |
| # Set proper permissions for the rc script | |
| chmod 755 /usr/local/etc/rc.d/beszel-agent | |
| else | |
| echo "FreeBSD rc service file already exists. Skipping creation." | |
| fi | |
| # Enable and start the service | |
| echo "Enabling and starting the agent service..." | |
| sysrc beszel_agent_enable="YES" | |
| sysrc beszel_agent_user="${AGENT_USER}" | |
| service beszel-agent restart | |
| # Check if service started successfully | |
| sleep 2 | |
| if ! service beszel-agent status | grep -q "is running"; then | |
| echo "Error: The Beszel Agent service failed to start. Checking logs..." | |
| tail -n 20 /var/log/beszel_agent.log | |
| exit 1 | |
| fi | |
| # Auto-update service for FreeBSD | |
| if [ "$AUTO_UPDATE_FLAG" = "true" ]; then | |
| AUTO_UPDATE="y" | |
| elif [ "$AUTO_UPDATE_FLAG" = "false" ]; then | |
| AUTO_UPDATE="n" | |
| else | |
| printf "\nEnable automatic daily updates for beszel-agent? (y/n): " | |
| read AUTO_UPDATE | |
| fi | |
| case "$AUTO_UPDATE" in | |
| [Yy]*) | |
| echo "Setting up daily automatic updates for beszel-agent..." | |
| # Create cron job in /etc/cron.d | |
| cat >/etc/cron.d/beszel-agent <<EOF | |
| # Beszel Agent daily update job | |
| 12 0 * * * root $BIN_PATH update >/dev/null 2>&1 | |
| EOF | |
| chmod 644 /etc/cron.d/beszel-agent | |
| printf "\nDaily updates have been enabled via /etc/cron.d.\n" | |
| ;; | |
| esac | |
| # Check service status | |
| if ! service beszel-agent status >/dev/null 2>&1; then | |
| echo "Error: The Beszel Agent service is not running." | |
| service beszel-agent status | |
| exit 1 | |
| fi | |
| else | |
| # Original systemd service installation code | |
| if [ ! -f /etc/systemd/system/beszel-agent.service ]; then | |
| echo "Creating the systemd service for the agent..." | |
| # Detect NVIDIA devices and grant device permissions | |
| NVIDIA_DEVICES=$(detect_nvidia_devices) | |
| cat >/etc/systemd/system/beszel-agent.service <<EOF | |
| [Unit] | |
| Description=Beszel Agent Service | |
| Wants=network-online.target | |
| After=network-online.target | |
| [Service] | |
| Environment="PORT=$PORT" | |
| Environment="KEY=$KEY" | |
| Environment="TOKEN=$TOKEN" | |
| Environment="HUB_URL=$HUB_URL" | |
| # Environment="EXTRA_FILESYSTEMS=sdb" | |
| ExecStart=$BIN_PATH | |
| User=beszel | |
| Restart=on-failure | |
| RestartSec=5 | |
| StateDirectory=beszel-agent | |
| # Security/sandboxing settings | |
| KeyringMode=private | |
| LockPersonality=yes | |
| ProtectClock=yes | |
| ProtectHome=read-only | |
| ProtectHostname=yes | |
| ProtectKernelLogs=yes | |
| ProtectSystem=strict | |
| RemoveIPC=yes | |
| RestrictSUIDSGID=true | |
| $(if [ -n "$NVIDIA_DEVICES" ]; then printf "%b" "# NVIDIA device permissions\n${NVIDIA_DEVICES}"; fi) | |
| [Install] | |
| WantedBy=multi-user.target | |
| EOF | |
| else | |
| echo "Systemd service file already exists. Skipping creation." | |
| fi | |
| # Load and start the service | |
| printf "\nLoading and starting the agent service...\n" | |
| systemctl daemon-reload | |
| systemctl enable beszel-agent.service >/dev/null 2>&1 | |
| systemctl restart beszel-agent.service | |
| # Prompt for auto-update setup | |
| if [ "$AUTO_UPDATE_FLAG" = "true" ]; then | |
| AUTO_UPDATE="y" | |
| sleep 1 # give time for the service to start | |
| elif [ "$AUTO_UPDATE_FLAG" = "false" ]; then | |
| AUTO_UPDATE="n" | |
| sleep 1 # give time for the service to start | |
| else | |
| printf "\nEnable automatic daily updates for beszel-agent? (y/n): " | |
| read AUTO_UPDATE | |
| fi | |
| case "$AUTO_UPDATE" in | |
| [Yy]*) | |
| echo "Setting up daily automatic updates for beszel-agent..." | |
| # Create systemd service for the daily update | |
| cat >/etc/systemd/system/beszel-agent-update.service <<EOF | |
| [Unit] | |
| Description=Update beszel-agent if needed | |
| Wants=beszel-agent.service | |
| [Service] | |
| Type=oneshot | |
| ExecStart=$BIN_PATH update | |
| EOF | |
| # Create systemd timer for the daily update | |
| cat >/etc/systemd/system/beszel-agent-update.timer <<EOF | |
| [Unit] | |
| Description=Run beszel-agent update daily | |
| [Timer] | |
| OnCalendar=daily | |
| Persistent=true | |
| RandomizedDelaySec=4h | |
| [Install] | |
| WantedBy=timers.target | |
| EOF | |
| systemctl daemon-reload | |
| systemctl enable --now beszel-agent-update.timer >/dev/null 2>&1 | |
| printf "\nDaily updates have been enabled.\n" | |
| ;; | |
| esac | |
| # Wait for the service to start or fail | |
| if [ "$(systemctl is-active beszel-agent.service)" != "active" ]; then | |
| echo "Error: The Beszel Agent service is not running." | |
| echo "$(systemctl status beszel-agent.service)" | |
| exit 1 | |
| fi | |
| fi | |
| printf "\n\033[32mBeszel Agent has been installed successfully! It is now running on $PORT.\033[0m\n" | |