beszel-install-agent.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. #!/bin/sh
  2. # Move is_alpine function to the top of the file
  3. is_alpine() {
  4. [ -f /etc/alpine-release ]
  5. }
  6. add_autoupdate_service() {
  7. echo "Setting up daily automatic updates for beszel-agent..."
  8. # Create systemd service for the daily update
  9. cat >/etc/systemd/system/beszel-agent-update.service <<EOF
  10. [Unit]
  11. Description=Update beszel-agent if needed
  12. Wants=beszel-agent.service
  13. [Service]
  14. Type=oneshot
  15. ExecStart=/bin/sh -c '/opt/beszel-agent/beszel-agent update | grep -q "Successfully updated" && systemctl restart beszel-agent'
  16. EOF
  17. # Create systemd timer for the daily update
  18. cat >/etc/systemd/system/beszel-agent-update.timer <<EOF
  19. [Unit]
  20. Description=Run beszel-agent update daily
  21. [Timer]
  22. OnCalendar=daily
  23. Persistent=true
  24. RandomizedDelaySec=4h
  25. [Install]
  26. WantedBy=timers.target
  27. EOF
  28. systemctl daemon-reload
  29. systemctl enable --now beszel-agent-update.timer
  30. printf "\nAutomatic daily updates have been enabled.\n"
  31. }
  32. version=0.0.1
  33. # Define default values
  34. PORT=45876
  35. UNINSTALL=false
  36. CHINA_MAINLAND=false
  37. GITHUB_URL="https://github.com"
  38. GITHUB_API_URL="https://api.github.com"
  39. KEY=""
  40. # Check for help flag first
  41. case "$1" in
  42. -h | --help)
  43. printf "Beszel Agent installation script\n\n"
  44. printf "Usage: ./install-agent.sh [options]\n\n"
  45. printf "Options: \n"
  46. printf " -k : SSH key (required, or interactive if not provided)\n"
  47. printf " -p : Port (default: $PORT)\n"
  48. printf " -u : Uninstall Beszel Agent\n"
  49. printf " -a : set daily auto-update agent binary\n"
  50. printf " --china-mirrors : Using GitHub mirror sources to resolve network timeout issues in mainland China\n"
  51. printf " -h, --help : Display this help message\n"
  52. exit 0
  53. ;;
  54. esac
  55. # Build sudo args by properly quoting everything
  56. build_sudo_args() {
  57. QUOTED_ARGS=""
  58. while [ $# -gt 0 ]; do
  59. if [ -n "$QUOTED_ARGS" ]; then
  60. QUOTED_ARGS="$QUOTED_ARGS "
  61. fi
  62. QUOTED_ARGS="$QUOTED_ARGS'$(echo "$1" | sed "s/'/'\\\\''/g")'"
  63. shift
  64. done
  65. echo "$QUOTED_ARGS"
  66. }
  67. # Check if running as root and re-execute with sudo if needed
  68. if [ "$(id -u)" != "0" ]; then
  69. if command -v sudo >/dev/null 2>&1; then
  70. SUDO_ARGS=$(build_sudo_args "$@")
  71. eval "exec sudo $0 $SUDO_ARGS"
  72. else
  73. echo "This script must be run as root. Please either:"
  74. echo "1. Run this script as root (su root)"
  75. echo "2. Install sudo and run with sudo"
  76. exit 1
  77. fi
  78. fi
  79. # Parse arguments
  80. while [ $# -gt 0 ]; do
  81. case "$1" in
  82. -k)
  83. shift
  84. KEY="$1"
  85. ;;
  86. -p)
  87. shift
  88. PORT="$1"
  89. ;;
  90. -u)
  91. UNINSTALL=true
  92. ;;
  93. --china-mirrors)
  94. CHINA_MAINLAND=true
  95. ;;
  96. -a)
  97. AUTO_UPDATE=true
  98. ;;
  99. *)
  100. echo "Invalid option: $1" >&2
  101. exit 1
  102. ;;
  103. esac
  104. shift
  105. done
  106. # Uninstall process
  107. if [ "$UNINSTALL" = true ]; then
  108. if is_alpine; then
  109. echo "Stopping and disabling the agent service..."
  110. rc-service beszel-agent stop
  111. rc-update del beszel-agent default
  112. echo "Removing the OpenRC service files..."
  113. rm -f /etc/init.d/beszel-agent
  114. # Remove the update service if it exists
  115. echo "Removing the daily update service..."
  116. rc-service beszel-agent-update stop 2>/dev/null
  117. rc-update del beszel-agent-update default 2>/dev/null
  118. rm -f /etc/init.d/beszel-agent-update
  119. # Remove log files
  120. echo "Removing log files..."
  121. rm -f /var/log/beszel-agent.log /var/log/beszel-agent.err
  122. else
  123. echo "Stopping and disabling the agent service..."
  124. systemctl stop beszel-agent.service
  125. systemctl disable beszel-agent.service
  126. echo "Removing the systemd service file..."
  127. rm /etc/systemd/system/beszel-agent.service
  128. # Remove the update timer and service if they exist
  129. echo "Removing the daily update service and timer..."
  130. systemctl stop beszel-agent-update.timer 2>/dev/null
  131. systemctl disable beszel-agent-update.timer 2>/dev/null
  132. rm -f /etc/systemd/system/beszel-agent-update.service
  133. rm -f /etc/systemd/system/beszel-agent-update.timer
  134. systemctl daemon-reload
  135. fi
  136. echo "Removing the Beszel Agent directory..."
  137. rm -rf /opt/beszel-agent
  138. echo "Removing the dedicated user for the agent service..."
  139. killall beszel-agent 2>/dev/null
  140. if is_alpine; then
  141. deluser beszel 2>/dev/null
  142. else
  143. userdel beszel 2>/dev/null
  144. fi
  145. echo "Beszel Agent has been uninstalled successfully!"
  146. exit 0
  147. fi
  148. if [ "$CHINA_MAINLAND" = true ]; then
  149. printf "\nConfirmed to use GitHub mirrors (ghp.ci) for download beszel-agent?\nThis helps to install Agent properly in mainland China. (Y/n): "
  150. read USE_MIRROR
  151. USE_MIRROR=${USE_MIRROR:-Y}
  152. if [ "$USE_MIRROR" = "Y" ] || [ "$USE_MIRROR" = "y" ]; then
  153. GITHUB_URL="https://ghp.ci/https://github.com"
  154. # In China, only github.com is blocked, while api.github.com is not (for now).
  155. # GITHUB_API_URL="https://api.github.com"
  156. echo "Using GitHub Mirror for downloads..."
  157. else
  158. echo "GitHub mirrors will not be used for installation."
  159. fi
  160. fi
  161. # Function to check if a package is installed
  162. package_installed() {
  163. command -v "$1" >/dev/null 2>&1
  164. }
  165. # Check for package manager and install necessary packages if not installed
  166. if is_alpine; then
  167. if ! package_installed tar || ! package_installed curl || ! package_installed coreutils; then
  168. apk update
  169. apk add tar curl coreutils shadow
  170. fi
  171. elif package_installed apt-get; then
  172. if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then
  173. apt-get update
  174. apt-get install -y tar curl coreutils
  175. fi
  176. elif package_installed yum; then
  177. if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then
  178. yum install -y tar curl coreutils
  179. fi
  180. elif package_installed pacman; then
  181. if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then
  182. pacman -Sy --noconfirm tar curl coreutils
  183. fi
  184. else
  185. echo "Warning: Please ensure 'tar' and 'curl' and 'sha256sum (coreutils)' are installed."
  186. fi
  187. # If no SSH key is provided, ask for the SSH key interactively
  188. if [ -z "$KEY" ]; then
  189. printf "Enter your SSH key: "
  190. read KEY
  191. fi
  192. # Verify checksum
  193. if command -v sha256sum >/dev/null; then
  194. CHECK_CMD="sha256sum"
  195. elif command -v md5 >/dev/null; then
  196. CHECK_CMD="md5 -q"
  197. else
  198. echo "No MD5 checksum utility found"
  199. exit 1
  200. fi
  201. # Create a dedicated user for the service if it doesn't exist
  202. if is_alpine; then
  203. if ! id -u beszel >/dev/null 2>&1; then
  204. echo "Creating a dedicated user for the Beszel Agent service..."
  205. adduser -D -H -s /sbin/nologin beszel
  206. fi
  207. # Add the user to the docker group to allow access to the Docker socket
  208. addgroup beszel docker
  209. else
  210. if ! id -u beszel >/dev/null 2>&1; then
  211. echo "Creating a dedicated user for the Beszel Agent service..."
  212. useradd -M -s /bin/false beszel
  213. fi
  214. # Add the user to the docker group to allow access to the Docker socket
  215. usermod -aG docker beszel
  216. fi
  217. # Create the directory for the Beszel Agent
  218. if [ ! -d "/opt/beszel-agent" ]; then
  219. echo "Creating the directory for the Beszel Agent..."
  220. mkdir -p /opt/beszel-agent
  221. chown beszel:beszel /opt/beszel-agent
  222. chmod 755 /opt/beszel-agent
  223. fi
  224. # Download and install the Beszel Agent
  225. echo "Downloading and installing the agent..."
  226. OS=$(uname -s | tr '[:upper:]' '[:lower:]')
  227. ARCH=$(uname -m | sed -e 's/x86_64/amd64/' -e 's/armv6l/arm/' -e 's/armv7l/arm/' -e 's/aarch64/arm64/')
  228. FILE_NAME="beszel-agent_${OS}_${ARCH}.tar.gz"
  229. LATEST_VERSION=$(curl -s "$GITHUB_API_URL""/repos/henrygd/beszel/releases/latest" | grep -o '"tag_name": "v[^"]*"' | cut -d'"' -f4 | tr -d 'v')
  230. if [ -z "$LATEST_VERSION" ]; then
  231. echo "Failed to get latest version"
  232. exit 1
  233. fi
  234. echo "Downloading and installing agent version ${LATEST_VERSION} from ${GITHUB_URL} ..."
  235. # Download checksums file
  236. TEMP_DIR=$(mktemp -d)
  237. cd "$TEMP_DIR" || exit 1
  238. CHECKSUM=$(curl -sL "$GITHUB_URL/henrygd/beszel/releases/download/v${LATEST_VERSION}/beszel_${LATEST_VERSION}_checksums.txt" | grep "$FILE_NAME" | cut -d' ' -f1)
  239. if [ -z "$CHECKSUM" ] || ! echo "$CHECKSUM" | grep -qE "^[a-fA-F0-9]{64}$"; then
  240. echo "Failed to get checksum or invalid checksum format"
  241. exit 1
  242. fi
  243. if ! curl -#L "$GITHUB_URL/henrygd/beszel/releases/download/v${LATEST_VERSION}/$FILE_NAME" -o "$FILE_NAME"; then
  244. echo "Failed to download the agent from ""$GITHUB_URL/henrygd/beszel/releases/download/v${LATEST_VERSION}/$FILE_NAME"
  245. rm -rf "$TEMP_DIR"
  246. exit 1
  247. fi
  248. if [ "$($CHECK_CMD "$FILE_NAME" | cut -d' ' -f1)" != "$CHECKSUM" ]; then
  249. echo "Checksum verification failed: $($CHECK_CMD "$FILE_NAME" | cut -d' ' -f1) & $CHECKSUM"
  250. rm -rf "$TEMP_DIR"
  251. exit 1
  252. fi
  253. if ! tar -xzf "$FILE_NAME" beszel-agent; then
  254. echo "Failed to extract the agent"
  255. rm -rf "$TEMP_DIR"
  256. exit 1
  257. fi
  258. mv beszel-agent /opt/beszel-agent/beszel-agent
  259. chown beszel:beszel /opt/beszel-agent/beszel-agent
  260. chmod 755 /opt/beszel-agent/beszel-agent
  261. # Cleanup
  262. rm -rf "$TEMP_DIR"
  263. # Modify service installation part, add Alpine check before systemd service creation
  264. if is_alpine; then
  265. echo "Creating OpenRC service for Alpine Linux..."
  266. cat > /etc/init.d/beszel-agent <<EOF
  267. #!/sbin/openrc-run
  268. name="beszel-agent"
  269. description="Beszel Agent Service"
  270. command="/opt/beszel-agent/beszel-agent"
  271. command_user="beszel"
  272. command_background="yes"
  273. pidfile="/run/\${RC_SVCNAME}.pid"
  274. output_log="/var/log/beszel-agent.log"
  275. error_log="/var/log/beszel-agent.err"
  276. start_pre() {
  277. checkpath -f -m 0644 -o beszel:beszel "\$output_log" "\$error_log"
  278. }
  279. export PORT="$PORT"
  280. export KEY="$KEY"
  281. depend() {
  282. need net
  283. after firewall
  284. }
  285. EOF
  286. chmod +x /etc/init.d/beszel-agent
  287. rc-update add beszel-agent default
  288. # Create log files with proper permissions
  289. touch /var/log/beszel-agent.log /var/log/beszel-agent.err
  290. chown beszel:beszel /var/log/beszel-agent.log /var/log/beszel-agent.err
  291. # Start the service
  292. rc-service beszel-agent restart
  293. # Check if service started successfully
  294. sleep 2
  295. if ! rc-service beszel-agent status | grep -q "started"; then
  296. echo "Error: The Beszel Agent service failed to start. Checking logs..."
  297. tail -n 20 /var/log/beszel-agent.err
  298. exit 1
  299. fi
  300. # Auto-update service for Alpine
  301. printf "\nWould you like to enable automatic daily updates for beszel-agent? (y/n): "
  302. read AUTO_UPDATE
  303. case "$AUTO_UPDATE" in
  304. [Yy]*)
  305. echo "Setting up daily automatic updates for beszel-agent..."
  306. cat > /etc/init.d/beszel-agent-update <<EOF
  307. #!/sbin/openrc-run
  308. name="beszel-agent-update"
  309. description="Update beszel-agent if needed"
  310. depend() {
  311. need beszel-agent
  312. }
  313. start() {
  314. ebegin "Checking for beszel-agent updates"
  315. if /opt/beszel-agent/beszel-agent update | grep -q "Successfully updated"; then
  316. rc-service beszel-agent restart
  317. fi
  318. eend $?
  319. }
  320. EOF
  321. chmod +x /etc/init.d/beszel-agent-update
  322. rc-update add beszel-agent-update default
  323. rc-service beszel-agent-update start
  324. printf "\nAutomatic daily updates have been enabled.\n"
  325. ;;
  326. esac
  327. # Check service status
  328. if ! rc-service beszel-agent status >/dev/null 2>&1; then
  329. echo "Error: The Beszel Agent service is not running."
  330. rc-service beszel-agent status
  331. exit 1
  332. fi
  333. else
  334. # Original systemd service installation code
  335. echo "Creating the systemd service for the agent..."
  336. cat >/etc/systemd/system/beszel-agent.service <<EOF
  337. [Unit]
  338. Description=Beszel Agent Service
  339. After=network.target
  340. [Service]
  341. Environment="PORT=$PORT"
  342. Environment="KEY=$KEY"
  343. # Environment="EXTRA_FILESYSTEMS=sdb"
  344. ExecStart=/opt/beszel-agent/beszel-agent
  345. User=beszel
  346. Restart=always
  347. RestartSec=5
  348. [Install]
  349. WantedBy=multi-user.target
  350. EOF
  351. # Load and start the service
  352. printf "\nLoading and starting the agent service...\n"
  353. systemctl daemon-reload
  354. systemctl enable beszel-agent.service
  355. systemctl start beszel-agent.service
  356. # enable auto-update if AUTO_UPDATE variable set up
  357. if [ "${AUTO_UPDATE}" = true ]; then
  358. add_autoupdate_service
  359. else
  360. # Prompt for auto-update setup
  361. printf "\nWould you like to enable automatic daily updates for beszel-agent? (y/n): "
  362. read AUTO_UPDATE
  363. case "$AUTO_UPDATE" in
  364. [Yy]*)
  365. add_autoupdate_service ;;
  366. esac
  367. fi
  368. # Wait for the service to start or fail
  369. if [ "$(systemctl is-active beszel-agent.service)" != "active" ]; then
  370. echo "Error: The Beszel Agent service is not running."
  371. echo "$(systemctl status beszel-agent.service)"
  372. exit 1
  373. fi
  374. fi
  375. printf "\n\033[32mBeszel Agent has been installed successfully! It is now running on port $PORT.\033[0m\n"