From 566b6c331ba8477859b716923b37b88b6f4673b4 Mon Sep 17 00:00:00 2001 From: Morgan Prior <36314+morganp@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:46:40 +0000 Subject: [PATCH 1/8] Add Homebrew (Linuxbrew) addon script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addon script that installs Homebrew into an existing LXC container. Dynamically detects the first non-root user, sets up multi-user access via linuxbrew group with setgid directories, and configures shell integration for both login and non-login shells. Tested on Debian 13 (trixie) — brew doctor reports "ready to brew". Co-Authored-By: Claude Opus 4.6 --- frontend/public/json/homebrew.json | 44 ++++++++++++ tools/addon/homebrew.sh | 106 +++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 frontend/public/json/homebrew.json create mode 100644 tools/addon/homebrew.sh diff --git a/frontend/public/json/homebrew.json b/frontend/public/json/homebrew.json new file mode 100644 index 000000000..c6ac92165 --- /dev/null +++ b/frontend/public/json/homebrew.json @@ -0,0 +1,44 @@ +{ + "name": "Homebrew (Linuxbrew)", + "slug": "homebrew", + "categories": [ + 20 + ], + "date_created": "2026-02-26", + "type": "addon", + "updateable": false, + "privileged": false, + "interface_port": null, + "documentation": "https://docs.brew.sh/", + "website": "https://brew.sh/", + "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/homebrew.webp", + "config_path": "", + "description": "Homebrew (Linuxbrew) is a package manager for Linux that installs software from source into a user-managed prefix, allowing non-root users to install development tools and utilities without system-wide changes.", + "install_methods": [ + { + "type": "default", + "script": "tools/addon/homebrew.sh", + "resources": { + "cpu": null, + "ram": null, + "hdd": null, + "os": null, + "version": null + } + } + ], + "default_credentials": { + "username": null, + "password": null + }, + "notes": [ + { + "text": "Execute within an existing LXC Console", + "type": "info" + }, + { + "text": "Requires at least one non-root user (uid >= 1000) in the container", + "type": "warning" + } + ] +} diff --git a/tools/addon/homebrew.sh b/tools/addon/homebrew.sh new file mode 100644 index 000000000..a6115bf6c --- /dev/null +++ b/tools/addon/homebrew.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: MorganCSIT +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://brew.sh | Github: https://github.com/Homebrew/brew + +function header_info { + clear + cat <<"EOF" + __ __ __ + / / / /___ ____ ___ ___ / /_ ________ _ __ + / /_/ / __ \/ __ `__ \/ _ \/ __ \/ ___/ _ \ | /| / / + / __ / /_/ / / / / / / __/ /_/ / / / __/ |/ |/ / +/_/ /_/\____/_/ /_/ /_/\___/_.___/_/ \___/|__/|__/ + (Linuxbrew) + +EOF +} +set -eEuo pipefail +YW=$(echo "\033[33m") +BL=$(echo "\033[36m") +RD=$(echo "\033[01;31m") +BGN=$(echo "\033[4;92m") +GN=$(echo "\033[1;92m") +DGN=$(echo "\033[32m") +CL=$(echo "\033[m") +CM="${GN}✓${CL}" +BFR="\\r\\033[K" +HOLD="-" + +msg_info() { + local msg="$1" + echo -ne " ${HOLD} ${YW}${msg}..." +} + +msg_ok() { + local msg="$1" + echo -e "${BFR} ${CM} ${GN}${msg}${CL}" +} + +msg_error() { + local msg="$1" + echo -e "${BFR} ${RD}✗ ${msg}${CL}" +} + +# Telemetry +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true +declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "homebrew" "addon" + +header_info + +whiptail --backtitle "Proxmox VE Helper Scripts" --title "Homebrew (Linuxbrew) Installer" --yesno "This Will Install Homebrew (Linuxbrew) on this LXC Container. Proceed?" 10 58 + +msg_info "Installing Dependencies" +apt-get install -y build-essential git curl file procps &>/dev/null +msg_ok "Installed Dependencies" + +msg_info "Detecting Non-Root User" +BREW_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 { print $1; exit }' /etc/passwd) +if [ -z "$BREW_USER" ]; then + msg_error "No non-root user found (uid >= 1000). Create a user first." + exit 1 +fi +msg_ok "Detected User: $BREW_USER" + +msg_info "Setting Up Homebrew Prefix" +export PATH="/usr/sbin:$PATH" +groupadd -f linuxbrew +mkdir -p /home/linuxbrew/.linuxbrew +chown -R "$BREW_USER":linuxbrew /home/linuxbrew +chmod 2775 /home/linuxbrew +chmod 2775 /home/linuxbrew/.linuxbrew +usermod -aG linuxbrew "$BREW_USER" +msg_ok "Set Up Homebrew Prefix" + +msg_info "Installing Homebrew" +su - "$BREW_USER" -c 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' &>/dev/null +msg_ok "Installed Homebrew" + +msg_info "Configuring Shell Integration" +cat > /etc/profile.d/homebrew.sh << 'EOF' +#!/bin/bash +if [ -d "/home/linuxbrew/.linuxbrew" ]; then + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" +fi +EOF +chmod +x /etc/profile.d/homebrew.sh + +BREW_USER_HOME=$(eval echo "~$BREW_USER") +if ! grep -q 'linuxbrew' "$BREW_USER_HOME/.bashrc" 2>/dev/null; then + cat >> "$BREW_USER_HOME/.bashrc" << 'EOF' + +# Homebrew (Linuxbrew) +if [ -d "/home/linuxbrew/.linuxbrew" ]; then + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" +fi +EOF +fi +msg_ok "Configured Shell Integration" + +msg_info "Verifying Installation" +su - "$BREW_USER" -c 'brew --version' +msg_ok "Homebrew Verified" + +echo -e "Successfully Installed!! Homebrew is ready for user ${BL}${BREW_USER}${CL}" From 0b68f923b68b0587bcfea3d0c4310238cfc94192 Mon Sep 17 00:00:00 2001 From: Morgan Prior <36314+morganp@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:58:41 +0000 Subject: [PATCH 2/8] Update tools/addon/homebrew.sh Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- tools/addon/homebrew.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/addon/homebrew.sh b/tools/addon/homebrew.sh index a6115bf6c..649ee4789 100644 --- a/tools/addon/homebrew.sh +++ b/tools/addon/homebrew.sh @@ -79,7 +79,7 @@ su - "$BREW_USER" -c 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.gi msg_ok "Installed Homebrew" msg_info "Configuring Shell Integration" -cat > /etc/profile.d/homebrew.sh << 'EOF' +cat <<'EOF'> /etc/profile.d/homebrew.sh #!/bin/bash if [ -d "/home/linuxbrew/.linuxbrew" ]; then eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" From 83df31c5da79bb9f8bb867accade167e8dda1ae9 Mon Sep 17 00:00:00 2001 From: Morgan Prior <36314+morganp@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:58:56 +0000 Subject: [PATCH 3/8] Update tools/addon/homebrew.sh Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- tools/addon/homebrew.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/addon/homebrew.sh b/tools/addon/homebrew.sh index 649ee4789..e31c9153b 100644 --- a/tools/addon/homebrew.sh +++ b/tools/addon/homebrew.sh @@ -53,7 +53,7 @@ header_info whiptail --backtitle "Proxmox VE Helper Scripts" --title "Homebrew (Linuxbrew) Installer" --yesno "This Will Install Homebrew (Linuxbrew) on this LXC Container. Proceed?" 10 58 msg_info "Installing Dependencies" -apt-get install -y build-essential git curl file procps &>/dev/null +apt install -y build-essential git curl file procps &>/dev/null msg_ok "Installed Dependencies" msg_info "Detecting Non-Root User" From ce3127f2b355451fe0b7aafe5f489dae61db5cff Mon Sep 17 00:00:00 2001 From: Morgan Prior <36314+morganp@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:59:42 +0000 Subject: [PATCH 4/8] Update tools/addon/homebrew.sh Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- tools/addon/homebrew.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/addon/homebrew.sh b/tools/addon/homebrew.sh index e31c9153b..a4ab0f216 100644 --- a/tools/addon/homebrew.sh +++ b/tools/addon/homebrew.sh @@ -87,7 +87,7 @@ fi EOF chmod +x /etc/profile.d/homebrew.sh -BREW_USER_HOME=$(eval echo "~$BREW_USER") +BREW_USER_HOME=$(getent passwd "$BREW_USER" | cut -d: -f6) if ! grep -q 'linuxbrew' "$BREW_USER_HOME/.bashrc" 2>/dev/null; then cat >> "$BREW_USER_HOME/.bashrc" << 'EOF' From da4e45695fd880192c0783cbdb01dcf3545a48fa Mon Sep 17 00:00:00 2001 From: Morgan Prior <36314+morganp@users.noreply.github.com> Date: Thu, 26 Feb 2026 13:59:56 +0000 Subject: [PATCH 5/8] Update tools/addon/homebrew.sh Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- tools/addon/homebrew.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/addon/homebrew.sh b/tools/addon/homebrew.sh index a4ab0f216..ff8b83448 100644 --- a/tools/addon/homebrew.sh +++ b/tools/addon/homebrew.sh @@ -100,7 +100,7 @@ fi msg_ok "Configured Shell Integration" msg_info "Verifying Installation" -su - "$BREW_USER" -c 'brew --version' +su - "$BREW_USER" -c 'brew --version' &>/dev/null msg_ok "Homebrew Verified" echo -e "Successfully Installed!! Homebrew is ready for user ${BL}${BREW_USER}${CL}" From 05b99489fe8ae030df03c52693da1a8f6ca68d9f Mon Sep 17 00:00:00 2001 From: Morgan Prior <36314+morganp@users.noreply.github.com> Date: Thu, 26 Feb 2026 15:50:37 +0000 Subject: [PATCH 6/8] Clarify error message: Homebrew cannot run as root Co-Authored-By: Claude Opus 4.6 --- tools/addon/homebrew.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/addon/homebrew.sh b/tools/addon/homebrew.sh index ff8b83448..b812ef65c 100644 --- a/tools/addon/homebrew.sh +++ b/tools/addon/homebrew.sh @@ -59,7 +59,7 @@ msg_ok "Installed Dependencies" msg_info "Detecting Non-Root User" BREW_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 { print $1; exit }' /etc/passwd) if [ -z "$BREW_USER" ]; then - msg_error "No non-root user found (uid >= 1000). Create a user first." + msg_error "No non-root user found (uid >= 1000). Homebrew cannot run as root. Create a user first." exit 1 fi msg_ok "Detected User: $BREW_USER" From 57ba5cd16910444b1faef23138f353156743728b Mon Sep 17 00:00:00 2001 From: Morgan Prior <36314+morganp@users.noreply.github.com> Date: Thu, 26 Feb 2026 20:49:33 +0000 Subject: [PATCH 7/8] Rewrite homebrew addon to use core.func/tools.func pattern Sources core.func, tools.func, error_handler.func, and api.func instead of inline color vars and msg functions. Adds structured sections (CONFIGURATION, OS DETECTION, UNINSTALL, INSTALL, MAIN) matching the qbittorrent-exporter/pihole-exporter pattern. Co-Authored-By: Claude Opus 4.6 --- tools/addon/homebrew.sh | 207 +++++++++++++++++++++++++--------------- 1 file changed, 132 insertions(+), 75 deletions(-) diff --git a/tools/addon/homebrew.sh b/tools/addon/homebrew.sh index b812ef65c..c906a1c0b 100644 --- a/tools/addon/homebrew.sh +++ b/tools/addon/homebrew.sh @@ -5,102 +5,159 @@ # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # Source: https://brew.sh | Github: https://github.com/Homebrew/brew -function header_info { - clear - cat <<"EOF" - __ __ __ - / / / /___ ____ ___ ___ / /_ ________ _ __ - / /_/ / __ \/ __ `__ \/ _ \/ __ \/ ___/ _ \ | /| / / - / __ / /_/ / / / / / / __/ /_/ / / / __/ |/ |/ / -/_/ /_/\____/_/ /_/ /_/\___/_.___/_/ \___/|__/|__/ - (Linuxbrew) - -EOF -} -set -eEuo pipefail -YW=$(echo "\033[33m") -BL=$(echo "\033[36m") -RD=$(echo "\033[01;31m") -BGN=$(echo "\033[4;92m") -GN=$(echo "\033[1;92m") -DGN=$(echo "\033[32m") -CL=$(echo "\033[m") -CM="${GN}✓${CL}" -BFR="\\r\\033[K" -HOLD="-" - -msg_info() { - local msg="$1" - echo -ne " ${HOLD} ${YW}${msg}..." -} - -msg_ok() { - local msg="$1" - echo -e "${BFR} ${CM} ${GN}${msg}${CL}" -} - -msg_error() { - local msg="$1" - echo -e "${BFR} ${RD}✗ ${msg}${CL}" -} - -# Telemetry +if ! command -v curl &>/dev/null; then + printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2 + apt-get update >/dev/null 2>&1 + apt-get install -y curl >/dev/null 2>&1 +fi +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func) +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true -declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "homebrew" "addon" -header_info +# Enable error handling +set -Eeuo pipefail +trap 'error_handler' ERR +load_functions +init_tool_telemetry "" "addon" -whiptail --backtitle "Proxmox VE Helper Scripts" --title "Homebrew (Linuxbrew) Installer" --yesno "This Will Install Homebrew (Linuxbrew) on this LXC Container. Proceed?" 10 58 +# ============================================================================== +# CONFIGURATION +# ============================================================================== +VERBOSE=${var_verbose:-no} +APP="homebrew" +APP_TYPE="tools" +INSTALL_PATH="/home/linuxbrew/.linuxbrew" -msg_info "Installing Dependencies" -apt install -y build-essential git curl file procps &>/dev/null -msg_ok "Installed Dependencies" - -msg_info "Detecting Non-Root User" -BREW_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 { print $1; exit }' /etc/passwd) -if [ -z "$BREW_USER" ]; then - msg_error "No non-root user found (uid >= 1000). Homebrew cannot run as root. Create a user first." +# ============================================================================== +# OS DETECTION +# ============================================================================== +if [[ -f "/etc/alpine-release" ]]; then + echo -e "${CROSS} Alpine is not supported by Homebrew. Exiting." + exit 1 +elif grep -qE 'ID=debian|ID=ubuntu' /etc/os-release; then + OS="Debian" +else + echo -e "${CROSS} Unsupported OS detected. Exiting." exit 1 fi -msg_ok "Detected User: $BREW_USER" -msg_info "Setting Up Homebrew Prefix" -export PATH="/usr/sbin:$PATH" -groupadd -f linuxbrew -mkdir -p /home/linuxbrew/.linuxbrew -chown -R "$BREW_USER":linuxbrew /home/linuxbrew -chmod 2775 /home/linuxbrew -chmod 2775 /home/linuxbrew/.linuxbrew -usermod -aG linuxbrew "$BREW_USER" -msg_ok "Set Up Homebrew Prefix" +# ============================================================================== +# UNINSTALL +# ============================================================================== +function uninstall() { + msg_info "Uninstalling Homebrew" -msg_info "Installing Homebrew" -su - "$BREW_USER" -c 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' &>/dev/null -msg_ok "Installed Homebrew" + BREW_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 { print $1; exit }' /etc/passwd) + if [[ -n "$BREW_USER" ]]; then + BREW_USER_HOME=$(getent passwd "$BREW_USER" | cut -d: -f6) + if [[ -f "$BREW_USER_HOME/.bashrc" ]]; then + sed -i '/# Homebrew (Linuxbrew)/,/^fi$/d' "$BREW_USER_HOME/.bashrc" + fi + fi -msg_info "Configuring Shell Integration" -cat <<'EOF'> /etc/profile.d/homebrew.sh + rm -rf /home/linuxbrew + rm -f /etc/profile.d/homebrew.sh + groupdel linuxbrew &>/dev/null || true + + msg_ok "Homebrew has been uninstalled" +} + +# ============================================================================== +# INSTALL +# ============================================================================== +function install() { + msg_info "Detecting Non-Root User" + BREW_USER=$(awk -F: '$3 >= 1000 && $3 < 65534 { print $1; exit }' /etc/passwd) + if [[ -z "$BREW_USER" ]]; then + msg_error "No non-root user found (uid >= 1000). Homebrew cannot run as root. Create a user first." + exit 1 + fi + msg_ok "Detected User: $BREW_USER" + + msg_info "Installing Dependencies" + $STD apt-get update + $STD apt-get install -y build-essential git curl file procps + msg_ok "Installed Dependencies" + + msg_info "Setting Up Homebrew Prefix" + export PATH="/usr/sbin:$PATH" + groupadd -f linuxbrew + mkdir -p /home/linuxbrew/.linuxbrew + chown -R "$BREW_USER":linuxbrew /home/linuxbrew + chmod 2775 /home/linuxbrew + chmod 2775 /home/linuxbrew/.linuxbrew + usermod -aG linuxbrew "$BREW_USER" + msg_ok "Set Up Homebrew Prefix" + + msg_info "Installing Homebrew" + $STD su - "$BREW_USER" -c 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' + msg_ok "Installed Homebrew" + + msg_info "Configuring Shell Integration" + cat <<'EOF'> /etc/profile.d/homebrew.sh #!/bin/bash if [ -d "/home/linuxbrew/.linuxbrew" ]; then eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" fi EOF -chmod +x /etc/profile.d/homebrew.sh + chmod +x /etc/profile.d/homebrew.sh -BREW_USER_HOME=$(getent passwd "$BREW_USER" | cut -d: -f6) -if ! grep -q 'linuxbrew' "$BREW_USER_HOME/.bashrc" 2>/dev/null; then - cat >> "$BREW_USER_HOME/.bashrc" << 'EOF' + BREW_USER_HOME=$(getent passwd "$BREW_USER" | cut -d: -f6) + if ! grep -q 'linuxbrew' "$BREW_USER_HOME/.bashrc" 2>/dev/null; then + cat >> "$BREW_USER_HOME/.bashrc" << 'EOF' # Homebrew (Linuxbrew) if [ -d "/home/linuxbrew/.linuxbrew" ]; then eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" fi EOF + fi + msg_ok "Configured Shell Integration" + + msg_info "Verifying Installation" + $STD su - "$BREW_USER" -c 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" && brew --version' + msg_ok "Homebrew Verified" + + echo "" + msg_ok "Homebrew installed successfully" + msg_ok "Ready for user: ${BL}${BREW_USER}${CL}" + msg_ok "Homebrew updates itself via: ${BL}brew update${CL}" +} + +# ============================================================================== +# MAIN +# ============================================================================== +header_info + +if [[ -d "$INSTALL_PATH" ]]; then + msg_warn "Homebrew is already installed." + echo "" + + echo -n "${TAB}Uninstall Homebrew? (y/N): " + read -r uninstall_prompt + if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then + uninstall + exit 0 + fi + + msg_warn "No action selected. Exiting." + exit 0 fi -msg_ok "Configured Shell Integration" -msg_info "Verifying Installation" -su - "$BREW_USER" -c 'brew --version' &>/dev/null -msg_ok "Homebrew Verified" +# Fresh installation +msg_warn "Homebrew is not installed." +echo "" +echo -e "${TAB}${INFO} This will install:" +echo -e "${TAB} - Homebrew (Linuxbrew) package manager" +echo -e "${TAB} - Shell integration for the detected non-root user" +echo "" -echo -e "Successfully Installed!! Homebrew is ready for user ${BL}${BREW_USER}${CL}" +echo -n "${TAB}Install Homebrew? (y/N): " +read -r install_prompt +if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then + install +else + msg_warn "Installation cancelled. Exiting." + exit 0 +fi From 2fc164e4d182afa891a7cfbf7713343eb243381d Mon Sep 17 00:00:00 2001 From: Morgan Prior <36314+morganp@users.noreply.github.com> Date: Fri, 27 Feb 2026 08:50:00 +0000 Subject: [PATCH 8/8] Use apt instead of apt-get in install function Co-Authored-By: Claude Opus 4.6 --- tools/addon/homebrew.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/addon/homebrew.sh b/tools/addon/homebrew.sh index c906a1c0b..2d3fd0c2e 100644 --- a/tools/addon/homebrew.sh +++ b/tools/addon/homebrew.sh @@ -76,8 +76,8 @@ function install() { msg_ok "Detected User: $BREW_USER" msg_info "Installing Dependencies" - $STD apt-get update - $STD apt-get install -y build-essential git curl file procps + $STD apt update + $STD apt install -y build-essential git file procps msg_ok "Installed Dependencies" msg_info "Setting Up Homebrew Prefix"