mirror of
https://github.com/henrygd/beszel.git
synced 2026-04-13 00:11:49 +02:00
Compare commits
8 Commits
v0.11.1
...
3a97edd0d5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a97edd0d5 | ||
|
|
ab1d1c1273 | ||
|
|
0fb39edae4 | ||
|
|
3a977a8e1f | ||
|
|
081979de24 | ||
|
|
23fe189797 | ||
|
|
e9d429b9b8 | ||
|
|
99202c85b6 |
2
.github/workflows/docker-images.yml
vendored
2
.github/workflows/docker-images.yml
vendored
@@ -3,7 +3,7 @@ name: Make docker images
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- 'xv*'
|
- 'v*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ builds:
|
|||||||
|
|
||||||
archives:
|
archives:
|
||||||
- id: beszel-agent
|
- id: beszel-agent
|
||||||
format: tar.gz
|
formats: [tar.gz]
|
||||||
builds:
|
builds:
|
||||||
- beszel-agent
|
- beszel-agent
|
||||||
name_template: >-
|
name_template: >-
|
||||||
@@ -60,10 +60,10 @@ archives:
|
|||||||
{{- .Arch }}
|
{{- .Arch }}
|
||||||
format_overrides:
|
format_overrides:
|
||||||
- goos: windows
|
- goos: windows
|
||||||
format: zip
|
formats: [zip]
|
||||||
|
|
||||||
- id: beszel
|
- id: beszel
|
||||||
format: tar.gz
|
formats: [tar.gz]
|
||||||
builds:
|
builds:
|
||||||
- beszel
|
- beszel
|
||||||
name_template: >-
|
name_template: >-
|
||||||
@@ -87,9 +87,6 @@ nfpms:
|
|||||||
- beszel-agent
|
- beszel-agent
|
||||||
formats:
|
formats:
|
||||||
- deb
|
- deb
|
||||||
# don't think this is needed with CGO_ENABLED=0
|
|
||||||
# dependencies:
|
|
||||||
# - libc6
|
|
||||||
contents:
|
contents:
|
||||||
- src: ../supplemental/debian/beszel-agent.service
|
- src: ../supplemental/debian/beszel-agent.service
|
||||||
dst: lib/systemd/system/beszel-agent.service
|
dst: lib/systemd/system/beszel-agent.service
|
||||||
@@ -173,6 +170,41 @@ brews:
|
|||||||
error_log_path "#{Dir.home}/.cache/beszel/beszel-agent.log"
|
error_log_path "#{Dir.home}/.cache/beszel/beszel-agent.log"
|
||||||
keep_alive true
|
keep_alive true
|
||||||
|
|
||||||
|
winget:
|
||||||
|
- ids: [beszel-agent]
|
||||||
|
name: beszel-agent
|
||||||
|
package_identifier: henrygd.beszel-agent
|
||||||
|
publisher: henrygd
|
||||||
|
license: MIT
|
||||||
|
license_url: 'https://github.com/henrygd/beszel/blob/main/LICENSE'
|
||||||
|
copyright: '2025 henrygd'
|
||||||
|
homepage: 'https://beszel.dev'
|
||||||
|
release_notes_url: 'https://github.com/henrygd/beszel/releases/tag/v{{ .Version }}'
|
||||||
|
publisher_support_url: 'https://github.com/henrygd/beszel/issues'
|
||||||
|
short_description: 'Agent for Beszel, a lightweight server monitoring platform.'
|
||||||
|
skip_upload: auto
|
||||||
|
description: |
|
||||||
|
Beszel is a lightweight server monitoring platform that includes Docker
|
||||||
|
statistics, historical data, and alert functions. It has a friendly web
|
||||||
|
interface, simple configuration, and is ready to use out of the box.
|
||||||
|
It supports automatic backup, multi-user, OAuth authentication, and
|
||||||
|
API access.
|
||||||
|
tags:
|
||||||
|
- homelab
|
||||||
|
- monitoring
|
||||||
|
- self-hosted
|
||||||
|
repository:
|
||||||
|
owner: henrygd
|
||||||
|
name: beszel-winget
|
||||||
|
branch: henrygd.beszel-agent-{{ .Version }}
|
||||||
|
pull_request:
|
||||||
|
enabled: false
|
||||||
|
draft: false
|
||||||
|
base:
|
||||||
|
owner: microsoft
|
||||||
|
name: winget-pkgs
|
||||||
|
branch: master
|
||||||
|
|
||||||
release:
|
release:
|
||||||
draft: true
|
draft: true
|
||||||
|
|
||||||
|
|||||||
@@ -8,18 +8,18 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
sshServer "github.com/gliderlabs/ssh"
|
"github.com/gliderlabs/ssh"
|
||||||
"golang.org/x/crypto/ssh"
|
gossh "golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerOptions struct {
|
type ServerOptions struct {
|
||||||
Addr string
|
Addr string
|
||||||
Network string
|
Network string
|
||||||
Keys []ssh.PublicKey
|
Keys []gossh.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Agent) StartServer(opts ServerOptions) error {
|
func (a *Agent) StartServer(opts ServerOptions) error {
|
||||||
sshServer.Handle(a.handleSession)
|
ssh.Handle(a.handleSession)
|
||||||
|
|
||||||
slog.Info("Starting SSH server", "addr", opts.Addr, "network", opts.Network)
|
slog.Info("Starting SSH server", "addr", opts.Addr, "network", opts.Network)
|
||||||
|
|
||||||
@@ -38,10 +38,10 @@ func (a *Agent) StartServer(opts ServerOptions) error {
|
|||||||
defer ln.Close()
|
defer ln.Close()
|
||||||
|
|
||||||
// Start SSH server on the listener
|
// Start SSH server on the listener
|
||||||
return sshServer.Serve(ln, nil, sshServer.NoPty(),
|
return ssh.Serve(ln, nil, ssh.NoPty(),
|
||||||
sshServer.PublicKeyAuth(func(ctx sshServer.Context, key sshServer.PublicKey) bool {
|
ssh.PublicKeyAuth(func(ctx ssh.Context, key ssh.PublicKey) bool {
|
||||||
for _, pubKey := range opts.Keys {
|
for _, pubKey := range opts.Keys {
|
||||||
if sshServer.KeysEqual(key, pubKey) {
|
if ssh.KeysEqual(key, pubKey) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ func (a *Agent) StartServer(opts ServerOptions) error {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Agent) handleSession(s sshServer.Session) {
|
func (a *Agent) handleSession(s ssh.Session) {
|
||||||
slog.Debug("New session", "client", s.RemoteAddr())
|
slog.Debug("New session", "client", s.RemoteAddr())
|
||||||
stats := a.gatherStats(s.Context().SessionID())
|
stats := a.gatherStats(s.Context().SessionID())
|
||||||
if err := json.NewEncoder(s).Encode(stats); err != nil {
|
if err := json.NewEncoder(s).Encode(stats); err != nil {
|
||||||
@@ -62,8 +62,8 @@ func (a *Agent) handleSession(s sshServer.Session) {
|
|||||||
|
|
||||||
// ParseKeys parses a string containing SSH public keys in authorized_keys format.
|
// ParseKeys parses a string containing SSH public keys in authorized_keys format.
|
||||||
// It returns a slice of ssh.PublicKey and an error if any key fails to parse.
|
// It returns a slice of ssh.PublicKey and an error if any key fails to parse.
|
||||||
func ParseKeys(input string) ([]ssh.PublicKey, error) {
|
func ParseKeys(input string) ([]gossh.PublicKey, error) {
|
||||||
var parsedKeys []ssh.PublicKey
|
var parsedKeys []gossh.PublicKey
|
||||||
for line := range strings.Lines(input) {
|
for line := range strings.Lines(input) {
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
// Skip empty lines or comments
|
// Skip empty lines or comments
|
||||||
@@ -71,7 +71,7 @@ func ParseKeys(input string) ([]ssh.PublicKey, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Parse the key
|
// Parse the key
|
||||||
parsedKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(line))
|
parsedKey, _, _, _, err := gossh.ParseAuthorizedKey([]byte(line))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse key: %s, error: %w", line, err)
|
return nil, fmt.Errorf("failed to parse key: %s, error: %w", line, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ param (
|
|||||||
[switch]$Elevated,
|
[switch]$Elevated,
|
||||||
[Parameter(Mandatory=$true)]
|
[Parameter(Mandatory=$true)]
|
||||||
[string]$Key,
|
[string]$Key,
|
||||||
[int]$Port = 45876
|
[int]$Port = 45876,
|
||||||
|
[string]$AgentPath = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if key is provided or empty
|
# Check if key is provided or empty
|
||||||
@@ -15,60 +16,147 @@ if ([string]::IsNullOrWhiteSpace($Key)) {
|
|||||||
# Stop on first error
|
# Stop on first error
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
#region Utility Functions
|
||||||
|
|
||||||
# Function to check if running as admin
|
# Function to check if running as admin
|
||||||
function Test-Admin {
|
function Test-Admin {
|
||||||
return ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
return ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Non-admin tasks - install Scoop and Scoop apps - Only run if we're not in elevated mode
|
# Function to check if a command exists
|
||||||
if (-not $Elevated) {
|
function Test-CommandExists {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$Command
|
||||||
|
)
|
||||||
|
return (Get-Command $Command -ErrorAction SilentlyContinue)
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Installation Methods
|
||||||
|
|
||||||
|
# Function to install Scoop
|
||||||
|
function Install-Scoop {
|
||||||
|
Write-Host "Installing Scoop..."
|
||||||
try {
|
try {
|
||||||
# Check if Scoop is already installed
|
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
|
||||||
if (Get-Command scoop -ErrorAction SilentlyContinue) {
|
|
||||||
|
if (-not (Test-CommandExists "scoop")) {
|
||||||
|
throw "Failed to install Scoop"
|
||||||
|
}
|
||||||
|
Write-Host "Scoop installed successfully."
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
throw "Failed to install Scoop: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install Git via Scoop
|
||||||
|
function Install-Git {
|
||||||
|
if (Test-CommandExists "git") {
|
||||||
|
Write-Host "Git is already installed."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Installing Git..."
|
||||||
|
scoop install git
|
||||||
|
|
||||||
|
if (-not (Test-CommandExists "git")) {
|
||||||
|
throw "Failed to install Git"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install NSSM
|
||||||
|
function Install-NSSM {
|
||||||
|
param (
|
||||||
|
[string]$Method = "Scoop" # Default to Scoop method
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Test-CommandExists "nssm") {
|
||||||
|
Write-Host "NSSM is already installed."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Installing NSSM..."
|
||||||
|
if ($Method -eq "Scoop") {
|
||||||
|
scoop install nssm
|
||||||
|
}
|
||||||
|
elseif ($Method -eq "WinGet") {
|
||||||
|
winget install -e --id NSSM.NSSM --accept-source-agreements --accept-package-agreements
|
||||||
|
|
||||||
|
# Refresh PATH environment variable to make NSSM available in current session
|
||||||
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw "Unsupported installation method: $Method"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-CommandExists "nssm")) {
|
||||||
|
throw "Failed to install NSSM"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install beszel-agent with Scoop
|
||||||
|
function Install-BeszelAgentWithScoop {
|
||||||
|
Write-Host "Adding beszel bucket..."
|
||||||
|
scoop bucket add beszel https://github.com/henrygd/beszel-scoops | Out-Null
|
||||||
|
|
||||||
|
Write-Host "Installing beszel-agent..."
|
||||||
|
scoop install beszel-agent | Out-Null
|
||||||
|
|
||||||
|
if (-not (Test-CommandExists "beszel-agent")) {
|
||||||
|
throw "Failed to install beszel-agent"
|
||||||
|
}
|
||||||
|
|
||||||
|
return $(Join-Path -Path $(scoop prefix beszel-agent) -ChildPath "beszel-agent.exe")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install beszel-agent with WinGet
|
||||||
|
function Install-BeszelAgentWithWinGet {
|
||||||
|
Write-Host "Installing beszel-agent..."
|
||||||
|
winget install --exact --id henrygd.beszel-agent --accept-source-agreements --accept-package-agreements | Out-Null
|
||||||
|
|
||||||
|
# Refresh PATH environment variable to make beszel-agent available in current session
|
||||||
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
||||||
|
|
||||||
|
# Find the path to the beszel-agent executable
|
||||||
|
$agentPath = (Get-Command beszel-agent -ErrorAction SilentlyContinue).Source
|
||||||
|
|
||||||
|
|
||||||
|
if (-not $agentPath) {
|
||||||
|
throw "Could not find beszel-agent executable path after installation"
|
||||||
|
}
|
||||||
|
|
||||||
|
return $agentPath
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to install using Scoop
|
||||||
|
function Install-WithScoop {
|
||||||
|
param (
|
||||||
|
[string]$Key,
|
||||||
|
[int]$Port
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Ensure Scoop is installed
|
||||||
|
if (-not (Test-CommandExists "scoop")) {
|
||||||
|
Install-Scoop | Out-Null
|
||||||
|
}
|
||||||
|
else {
|
||||||
Write-Host "Scoop is already installed."
|
Write-Host "Scoop is already installed."
|
||||||
} else {
|
|
||||||
Write-Host "Installing Scoop..."
|
|
||||||
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
|
|
||||||
|
|
||||||
if (-not (Get-Command scoop -ErrorAction SilentlyContinue)) {
|
|
||||||
throw "Failed to install Scoop"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if git is already installed
|
|
||||||
if (Get-Command git -ErrorAction SilentlyContinue) {
|
|
||||||
Write-Host "Git is already installed."
|
|
||||||
} else {
|
|
||||||
Write-Host "Installing Git..."
|
|
||||||
scoop install git
|
|
||||||
|
|
||||||
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
|
|
||||||
throw "Failed to install Git"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if nssm is already installed
|
|
||||||
if (Get-Command nssm -ErrorAction SilentlyContinue) {
|
|
||||||
Write-Host "NSSM is already installed."
|
|
||||||
} else {
|
|
||||||
Write-Host "Installing NSSM..."
|
|
||||||
scoop install nssm
|
|
||||||
|
|
||||||
if (-not (Get-Command nssm -ErrorAction SilentlyContinue)) {
|
|
||||||
throw "Failed to install NSSM"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add bucket and install agent
|
# Install Git (required for Scoop buckets)
|
||||||
Write-Host "Adding beszel bucket..."
|
Install-Git | Out-Null
|
||||||
scoop bucket add beszel https://github.com/henrygd/beszel-scoops
|
|
||||||
|
|
||||||
Write-Host "Installing beszel-agent..."
|
# Install NSSM
|
||||||
scoop install beszel-agent
|
Install-NSSM -Method "Scoop" | Out-Null
|
||||||
|
|
||||||
if (-not (Get-Command beszel-agent -ErrorAction SilentlyContinue)) {
|
# Install beszel-agent
|
||||||
throw "Failed to install beszel-agent"
|
$agentPath = Install-BeszelAgentWithScoop
|
||||||
}
|
|
||||||
|
return $agentPath
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
||||||
@@ -77,27 +165,48 @@ if (-not $Elevated) {
|
|||||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Check if we need admin privileges for the NSSM part
|
# Function to install using WinGet
|
||||||
if (-not (Test-Admin)) {
|
function Install-WithWinGet {
|
||||||
Write-Host "Admin privileges required for NSSM. Relaunching as admin..." -ForegroundColor Yellow
|
param (
|
||||||
Write-Host "Check service status with 'nssm status beszel-agent'"
|
[string]$Key,
|
||||||
Write-Host "Edit service configuration with 'nssm edit beszel-agent'"
|
[int]$Port
|
||||||
|
)
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Install NSSM
|
||||||
|
Install-NSSM -Method "WinGet" | Out-Null
|
||||||
|
|
||||||
# Relaunch the script with the -Elevated switch and pass parameters
|
# Install beszel-agent
|
||||||
Start-Process powershell.exe -Verb RunAs -ArgumentList "-File `"$PSCommandPath`" -Elevated -Key `"$Key`" -Port $Port"
|
$agentPath = Install-BeszelAgentWithWinGet
|
||||||
exit
|
|
||||||
|
return $agentPath
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
||||||
|
Write-Host "Installation failed. Please check the error message above." -ForegroundColor Red
|
||||||
|
Write-Host "Press any key to exit..." -ForegroundColor Red
|
||||||
|
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||||
|
exit 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Admin tasks - service installation and firewall rules
|
#endregion
|
||||||
try {
|
|
||||||
$agentPath = Join-Path -Path $(scoop prefix beszel-agent) -ChildPath "beszel-agent.exe"
|
#region Service Configuration
|
||||||
if (-not $agentPath) {
|
|
||||||
throw "Could not find beszel-agent executable. Make sure it was properly installed."
|
# Function to install and configure the NSSM service
|
||||||
}
|
function Install-NSSMService {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$AgentPath,
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$Key,
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[int]$Port
|
||||||
|
)
|
||||||
|
|
||||||
# Install and configure the service
|
|
||||||
Write-Host "Installing beszel-agent service..."
|
Write-Host "Installing beszel-agent service..."
|
||||||
|
|
||||||
# Check if service already exists
|
# Check if service already exists
|
||||||
@@ -112,7 +221,7 @@ try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nssm install beszel-agent $agentPath
|
nssm install beszel-agent $AgentPath
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
throw "Failed to install beszel-agent service"
|
throw "Failed to install beszel-agent service"
|
||||||
}
|
}
|
||||||
@@ -129,6 +238,14 @@ try {
|
|||||||
$logFile = "$logDir\beszel-agent.log"
|
$logFile = "$logDir\beszel-agent.log"
|
||||||
nssm set beszel-agent AppStdout $logFile
|
nssm set beszel-agent AppStdout $logFile
|
||||||
nssm set beszel-agent AppStderr $logFile
|
nssm set beszel-agent AppStderr $logFile
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to configure firewall rules
|
||||||
|
function Configure-Firewall {
|
||||||
|
param (
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[int]$Port
|
||||||
|
)
|
||||||
|
|
||||||
# Create a firewall rule if it doesn't exist
|
# Create a firewall rule if it doesn't exist
|
||||||
$ruleName = "Allow beszel-agent"
|
$ruleName = "Allow beszel-agent"
|
||||||
@@ -154,31 +271,121 @@ try {
|
|||||||
Write-Host "Warning: Failed to create firewall rule: $($_.Exception.Message)" -ForegroundColor Yellow
|
Write-Host "Warning: Failed to create firewall rule: $($_.Exception.Message)" -ForegroundColor Yellow
|
||||||
Write-Host "You may need to manually create a firewall rule for port $Port." -ForegroundColor Yellow
|
Write-Host "You may need to manually create a firewall rule for port $Port." -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Host "Starting beszel-agent service..."
|
|
||||||
nssm start beszel-agent
|
|
||||||
if ($LASTEXITCODE -ne 0) {
|
|
||||||
throw "Failed to start beszel-agent service"
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Host "Checking beszel-agent service status..."
|
|
||||||
Start-Sleep -Seconds 5 # Allow time to start before checking status
|
|
||||||
$serviceStatus = nssm status beszel-agent
|
|
||||||
|
|
||||||
if ($serviceStatus -eq "SERVICE_RUNNING") {
|
|
||||||
Write-Host "Success! The beszel-agent service is running properly." -ForegroundColor Green
|
|
||||||
} else {
|
|
||||||
Write-Host "Warning: The service status is '$serviceStatus' instead of 'SERVICE_RUNNING'." -ForegroundColor Yellow
|
|
||||||
Write-Host "You may need to troubleshoot the service installation." -ForegroundColor Yellow
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
|
||||||
Write-Host "Installation failed. Please check the error message above." -ForegroundColor Red
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Pause to see results before exit if this is an elevated window
|
# Function to start and monitor the service
|
||||||
|
function Start-BeszelAgentService {
|
||||||
|
Write-Host "Starting beszel-agent service..."
|
||||||
|
nssm start beszel-agent
|
||||||
|
$startResult = $LASTEXITCODE
|
||||||
|
|
||||||
|
# Only enter the status check loop if the NSSM start command failed
|
||||||
|
if ($startResult -ne 0) {
|
||||||
|
Write-Host "NSSM start command returned error code: $startResult" -ForegroundColor Yellow
|
||||||
|
Write-Host "This could be due to 'SERVICE_START_PENDING' state. Checking service status..."
|
||||||
|
|
||||||
|
# Allow up to 10 seconds for the service to start, checking every second
|
||||||
|
$maxWaitTime = 10 # seconds
|
||||||
|
$elapsedTime = 0
|
||||||
|
$serviceStarted = $false
|
||||||
|
|
||||||
|
while (-not $serviceStarted -and $elapsedTime -lt $maxWaitTime) {
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
$elapsedTime += 1
|
||||||
|
|
||||||
|
$serviceStatus = nssm status beszel-agent
|
||||||
|
|
||||||
|
if ($serviceStatus -eq "SERVICE_RUNNING") {
|
||||||
|
$serviceStarted = $true
|
||||||
|
Write-Host "Success! The beszel-agent service is now running." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
elseif ($serviceStatus -like "*PENDING*") {
|
||||||
|
Write-Host "Service is still starting (status: $serviceStatus)... waiting" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "Warning: The service status is '$serviceStatus' instead of 'SERVICE_RUNNING'." -ForegroundColor Yellow
|
||||||
|
Write-Host "You may need to troubleshoot the service installation." -ForegroundColor Yellow
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $serviceStarted) {
|
||||||
|
Write-Host "Service did not reach running state." -ForegroundColor Yellow
|
||||||
|
Write-Host "You can check status manually with 'nssm status beszel-agent'" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# NSSM start command was successful
|
||||||
|
Write-Host "Success! The beszel-agent service is running properly." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Main Script Execution
|
||||||
|
|
||||||
|
# Non-admin tasks - Only run if we're not in elevated mode
|
||||||
|
if (-not $Elevated) {
|
||||||
|
try {
|
||||||
|
# Determine installation method
|
||||||
|
$AgentPath = ""
|
||||||
|
|
||||||
|
if (Test-CommandExists "scoop") {
|
||||||
|
Write-Host "Using Scoop for installation..."
|
||||||
|
$AgentPath = Install-WithScoop -Key $Key -Port $Port
|
||||||
|
}
|
||||||
|
elseif (Test-CommandExists "winget") {
|
||||||
|
Write-Host "Using WinGet for installation..."
|
||||||
|
$AgentPath = Install-WithWinGet -Key $Key -Port $Port
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "Neither Scoop nor WinGet is installed. Installing Scoop..."
|
||||||
|
$AgentPath = Install-WithScoop -Key $Key -Port $Port
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if we need admin privileges for the NSSM part
|
||||||
|
if (-not (Test-Admin)) {
|
||||||
|
Write-Host "Admin privileges required for NSSM. Relaunching as admin..." -ForegroundColor Yellow
|
||||||
|
Write-Host "Check service status with 'nssm status beszel-agent'"
|
||||||
|
Write-Host "Edit service configuration with 'nssm edit beszel-agent'"
|
||||||
|
|
||||||
|
# Relaunch the script with the -Elevated switch and pass parameters
|
||||||
|
Start-Process powershell.exe -Verb RunAs -ArgumentList "-File `"$PSCommandPath`" -Elevated -Key `"$Key`" -Port $Port -AgentPath `"$AgentPath`""
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
||||||
|
Write-Host "Installation failed. Please check the error message above." -ForegroundColor Red
|
||||||
|
Write-Host "Press any key to exit..." -ForegroundColor Red
|
||||||
|
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Admin tasks - service installation and firewall rules
|
||||||
if ($Elevated) {
|
if ($Elevated) {
|
||||||
|
try {
|
||||||
|
if (-not $AgentPath) {
|
||||||
|
throw "Could not find beszel-agent executable. Make sure it was properly installed."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install the service
|
||||||
|
Install-NSSMService -AgentPath $AgentPath -Key $Key -Port $Port
|
||||||
|
|
||||||
|
# Configure firewall
|
||||||
|
Configure-Firewall -Port $Port
|
||||||
|
|
||||||
|
# Start the service
|
||||||
|
Start-BeszelAgentService
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
||||||
|
Write-Host "Installation failed. Please check the error message above." -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pause to see results before exit if this is an elevated window
|
||||||
Write-Host "Press any key to exit..." -ForegroundColor Cyan
|
Write-Host "Press any key to exit..." -ForegroundColor Cyan
|
||||||
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|||||||
@@ -8,7 +8,53 @@ is_openwrt() {
|
|||||||
cat /etc/os-release | grep -q "OpenWrt"
|
cat /etc/os-release | grep -q "OpenWrt"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to ensure the proxy URL ends with a /
|
# 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 "/opt/beszel-agent/beszel-agent" >/dev/null 2>&1; then
|
||||||
|
restorecon -v /opt/beszel-agent/beszel-agent >/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 /opt/beszel-agent/beszel-agent || echo "Warning: Failed to set SELinux context for binary."
|
||||||
|
chcon -R -t bin_t /opt/beszel-agent || 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 "/opt/beszel-agent/beszel-agent" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure the proxy URL ends with a /
|
||||||
ensure_trailing_slash() {
|
ensure_trailing_slash() {
|
||||||
if [ -n "$1" ]; then
|
if [ -n "$1" ]; then
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@@ -20,7 +66,7 @@ ensure_trailing_slash() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Define default values
|
# Default values
|
||||||
PORT=45876
|
PORT=45876
|
||||||
UNINSTALL=false
|
UNINSTALL=false
|
||||||
GITHUB_URL="https://github.com"
|
GITHUB_URL="https://github.com"
|
||||||
@@ -141,6 +187,9 @@ done
|
|||||||
|
|
||||||
# Uninstall process
|
# Uninstall process
|
||||||
if [ "$UNINSTALL" = true ]; then
|
if [ "$UNINSTALL" = true ]; then
|
||||||
|
# Clean up SELinux contexts before removing files
|
||||||
|
cleanup_selinux_context
|
||||||
|
|
||||||
if is_alpine; then
|
if is_alpine; then
|
||||||
echo "Stopping and disabling the agent service..."
|
echo "Stopping and disabling the agent service..."
|
||||||
rc-service beszel-agent stop
|
rc-service beszel-agent stop
|
||||||
@@ -334,6 +383,9 @@ mv beszel-agent /opt/beszel-agent/beszel-agent
|
|||||||
chown beszel:beszel /opt/beszel-agent/beszel-agent
|
chown beszel:beszel /opt/beszel-agent/beszel-agent
|
||||||
chmod 755 /opt/beszel-agent/beszel-agent
|
chmod 755 /opt/beszel-agent/beszel-agent
|
||||||
|
|
||||||
|
# Set SELinux context if needed
|
||||||
|
set_selinux_context
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
rm -rf "$TEMP_DIR"
|
rm -rf "$TEMP_DIR"
|
||||||
|
|
||||||
@@ -528,7 +580,6 @@ StateDirectory=beszel-agent
|
|||||||
KeyringMode=private
|
KeyringMode=private
|
||||||
LockPersonality=yes
|
LockPersonality=yes
|
||||||
NoNewPrivileges=yes
|
NoNewPrivileges=yes
|
||||||
PrivateTmp=yes
|
|
||||||
ProtectClock=yes
|
ProtectClock=yes
|
||||||
ProtectHome=read-only
|
ProtectHome=read-only
|
||||||
ProtectHostname=yes
|
ProtectHostname=yes
|
||||||
@@ -548,6 +599,37 @@ EOF
|
|||||||
systemctl enable beszel-agent.service
|
systemctl enable beszel-agent.service
|
||||||
systemctl start beszel-agent.service
|
systemctl start beszel-agent.service
|
||||||
|
|
||||||
|
# Create the update script
|
||||||
|
echo "Creating the update script..."
|
||||||
|
cat >/opt/beszel-agent/run-update.sh <<'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if /opt/beszel-agent/beszel-agent update | grep -q "Successfully updated"; then
|
||||||
|
echo "Update found, checking SELinux context."
|
||||||
|
if command -v getenforce >/dev/null 2>&1 && [ "$(getenforce)" != "Disabled" ]; then
|
||||||
|
echo "SELinux enabled, applying context..."
|
||||||
|
if command -v chcon >/dev/null 2>&1; then
|
||||||
|
chcon -t bin_t /opt/beszel-agent/beszel-agent || echo "Warning: chcon command failed to apply context."
|
||||||
|
fi
|
||||||
|
if command -v restorecon >/dev/null 2>&1; then
|
||||||
|
restorecon -v /opt/beszel-agent/beszel-agent >/dev/null 2>&1 || echo "Warning: restorecon command failed to apply context."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "Restarting beszel-agent service..."
|
||||||
|
systemctl restart beszel-agent
|
||||||
|
echo "Update process finished."
|
||||||
|
else
|
||||||
|
echo "No updates found or applied."
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chown root:root /opt/beszel-agent/run-update.sh
|
||||||
|
chmod +x /opt/beszel-agent/run-update.sh
|
||||||
|
|
||||||
# Prompt for auto-update setup
|
# Prompt for auto-update setup
|
||||||
if [ "$AUTO_UPDATE_FLAG" = "true" ]; then
|
if [ "$AUTO_UPDATE_FLAG" = "true" ]; then
|
||||||
AUTO_UPDATE="y"
|
AUTO_UPDATE="y"
|
||||||
@@ -571,7 +653,7 @@ Wants=beszel-agent.service
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=/bin/sh -c '/opt/beszel-agent/beszel-agent update | grep -q "Successfully updated" && (echo "Update found, restarting beszel-agent" && systemctl restart beszel-agent) || echo "No updates found"'
|
ExecStart=/opt/beszel-agent/run-update.sh
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Create systemd timer for the daily update
|
# Create systemd timer for the daily update
|
||||||
|
|||||||
Reference in New Issue
Block a user