mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 18:45:53 +00:00
fix: Update repository URL in script and README
This commit is contained in:
@@ -15,6 +15,7 @@ A lightweight monitoring application for Proxmox VE that displays real-time stat
|
||||
- [Running the Application](#-running-the-application)
|
||||
- [Running the Application (Node.js)](#️-running-the-application-nodejs)
|
||||
- [Running with Docker Compose](#-running-with-docker-compose)
|
||||
- [Running with LXC Installation Script](#-running-with-lxc-installation-script)
|
||||
- [Features](#-features)
|
||||
- [System Requirements](#-system-requirements)
|
||||
- [Contributing](#-contributing)
|
||||
@@ -152,6 +153,46 @@ docker compose down
|
||||
|
||||
*Note: If you modify the `server/.env` file after the container is already running, you may need to restart the container for the changes to take effect. You can do this by running `docker compose down` followed by `docker compose up -d`, or by using `docker compose up -d --force-recreate`.*
|
||||
|
||||
## 🚀 Running with LXC Installation Script (Recommended for Proxmox)
|
||||
|
||||
For users running Proxmox VE, a convenient installation script is provided to set up Pulse inside an LXC container (Debian/Ubuntu based). This script automates dependency installation, configuration, and setting up a systemd service.
|
||||
|
||||
**Prerequisites:**
|
||||
- A running Proxmox VE environment.
|
||||
- A Debian or Ubuntu based LXC container created in Proxmox.
|
||||
- Network connectivity from the LXC to your Proxmox server.
|
||||
- You will need your Proxmox API Token details ([See Creating a Proxmox API Token](#creating-a-proxmox-api-token)).
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. **Access LXC Console:** Log in to the console of your newly created LXC container (e.g., via the Proxmox web UI or SSH).
|
||||
|
||||
2. **Download and Run the Script:** Execute the following command in the LXC console. This downloads the script and runs it with `sudo`:
|
||||
```bash
|
||||
bash -c "$(wget -qLO - https://raw.githubusercontent.com/rcourtman/Pulse/main/scripts/install-pulse.sh)" --
|
||||
```
|
||||
* Alternatively, you can download it first and then run it:
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/rcourtman/Pulse/main/scripts/install-pulse.sh
|
||||
chmod +x install-pulse.sh
|
||||
sudo ./install-pulse.sh
|
||||
```
|
||||
|
||||
3. **Follow Prompts:** The script will guide you through the installation process:
|
||||
* It will update the container and install necessary packages (`git`, `curl`, `nodejs`, `npm`).
|
||||
* It will ask for your Proxmox Host URL, API Token ID, and API Token Secret.
|
||||
* It will ask about allowing self-signed certificates and optionally setting a custom port.
|
||||
* It will configure Pulse and set it up as a `systemd` service (`pulse-proxmox.service`) to run automatically.
|
||||
|
||||
4. **Access Pulse:** Once the script finishes, it will display the URL (using the LXC's IP address) where you can access the Pulse dashboard (e.g., `http://<LXC-IP-ADDRESS>:7655`).
|
||||
|
||||
**Managing the Service:**
|
||||
|
||||
- **Check Status:** `sudo systemctl status pulse-proxmox.service`
|
||||
- **Stop Service:** `sudo systemctl stop pulse-proxmox.service`
|
||||
- **Start Service:** `sudo systemctl start pulse-proxmox.service`
|
||||
- **View Logs:** `sudo journalctl -u pulse-proxmox.service -f`
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- Lightweight monitoring for Proxmox VE nodes.
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Pulse for Proxmox VE LXC Installation Script
|
||||
# This script automates the installation and setup of Pulse within a Proxmox LXC container.
|
||||
|
||||
# --- Configuration ---
|
||||
NODE_MAJOR_VERSION=20 # Specify the desired Node.js major version (e.g., 18, 20)
|
||||
PULSE_DIR="/opt/pulse-proxmox"
|
||||
PULSE_USER="pulse" # Dedicated user to run Pulse
|
||||
SERVICE_NAME="pulse-proxmox.service"
|
||||
|
||||
# --- Helper Functions ---
|
||||
print_info() {
|
||||
echo -e "\033[1;34m[INFO]\033[0m $1"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "\033[1;32m[SUCCESS]\033[0m $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "\033[1;33m[WARNING]\033[0m $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "\033[1;31m[ERROR]\033[0m $1" >&2
|
||||
}
|
||||
|
||||
check_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
print_error "This script must be run as root. Please use sudo."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
apt_update_upgrade() {
|
||||
print_info "Updating package lists and upgrading packages..."
|
||||
if apt-get update > /dev/null && apt-get upgrade -y > /dev/null; then
|
||||
print_success "System packages updated and upgraded."
|
||||
else
|
||||
print_error "Failed to update/upgrade system packages."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
install_dependencies() {
|
||||
print_info "Installing necessary dependencies (git, curl, sudo)..."
|
||||
if apt-get install -y git curl sudo > /dev/null; then
|
||||
print_success "Dependencies installed."
|
||||
else
|
||||
print_error "Failed to install dependencies."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
setup_node() {
|
||||
print_info "Setting up Node.js repository (NodeSource)..."
|
||||
# Check if Node.js is already installed and meets version requirement (optional, for robustness)
|
||||
# node_version=$(node -v 2>/dev/null | sed 's/v//' | cut -d. -f1)
|
||||
# if [[ "$node_version" -ge "$NODE_MAJOR_VERSION" ]]; then
|
||||
# print_info "Node.js version ${node_version} already installed and meets requirement (>=${NODE_MAJOR_VERSION}). Skipping setup."
|
||||
# return 0
|
||||
# fi
|
||||
|
||||
if ! command -v curl &> /dev/null; then
|
||||
print_error "curl is required but not found. Please install it first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Add NodeSource repository GPG key and setup script
|
||||
KEYRING_DIR="/usr/share/keyrings"
|
||||
KEYRING_FILE="$KEYRING_DIR/nodesource.gpg"
|
||||
if [ ! -d "$KEYRING_DIR" ]; then
|
||||
mkdir -p "$KEYRING_DIR" || { print_error "Failed to create $KEYRING_DIR"; exit 1; }
|
||||
fi
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o "$KEYRING_FILE"
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "Failed to download or process NodeSource GPG key."
|
||||
rm -f "$KEYRING_FILE" # Clean up partial file
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Add the repository configuration
|
||||
echo "deb [signed-by=$KEYRING_FILE] https://deb.nodesource.com/node_$NODE_MAJOR_VERSION.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "Failed to add NodeSource repository to sources list."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_info "Updating package list after adding NodeSource repository..."
|
||||
if ! apt-get update > /dev/null; then
|
||||
print_error "Failed to update package list after adding NodeSource repository."
|
||||
# Attempt cleanup
|
||||
rm -f /etc/apt/sources.list.d/nodesource.list "$KEYRING_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_info "Installing Node.js ${NODE_MAJOR_VERSION}.x..."
|
||||
if apt-get install nodejs -y > /dev/null; then
|
||||
print_success "Node.js ${NODE_MAJOR_VERSION}.x installed successfully."
|
||||
print_info "Node version: $(node -v)"
|
||||
print_info "npm version: $(npm -v)"
|
||||
else
|
||||
print_error "Failed to install Node.js."
|
||||
# Attempt cleanup
|
||||
rm -f /etc/apt/sources.list.d/nodesource.list "$KEYRING_FILE"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
create_pulse_user() {
|
||||
print_info "Creating dedicated user '$PULSE_USER'..."
|
||||
if id "$PULSE_USER" &>/dev/null; then
|
||||
print_warning "User '$PULSE_USER' already exists. Skipping creation."
|
||||
else
|
||||
# Create a system user with no login shell and no home directory (or specify one if needed)
|
||||
useradd -r -s /bin/false "$PULSE_USER"
|
||||
if [ $? -eq 0 ]; then
|
||||
print_success "User '$PULSE_USER' created successfully."
|
||||
else
|
||||
print_error "Failed to create user '$PULSE_USER'."
|
||||
# Decide if this is fatal. Maybe allow script to continue if user exists?
|
||||
# For now, exiting as it might indicate a problem.
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
clone_repository() {
|
||||
print_info "Cloning Pulse repository into $PULSE_DIR..."
|
||||
if [ -d "$PULSE_DIR" ]; then
|
||||
print_warning "Directory $PULSE_DIR already exists. Assuming repo is already cloned or manually placed."
|
||||
# Optionally, add logic here to pull latest changes if desired
|
||||
# cd "$PULSE_DIR" && git pull origin main
|
||||
else
|
||||
# Clone the main branch. Consider adding --depth 1 for faster clone if history isn't needed.
|
||||
if git clone https://github.com/rcourtman/Pulse.git "$PULSE_DIR" > /dev/null 2>&1; then
|
||||
print_success "Repository cloned successfully."
|
||||
else
|
||||
print_error "Failed to clone repository."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
install_npm_deps() {
|
||||
print_info "Installing npm dependencies..."
|
||||
if [ ! -d "$PULSE_DIR" ]; then
|
||||
print_error "Pulse directory $PULSE_DIR not found. Cannot install dependencies."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$PULSE_DIR" || { print_error "Failed to change directory to $PULSE_DIR"; exit 1; }
|
||||
|
||||
print_info "Installing root dependencies..."
|
||||
# Use --unsafe-perm if running npm install as root, which might be necessary for some packages
|
||||
# Use --omit=dev to skip development dependencies
|
||||
if npm install --omit=dev --unsafe-perm > /dev/null 2>&1; then
|
||||
print_success "Root dependencies installed."
|
||||
else
|
||||
print_error "Failed to install root npm dependencies."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_info "Installing server dependencies..."
|
||||
cd server || { print_error "Failed to change directory to $PULSE_DIR/server"; exit 1; }
|
||||
if npm install --omit=dev --unsafe-perm > /dev/null 2>&1; then
|
||||
print_success "Server dependencies installed."
|
||||
else
|
||||
print_error "Failed to install server npm dependencies."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Return to script execution directory or root, if needed
|
||||
cd ..
|
||||
}
|
||||
|
||||
set_permissions() {
|
||||
print_info "Setting permissions for $PULSE_DIR..."
|
||||
if chown -R "$PULSE_USER":"$PULSE_USER" "$PULSE_DIR"; then
|
||||
print_success "Permissions set correctly."
|
||||
else
|
||||
print_error "Failed to set permissions for $PULSE_DIR."
|
||||
# This might not be fatal, but could cause runtime issues. Log warning?
|
||||
print_warning "Check ownership and permissions for $PULSE_DIR."
|
||||
fi
|
||||
}
|
||||
|
||||
configure_environment() {
|
||||
print_info "Configuring Pulse environment..."
|
||||
local env_example_path="$PULSE_DIR/server/.env.example"
|
||||
local env_path="$PULSE_DIR/server/.env"
|
||||
|
||||
if [ ! -f "$env_example_path" ]; then
|
||||
print_error "Environment example file not found at $env_example_path. Cannot configure."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if .env already exists
|
||||
if [ -f "$env_path" ]; then
|
||||
print_warning "Configuration file $env_path already exists."
|
||||
read -p "Overwrite existing configuration? (y/N): " overwrite_confirm
|
||||
if [[ ! "$overwrite_confirm" =~ ^[Yy]$ ]]; then
|
||||
print_info "Skipping environment configuration."
|
||||
return 0 # Exit the function successfully without configuring
|
||||
fi
|
||||
print_info "Proceeding to overwrite existing configuration..."
|
||||
fi
|
||||
|
||||
# --- Gather Proxmox Details ---
|
||||
echo "Please provide your Proxmox connection details:"
|
||||
read -p " -> Proxmox Host URL (e.g., https://192.168.1.100:8006): " proxmox_host
|
||||
while [ -z "$proxmox_host" ]; do
|
||||
print_warning "Proxmox Host URL cannot be empty."
|
||||
read -p " -> Proxmox Host URL (e.g., https://192.168.1.100:8006): " proxmox_host
|
||||
done
|
||||
|
||||
read -p " -> Proxmox API Token ID (e.g., user@pam!tokenid): " proxmox_token_id
|
||||
while [ -z "$proxmox_token_id" ]; do
|
||||
print_warning "Proxmox Token ID cannot be empty."
|
||||
read -p " -> Proxmox API Token ID (e.g., user@pam!tokenid): " proxmox_token_id
|
||||
done
|
||||
|
||||
# Use -s for silent input for the secret
|
||||
read -sp " -> Proxmox API Token Secret: " proxmox_token_secret
|
||||
echo # Add a newline after secret input
|
||||
while [ -z "$proxmox_token_secret" ]; do
|
||||
print_warning "Proxmox Token Secret cannot be empty."
|
||||
read -sp " -> Proxmox API Token Secret: " proxmox_token_secret
|
||||
echo
|
||||
done
|
||||
|
||||
# --- Optional Settings ---
|
||||
read -p "Allow self-signed certificates for Proxmox? (y/N): " allow_self_signed
|
||||
local self_signed_value="false"
|
||||
if [[ "$allow_self_signed" =~ ^[Yy]$ ]]; then
|
||||
self_signed_value="true"
|
||||
fi
|
||||
|
||||
read -p "Port for Pulse server (leave blank for default 7655): " pulse_port
|
||||
local port_value="7655"
|
||||
if [ -n "$pulse_port" ]; then
|
||||
# Basic validation: check if it's a number (optional)
|
||||
if [[ "$pulse_port" =~ ^[0-9]+$ ]] && [ "$pulse_port" -ge 1 ] && [ "$pulse_port" -le 65535 ]; then
|
||||
port_value="$pulse_port"
|
||||
else
|
||||
print_warning "Invalid port number entered. Using default 7655."
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Create .env file ---
|
||||
print_info "Creating $env_path from example..."
|
||||
if cp "$env_example_path" "$env_path"; then
|
||||
# Use sed to replace placeholders. Use a different delimiter for sed if URLs contain slashes
|
||||
sed -i "s|^PROXMOX_HOST=.*|PROXMOX_HOST=$proxmox_host|" "$env_path"
|
||||
sed -i "s|^PROXMOX_TOKEN_ID=.*|PROXMOX_TOKEN_ID=$proxmox_token_id|" "$env_path"
|
||||
sed -i "s|^PROXMOX_TOKEN_SECRET=.*|PROXMOX_TOKEN_SECRET=$proxmox_token_secret|" "$env_path"
|
||||
sed -i "s|^PROXMOX_ALLOW_SELF_SIGNED_CERTS=.*|PROXMOX_ALLOW_SELF_SIGNED_CERTS=$self_signed_value|" "$env_path"
|
||||
sed -i "s|^PORT=.*|PORT=$port_value|" "$env_path"
|
||||
|
||||
# Set ownership
|
||||
chown "$PULSE_USER":"$PULSE_USER" "$env_path"
|
||||
chmod 600 "$env_path" # Restrict permissions for security
|
||||
|
||||
print_success "Environment configured successfully in $env_path."
|
||||
else
|
||||
print_error "Failed to copy $env_example_path to $env_path."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
setup_systemd_service() {
|
||||
print_info "Setting up systemd service ($SERVICE_NAME)..."
|
||||
local service_file="/etc/systemd/system/$SERVICE_NAME"
|
||||
|
||||
# Find Node path (needed for systemd ExecStart)
|
||||
local node_path
|
||||
node_path=$(command -v node)
|
||||
if [ -z "$node_path" ]; then
|
||||
print_error "Could not find Node.js executable path. Cannot create service."
|
||||
exit 1
|
||||
fi
|
||||
# Find npm path (needed for systemd ExecStart)
|
||||
local npm_path
|
||||
npm_path=$(command -v npm)
|
||||
if [ -z "$npm_path" ]; then
|
||||
print_warning "Could not find npm executable path. Service might require adjustment."
|
||||
# Try to find it relative to node? Often in ../lib/node_modules/npm/bin/npm-cli.js
|
||||
local node_dir
|
||||
node_dir=$(dirname "$node_path")
|
||||
# This is a common structure, adjust if needed
|
||||
npm_path="$node_dir/npm" # Adjust if npm is installed elsewhere
|
||||
if ! command -v "$npm_path" &> /dev/null; then
|
||||
print_error "Could not reliably find npm executable path. Cannot create service."
|
||||
exit 1
|
||||
fi
|
||||
print_info "Found npm at $npm_path"
|
||||
fi
|
||||
|
||||
print_info "Creating service file at $service_file..."
|
||||
# Use a HEREDOC to write the service file contents
|
||||
cat << EOF > "$service_file"
|
||||
[Unit]
|
||||
Description=Pulse for Proxmox VE Monitoring Application
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=$PULSE_USER
|
||||
Group=$PULSE_USER
|
||||
WorkingDirectory=$PULSE_DIR
|
||||
|
||||
# Start command using absolute paths found earlier
|
||||
ExecStart=$node_path $npm_path run start
|
||||
|
||||
# Restart policy
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# Environment (optional, if needed, but .env should handle this)
|
||||
# Environment="NODE_ENV=production"
|
||||
|
||||
# Standard output/error logging
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
print_error "Failed to create systemd service file $service_file."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set permissions for the service file
|
||||
chmod 644 "$service_file"
|
||||
|
||||
print_info "Reloading systemd daemon..."
|
||||
systemctl daemon-reload
|
||||
|
||||
print_info "Enabling $SERVICE_NAME to start on boot..."
|
||||
if systemctl enable "$SERVICE_NAME" > /dev/null 2>&1; then
|
||||
print_success "Service enabled successfully."
|
||||
else
|
||||
print_error "Failed to enable systemd service."
|
||||
# Attempt cleanup of service file?
|
||||
# rm -f "$service_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_info "Starting $SERVICE_NAME..."
|
||||
if systemctl start "$SERVICE_NAME"; then
|
||||
print_success "Service started successfully."
|
||||
else
|
||||
print_error "Failed to start systemd service."
|
||||
print_warning "Please check the service status using: systemctl status $SERVICE_NAME"
|
||||
print_warning "And check the logs using: journalctl -u $SERVICE_NAME"
|
||||
# Don't necessarily exit, user might be able to fix it.
|
||||
fi
|
||||
}
|
||||
|
||||
final_instructions() {
|
||||
# Try to get the IP address of the container
|
||||
local ip_address
|
||||
ip_address=$(hostname -I | awk '{print $1}') # Get the first IP address
|
||||
local port_value
|
||||
# Read the port from the .env file, fallback to default if not found/readable
|
||||
local env_path="$PULSE_DIR/server/.env"
|
||||
if [ -f "$env_path" ] && grep -q '^PORT=' "$env_path"; then
|
||||
port_value=$(grep '^PORT=' "$env_path" | cut -d'=' -f2)
|
||||
else
|
||||
port_value="7655" # Default port
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_success "Pulse for Proxmox VE installation and setup complete!"
|
||||
echo "-------------------------------------------------------------"
|
||||
print_info "You should be able to access the Pulse dashboard at:"
|
||||
if [ -n "$ip_address" ]; then
|
||||
echo " http://$ip_address:$port_value"
|
||||
else
|
||||
echo " http://<YOUR-LXC-IP>:$port_value"
|
||||
print_warning "Could not automatically determine the LXC IP address."
|
||||
fi
|
||||
echo ""
|
||||
print_info "The Pulse service ($SERVICE_NAME) is running and enabled on boot."
|
||||
print_info "To check the status: sudo systemctl status $SERVICE_NAME"
|
||||
print_info "To view logs: sudo journalctl -u $SERVICE_NAME -f"
|
||||
print_info "Configuration file: $PULSE_DIR/server/.env"
|
||||
echo "-------------------------------------------------------------"
|
||||
}
|
||||
|
||||
# --- Main Execution ---
|
||||
check_root
|
||||
apt_update_upgrade
|
||||
install_dependencies
|
||||
setup_node
|
||||
create_pulse_user
|
||||
clone_repository
|
||||
install_npm_deps
|
||||
set_permissions
|
||||
configure_environment
|
||||
setup_systemd_service
|
||||
final_instructions
|
||||
|
||||
print_info "Script finished."
|
||||
|
||||
# --- Placeholder for next steps ---
|
||||
# 1. Create dedicated user
|
||||
# 2. Clone repository
|
||||
# 3. Install npm dependencies
|
||||
# 4. Configure .env
|
||||
# 5. Setup systemd service
|
||||
# 6. Final instructions
|
||||
|
||||
echo ""
|
||||
print_success "Script execution will continue..." # Placeholder
|
||||
Reference in New Issue
Block a user