mirror of
				https://github.com/community-scripts/ProxmoxVE.git
				synced 2025-11-04 10:22:50 +00:00 
			
		
		
		
	Compare commits
	
		
			18 Commits
		
	
	
		
			2025-05-14
			...
			2025-05-15
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					1fdda378ac | ||
| 
						 | 
					7b62fd4866 | ||
| 
						 | 
					0da24e2651 | ||
| 
						 | 
					fd689e94ed | ||
| 
						 | 
					47155ac280 | ||
| 
						 | 
					aa57bac96d | ||
| 
						 | 
					24d730c120 | ||
| 
						 | 
					de9ae6eaa9 | ||
| 
						 | 
					4fd065a4bd | ||
| 
						 | 
					e26aac187b | ||
| 
						 | 
					5e63b70e83 | ||
| 
						 | 
					292ab6e54b | ||
| 
						 | 
					7d924fac27 | ||
| 
						 | 
					4b31957617 | ||
| 
						 | 
					35c99ae503 | ||
| 
						 | 
					62189321cc | ||
| 
						 | 
					59dfdc9af6 | ||
| 
						 | 
					19cf4d3dc2 | 
@@ -184,7 +184,7 @@ msg_info "Installing Dependencies"
 | 
			
		||||
$STD apt-get install -y ...
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
read -p "Do you wish to enable HTTPS mode? (y/N): " httpschoice
 | 
			
		||||
read -p "${TAB3}Do you wish to enable HTTPS mode? (y/N): " httpschoice
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 6.2 **Verbosity**
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -14,8 +14,29 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
 | 
			
		||||
All LXC instances created using this repository come pre-installed with Midnight Commander, which is a command-line tool (`mc`) that offers a user-friendly file and directory management interface for the terminal environment.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 2025-05-16
 | 
			
		||||
 | 
			
		||||
## 2025-05-15
 | 
			
		||||
 | 
			
		||||
### 🆕 New Scripts
 | 
			
		||||
 | 
			
		||||
  - bitmagnet ([#4493](https://github.com/community-scripts/ProxmoxVE/pull/4493))
 | 
			
		||||
 | 
			
		||||
### 🚀 Updated Scripts
 | 
			
		||||
 | 
			
		||||
  - core: Add TAB3 formatting var to core [@tremor021](https://github.com/tremor021) ([#4496](https://github.com/community-scripts/ProxmoxVE/pull/4496))
 | 
			
		||||
- Update scripts that use "read -p" to properly indent text [@tremor021](https://github.com/tremor021) ([#4498](https://github.com/community-scripts/ProxmoxVE/pull/4498))
 | 
			
		||||
 | 
			
		||||
  - #### ✨ New Features
 | 
			
		||||
 | 
			
		||||
    - tools.func: fix some things & add ruby default function [@MickLesk](https://github.com/MickLesk) ([#4507](https://github.com/community-scripts/ProxmoxVE/pull/4507))
 | 
			
		||||
 | 
			
		||||
### 🧰 Maintenance
 | 
			
		||||
 | 
			
		||||
  - #### 💾 Core
 | 
			
		||||
 | 
			
		||||
    - core: fix bridge detection for OVS  [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#4495](https://github.com/community-scripts/ProxmoxVE/pull/4495))
 | 
			
		||||
 | 
			
		||||
## 2025-05-14
 | 
			
		||||
 | 
			
		||||
### 🆕 New Scripts
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										89
									
								
								ct/alpine-bitmagnet.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								ct/alpine-bitmagnet.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
 | 
			
		||||
# Copyright (c) 2021-2025 community-scripts ORG
 | 
			
		||||
# Author: Slaviša Arežina (tremor021)
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
# Source: https://github.com/bitmagnet-io/bitmagnet
 | 
			
		||||
 | 
			
		||||
APP="Alpine-bitmagnet"
 | 
			
		||||
var_tags="${var_tags:-alpine;torrent}"
 | 
			
		||||
var_cpu="${var_cpu:-2}"
 | 
			
		||||
var_ram="${var_ram:-1024}"
 | 
			
		||||
var_disk="${var_disk:-3}"
 | 
			
		||||
var_os="${var_os:-alpine}"
 | 
			
		||||
var_version="${var_version:-3.21}"
 | 
			
		||||
var_unprivileged="${var_unprivileged:-1}"
 | 
			
		||||
 | 
			
		||||
header_info "$APP"
 | 
			
		||||
variables
 | 
			
		||||
color
 | 
			
		||||
catch_errors
 | 
			
		||||
 | 
			
		||||
function update_script() {
 | 
			
		||||
  header_info
 | 
			
		||||
 | 
			
		||||
  if [[ ! -d /opt/bitmagnet ]]; then
 | 
			
		||||
    msg_error "No ${APP} Installation Found!"
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
  RELEASE=$(curl -fsSL https://api.github.com/repos/bitmagnet-io/bitmagnet/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
  if [ "${RELEASE}" != "$(cat /opt/bitmagnet_version.txt)" ] || [ ! -f /opt/bitmagnet_version.txt ]; then
 | 
			
		||||
    msg_info "Backing up database"
 | 
			
		||||
    rm -f /tmp/backup.sql
 | 
			
		||||
    $STD sudo -u postgres pg_dump \
 | 
			
		||||
      --column-inserts \
 | 
			
		||||
      --data-only \
 | 
			
		||||
      --on-conflict-do-nothing \
 | 
			
		||||
      --rows-per-insert=1000 \
 | 
			
		||||
      --table=metadata_sources \
 | 
			
		||||
      --table=content \
 | 
			
		||||
      --table=content_attributes \
 | 
			
		||||
      --table=content_collections \
 | 
			
		||||
      --table=content_collections_content \
 | 
			
		||||
      --table=torrent_sources \
 | 
			
		||||
      --table=torrents \
 | 
			
		||||
      --table=torrent_files \
 | 
			
		||||
      --table=torrent_hints \
 | 
			
		||||
      --table=torrent_contents \
 | 
			
		||||
      --table=torrent_tags \
 | 
			
		||||
      --table=torrents_torrent_sources \
 | 
			
		||||
      --table=key_values \
 | 
			
		||||
      bitmagnet \
 | 
			
		||||
      >/tmp/backup.sql
 | 
			
		||||
    mv /tmp/backup.sql /opt/
 | 
			
		||||
    msg_ok "Database backed up"
 | 
			
		||||
 | 
			
		||||
    msg_info "Updating ${APP} from $(cat /opt/bitmagnet_version.txt) to ${RELEASE}"
 | 
			
		||||
    $STD apk -U upgrade
 | 
			
		||||
    $STD service bitmagnet stop
 | 
			
		||||
    [ -f /opt/bitmagnet/.env ] && cp /opt/bitmagnet/.env /opt/
 | 
			
		||||
    [ -f /opt/bitmagnet/config.yml ] && cp /opt/bitmagnet/config.yml /opt/
 | 
			
		||||
    rm -rf /opt/bitmagnet/*
 | 
			
		||||
    temp_file=$(mktemp)
 | 
			
		||||
    curl -fsSL "https://github.com/bitmagnet-io/bitmagnet/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
 | 
			
		||||
    tar zxf "$temp_file" --strip-components=1 -C /opt/bitmagnet
 | 
			
		||||
    cd /opt/bitmagnet
 | 
			
		||||
    VREL=v$RELEASE
 | 
			
		||||
    $STD go build -ldflags "-s -w -X github.com/bitmagnet-io/bitmagnet/internal/version.GitTag=$VREL"
 | 
			
		||||
    chmod +x bitmagnet
 | 
			
		||||
    [ -f "/opt/.env" ] && cp "/opt/.env" /opt/bitmagnet/
 | 
			
		||||
    [ -f "/opt/config.yml" ] && cp "/opt/config.yml" /opt/bitmagnet/
 | 
			
		||||
    rm -f "$temp_file"
 | 
			
		||||
    echo "${RELEASE}" >/opt/bitmagnet_version.txt
 | 
			
		||||
    $STD service bitmagnet start
 | 
			
		||||
    msg_ok "Updated Successfully"
 | 
			
		||||
  else
 | 
			
		||||
    msg_ok "No update required. ${APP} is already at ${RELEASE}"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  exit 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
start
 | 
			
		||||
build_container
 | 
			
		||||
description
 | 
			
		||||
 | 
			
		||||
msg_ok "Completed Successfully!\n"
 | 
			
		||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
 | 
			
		||||
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
 | 
			
		||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3333${CL}"
 | 
			
		||||
							
								
								
									
										98
									
								
								ct/bitmagnet.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								ct/bitmagnet.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
 | 
			
		||||
# Copyright (c) 2021-2025 community-scripts ORG
 | 
			
		||||
# Author: Slaviša Arežina (tremor021)
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
# Source: https://github.com/bitmagnet/bitmagnet
 | 
			
		||||
 | 
			
		||||
APP="Bitmagnet"
 | 
			
		||||
var_tags="${var_tags:-os}"
 | 
			
		||||
var_cpu="${var_cpu:-2}"
 | 
			
		||||
var_ram="${var_ram:-1024}"
 | 
			
		||||
var_disk="${var_disk:-4}"
 | 
			
		||||
var_os="${var_os:-debian}"
 | 
			
		||||
var_version="${var_version:-12}"
 | 
			
		||||
var_unprivileged="${var_unprivileged:-1}"
 | 
			
		||||
 | 
			
		||||
header_info "$APP"
 | 
			
		||||
variables
 | 
			
		||||
color
 | 
			
		||||
catch_errors
 | 
			
		||||
 | 
			
		||||
function update_script() {
 | 
			
		||||
  header_info
 | 
			
		||||
  check_container_storage
 | 
			
		||||
  check_container_resources
 | 
			
		||||
  if [[ ! -d /opt/bitmagnet ]]; then
 | 
			
		||||
    msg_error "No ${APP} Installation Found!"
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
  RELEASE=$(curl -fsSL https://api.github.com/repos/bitmagnet-io/bitmagnet/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
  if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
 | 
			
		||||
    msg_info "Stopping Service"
 | 
			
		||||
    systemctl stop bitmagnet-web
 | 
			
		||||
    msg_ok "Stopped Service"
 | 
			
		||||
 | 
			
		||||
    msg_info "Backing up database"
 | 
			
		||||
    rm -f /tmp/backup.sql
 | 
			
		||||
    $STD sudo -u postgres pg_dump \
 | 
			
		||||
      --column-inserts \
 | 
			
		||||
      --data-only \
 | 
			
		||||
      --on-conflict-do-nothing \
 | 
			
		||||
      --rows-per-insert=1000 \
 | 
			
		||||
      --table=metadata_sources \
 | 
			
		||||
      --table=content \
 | 
			
		||||
      --table=content_attributes \
 | 
			
		||||
      --table=content_collections \
 | 
			
		||||
      --table=content_collections_content \
 | 
			
		||||
      --table=torrent_sources \
 | 
			
		||||
      --table=torrents \
 | 
			
		||||
      --table=torrent_files \
 | 
			
		||||
      --table=torrent_hints \
 | 
			
		||||
      --table=torrent_contents \
 | 
			
		||||
      --table=torrent_tags \
 | 
			
		||||
      --table=torrents_torrent_sources \
 | 
			
		||||
      --table=key_values \
 | 
			
		||||
      bitmagnet \
 | 
			
		||||
      >/tmp/backup.sql
 | 
			
		||||
    mv /tmp/backup.sql /opt/
 | 
			
		||||
    msg_ok "Database backed up"
 | 
			
		||||
 | 
			
		||||
    msg_info "Updating ${APP} to v${RELEASE}"
 | 
			
		||||
    [ -f /opt/bitmagnet/.env ] && cp /opt/bitmagnet/.env /opt/
 | 
			
		||||
    [ -f /opt/bitmagnet/config.yml ] && cp /opt/bitmagnet/config.yml /opt/
 | 
			
		||||
    rm -rf /opt/bitmagnet/*
 | 
			
		||||
    temp_file=$(mktemp)
 | 
			
		||||
    curl -fsSL "https://github.com/bitmagnet-io/bitmagnet/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
 | 
			
		||||
    tar zxf "$temp_file" --strip-components=1 -C /opt/bitmagnet
 | 
			
		||||
    cd /opt/bitmagnet
 | 
			
		||||
    VREL=v$RELEASE
 | 
			
		||||
    $STD go build -ldflags "-s -w -X github.com/bitmagnet-io/bitmagnet/internal/version.GitTag=$VREL"
 | 
			
		||||
    chmod +x bitmagnet
 | 
			
		||||
    [ -f "/opt/.env" ] && cp "/opt/.env" /opt/bitmagnet/
 | 
			
		||||
    [ -f "/opt/config.yml" ] && cp "/opt/config.yml" /opt/bitmagnet/
 | 
			
		||||
    echo "${RELEASE}" >/opt/${APP}_version.txt
 | 
			
		||||
    msg_ok "Updated $APP to v${RELEASE}"
 | 
			
		||||
 | 
			
		||||
    msg_info "Starting Service"
 | 
			
		||||
    systemctl start bitmagnet-web
 | 
			
		||||
    msg_ok "Started Service"
 | 
			
		||||
 | 
			
		||||
    msg_info "Cleaning up"
 | 
			
		||||
    rm -f "$temp_file"
 | 
			
		||||
    msg_ok "Cleaned"
 | 
			
		||||
    msg_ok "Updated Successfully"
 | 
			
		||||
  else
 | 
			
		||||
    msg_ok "No update required. ${APP} is already at v${RELEASE}"
 | 
			
		||||
  fi
 | 
			
		||||
  exit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
start
 | 
			
		||||
build_container
 | 
			
		||||
description
 | 
			
		||||
 | 
			
		||||
msg_ok "Completed Successfully!\n"
 | 
			
		||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
 | 
			
		||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
 | 
			
		||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3333${CL}"
 | 
			
		||||
							
								
								
									
										32
									
								
								ct/go2rtc.sh
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								ct/go2rtc.sh
									
									
									
									
									
								
							@@ -6,7 +6,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
 | 
			
		||||
# Source: https://github.com/AlexxIT/go2rtc
 | 
			
		||||
 | 
			
		||||
APP="go2rtc"
 | 
			
		||||
var_tags="${var_tags:-recorder;video}"
 | 
			
		||||
var_tags="${var_tags:-streaming;video}"
 | 
			
		||||
var_cpu="${var_cpu:-2}"
 | 
			
		||||
var_ram="${var_ram:-2048}"
 | 
			
		||||
var_disk="${var_disk:-4}"
 | 
			
		||||
@@ -20,22 +20,22 @@ color
 | 
			
		||||
catch_errors
 | 
			
		||||
 | 
			
		||||
function update_script() {
 | 
			
		||||
    header_info
 | 
			
		||||
    check_container_storage
 | 
			
		||||
    check_container_resources
 | 
			
		||||
    if [[ ! -d /opt/go2rtc ]]; then
 | 
			
		||||
        msg_error "No ${APP} Installation Found!"
 | 
			
		||||
        exit
 | 
			
		||||
    fi
 | 
			
		||||
    msg_info "Updating $APP"
 | 
			
		||||
    systemctl stop go2rtc
 | 
			
		||||
    cd /opt/go2rtc
 | 
			
		||||
    rm go2rtc_linux_amd64
 | 
			
		||||
    curl -fsSL "https://github.com/AlexxIT/go2rtc/releases/latest/download/go2rtc_linux_amd64" -o $(basename "https://github.com/AlexxIT/go2rtc/releases/latest/download/go2rtc_linux_amd64")
 | 
			
		||||
    chmod +x go2rtc_linux_amd64
 | 
			
		||||
    systemctl start go2rtc
 | 
			
		||||
    msg_ok "Updated $APP"
 | 
			
		||||
  header_info
 | 
			
		||||
  check_container_storage
 | 
			
		||||
  check_container_resources
 | 
			
		||||
  if [[ ! -d /opt/go2rtc ]]; then
 | 
			
		||||
    msg_error "No ${APP} Installation Found!"
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
  msg_info "Updating $APP"
 | 
			
		||||
  systemctl stop go2rtc
 | 
			
		||||
  cd /opt/go2rtc
 | 
			
		||||
  rm go2rtc_linux_amd64
 | 
			
		||||
  curl -fsSL "https://github.com/AlexxIT/go2rtc/releases/latest/download/go2rtc_linux_amd64" -o $(basename "https://github.com/AlexxIT/go2rtc/releases/latest/download/go2rtc_linux_amd64")
 | 
			
		||||
  chmod +x go2rtc_linux_amd64
 | 
			
		||||
  systemctl start go2rtc
 | 
			
		||||
  msg_ok "Updated $APP"
 | 
			
		||||
  exit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
start
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								ct/headers/alpine-bitmagnet
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								ct/headers/alpine-bitmagnet
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
    ___    __      _                  __    _ __                                   __ 
 | 
			
		||||
   /   |  / /___  (_)___  ___        / /_  (_) /_____ ___  ____ _____ _____  ___  / /_
 | 
			
		||||
  / /| | / / __ \/ / __ \/ _ \______/ __ \/ / __/ __ `__ \/ __ `/ __ `/ __ \/ _ \/ __/
 | 
			
		||||
 / ___ |/ / /_/ / / / / /  __/_____/ /_/ / / /_/ / / / / / /_/ / /_/ / / / /  __/ /_  
 | 
			
		||||
/_/  |_/_/ .___/_/_/ /_/\___/     /_.___/_/\__/_/ /_/ /_/\__,_/\__, /_/ /_/\___/\__/  
 | 
			
		||||
        /_/                                                   /____/                  
 | 
			
		||||
							
								
								
									
										6
									
								
								ct/headers/bitmagnet
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								ct/headers/bitmagnet
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
    ____  _ __                                   __ 
 | 
			
		||||
   / __ )(_) /_____ ___  ____ _____ _____  ___  / /_
 | 
			
		||||
  / __  / / __/ __ `__ \/ __ `/ __ `/ __ \/ _ \/ __/
 | 
			
		||||
 / /_/ / / /_/ / / / / / /_/ / /_/ / / / /  __/ /_  
 | 
			
		||||
/_____/_/\__/_/ /_/ /_/\__,_/\__, /_/ /_/\___/\__/  
 | 
			
		||||
                            /____/                  
 | 
			
		||||
@@ -151,7 +151,7 @@ EOF
 | 
			
		||||
    systemctl start homarr
 | 
			
		||||
    msg_ok "Started Services"
 | 
			
		||||
    msg_ok "Updated Successfully"
 | 
			
		||||
    read -p "It's recommended to reboot the LXC after an update, would you like to reboot the LXC now ? (y/n): " choice
 | 
			
		||||
    read -p "${TAB3}It's recommended to reboot the LXC after an update, would you like to reboot the LXC now ? (y/n): " choice
 | 
			
		||||
    if [[ "$choice" =~ ^[Yy]$ ]]; then
 | 
			
		||||
      reboot
 | 
			
		||||
    fi
 | 
			
		||||
 
 | 
			
		||||
@@ -114,7 +114,7 @@ function update_script() {
 | 
			
		||||
 | 
			
		||||
  if [ "$UPD" == "3" ]; then
 | 
			
		||||
    set +Eeuo pipefail
 | 
			
		||||
    read -r -p "Would you like to use No Authentication? <y/N> " prompt
 | 
			
		||||
    read -r -p "${TAB3}Would you like to use No Authentication? <y/N> " prompt
 | 
			
		||||
    msg_info "Installing FileBrowser"
 | 
			
		||||
    RELEASE=$(curl -fsSL https://api.github.com/repos/filebrowser/filebrowser/releases/latest | grep -o '"tag_name": ".*"' | sed 's/"//g' | sed 's/tag_name: //g')
 | 
			
		||||
    $STD curl -fsSL https://github.com/filebrowser/filebrowser/releases/download/$RELEASE/linux-amd64-filebrowser.tar.gz | tar -xzv -C /usr/local/bin
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								frontend/public/json/bitmagnet.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								frontend/public/json/bitmagnet.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "Bitmagnet",
 | 
			
		||||
  "slug": "bitmagnet",
 | 
			
		||||
  "categories": [
 | 
			
		||||
    11
 | 
			
		||||
  ],
 | 
			
		||||
  "date_created": "2025-05-15",
 | 
			
		||||
  "type": "ct",
 | 
			
		||||
  "updateable": true,
 | 
			
		||||
  "privileged": false,
 | 
			
		||||
  "interface_port": 3333,
 | 
			
		||||
  "documentation": "https://bitmagnet.io/setup.html",
 | 
			
		||||
  "website": "https://bitmagnet.io/",
 | 
			
		||||
  "logo": "https://raw.githubusercontent.com/selfhst/icons/refs/heads/main/webp/bitmagnet.webp",
 | 
			
		||||
  "config_path": "`/opt/bitmagnet/config.yml` or `/opt/bitmagnet/.env`",
 | 
			
		||||
  "description": "A self-hosted BitTorrent indexer, DHT crawler, content classifier and torrent search engine with web UI, GraphQL API and Servarr stack integration.",
 | 
			
		||||
  "install_methods": [
 | 
			
		||||
    {
 | 
			
		||||
      "type": "default",
 | 
			
		||||
      "script": "ct/bitmagnet.sh",
 | 
			
		||||
      "resources": {
 | 
			
		||||
        "cpu": 2,
 | 
			
		||||
        "ram": 1024,
 | 
			
		||||
        "hdd": 4,
 | 
			
		||||
        "os": "debian",
 | 
			
		||||
        "version": "12"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "type": "alpine",
 | 
			
		||||
      "script": "ct/alpine-bitmagnet.sh",
 | 
			
		||||
      "resources": {
 | 
			
		||||
        "cpu": 2,
 | 
			
		||||
        "ram": 1024,
 | 
			
		||||
        "hdd": 3,
 | 
			
		||||
        "os": "alpine",
 | 
			
		||||
        "version": "3.21"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "default_credentials": {
 | 
			
		||||
    "username": null,
 | 
			
		||||
    "password": null
 | 
			
		||||
  },
 | 
			
		||||
  "notes": [
 | 
			
		||||
    {
 | 
			
		||||
      "text": "During installation you will be asked to enter your TMDB API key, if you wanna use it. Make sure you have it ready.",
 | 
			
		||||
      "type": "info"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,99 @@
 | 
			
		||||
[
 | 
			
		||||
  {
 | 
			
		||||
    "name": "ipfs/kubo",
 | 
			
		||||
    "version": "v0.34.1",
 | 
			
		||||
    "date": "2025-03-25T18:11:12Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "coder/code-server",
 | 
			
		||||
    "version": "v4.100.2",
 | 
			
		||||
    "date": "2025-05-15T23:02:46Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "influxdata/influxdb",
 | 
			
		||||
    "version": "v3.0.3",
 | 
			
		||||
    "date": "2025-05-15T19:56:23Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "clusterzx/paperless-ai",
 | 
			
		||||
    "version": "v2.7.8",
 | 
			
		||||
    "date": "2025-05-15T18:04:54Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "goauthentik/authentik",
 | 
			
		||||
    "version": "version/2025.4.1",
 | 
			
		||||
    "date": "2025-05-15T17:48:29Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "cloudflare/cloudflared",
 | 
			
		||||
    "version": "2025.5.0",
 | 
			
		||||
    "date": "2025-05-15T17:09:50Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "apache/cassandra",
 | 
			
		||||
    "version": "4.1.9-tentative",
 | 
			
		||||
    "date": "2025-05-15T15:52:53Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "VictoriaMetrics/VictoriaMetrics",
 | 
			
		||||
    "version": "pmm-6401-v1.117.1",
 | 
			
		||||
    "date": "2025-05-15T15:45:22Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "ellite/Wallos",
 | 
			
		||||
    "version": "v3.1.1",
 | 
			
		||||
    "date": "2025-05-15T15:17:57Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "bunkerity/bunkerweb",
 | 
			
		||||
    "version": "v1.6.1",
 | 
			
		||||
    "date": "2025-03-15T17:29:17Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Checkmk/checkmk",
 | 
			
		||||
    "version": "v2.4.0p1",
 | 
			
		||||
    "date": "2025-05-15T12:41:12Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "zwave-js/zwave-js-ui",
 | 
			
		||||
    "version": "v10.5.1",
 | 
			
		||||
    "date": "2025-05-15T09:59:28Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "theonedev/onedev",
 | 
			
		||||
    "version": "v11.9.7",
 | 
			
		||||
    "date": "2025-05-15T07:03:28Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "mattermost/mattermost",
 | 
			
		||||
    "version": "v10.6.5",
 | 
			
		||||
    "date": "2025-05-15T07:06:52Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "cross-seed/cross-seed",
 | 
			
		||||
    "version": "v6.12.4",
 | 
			
		||||
    "date": "2025-05-11T11:41:32Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "morpheus65535/bazarr",
 | 
			
		||||
    "version": "v1.5.2",
 | 
			
		||||
    "date": "2025-05-11T16:40:55Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Jackett/Jackett",
 | 
			
		||||
    "version": "v0.22.1900",
 | 
			
		||||
    "date": "2025-05-15T06:01:04Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "FlowiseAI/Flowise",
 | 
			
		||||
    "version": "flowise@3.0.0",
 | 
			
		||||
    "date": "2025-05-15T01:49:47Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "ollama/ollama",
 | 
			
		||||
    "version": "v0.7.0-rc1",
 | 
			
		||||
    "date": "2025-05-14T03:58:02Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "advplyr/audiobookshelf",
 | 
			
		||||
    "version": "v2.22.0",
 | 
			
		||||
@@ -30,20 +125,15 @@
 | 
			
		||||
    "date": "2025-05-11T22:18:43Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "coder/code-server",
 | 
			
		||||
    "version": "v4.100.1",
 | 
			
		||||
    "date": "2025-05-14T18:08:16Z"
 | 
			
		||||
    "name": "keycloak/keycloak",
 | 
			
		||||
    "version": "26.2.4",
 | 
			
		||||
    "date": "2025-05-08T09:10:10Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "MediaBrowser/Emby.Releases",
 | 
			
		||||
    "version": "4.8.11.0",
 | 
			
		||||
    "date": "2025-03-10T06:39:11Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Checkmk/checkmk",
 | 
			
		||||
    "version": "v2.3.0p32+security",
 | 
			
		||||
    "date": "2025-05-14T15:37:55Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Athou/commafeed",
 | 
			
		||||
    "version": "5.9.0",
 | 
			
		||||
@@ -64,11 +154,6 @@
 | 
			
		||||
    "version": "0.42.1",
 | 
			
		||||
    "date": "2020-06-07T07:27:04Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "zwave-js/zwave-js-ui",
 | 
			
		||||
    "version": "v10.5.0",
 | 
			
		||||
    "date": "2025-05-14T13:21:21Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "firefly-iii/firefly-iii",
 | 
			
		||||
    "version": "v6.2.12",
 | 
			
		||||
@@ -95,30 +180,15 @@
 | 
			
		||||
    "date": "2024-08-29T22:32:51Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "morpheus65535/bazarr",
 | 
			
		||||
    "version": "v1.5.2",
 | 
			
		||||
    "date": "2025-05-11T16:40:55Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Jackett/Jackett",
 | 
			
		||||
    "version": "v0.22.1895",
 | 
			
		||||
    "date": "2025-05-14T05:59:00Z"
 | 
			
		||||
    "name": "runtipi/runtipi",
 | 
			
		||||
    "version": "nightly",
 | 
			
		||||
    "date": "2025-05-14T06:48:39Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "TandoorRecipes/recipes",
 | 
			
		||||
    "version": "2.0.0-alpha-4",
 | 
			
		||||
    "date": "2025-05-14T05:01:45Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "ollama/ollama",
 | 
			
		||||
    "version": "v0.6.9-rc0",
 | 
			
		||||
    "date": "2025-05-10T18:57:30Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "cross-seed/cross-seed",
 | 
			
		||||
    "version": "v6.12.4",
 | 
			
		||||
    "date": "2025-05-11T11:41:32Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "netbox-community/netbox",
 | 
			
		||||
    "version": "v4.3.1",
 | 
			
		||||
@@ -129,11 +199,6 @@
 | 
			
		||||
    "version": "v0.28.1",
 | 
			
		||||
    "date": "2025-05-13T18:45:47Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "keycloak/keycloak",
 | 
			
		||||
    "version": "26.2.4",
 | 
			
		||||
    "date": "2025-05-08T09:10:10Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "OctoPrint/OctoPrint",
 | 
			
		||||
    "version": "1.11.1",
 | 
			
		||||
@@ -144,11 +209,6 @@
 | 
			
		||||
    "version": "8.0.1",
 | 
			
		||||
    "date": "2025-05-13T13:31:53Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "theonedev/onedev",
 | 
			
		||||
    "version": "v11.9.6",
 | 
			
		||||
    "date": "2025-05-13T12:16:17Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "element-hq/synapse",
 | 
			
		||||
    "version": "v1.129.0",
 | 
			
		||||
@@ -184,11 +244,6 @@
 | 
			
		||||
    "version": "v2.1.0.118-2.1.0.118_canary_2025-05-12",
 | 
			
		||||
    "date": "2025-05-12T18:50:44Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "runtipi/runtipi",
 | 
			
		||||
    "version": "nightly",
 | 
			
		||||
    "date": "2025-05-12T18:39:33Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "neo4j/neo4j",
 | 
			
		||||
    "version": "4.4.43",
 | 
			
		||||
@@ -209,21 +264,11 @@
 | 
			
		||||
    "version": "v1.1.0",
 | 
			
		||||
    "date": "2025-05-12T14:40:27Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "VictoriaMetrics/VictoriaMetrics",
 | 
			
		||||
    "version": "pmm-6401-v1.117.0",
 | 
			
		||||
    "date": "2025-05-12T13:24:20Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "apache/tika",
 | 
			
		||||
    "version": "3.2.0-rc1",
 | 
			
		||||
    "date": "2025-05-12T13:06:47Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "mattermost/mattermost",
 | 
			
		||||
    "version": "v10.7.2",
 | 
			
		||||
    "date": "2025-05-12T10:42:32Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "dgtlmoon/changedetection.io",
 | 
			
		||||
    "version": "0.49.17",
 | 
			
		||||
@@ -309,11 +354,6 @@
 | 
			
		||||
    "version": "v0.53.0",
 | 
			
		||||
    "date": "2025-05-08T19:56:55Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "ellite/Wallos",
 | 
			
		||||
    "version": "v3.1.0",
 | 
			
		||||
    "date": "2025-05-08T15:33:17Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "BookStackApp/BookStack",
 | 
			
		||||
    "version": "v25.02.4",
 | 
			
		||||
@@ -339,11 +379,6 @@
 | 
			
		||||
    "version": "v5.36.3",
 | 
			
		||||
    "date": "2025-05-07T17:22:07Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "ipfs/kubo",
 | 
			
		||||
    "version": "v0.34.1",
 | 
			
		||||
    "date": "2025-03-25T18:11:12Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "donaldzou/WGDashboard",
 | 
			
		||||
    "version": "v4.2.3",
 | 
			
		||||
@@ -394,11 +429,6 @@
 | 
			
		||||
    "version": "@jupyter-notebook/ui-components@7.5.0-alpha.0",
 | 
			
		||||
    "date": "2025-05-07T09:12:08Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "influxdata/influxdb",
 | 
			
		||||
    "version": "v1.12.1rc0",
 | 
			
		||||
    "date": "2025-05-06T20:56:30Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "sysadminsmedia/homebox",
 | 
			
		||||
    "version": "v0.19.0",
 | 
			
		||||
@@ -564,21 +594,11 @@
 | 
			
		||||
    "version": "1.6.13",
 | 
			
		||||
    "date": "2025-04-30T16:38:35Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "cloudflare/cloudflared",
 | 
			
		||||
    "version": "2025.4.2",
 | 
			
		||||
    "date": "2025-04-30T14:16:11Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "docmost/docmost",
 | 
			
		||||
    "version": "v0.20.4",
 | 
			
		||||
    "date": "2025-04-30T14:15:16Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "goauthentik/authentik",
 | 
			
		||||
    "version": "version/2025.4.0",
 | 
			
		||||
    "date": "2025-04-30T12:34:14Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "hivemq/hivemq-community-edition",
 | 
			
		||||
    "version": "2025.3",
 | 
			
		||||
@@ -614,11 +634,6 @@
 | 
			
		||||
    "version": "v1.132.3",
 | 
			
		||||
    "date": "2025-04-28T14:11:06Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "FlowiseAI/Flowise",
 | 
			
		||||
    "version": "flowise@2.2.8",
 | 
			
		||||
    "date": "2025-04-28T08:27:00Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "karakeep-app/karakeep",
 | 
			
		||||
    "version": "v0.24.1",
 | 
			
		||||
@@ -764,11 +779,6 @@
 | 
			
		||||
    "version": "4.5.1",
 | 
			
		||||
    "date": "2025-04-11T09:57:47Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "apache/cassandra",
 | 
			
		||||
    "version": "cassandra-5.0.4",
 | 
			
		||||
    "date": "2025-04-10T16:32:00Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Threadfin/Threadfin",
 | 
			
		||||
    "version": "1.2.32",
 | 
			
		||||
@@ -854,11 +864,6 @@
 | 
			
		||||
    "version": "v4.7.0",
 | 
			
		||||
    "date": "2025-03-29T03:50:50Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "bunkerity/bunkerweb",
 | 
			
		||||
    "version": "v1.6.1",
 | 
			
		||||
    "date": "2025-03-15T17:29:17Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "grocy/grocy",
 | 
			
		||||
    "version": "v4.5.0",
 | 
			
		||||
@@ -899,11 +904,6 @@
 | 
			
		||||
    "version": "v4.3.1",
 | 
			
		||||
    "date": "2025-03-23T09:02:54Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "clusterzx/paperless-ai",
 | 
			
		||||
    "version": "v2.7.6",
 | 
			
		||||
    "date": "2025-03-21T19:24:53Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "seanmorley15/AdventureLog",
 | 
			
		||||
    "version": "v0.9.0",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										85
									
								
								install/alpine-bitmagnet-install.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								install/alpine-bitmagnet-install.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2021-2025 community-scripts ORG
 | 
			
		||||
# Author: Slaviša Arežina (tremor021)
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
# Source: https://github.com/bitmagnet-io/bitmagnet
 | 
			
		||||
 | 
			
		||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
 | 
			
		||||
color
 | 
			
		||||
verb_ip6
 | 
			
		||||
catch_errors
 | 
			
		||||
setting_up_container
 | 
			
		||||
network_check
 | 
			
		||||
update_os
 | 
			
		||||
 | 
			
		||||
msg_info "Installing dependencies"
 | 
			
		||||
$STD apk add --no-cache \
 | 
			
		||||
  gcc \
 | 
			
		||||
  musl-dev \
 | 
			
		||||
  git \
 | 
			
		||||
  iproute2-ss \
 | 
			
		||||
  sudo
 | 
			
		||||
$STD apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community go
 | 
			
		||||
msg_ok "Installed dependencies"
 | 
			
		||||
 | 
			
		||||
msg_info "Installing PostgreSQL"
 | 
			
		||||
$STD apk add --no-cache \
 | 
			
		||||
  postgresql16 \
 | 
			
		||||
  postgresql16-contrib \
 | 
			
		||||
  postgresql16-openrc
 | 
			
		||||
$STD rc-update add postgresql
 | 
			
		||||
$STD rc-service postgresql start
 | 
			
		||||
msg_ok "Installed PostreSQL"
 | 
			
		||||
 | 
			
		||||
RELEASE=$(curl -fsSL https://api.github.com/repos/bitmagnet-io/bitmagnet/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
 | 
			
		||||
msg_info "Installing bitmagnet v${RELEASE}"
 | 
			
		||||
mkdir -p /opt/bitmagnet
 | 
			
		||||
temp_file=$(mktemp)
 | 
			
		||||
curl -fsSL "https://github.com/bitmagnet-io/bitmagnet/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
 | 
			
		||||
tar zxf "$temp_file" --strip-components=1 -C /opt/bitmagnet
 | 
			
		||||
cd /opt/bitmagnet
 | 
			
		||||
VREL=v$RELEASE
 | 
			
		||||
$STD go build -ldflags "-s -w -X github.com/bitmagnet-io/bitmagnet/internal/version.GitTag=$VREL"
 | 
			
		||||
chmod +x bitmagnet
 | 
			
		||||
$STD su - postgres -c "psql -c 'CREATE DATABASE bitmagnet;'"
 | 
			
		||||
echo "${RELEASE}" >/opt/bitmagnet_version.txt
 | 
			
		||||
msg_ok "Installed bitmagnet v${RELEASE}"
 | 
			
		||||
 | 
			
		||||
read -rp "${TAB3}Enter your TMDB API key if you have one: " tmdbapikey
 | 
			
		||||
 | 
			
		||||
msg_info "Enabling bitmagnet Service"
 | 
			
		||||
cat <<EOF >/etc/init.d/bitmagnet
 | 
			
		||||
#!/sbin/openrc-run
 | 
			
		||||
description="bitmagnet Service"
 | 
			
		||||
directory="/opt/bitmagnet"
 | 
			
		||||
command="/opt/bitmagnet/bitmagnet"
 | 
			
		||||
command_args="worker run --all"
 | 
			
		||||
command_background="true"
 | 
			
		||||
command_user="root"
 | 
			
		||||
pidfile="/var/run/bitmagnet.pid"
 | 
			
		||||
 | 
			
		||||
depend() {
 | 
			
		||||
    use net
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
start_pre() {
 | 
			
		||||
    export TMDB_API_KEY="$tmdbapikey"
 | 
			
		||||
}
 | 
			
		||||
EOF
 | 
			
		||||
chmod +x /etc/init.d/bitmagnet
 | 
			
		||||
$STD rc-update add bitmagnet default
 | 
			
		||||
msg_ok "Enabled bitmagnet Service"
 | 
			
		||||
 | 
			
		||||
msg_info "Starting bitmagnet"
 | 
			
		||||
$STD service bitmagnet start
 | 
			
		||||
msg_ok "Started bitmagnet"
 | 
			
		||||
 | 
			
		||||
motd_ssh
 | 
			
		||||
customize
 | 
			
		||||
 | 
			
		||||
msg_info "Cleaning up"
 | 
			
		||||
rm -f "$temp_file"
 | 
			
		||||
$STD apk cache clean
 | 
			
		||||
msg_ok "Cleaned"
 | 
			
		||||
@@ -29,13 +29,13 @@ $STD rc-update add docker default
 | 
			
		||||
msg_ok "Installed Docker"
 | 
			
		||||
 | 
			
		||||
get_latest_release() {
 | 
			
		||||
  curl -fsSL https://api.github.com/repos/$1/releases/latest | grep '"tag_name":' | cut -d'"' -f4
 | 
			
		||||
  curl -fsSL https://api.github.com/repos/"$1"/releases/latest | grep '"tag_name":' | cut -d'"' -f4
 | 
			
		||||
}
 | 
			
		||||
PORTAINER_LATEST_VERSION=$(get_latest_release "portainer/portainer")
 | 
			
		||||
DOCKER_COMPOSE_LATEST_VERSION=$(get_latest_release "docker/compose")
 | 
			
		||||
PORTAINER_AGENT_LATEST_VERSION=$(get_latest_release "portainer/agent")
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Portainer? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Portainer? <y/N> " prompt
 | 
			
		||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Portainer $PORTAINER_LATEST_VERSION"
 | 
			
		||||
  docker volume create portainer_data >/dev/null
 | 
			
		||||
@@ -49,7 +49,7 @@ if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
    portainer/portainer-ce:latest
 | 
			
		||||
  msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION"
 | 
			
		||||
else
 | 
			
		||||
  read -r -p "Would you like to add the Portainer Agent? <y/N> " prompt
 | 
			
		||||
  read -r -p "${TAB3}Would you like to add the Portainer Agent? <y/N> " prompt
 | 
			
		||||
  if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
    msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION"
 | 
			
		||||
    $STD docker run -d \
 | 
			
		||||
@@ -62,13 +62,13 @@ else
 | 
			
		||||
    msg_ok "Installed Portainer Agent $PORTAINER_AGENT_LATEST_VERSION"
 | 
			
		||||
  fi
 | 
			
		||||
fi
 | 
			
		||||
read -r -p "Would you like to add Docker Compose? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Docker Compose? <y/N> " prompt
 | 
			
		||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Docker Compose $DOCKER_COMPOSE_LATEST_VERSION"
 | 
			
		||||
  DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
 | 
			
		||||
  mkdir -p $DOCKER_CONFIG/cli-plugins
 | 
			
		||||
  curl -fsSL https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_LATEST_VERSION/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
 | 
			
		||||
  chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
 | 
			
		||||
  mkdir -p "$DOCKER_CONFIG"/cli-plugins
 | 
			
		||||
  curl -fsSL https://github.com/docker/compose/releases/download/"$DOCKER_COMPOSE_LATEST_VERSION"/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
 | 
			
		||||
  chmod +x "$DOCKER_CONFIG"/cli-plugins/docker-compose
 | 
			
		||||
  msg_ok "Installed Docker Compose $DOCKER_COMPOSE_LATEST_VERSION"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,11 +26,11 @@ $STD rc-update add docker boot
 | 
			
		||||
$STD service docker start
 | 
			
		||||
msg_ok "Enabled Docker Service"
 | 
			
		||||
 | 
			
		||||
echo "Choose the database for Komodo installation:"
 | 
			
		||||
echo "1) MongoDB (recommended)"
 | 
			
		||||
echo "2) SQLite"
 | 
			
		||||
echo "3) PostgreSQL"
 | 
			
		||||
read -rp "Enter your choice (default: 1): " DB_CHOICE
 | 
			
		||||
echo "${TAB3}Choose the database for Komodo installation:"
 | 
			
		||||
echo "${TAB3}1) MongoDB (recommended)"
 | 
			
		||||
echo "${TAB3}2) SQLite"
 | 
			
		||||
echo "${TAB3}3) PostgreSQL"
 | 
			
		||||
read -rp "${TAB3}Enter your choice (default: 1): " DB_CHOICE
 | 
			
		||||
DB_CHOICE=${DB_CHOICE:-1}
 | 
			
		||||
 | 
			
		||||
case $DB_CHOICE in
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql >/dev/null
 | 
			
		||||
$STD rc-service mariadb start
 | 
			
		||||
msg_ok "MariaDB Configured"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to install Adminer with lighttpd? <y/N>: " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to install Adminer with lighttpd? <y/N>: " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Adminer and dependencies"
 | 
			
		||||
  $STD apk add --no-cache \
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ sed -i '/^host\s\+all\s\+all\s\+127.0.0.1\/32\s\+md5/ s/.*/host all all 0.0.0.0\
 | 
			
		||||
$STD rc-service postgresql restart
 | 
			
		||||
msg_ok "Configured and Restarted PostgreSQL"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to install Adminer with lighttpd? <y/N>: " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to install Adminer with lighttpd? <y/N>: " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Adminer and dependencies"
 | 
			
		||||
  $STD apk add --no-cache \
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ msg_info "Installing Traefik"
 | 
			
		||||
$STD apk add traefik --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community
 | 
			
		||||
msg_ok "Installed Traefik"
 | 
			
		||||
 | 
			
		||||
read -p "Enable Traefik WebUI (Port 8080)? [y/N]: " enable_webui
 | 
			
		||||
read -p "${TAB3}Enable Traefik WebUI (Port 8080)? [y/N]: " enable_webui
 | 
			
		||||
if [[ "$enable_webui" =~ ^[Yy]$ ]]; then
 | 
			
		||||
  msg_info "Configuring Traefik WebUI"
 | 
			
		||||
  mkdir -p /etc/traefik/config
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ $STD rc-update add sysctl
 | 
			
		||||
$STD sysctl -p /etc/sysctl.conf
 | 
			
		||||
msg_ok "Installed WireGuard"
 | 
			
		||||
 | 
			
		||||
read -rp "Do you want to install WGDashboard? (y/N): " INSTALL_WGD
 | 
			
		||||
read -rp "${TAB3}Do you want to install WGDashboard? (y/N): " INSTALL_WGD
 | 
			
		||||
if [[ "$INSTALL_WGD" =~ ^[Yy]$ ]]; then
 | 
			
		||||
  msg_info "Installing additional dependencies for WGDashboard"
 | 
			
		||||
  $STD apk add --no-cache \
 | 
			
		||||
 
 | 
			
		||||
@@ -15,10 +15,10 @@ update_os
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Dependencies"
 | 
			
		||||
$STD apt-get install -y \
 | 
			
		||||
    gnupg2 \
 | 
			
		||||
    lsb-release \
 | 
			
		||||
    gpg \
 | 
			
		||||
    apt-transport-https
 | 
			
		||||
  gnupg2 \
 | 
			
		||||
  lsb-release \
 | 
			
		||||
  gpg \
 | 
			
		||||
  apt-transport-https
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
msg_info "Setting up Adoptium Repository"
 | 
			
		||||
@@ -28,90 +28,90 @@ echo "deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_COD
 | 
			
		||||
$STD apt-get update
 | 
			
		||||
msg_ok "Set up Adoptium Repository"
 | 
			
		||||
 | 
			
		||||
read -r -p "Which Tomcat version would you like to install? (9, 10.1, 11): " version
 | 
			
		||||
read -r -p "${TAB3}Which Tomcat version would you like to install? (9, 10.1, 11): " version
 | 
			
		||||
case $version in
 | 
			
		||||
9)
 | 
			
		||||
    TOMCAT_VERSION="9"
 | 
			
		||||
    echo "Which LTS Java version would you like to use? (8, 11, 17, 21): "
 | 
			
		||||
    read -r jdk_version
 | 
			
		||||
    case $jdk_version in
 | 
			
		||||
    8)
 | 
			
		||||
        msg_info "Installing Temurin JDK 8 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
        $STD apt-get install -y temurin-8-jdk
 | 
			
		||||
        msg_ok "Setup Temurin JDK 8 (LTS)"
 | 
			
		||||
        ;;
 | 
			
		||||
    11)
 | 
			
		||||
        msg_info "Installing Temurin JDK 11 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
        $STD apt-get install -y temurin-11-jdk
 | 
			
		||||
        msg_ok "Setup Temurin JDK 11 (LTS)"
 | 
			
		||||
        ;;
 | 
			
		||||
    17)
 | 
			
		||||
        msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
        $STD apt-get install -qqy temurin-17-jdk
 | 
			
		||||
        msg_ok "Setup Temurin JDK 17 (LTS)"
 | 
			
		||||
        ;;
 | 
			
		||||
    21)
 | 
			
		||||
        msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
        $STD apt-get install -y temurin-21-jdk
 | 
			
		||||
        msg_ok "Setup Temurin JDK 21 (LTS)"
 | 
			
		||||
        ;;
 | 
			
		||||
    *)
 | 
			
		||||
        msg_error "Invalid JDK version selected. Please enter 8, 11, 17 or 21."
 | 
			
		||||
        exit 1
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
  TOMCAT_VERSION="9"
 | 
			
		||||
  echo "Which LTS Java version would you like to use? (8, 11, 17, 21): "
 | 
			
		||||
  read -r jdk_version
 | 
			
		||||
  case $jdk_version in
 | 
			
		||||
  8)
 | 
			
		||||
    msg_info "Installing Temurin JDK 8 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
    $STD apt-get install -y temurin-8-jdk
 | 
			
		||||
    msg_ok "Setup Temurin JDK 8 (LTS)"
 | 
			
		||||
    ;;
 | 
			
		||||
10 | 10.1)
 | 
			
		||||
    TOMCAT_VERSION="10"
 | 
			
		||||
    echo "Which LTS Java version would you like to use? (11, 17): "
 | 
			
		||||
    read -r jdk_version
 | 
			
		||||
    case $jdk_version in
 | 
			
		||||
    11)
 | 
			
		||||
        msg_info "Installing Temurin JDK 11 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
        $STD apt-get install -y temurin-11-jdk
 | 
			
		||||
        msg_ok "Setup Temurin JDK 11"
 | 
			
		||||
        ;;
 | 
			
		||||
    17)
 | 
			
		||||
        msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
        $STD apt-get install -y temurin-17-jdk
 | 
			
		||||
        msg_ok "Setup Temurin JDK 17"
 | 
			
		||||
        ;;
 | 
			
		||||
    21)
 | 
			
		||||
        msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
        $STD apt-get install -y temurin-21-jdk
 | 
			
		||||
        msg_ok "Setup Temurin JDK 21 (LTS)"
 | 
			
		||||
        ;;
 | 
			
		||||
    *)
 | 
			
		||||
        msg_error "Invalid JDK version selected. Please enter 11 or 17."
 | 
			
		||||
        exit 1
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
  11)
 | 
			
		||||
    msg_info "Installing Temurin JDK 11 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
    $STD apt-get install -y temurin-11-jdk
 | 
			
		||||
    msg_ok "Setup Temurin JDK 11 (LTS)"
 | 
			
		||||
    ;;
 | 
			
		||||
11)
 | 
			
		||||
    TOMCAT_VERSION="11"
 | 
			
		||||
    echo "Which LTS Java version would you like to use? (17, 21): "
 | 
			
		||||
    read -r jdk_version
 | 
			
		||||
    case $jdk_version in
 | 
			
		||||
    17)
 | 
			
		||||
        msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
        $STD apt-get install -qqy temurin-17-jdk
 | 
			
		||||
        msg_ok "Setup Temurin JDK 17"
 | 
			
		||||
        ;;
 | 
			
		||||
    21)
 | 
			
		||||
        msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
        $STD apt-get install -y temurin-21-jdk
 | 
			
		||||
        msg_ok "Setup Temurin JDK 21 (LTS)"
 | 
			
		||||
        ;;
 | 
			
		||||
    *)
 | 
			
		||||
        msg_error "Invalid JDK version selected. Please enter 17 or 21."
 | 
			
		||||
        exit 1
 | 
			
		||||
        ;;
 | 
			
		||||
    esac
 | 
			
		||||
  17)
 | 
			
		||||
    msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
    $STD apt-get install -qqy temurin-17-jdk
 | 
			
		||||
    msg_ok "Setup Temurin JDK 17 (LTS)"
 | 
			
		||||
    ;;
 | 
			
		||||
*)
 | 
			
		||||
    msg_error "Invalid Tomcat version selected. Please enter 9, 10.1 or 11."
 | 
			
		||||
  21)
 | 
			
		||||
    msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
    $STD apt-get install -y temurin-21-jdk
 | 
			
		||||
    msg_ok "Setup Temurin JDK 21 (LTS)"
 | 
			
		||||
    ;;
 | 
			
		||||
  *)
 | 
			
		||||
    msg_error "Invalid JDK version selected. Please enter 8, 11, 17 or 21."
 | 
			
		||||
    exit 1
 | 
			
		||||
    ;;
 | 
			
		||||
  esac
 | 
			
		||||
  ;;
 | 
			
		||||
10 | 10.1)
 | 
			
		||||
  TOMCAT_VERSION="10"
 | 
			
		||||
  echo "Which LTS Java version would you like to use? (11, 17): "
 | 
			
		||||
  read -r jdk_version
 | 
			
		||||
  case $jdk_version in
 | 
			
		||||
  11)
 | 
			
		||||
    msg_info "Installing Temurin JDK 11 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
    $STD apt-get install -y temurin-11-jdk
 | 
			
		||||
    msg_ok "Setup Temurin JDK 11"
 | 
			
		||||
    ;;
 | 
			
		||||
  17)
 | 
			
		||||
    msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
    $STD apt-get install -y temurin-17-jdk
 | 
			
		||||
    msg_ok "Setup Temurin JDK 17"
 | 
			
		||||
    ;;
 | 
			
		||||
  21)
 | 
			
		||||
    msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
    $STD apt-get install -y temurin-21-jdk
 | 
			
		||||
    msg_ok "Setup Temurin JDK 21 (LTS)"
 | 
			
		||||
    ;;
 | 
			
		||||
  *)
 | 
			
		||||
    msg_error "Invalid JDK version selected. Please enter 11 or 17."
 | 
			
		||||
    exit 1
 | 
			
		||||
    ;;
 | 
			
		||||
  esac
 | 
			
		||||
  ;;
 | 
			
		||||
11)
 | 
			
		||||
  TOMCAT_VERSION="11"
 | 
			
		||||
  echo "Which LTS Java version would you like to use? (17, 21): "
 | 
			
		||||
  read -r jdk_version
 | 
			
		||||
  case $jdk_version in
 | 
			
		||||
  17)
 | 
			
		||||
    msg_info "Installing Temurin JDK 17 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
    $STD apt-get install -qqy temurin-17-jdk
 | 
			
		||||
    msg_ok "Setup Temurin JDK 17"
 | 
			
		||||
    ;;
 | 
			
		||||
  21)
 | 
			
		||||
    msg_info "Installing Temurin JDK 21 (LTS) for Tomcat $TOMCAT_VERSION"
 | 
			
		||||
    $STD apt-get install -y temurin-21-jdk
 | 
			
		||||
    msg_ok "Setup Temurin JDK 21 (LTS)"
 | 
			
		||||
    ;;
 | 
			
		||||
  *)
 | 
			
		||||
    msg_error "Invalid JDK version selected. Please enter 17 or 21."
 | 
			
		||||
    exit 1
 | 
			
		||||
    ;;
 | 
			
		||||
  esac
 | 
			
		||||
  ;;
 | 
			
		||||
*)
 | 
			
		||||
  msg_error "Invalid Tomcat version selected. Please enter 9, 10.1 or 11."
 | 
			
		||||
  exit 1
 | 
			
		||||
  ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Tomcat $TOMCAT_VERSION"
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ msg_info "Installing Aria2"
 | 
			
		||||
$STD apt-get install -y aria2
 | 
			
		||||
msg_ok "Installed Aria2"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add AriaNG? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add AriaNG? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing AriaNG"
 | 
			
		||||
  $STD apt-get install -y nginx
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ curl -fsSL "https://github.com/authelia/authelia/releases/download/${RELEASE}/au
 | 
			
		||||
$STD dpkg -i "authelia_${RELEASE}_amd64.deb"
 | 
			
		||||
msg_ok "Install Authelia completed"
 | 
			
		||||
 | 
			
		||||
read -p "Enter your domain (ex. example.com): " DOMAIN
 | 
			
		||||
read -p "${TAB3}Enter your domain (ex. example.com): " DOMAIN
 | 
			
		||||
 | 
			
		||||
msg_info "Setting Authelia up"
 | 
			
		||||
touch /etc/authelia/emails.txt
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										78
									
								
								install/bitmagnet-install.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								install/bitmagnet-install.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2021-2025 community-scripts ORG
 | 
			
		||||
# Author: Slaviša Arežina (tremor021)
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
# Source: https://github.com/bitmagnet-io/bitmagnet
 | 
			
		||||
 | 
			
		||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
 | 
			
		||||
color
 | 
			
		||||
verb_ip6
 | 
			
		||||
catch_errors
 | 
			
		||||
setting_up_container
 | 
			
		||||
network_check
 | 
			
		||||
update_os
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Dependencies"
 | 
			
		||||
$STD apt-get install -y \
 | 
			
		||||
  iproute2 \
 | 
			
		||||
  gcc \
 | 
			
		||||
  musl-dev
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
PG_VERSION="16" install_postgresql
 | 
			
		||||
install_go
 | 
			
		||||
RELEASE=$(curl -fsSL https://api.github.com/repos/bitmagnet-io/bitmagnet/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
 | 
			
		||||
msg_info "Installing bitmagnet v${RELEASE}"
 | 
			
		||||
mkdir -p /opt/bitmagnet
 | 
			
		||||
temp_file=$(mktemp)
 | 
			
		||||
curl -fsSL "https://github.com/bitmagnet-io/bitmagnet/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
 | 
			
		||||
tar zxf "$temp_file" --strip-components=1 -C /opt/bitmagnet
 | 
			
		||||
cd /opt/bitmagnet
 | 
			
		||||
VREL=v$RELEASE
 | 
			
		||||
$STD go build -ldflags "-s -w -X github.com/bitmagnet-io/bitmagnet/internal/version.GitTag=$VREL"
 | 
			
		||||
chmod +x bitmagnet
 | 
			
		||||
POSTGRES_PASSWORD=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
 | 
			
		||||
$STD sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD '$POSTGRES_PASSWORD';"
 | 
			
		||||
$STD sudo -u postgres psql -c "CREATE DATABASE bitmagnet;"
 | 
			
		||||
{
 | 
			
		||||
  echo "PostgreSQL Credentials"
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo "postgres user password: $POSTGRES_PASSWORD"
 | 
			
		||||
} >>~/postgres.creds
 | 
			
		||||
echo "${RELEASE}" >/opt/bitmagnet_version.txt
 | 
			
		||||
msg_ok "Installed bitmagnet v${RELEASE}"
 | 
			
		||||
 | 
			
		||||
read -r -p "${TAB3}Enter your TMDB API key if you have one: " tmdbapikey
 | 
			
		||||
 | 
			
		||||
msg_info "Creating Service"
 | 
			
		||||
cat <<EOF >/etc/systemd/system/bitmagnet-web.service
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=bitmagnet Web GUI
 | 
			
		||||
After=network-online.target
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
User=root
 | 
			
		||||
WorkingDirectory=/opt/bitmagnet
 | 
			
		||||
ExecStart=/opt/bitmagnet/bitmagnet worker run --all
 | 
			
		||||
Environment=POSTGRES_HOST=localhost
 | 
			
		||||
Environment=POSTGRES_PASSWORD=$POSTGRES_PASSWORD
 | 
			
		||||
Environment=TMDB_API_KEY=$tmdbapikey
 | 
			
		||||
Restart=on-failure
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
EOF
 | 
			
		||||
systemctl enable -q --now bitmagnet-web
 | 
			
		||||
msg_ok "Created Service"
 | 
			
		||||
 | 
			
		||||
motd_ssh
 | 
			
		||||
customize
 | 
			
		||||
 | 
			
		||||
msg_info "Cleaning up"
 | 
			
		||||
rm -f "$temp_file"
 | 
			
		||||
$STD apt-get -y autoremove
 | 
			
		||||
$STD apt-get -y autoclean
 | 
			
		||||
msg_ok "Cleaned"
 | 
			
		||||
@@ -15,7 +15,7 @@ update_os
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Dependencies"
 | 
			
		||||
$STD apt-get install -y \
 | 
			
		||||
    gnupg
 | 
			
		||||
  gnupg
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
msg_info "Setting up Node.js Repository"
 | 
			
		||||
@@ -43,7 +43,7 @@ $STD npm install
 | 
			
		||||
echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt"
 | 
			
		||||
msg_ok "Installed ByteStash"
 | 
			
		||||
 | 
			
		||||
read -p "Do you want to allow registration of multiple accounts? [y/n]: " allowreg
 | 
			
		||||
read -p "${TAB3}Do you want to allow registration of multiple accounts? [y/n]: " allowreg
 | 
			
		||||
 | 
			
		||||
msg_info "Creating Service"
 | 
			
		||||
cat <<EOF >/etc/systemd/system/bytestash-backend.service
 | 
			
		||||
@@ -62,7 +62,7 @@ WantedBy=multi-user.target
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
if [[ "$allowreg" =~ ^[Yy]$ ]]; then
 | 
			
		||||
    sed -i '8i\Environment=ALLOW_NEW_ACCOUNTS=true' /etc/systemd/system/bytestash-backend.service
 | 
			
		||||
  sed -i '8i\Environment=ALLOW_NEW_ACCOUNTS=true' /etc/systemd/system/bytestash-backend.service
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
cat <<EOF >/etc/systemd/system/bytestash-frontend.service
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ $STD apt-get update
 | 
			
		||||
$STD apt-get install -y caddy
 | 
			
		||||
msg_ok "Installed Caddy"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to install xCaddy Addon? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to install xCaddy Addon? <y/N> " prompt
 | 
			
		||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Golang"
 | 
			
		||||
  set +o pipefail
 | 
			
		||||
@@ -46,7 +46,7 @@ if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  cd /opt
 | 
			
		||||
  RELEASE=$(curl -fsSL https://api.github.com/repos/caddyserver/xcaddy/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
 | 
			
		||||
  curl -fsSL "https://github.com/caddyserver/xcaddy/releases/download/${RELEASE}/xcaddy_${RELEASE:1}_linux_amd64.deb" -o $(basename "https://github.com/caddyserver/xcaddy/releases/download/${RELEASE}/xcaddy_${RELEASE:1}_linux_amd64.deb")
 | 
			
		||||
  $STD dpkg -i xcaddy_${RELEASE:1}_linux_amd64.deb
 | 
			
		||||
  $STD dpkg -i xcaddy_"${RELEASE:1}"_linux_amd64.deb
 | 
			
		||||
  rm -rf /opt/xcaddy*
 | 
			
		||||
  $STD xcaddy build
 | 
			
		||||
  msg_ok "Setup xCaddy"
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ $STD apt-get update
 | 
			
		||||
$STD apt-get install -y cloudflared
 | 
			
		||||
msg_ok "Installed Cloudflared"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to configure cloudflared as a DNS-over-HTTPS (DoH) proxy? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to configure cloudflared as a DNS-over-HTTPS (DoH) proxy? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Creating Service"
 | 
			
		||||
  cat <<EOF >/usr/local/etc/cloudflared/config.yml
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,8 @@ update_os
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Dependencies"
 | 
			
		||||
$STD apt-get install -y \
 | 
			
		||||
    gnupg \
 | 
			
		||||
    git
 | 
			
		||||
  gnupg \
 | 
			
		||||
  git
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
msg_info "Setting up Node.js Repository"
 | 
			
		||||
@@ -30,7 +30,7 @@ $STD apt-get update
 | 
			
		||||
$STD apt-get install -y nodejs
 | 
			
		||||
msg_ok "Setup Node.js"
 | 
			
		||||
 | 
			
		||||
read -p "Install OnlyOffice components instead of CKEditor? (Y/N): " onlyoffice
 | 
			
		||||
read -p "${TAB3}Install OnlyOffice components instead of CKEditor? (Y/N): " onlyoffice
 | 
			
		||||
 | 
			
		||||
msg_info "Setup ${APPLICATION}"
 | 
			
		||||
temp_file=$(mktemp)
 | 
			
		||||
@@ -47,7 +47,7 @@ IP=$(hostname -I | awk '{print $1}')
 | 
			
		||||
sed -i "51s/localhost/${IP}/g" /opt/cryptpad/config/config.js
 | 
			
		||||
sed -i "80s#//httpAddress: 'localhost'#httpAddress: '0.0.0.0'#g" /opt/cryptpad/config/config.js
 | 
			
		||||
if [[ "$onlyoffice" =~ ^[Yy]$ ]]; then
 | 
			
		||||
    $STD bash -c "./install-onlyoffice.sh --accept-license"
 | 
			
		||||
  $STD bash -c "./install-onlyoffice.sh --accept-license"
 | 
			
		||||
fi
 | 
			
		||||
echo "${RELEASE}" >/opt/${APPLICATION}_version.txt
 | 
			
		||||
msg_ok "Setup ${APPLICATION}"
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ network_check
 | 
			
		||||
update_os
 | 
			
		||||
 | 
			
		||||
get_latest_release() {
 | 
			
		||||
  curl -fsSL https://api.github.com/repos/$1/releases/latest | grep '"tag_name":' | cut -d'"' -f4
 | 
			
		||||
  curl -fsSL https://api.github.com/repos/"$1"/releases/latest | grep '"tag_name":' | cut -d'"' -f4
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DOCKER_LATEST_VERSION=$(get_latest_release "moby/moby")
 | 
			
		||||
@@ -29,7 +29,7 @@ echo -e '{\n  "log-driver": "journald"\n}' >/etc/docker/daemon.json
 | 
			
		||||
$STD sh <(curl -fsSL https://get.docker.com)
 | 
			
		||||
msg_ok "Installed Docker $DOCKER_LATEST_VERSION"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Portainer? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Portainer? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Portainer $PORTAINER_LATEST_VERSION"
 | 
			
		||||
  docker volume create portainer_data >/dev/null
 | 
			
		||||
@@ -43,7 +43,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
    portainer/portainer-ce:latest
 | 
			
		||||
  msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION"
 | 
			
		||||
else
 | 
			
		||||
  read -r -p "Would you like to add the Portainer Agent? <y/N> " prompt
 | 
			
		||||
  read -r -p "${TAB3}Would you like to add the Portainer Agent? <y/N> " prompt
 | 
			
		||||
  if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
    msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION"
 | 
			
		||||
    $STD docker run -d \
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ cd /opt/dockge
 | 
			
		||||
$STD docker compose up -d
 | 
			
		||||
msg_ok "Installed Dockge"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Immich? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Immich? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Adding Immich compose.yaml"
 | 
			
		||||
  mkdir -p /opt/stacks/immich
 | 
			
		||||
@@ -50,7 +50,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_ok "Added Immich compose.yaml"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Home Assistant? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Home Assistant? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Adding Home Assistant compose.yaml"
 | 
			
		||||
  mkdir -p /opt/stacks/homeassistant
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
msg_info "Configure Application"
 | 
			
		||||
var_project_name="default"
 | 
			
		||||
read -r -p "Type the assembly name of the project: " var_project_name
 | 
			
		||||
read -r -p "${TAB3}Type the assembly name of the project: " var_project_name
 | 
			
		||||
echo "Target assembly: '${var_project_name}'"
 | 
			
		||||
msg_ok "Application Configured"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ $STD apt-get install -y nodejs
 | 
			
		||||
$STD npm install -g yarn
 | 
			
		||||
msg_ok "Installed Node.js"
 | 
			
		||||
 | 
			
		||||
read -p "Please enter the name for your server: " servername
 | 
			
		||||
read -p "${TAB3}Please enter the name for your server: " servername
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Element Synapse"
 | 
			
		||||
curl -fsSL "https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg" -o "/usr/share/keyrings/matrix-org-archive-keyring.gpg"
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ $STD apt-get install -y \
 | 
			
		||||
  imagemagick
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
read -r -p "Do you need the intel-media-va-driver-non-free driver for HW encoding (Debian 12 only)? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Do you need the intel-media-va-driver-non-free driver for HW encoding (Debian 12 only)? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Intel Hardware Acceleration (non-free)"
 | 
			
		||||
  cat <<EOF >/etc/apt/sources.list.d/non-free.list
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ curl -fsSL "https://repos.influxdata.com/influxdata-archive_compat.key" | gpg --
 | 
			
		||||
echo "deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive_compat.gpg] https://repos.influxdata.com/debian stable main" >/etc/apt/sources.list.d/influxdata.list
 | 
			
		||||
msg_ok "Set up InfluxDB Repository"
 | 
			
		||||
 | 
			
		||||
read -r -p "Which version of InfluxDB to install? (1 or 2) " prompt
 | 
			
		||||
read -r -p "${TAB3}Which version of InfluxDB to install? (1 or 2) " prompt
 | 
			
		||||
if [[ $prompt == "2" ]]; then
 | 
			
		||||
  INFLUX="2"
 | 
			
		||||
else
 | 
			
		||||
@@ -43,7 +43,7 @@ fi
 | 
			
		||||
$STD systemctl enable --now influxdb
 | 
			
		||||
msg_ok "Installed InfluxDB"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Telegraf? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Telegraf? <y/N> " prompt
 | 
			
		||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Telegraf"
 | 
			
		||||
  $STD apt-get install -y telegraf
 | 
			
		||||
 
 | 
			
		||||
@@ -21,9 +21,9 @@ msg_ok "Setup Python 3"
 | 
			
		||||
msg_info "Setup Kometa"
 | 
			
		||||
temp_file=$(mktemp)
 | 
			
		||||
RELEASE=$(curl -fsSL https://api.github.com/repos/Kometa-Team/Kometa/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
curl -fsSL "https://github.com/Kometa-Team/Kometa/archive/refs/tags/v${RELEASE}.tar.gz" -o ""$temp_file""
 | 
			
		||||
curl -fsSL "https://github.com/Kometa-Team/Kometa/archive/refs/tags/v${RELEASE}.tar.gz" -o """$temp_file"""
 | 
			
		||||
tar -xzf "$temp_file"
 | 
			
		||||
mv Kometa-${RELEASE} /opt/kometa
 | 
			
		||||
mv Kometa-"${RELEASE}" /opt/kometa
 | 
			
		||||
cd /opt/kometa
 | 
			
		||||
$STD pip install -r requirements.txt --ignore-installed
 | 
			
		||||
mkdir -p config/assets
 | 
			
		||||
@@ -31,10 +31,10 @@ cp config/config.yml.template config/config.yml
 | 
			
		||||
echo "${RELEASE}" >/opt/kometa_version.txt
 | 
			
		||||
msg_ok "Setup Kometa"
 | 
			
		||||
 | 
			
		||||
read -p "Enter your TMDb API key: " TMDBKEY
 | 
			
		||||
read -p "Enter your Plex URL: " PLEXURL
 | 
			
		||||
read -p "Enter your Plex token: " PLEXTOKEN
 | 
			
		||||
sed -i -e "s#url: http://192.168.1.12:32400#url: $PLEXURL#g" /opt/kometa/config/config.yml
 | 
			
		||||
read -p "${TAB3}nter your TMDb API key: " TMDBKEY
 | 
			
		||||
read -p "${TAB3}Enter your Plex URL: " PLEXURL
 | 
			
		||||
read -p "${TAB3}Enter your Plex token: " PLEXTOKEN
 | 
			
		||||
sed -i -e "s#url: http://192.168.1.12:32400#url: $PLEXURL #g" /opt/kometa/config/config.yml
 | 
			
		||||
sed -i -e "s/token: ####################/token: $PLEXTOKEN/g" /opt/kometa/config/config.yml
 | 
			
		||||
sed -i -e "s/apikey: ################################/apikey: $TMDBKEY/g" /opt/kometa/config/config.yml
 | 
			
		||||
 | 
			
		||||
@@ -61,7 +61,7 @@ motd_ssh
 | 
			
		||||
customize
 | 
			
		||||
 | 
			
		||||
msg_info "Cleaning up"
 | 
			
		||||
rm -f $temp_file
 | 
			
		||||
rm -f "$temp_file"
 | 
			
		||||
$STD apt-get -y autoremove
 | 
			
		||||
$STD apt-get -y autoclean
 | 
			
		||||
msg_ok "Cleaned"
 | 
			
		||||
 
 | 
			
		||||
@@ -37,11 +37,11 @@ $STD apt-get install -y \
 | 
			
		||||
  docker-compose-plugin
 | 
			
		||||
msg_ok "Installed Docker"
 | 
			
		||||
 | 
			
		||||
echo "Choose the database for Komodo installation:"
 | 
			
		||||
echo "1) MongoDB (recommended)"
 | 
			
		||||
echo "2) SQLite"
 | 
			
		||||
echo "3) PostgreSQL"
 | 
			
		||||
read -rp "Enter your choice (default: 1): " DB_CHOICE
 | 
			
		||||
echo "${TAB3}Choose the database for Komodo installation:"
 | 
			
		||||
echo "${TAB3}1) MongoDB (recommended)"
 | 
			
		||||
echo "${TAB3}2) SQLite"
 | 
			
		||||
echo "${TAB3}3) PostgreSQL"
 | 
			
		||||
read -rp "${TAB3}Enter your choice (default: 1): " DB_CHOICE
 | 
			
		||||
DB_CHOICE=${DB_CHOICE:-1}
 | 
			
		||||
 | 
			
		||||
case $DB_CHOICE in
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,7 @@ install_postgresql
 | 
			
		||||
msg_info "Installing Rust"
 | 
			
		||||
curl -fsSL https://sh.rustup.rs -o rustup-init.sh
 | 
			
		||||
$STD bash rustup-init.sh -y --profile minimal
 | 
			
		||||
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.bashrc
 | 
			
		||||
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >>~/.bashrc
 | 
			
		||||
export PATH="$HOME/.cargo/bin:$PATH"
 | 
			
		||||
rm rustup-init.sh
 | 
			
		||||
$STD cargo install monolith
 | 
			
		||||
@@ -56,7 +56,7 @@ $STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';"
 | 
			
		||||
} >>~/linkwarden.creds
 | 
			
		||||
msg_ok "Set up PostgreSQL DB"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Adminer? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Adminer? <y/N> " prompt
 | 
			
		||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Adminer"
 | 
			
		||||
  $STD apt install -y adminer
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ sed -i 's/^# *\(port *=.*\)/\1/' /etc/mysql/my.cnf
 | 
			
		||||
sed -i 's/^bind-address/#bind-address/g' /etc/mysql/mariadb.conf.d/50-server.cnf
 | 
			
		||||
msg_ok "Installed MariaDB"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add PhpMyAdmin? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add PhpMyAdmin? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing phpMyAdmin"
 | 
			
		||||
  $STD apt-get install -y \
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ update_os
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Dependencies"
 | 
			
		||||
$STD apt-get install -y \
 | 
			
		||||
    gnupg
 | 
			
		||||
  gnupg
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
msg_info "Setup ${APPLICATION}"
 | 
			
		||||
@@ -27,49 +27,49 @@ curl -fsSL https://raw.githubusercontent.com/meilisearch/meilisearch/latest/conf
 | 
			
		||||
MASTER_KEY=$(openssl rand -base64 12)
 | 
			
		||||
LOCAL_IP="$(hostname -I | awk '{print $1}')"
 | 
			
		||||
sed -i \
 | 
			
		||||
    -e 's|^env =.*|env = "production"|' \
 | 
			
		||||
    -e "s|^# master_key =.*|master_key = \"$MASTER_KEY\"|" \
 | 
			
		||||
    -e 's|^db_path =.*|db_path = "/var/lib/meilisearch/data"|' \
 | 
			
		||||
    -e 's|^dump_dir =.*|dump_dir = "/var/lib/meilisearch/dumps"|' \
 | 
			
		||||
    -e 's|^snapshot_dir =.*|snapshot_dir = "/var/lib/meilisearch/snapshots"|' \
 | 
			
		||||
    -e 's|^# no_analytics = true|no_analytics = true|' \
 | 
			
		||||
    -e 's|^http_addr =.*|http_addr = "0.0.0.0:7700"|' \
 | 
			
		||||
    /etc/meilisearch.toml
 | 
			
		||||
  -e 's|^env =.*|env = "production"|' \
 | 
			
		||||
  -e "s|^# master_key =.*|master_key = \"$MASTER_KEY\"|" \
 | 
			
		||||
  -e 's|^db_path =.*|db_path = "/var/lib/meilisearch/data"|' \
 | 
			
		||||
  -e 's|^dump_dir =.*|dump_dir = "/var/lib/meilisearch/dumps"|' \
 | 
			
		||||
  -e 's|^snapshot_dir =.*|snapshot_dir = "/var/lib/meilisearch/snapshots"|' \
 | 
			
		||||
  -e 's|^# no_analytics = true|no_analytics = true|' \
 | 
			
		||||
  -e 's|^http_addr =.*|http_addr = "0.0.0.0:7700"|' \
 | 
			
		||||
  /etc/meilisearch.toml
 | 
			
		||||
echo "${RELEASE}" >/opt/${APPLICATION}_version.txt
 | 
			
		||||
msg_ok "Setup ${APPLICATION}"
 | 
			
		||||
 | 
			
		||||
read -r -p "Do you want add meilisearch-ui? [y/n]: " prompt
 | 
			
		||||
read -r -p "${TAB3}Do you want add meilisearch-ui? [y/n]: " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
    msg_info "Setting up Node.js Repository"
 | 
			
		||||
    mkdir -p /etc/apt/keyrings
 | 
			
		||||
    curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
 | 
			
		||||
    echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list
 | 
			
		||||
    msg_ok "Set up Node.js Repository"
 | 
			
		||||
  msg_info "Setting up Node.js Repository"
 | 
			
		||||
  mkdir -p /etc/apt/keyrings
 | 
			
		||||
  curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
 | 
			
		||||
  echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list
 | 
			
		||||
  msg_ok "Set up Node.js Repository"
 | 
			
		||||
 | 
			
		||||
    msg_info "Installing Node.js"
 | 
			
		||||
    $STD apt-get update
 | 
			
		||||
    $STD apt-get install -y nodejs
 | 
			
		||||
    $STD npm install -g pnpm
 | 
			
		||||
    msg_ok "Installed Node.js"
 | 
			
		||||
  msg_info "Installing Node.js"
 | 
			
		||||
  $STD apt-get update
 | 
			
		||||
  $STD apt-get install -y nodejs
 | 
			
		||||
  $STD npm install -g pnpm
 | 
			
		||||
  msg_ok "Installed Node.js"
 | 
			
		||||
 | 
			
		||||
    msg_info "Setup ${APPLICATION}-ui"
 | 
			
		||||
    tmp_file=$(mktemp)
 | 
			
		||||
    tmp_dir=$(mktemp -d)
 | 
			
		||||
    mkdir -p /opt/meilisearch-ui
 | 
			
		||||
    RELEASE_UI=$(curl -s https://api.github.com/repos/riccox/meilisearch-ui/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
 | 
			
		||||
    curl -fsSL "https://github.com/riccox/meilisearch-ui/archive/refs/tags/${RELEASE_UI}.zip" -o $tmp_file
 | 
			
		||||
    unzip -q "$tmp_file" -d "$tmp_dir"
 | 
			
		||||
    mv "$tmp_dir"/*/* /opt/meilisearch-ui/
 | 
			
		||||
    cd /opt/meilisearch-ui
 | 
			
		||||
    sed -i 's|const hash = execSync("git rev-parse HEAD").toString().trim();|const hash = "unknown";|' /opt/meilisearch-ui/vite.config.ts
 | 
			
		||||
    $STD pnpm install
 | 
			
		||||
    cat <<EOF > /opt/meilisearch-ui/.env.local
 | 
			
		||||
  msg_info "Setup ${APPLICATION}-ui"
 | 
			
		||||
  tmp_file=$(mktemp)
 | 
			
		||||
  tmp_dir=$(mktemp -d)
 | 
			
		||||
  mkdir -p /opt/meilisearch-ui
 | 
			
		||||
  RELEASE_UI=$(curl -s https://api.github.com/repos/riccox/meilisearch-ui/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
 | 
			
		||||
  curl -fsSL "https://github.com/riccox/meilisearch-ui/archive/refs/tags/${RELEASE_UI}.zip" -o "$tmp_file"
 | 
			
		||||
  unzip -q "$tmp_file" -d "$tmp_dir"
 | 
			
		||||
  mv "$tmp_dir"/*/* /opt/meilisearch-ui/
 | 
			
		||||
  cd /opt/meilisearch-ui
 | 
			
		||||
  sed -i 's|const hash = execSync("git rev-parse HEAD").toString().trim();|const hash = "unknown";|' /opt/meilisearch-ui/vite.config.ts
 | 
			
		||||
  $STD pnpm install
 | 
			
		||||
  cat <<EOF >/opt/meilisearch-ui/.env.local
 | 
			
		||||
VITE_SINGLETON_MODE=true
 | 
			
		||||
VITE_SINGLETON_HOST=http://${LOCAL_IP}:7700
 | 
			
		||||
VITE_SINGLETON_API_KEY=${MASTER_KEY}
 | 
			
		||||
EOF
 | 
			
		||||
    echo "${RELEASE_UI}" >/opt/${APPLICATION}-ui_version.txt
 | 
			
		||||
    msg_ok "Setup ${APPLICATION}-ui"
 | 
			
		||||
  echo "${RELEASE_UI}" >/opt/${APPLICATION}-ui_version.txt
 | 
			
		||||
  msg_ok "Setup ${APPLICATION}-ui"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
msg_info "Setting up Services"
 | 
			
		||||
@@ -88,7 +88,7 @@ EOF
 | 
			
		||||
systemctl enable -q --now meilisearch
 | 
			
		||||
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
cat <<EOF > /etc/systemd/system/meilisearch-ui.service
 | 
			
		||||
  cat <<EOF >/etc/systemd/system/meilisearch-ui.service
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Meilisearch UI Service
 | 
			
		||||
After=network.target meilisearch.service
 | 
			
		||||
@@ -107,12 +107,11 @@ SyslogIdentifier=meilisearch-ui
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
EOF
 | 
			
		||||
systemctl enable -q --now meilisearch-ui
 | 
			
		||||
  systemctl enable -q --now meilisearch-ui
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
msg_ok "Set up Services"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
motd_ssh
 | 
			
		||||
customize
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ msg_info "Installing Dependencies"
 | 
			
		||||
$STD apt-get install -y gnupg
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
read -p "Do you want to install MongoDB 8.0 instead of 7.0? [y/N]: " install_mongodb_8
 | 
			
		||||
read -p "${TAB3}Do you want to install MongoDB 8.0 instead of 7.0? [y/N]: " install_mongodb_8
 | 
			
		||||
if [[ "$install_mongodb_8" =~ ^[Yy]$ ]]; then
 | 
			
		||||
  MONGODB_VERSION="8.0"
 | 
			
		||||
else
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
RELEASE_REPO="mysql-8.0"
 | 
			
		||||
RELEASE_AUTH="mysql_native_password"
 | 
			
		||||
read -r -p "Would you like to install the MySQL 8.4 LTS release instead of MySQL 8.0 (bug fix track; EOL April-2026)? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to install the MySQL 8.4 LTS release instead of MySQL 8.0 (bug fix track; EOL April-2026)? <y/N> " prompt
 | 
			
		||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  RELEASE_REPO="mysql-8.4-lts"
 | 
			
		||||
  RELEASE_AUTH="caching_sha2_password"
 | 
			
		||||
@@ -50,7 +50,7 @@ echo -e "MySQL user: root" >>~/mysql.creds
 | 
			
		||||
echo -e "MySQL password: $ADMIN_PASS" >>~/mysql.creds
 | 
			
		||||
msg_ok "MySQL Server configured"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add PhpMyAdmin? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add PhpMyAdmin? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing phpMyAdmin"
 | 
			
		||||
  $STD apt-get install -y \
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ update_os
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Dependencies (Patience)"
 | 
			
		||||
$STD apt-get install -y \
 | 
			
		||||
    ffmpeg
 | 
			
		||||
  ffmpeg
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Navidrome"
 | 
			
		||||
@@ -27,9 +27,9 @@ systemctl enable -q --now navidrome
 | 
			
		||||
echo "${RELEASE}" >/opt/Navidrome_version.txt
 | 
			
		||||
msg_ok "Installed Navidrome"
 | 
			
		||||
 | 
			
		||||
read -p "Do you want to install filebrowser addon? (y/n) " -n 1 -r
 | 
			
		||||
read -p "${TAB3}Do you want to install filebrowser addon? (y/n) " -n 1 -r
 | 
			
		||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
 | 
			
		||||
    bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/filebrowser.sh)"
 | 
			
		||||
  bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/filebrowser.sh)"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
motd_ssh
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@ RELEASE=$(curl -fsSL https://api.github.com/repos/NginxProxyManager/nginx-proxy-
 | 
			
		||||
  grep "tag_name" |
 | 
			
		||||
  awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to install an older version (v2.10.4)? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to install an older version (v2.10.4)? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Downloading Nginx Proxy Manager v2.10.4"
 | 
			
		||||
  curl -fsSL "https://codeload.github.com/NginxProxyManager/nginx-proxy-manager/tar.gz/v2.10.4" | tar -xz
 | 
			
		||||
@@ -71,7 +71,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
else
 | 
			
		||||
  msg_info "Downloading Nginx Proxy Manager v${RELEASE}"
 | 
			
		||||
  curl -fsSL "https://codeload.github.com/NginxProxyManager/nginx-proxy-manager/tar.gz/v${RELEASE}" | tar -xz
 | 
			
		||||
  cd ./nginx-proxy-manager-${RELEASE}
 | 
			
		||||
  cd ./nginx-proxy-manager-"${RELEASE}"
 | 
			
		||||
  msg_ok "Downloaded Nginx Proxy Manager v${RELEASE}"
 | 
			
		||||
fi
 | 
			
		||||
msg_info "Setting up Environment"
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,9 @@ update_os
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Dependencies"
 | 
			
		||||
$STD apk add \
 | 
			
		||||
    tzdata \
 | 
			
		||||
    gawk \
 | 
			
		||||
    yq
 | 
			
		||||
  tzdata \
 | 
			
		||||
  gawk \
 | 
			
		||||
  yq
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Docker & Compose"
 | 
			
		||||
@@ -26,7 +26,7 @@ $STD rc-service docker start
 | 
			
		||||
$STD rc-update add docker default
 | 
			
		||||
 | 
			
		||||
get_latest_release() {
 | 
			
		||||
    curl -fsSL https://api.github.com/repos/$1/releases/latest | grep '"tag_name":' | cut -d'"' -f4
 | 
			
		||||
  curl -fsSL https://api.github.com/repos/$1/releases/latest | grep '"tag_name":' | cut -d'"' -f4
 | 
			
		||||
}
 | 
			
		||||
DOCKER_COMPOSE_LATEST_VERSION=$(get_latest_release "docker/compose")
 | 
			
		||||
DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
 | 
			
		||||
@@ -42,20 +42,20 @@ msg_ok "Fetched NPMplus"
 | 
			
		||||
 | 
			
		||||
attempts=0
 | 
			
		||||
while true; do
 | 
			
		||||
    read -r -p "Enter your TZ Identifier (e.g., Europe/Berlin): " TZ_INPUT
 | 
			
		||||
    if validate_tz "$TZ_INPUT"; then
 | 
			
		||||
        break
 | 
			
		||||
    fi
 | 
			
		||||
    msg_error "Invalid timezone! Please enter a valid TZ identifier."
 | 
			
		||||
  read -r -p "${TAB3}Enter your TZ Identifier (e.g., Europe/Berlin): " TZ_INPUT
 | 
			
		||||
  if validate_tz "$TZ_INPUT"; then
 | 
			
		||||
    break
 | 
			
		||||
  fi
 | 
			
		||||
  msg_error "Invalid timezone! Please enter a valid TZ identifier."
 | 
			
		||||
 | 
			
		||||
    attempts=$((attempts + 1))
 | 
			
		||||
    if [[ "$attempts" -ge 3 ]]; then
 | 
			
		||||
        msg_error "Maximum attempts reached. Exiting."
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
  attempts=$((attempts + 1))
 | 
			
		||||
  if [[ "$attempts" -ge 3 ]]; then
 | 
			
		||||
    msg_error "Maximum attempts reached. Exiting."
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
read -r -p "Enter your ACME Email: " ACME_EMAIL_INPUT
 | 
			
		||||
read -r -p "${TAB3}Enter your ACME Email: " ACME_EMAIL_INPUT
 | 
			
		||||
 | 
			
		||||
yq -i "
 | 
			
		||||
  .services.npmplus.environment |=
 | 
			
		||||
@@ -67,20 +67,20 @@ msg_info "Building and Starting NPMplus (Patience)"
 | 
			
		||||
$STD docker compose up -d
 | 
			
		||||
CONTAINER_ID=""
 | 
			
		||||
for i in {1..60}; do
 | 
			
		||||
    CONTAINER_ID=$(docker ps --filter "name=npmplus" --format "{{.ID}}")
 | 
			
		||||
    if [[ -n "$CONTAINER_ID" ]]; then
 | 
			
		||||
        STATUS=$(docker inspect --format '{{.State.Health.Status}}' "$CONTAINER_ID" 2>/dev/null || echo "starting")
 | 
			
		||||
        if [[ "$STATUS" == "healthy" ]]; then
 | 
			
		||||
            msg_ok "NPMplus is running and healthy"
 | 
			
		||||
            break
 | 
			
		||||
        elif [[ "$STATUS" == "unhealthy" ]]; then
 | 
			
		||||
            msg_error "NPMplus container is unhealthy! Check logs."
 | 
			
		||||
            docker logs "$CONTAINER_ID"
 | 
			
		||||
            exit 1
 | 
			
		||||
        fi
 | 
			
		||||
  CONTAINER_ID=$(docker ps --filter "name=npmplus" --format "{{.ID}}")
 | 
			
		||||
  if [[ -n "$CONTAINER_ID" ]]; then
 | 
			
		||||
    STATUS=$(docker inspect --format '{{.State.Health.Status}}' "$CONTAINER_ID" 2>/dev/null || echo "starting")
 | 
			
		||||
    if [[ "$STATUS" == "healthy" ]]; then
 | 
			
		||||
      msg_ok "NPMplus is running and healthy"
 | 
			
		||||
      break
 | 
			
		||||
    elif [[ "$STATUS" == "unhealthy" ]]; then
 | 
			
		||||
      msg_error "NPMplus container is unhealthy! Check logs."
 | 
			
		||||
      docker logs "$CONTAINER_ID"
 | 
			
		||||
      exit 1
 | 
			
		||||
    fi
 | 
			
		||||
    sleep 2
 | 
			
		||||
    [[ $i -eq 60 ]] && msg_error "NPMplus container did not become healthy within 120s." && docker logs "$CONTAINER_ID" && exit 1
 | 
			
		||||
  fi
 | 
			
		||||
  sleep 2
 | 
			
		||||
  [[ $i -eq 60 ]] && msg_error "NPMplus container did not become healthy within 120s." && docker logs "$CONTAINER_ID" && exit 1
 | 
			
		||||
done
 | 
			
		||||
msg_ok "Builded and started NPMplus"
 | 
			
		||||
 | 
			
		||||
@@ -90,18 +90,18 @@ customize
 | 
			
		||||
msg_info "Retrieving Default Login (Patience)"
 | 
			
		||||
PASSWORD_FOUND=0
 | 
			
		||||
for i in {1..60}; do
 | 
			
		||||
    PASSWORD_LINE=$(docker logs "$CONTAINER_ID" 2>&1 | awk '/Creating a new user:/ { print; exit }')
 | 
			
		||||
    if [[ -n "$PASSWORD_LINE" ]]; then
 | 
			
		||||
        PASSWORD=$(echo "$PASSWORD_LINE" | awk -F 'password: ' '{print $2}')
 | 
			
		||||
        echo -e "username: admin@example.org\npassword: $PASSWORD" >/opt/.npm_pwd
 | 
			
		||||
        msg_ok "Saved default login to /opt/.npm_pwd"
 | 
			
		||||
        PASSWORD_FOUND=1
 | 
			
		||||
        break
 | 
			
		||||
    fi
 | 
			
		||||
    sleep 2
 | 
			
		||||
  PASSWORD_LINE=$(docker logs "$CONTAINER_ID" 2>&1 | awk '/Creating a new user:/ { print; exit }')
 | 
			
		||||
  if [[ -n "$PASSWORD_LINE" ]]; then
 | 
			
		||||
    PASSWORD=$(echo "$PASSWORD_LINE" | awk -F 'password: ' '{print $2}')
 | 
			
		||||
    echo -e "username: admin@example.org\npassword: $PASSWORD" >/opt/.npm_pwd
 | 
			
		||||
    msg_ok "Saved default login to /opt/.npm_pwd"
 | 
			
		||||
    PASSWORD_FOUND=1
 | 
			
		||||
    break
 | 
			
		||||
  fi
 | 
			
		||||
  sleep 2
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
if [[ $PASSWORD_FOUND -eq 0 ]]; then
 | 
			
		||||
    msg_error "Could not retrieve default login after 60 seconds."
 | 
			
		||||
    echo -e "\nYou can manually check the container logs with:\n  docker logs $CONTAINER_ID | grep 'Creating a new user:'\n"
 | 
			
		||||
  msg_error "Could not retrieve default login after 60 seconds."
 | 
			
		||||
  echo -e "\nYou can manually check the container logs with:\n  docker logs $CONTAINER_ID | grep 'Creating a new user:'\n"
 | 
			
		||||
fi
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ export NODE_OPTIONS="--max-old-space-size=3584"
 | 
			
		||||
$STD npm run build
 | 
			
		||||
msg_ok "Installed Open WebUI"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Ollama? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Ollama? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Ollama"
 | 
			
		||||
  curl -fsSLO https://ollama.com/download/ollama-linux-amd64.tgz
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
# Source: https://github.com/openziti/ziti
 | 
			
		||||
 | 
			
		||||
source /dev/stdin <<< "$FUNCTIONS_FILE_PATH"
 | 
			
		||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
 | 
			
		||||
color
 | 
			
		||||
verb_ip6
 | 
			
		||||
catch_errors
 | 
			
		||||
@@ -25,18 +25,18 @@ $STD apt-get update
 | 
			
		||||
$STD apt-get install -y openziti-controller openziti-console
 | 
			
		||||
msg_ok "Installed openziti"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to go through the auto configuration now? <y/N>" prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to go through the auto configuration now? <y/N>" prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  IPADDRESS=$(hostname -I | awk '{print $1}')
 | 
			
		||||
  GEN_FQDN="controller.${IPADDRESS}.sslip.io"
 | 
			
		||||
  read -r -p "Please enter the controller FQDN [${GEN_FQDN}]: " ZITI_CTRL_ADVERTISED_ADDRESS
 | 
			
		||||
  read -r -p "${TAB3}Please enter the controller FQDN [${GEN_FQDN}]: " ZITI_CTRL_ADVERTISED_ADDRESS
 | 
			
		||||
  ZITI_CTRL_ADVERTISED_ADDRESS=${ZITI_CTRL_ADVERTISED_ADDRESS:-$GEN_FQDN}
 | 
			
		||||
  read -r -p "Please enter the controller port [1280]: " ZITI_CTRL_ADVERTISED_PORT
 | 
			
		||||
  read -r -p "${TAB3}Please enter the controller port [1280]: " ZITI_CTRL_ADVERTISED_PORT
 | 
			
		||||
  ZITI_CTRL_ADVERTISED_PORT=${ZITI_CTRL_ADVERTISED_PORT:-1280}
 | 
			
		||||
  read -r -p "Please enter the controller admin user [admin]: " ZITI_USER
 | 
			
		||||
  read -r -p "${TAB3}Please enter the controller admin user [admin]: " ZITI_USER
 | 
			
		||||
  ZITI_USER=${ZITI_USER:-admin}
 | 
			
		||||
  GEN_PWD=$(head -c128 /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9!@#$%^*_+~' | cut -c 1-12)
 | 
			
		||||
  read -r -p "Please enter the controller admin password [${GEN_PWD}]:" ZITI_PWD
 | 
			
		||||
  read -r -p "${TAB3}Please enter the controller admin password [${GEN_PWD}]:" ZITI_PWD
 | 
			
		||||
  ZITI_PWD=${ZITI_PWD:-$GEN_PWD}
 | 
			
		||||
  CONFIG_FILE="/opt/openziti/etc/controller/bootstrap.env"
 | 
			
		||||
  sed -i "s|^ZITI_CTRL_ADVERTISED_ADDRESS=.*|ZITI_CTRL_ADVERTISED_ADDRESS='${ZITI_CTRL_ADVERTISED_ADDRESS}'|" "$CONFIG_FILE"
 | 
			
		||||
 
 | 
			
		||||
@@ -27,16 +27,16 @@ sed -i '0,/^ExecStart/ { /^ExecStart/ { n; s|^ExecStart.*|ExecStart=/opt/openzit
 | 
			
		||||
systemctl daemon-reload
 | 
			
		||||
msg_ok "Installed openziti"
 | 
			
		||||
 | 
			
		||||
read -r -p "Please paste an identity enrollment token(JTW)" prompt
 | 
			
		||||
read -r -p "${TAB3}Please paste an identity enrollment token(JTW)" prompt
 | 
			
		||||
if [[ ${prompt} ]]; then
 | 
			
		||||
    msg_info "Adding identity"
 | 
			
		||||
    echo "${prompt}" >/opt/openziti/etc/identities/identity.jwt
 | 
			
		||||
    chown ziti:ziti /opt/openziti/etc/identities/identity.jwt
 | 
			
		||||
    systemctl enable -q --now ziti-edge-tunnel
 | 
			
		||||
    msg_ok "Service Started"
 | 
			
		||||
  msg_info "Adding identity"
 | 
			
		||||
  echo "${prompt}" >/opt/openziti/etc/identities/identity.jwt
 | 
			
		||||
  chown ziti:ziti /opt/openziti/etc/identities/identity.jwt
 | 
			
		||||
  systemctl enable -q --now ziti-edge-tunnel
 | 
			
		||||
  msg_ok "Service Started"
 | 
			
		||||
else
 | 
			
		||||
    systemctl enable -q ziti-edge-tunnel
 | 
			
		||||
    msg_error "No identity provided; please place an identity file in /opt/openziti/etc/identities/ and restart the service"
 | 
			
		||||
  systemctl enable -q ziti-edge-tunnel
 | 
			
		||||
  msg_error "No identity provided; please place an identity file in /opt/openziti/etc/identities/ and restart the service"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
motd_ssh
 | 
			
		||||
 
 | 
			
		||||
@@ -50,8 +50,8 @@ msg_info "Setup Paperless-GPT"
 | 
			
		||||
temp_file=$(mktemp)
 | 
			
		||||
RELEASE=$(curl -fsSL https://api.github.com/repos/icereed/paperless-gpt/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
curl -fsSL "https://github.com/icereed/paperless-gpt/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
 | 
			
		||||
tar zxf $temp_file
 | 
			
		||||
mv paperless-gpt-${RELEASE} /opt/paperless-gpt
 | 
			
		||||
tar zxf "$temp_file"
 | 
			
		||||
mv paperless-gpt-"${RELEASE}" /opt/paperless-gpt
 | 
			
		||||
cd /opt/paperless-gpt/web-app
 | 
			
		||||
$STD npm install
 | 
			
		||||
$STD npm run build
 | 
			
		||||
@@ -64,16 +64,16 @@ echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt"
 | 
			
		||||
msg_ok "Setup Paperless-GPT"
 | 
			
		||||
 | 
			
		||||
mkdir -p /opt/paperless-gpt-data
 | 
			
		||||
read -p "Do you want to enter the Paperless local URL now? (y/n) " input_url
 | 
			
		||||
read -p "${TAB3}Do you want to enter the Paperless local URL now? (y/n) " input_url
 | 
			
		||||
if [[ "$input_url" =~ ^[Yy]$ ]]; then
 | 
			
		||||
  read -p "Enter your Paperless-NGX instance URL (e.g., http://192.168.1.100:8000): " PAPERLESS_BASE_URL
 | 
			
		||||
  read -p "${TAB3}Enter your Paperless-NGX instance URL (e.g., http://192.168.1.100:8000): " PAPERLESS_BASE_URL
 | 
			
		||||
else
 | 
			
		||||
  PAPERLESS_BASE_URL="http://your_paperless_ngx_url"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
read -p "Do you want to enter the Paperless API token now? (y/n) " input_token
 | 
			
		||||
read -p "${TAB3}Do you want to enter the Paperless API token now? (y/n) " input_token
 | 
			
		||||
if [[ "$input_token" =~ ^[Yy]$ ]]; then
 | 
			
		||||
  read -p "Enter your Paperless API token: " PAPERLESS_API_TOKEN
 | 
			
		||||
  read -p "${TAB3}Enter your Paperless API token: " PAPERLESS_API_TOKEN
 | 
			
		||||
else
 | 
			
		||||
  PAPERLESS_API_TOKEN="your_paperless_api_token"
 | 
			
		||||
fi
 | 
			
		||||
@@ -129,7 +129,7 @@ motd_ssh
 | 
			
		||||
customize
 | 
			
		||||
 | 
			
		||||
msg_info "Cleaning up"
 | 
			
		||||
rm -f $temp_file
 | 
			
		||||
rm -f "$temp_file"
 | 
			
		||||
$STD apt-get -y autoremove
 | 
			
		||||
$STD apt-get -y autoclean
 | 
			
		||||
msg_ok "Cleaned"
 | 
			
		||||
 
 | 
			
		||||
@@ -125,7 +125,7 @@ cd /opt/paperless/src
 | 
			
		||||
$STD python3 manage.py migrate
 | 
			
		||||
msg_ok "Set up PostgreSQL database"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Adminer? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Adminer? <y/N> " prompt
 | 
			
		||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Adminer"
 | 
			
		||||
  $STD apt install -y adminer
 | 
			
		||||
 
 | 
			
		||||
@@ -54,9 +54,9 @@ $STD pihole-FTL --config ntp.sync.interval 0
 | 
			
		||||
systemctl restart pihole-FTL.service
 | 
			
		||||
msg_ok "Installed Pi-hole"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Unbound? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Unbound? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  read -r -p "Unbound is configured as a recursive DNS server by default, would you like it to be configured as a forwarding DNS server (using DNS-over-TLS (DoT)) instead? <y/N> " prompt
 | 
			
		||||
  read -r -p "${TAB3}Unbound is configured as a recursive DNS server by default, would you like it to be configured as a forwarding DNS server (using DNS-over-TLS (DoT)) instead? <y/N> " prompt
 | 
			
		||||
  msg_info "Installing Unbound"
 | 
			
		||||
  $STD apt-get install -y unbound
 | 
			
		||||
  cat <<EOF >/etc/unbound/unbound.conf.d/pi-hole.conf
 | 
			
		||||
 
 | 
			
		||||
@@ -42,7 +42,7 @@ rm -f "$temp_file"
 | 
			
		||||
set -o pipefail
 | 
			
		||||
msg_ok "Installed Golang"
 | 
			
		||||
 | 
			
		||||
read -r -p "What public URL do you want to use (e.g. pocketid.mydomain.com)? " public_url
 | 
			
		||||
read -r -p "${TAB3}What public URL do you want to use (e.g. pocketid.mydomain.com)? " public_url
 | 
			
		||||
msg_info "Setup Pocket ID"
 | 
			
		||||
cd /opt
 | 
			
		||||
RELEASE=$(curl -fsSL https://api.github.com/repos/pocket-id/pocket-id/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ $STD systemctl enable --now podman.socket
 | 
			
		||||
echo -e 'unqualified-search-registries=["docker.io"]' >>/etc/containers/registries.conf
 | 
			
		||||
msg_ok "Installed Podman"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Portainer? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Portainer? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Portainer $PORTAINER_LATEST_VERSION"
 | 
			
		||||
  podman volume create portainer_data >/dev/null
 | 
			
		||||
@@ -63,7 +63,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
    portainer/portainer-ce:latest
 | 
			
		||||
  msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION"
 | 
			
		||||
else
 | 
			
		||||
  read -r -p "Would you like to add the Portainer Agent? <y/N> " prompt
 | 
			
		||||
  read -r -p "${TAB3}Would you like to add the Portainer Agent? <y/N> " prompt
 | 
			
		||||
  if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
    msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION"
 | 
			
		||||
    podman volume create temp >/dev/null
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ $STD systemctl enable --now podman.socket
 | 
			
		||||
echo -e 'unqualified-search-registries=["docker.io"]' >>/etc/containers/registries.conf
 | 
			
		||||
msg_ok "Installed Podman"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Portainer? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Portainer? <y/N> " prompt
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Portainer $PORTAINER_LATEST_VERSION"
 | 
			
		||||
  podman volume create portainer_data >/dev/null
 | 
			
		||||
@@ -63,7 +63,7 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
    portainer/portainer-ce:latest
 | 
			
		||||
  msg_ok "Installed Portainer $PORTAINER_LATEST_VERSION"
 | 
			
		||||
else
 | 
			
		||||
  read -r -p "Would you like to add the Portainer Agent? <y/N> " prompt
 | 
			
		||||
  read -r -p "${TAB3}Would you like to add the Portainer Agent? <y/N> " prompt
 | 
			
		||||
  if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
    msg_info "Installing Portainer agent $PORTAINER_AGENT_LATEST_VERSION"
 | 
			
		||||
    podman volume create temp >/dev/null
 | 
			
		||||
 
 | 
			
		||||
@@ -130,7 +130,7 @@ EOF
 | 
			
		||||
sudo systemctl restart postgresql
 | 
			
		||||
msg_ok "Installed PostgreSQL"
 | 
			
		||||
 | 
			
		||||
read -r -p "Would you like to add Adminer? <y/N> " prompt
 | 
			
		||||
read -r -p "${TAB3}Would you like to add Adminer? <y/N> " prompt
 | 
			
		||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing Adminer"
 | 
			
		||||
  $STD apt install -y adminer
 | 
			
		||||
 
 | 
			
		||||
@@ -53,9 +53,9 @@ $STD mysql -u root -e "GRANT ALL ON $DB_NAME.* TO '$DB_USER'@'localhost'; FLUSH
 | 
			
		||||
} >>~/pterodactyl-panel.creds
 | 
			
		||||
msg_ok "Set up MariaDB"
 | 
			
		||||
 | 
			
		||||
read -p "Provide an email address for admin login, this should be a valid email address: " ADMIN_EMAIL
 | 
			
		||||
read -p "Enter your First Name: " NAME_FIRST
 | 
			
		||||
read -p "Enter your Last Name: " NAME_LAST
 | 
			
		||||
read -p "${TAB3}Provide an email address for admin login, this should be a valid email address: " ADMIN_EMAIL
 | 
			
		||||
read -p "${TAB3}nter your First Name: " NAME_FIRST
 | 
			
		||||
read -p "${TAB3}Enter your Last Name: " NAME_LAST
 | 
			
		||||
 | 
			
		||||
msg_info "Installing pterodactyl Panel"
 | 
			
		||||
RELEASE=$(curl -fsSL https://api.github.com/repos/pterodactyl/panel/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >>~/.bash_profile
 | 
			
		||||
source ~/.bash_profile
 | 
			
		||||
msg_ok "Installed SQL Server Tools"
 | 
			
		||||
 | 
			
		||||
read -r -p "Do you want to run the SQL server setup now? (Later is also possible) <y/N>" prompt
 | 
			
		||||
read -r -p "${TAB3}Do you want to run the SQL server setup now? (Later is also possible) <y/N>" prompt
 | 
			
		||||
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  /opt/mssql/bin/mssql-conf setup
 | 
			
		||||
else
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ color() {
 | 
			
		||||
  BFR="\\r\\033[K"
 | 
			
		||||
  BOLD=$(echo "\033[1m")
 | 
			
		||||
  TAB="  "
 | 
			
		||||
  TAB3="      "
 | 
			
		||||
 | 
			
		||||
  # System
 | 
			
		||||
  RETRY_NUM=10
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@ color() {
 | 
			
		||||
  BOLD=$(echo "\033[1m")
 | 
			
		||||
  HOLD=" "
 | 
			
		||||
  TAB="  "
 | 
			
		||||
  TAB3="      "
 | 
			
		||||
 | 
			
		||||
  # Icons
 | 
			
		||||
  CM="${TAB}✔️${TAB}"
 | 
			
		||||
@@ -528,29 +529,29 @@ advanced_settings() {
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  BRIDGES=""
 | 
			
		||||
  IFACE_FILEPATH_LIST="/etc/network/interfaces"$'\n'$(find "/etc/network/interfaces.d/" -type f)
 | 
			
		||||
  OLD_IFS=$IFS; IFS=$'\n'
 | 
			
		||||
  OLD_IFS=$IFS
 | 
			
		||||
  IFS=$'\n'
 | 
			
		||||
 | 
			
		||||
  for iface_filepath in ${IFACE_FILEPATH_LIST}; do
 | 
			
		||||
    iface_indexes_tmpfile=$(mktemp -q -u '.iface-XXXX')
 | 
			
		||||
 | 
			
		||||
    ( grep -Pn '^\s*iface' "${iface_filepath}" | cut -d':' -f1 && wc -l "${iface_filepath}" | cut -d' ' -f1 ) | \
 | 
			
		||||
    awk 'FNR==1 {line=$0; next} {print line":"$0-1; line=$0}' > "${iface_indexes_tmpfile}"
 | 
			
		||||
    (grep -Pn '^\s*iface' "${iface_filepath}" | cut -d':' -f1 && wc -l "${iface_filepath}" | cut -d' ' -f1) |
 | 
			
		||||
      awk 'FNR==1 {line=$0; next} {print line":"$0-1; line=$0}' >"${iface_indexes_tmpfile}"
 | 
			
		||||
 | 
			
		||||
    if [ -f "${iface_indexes_tmpfile}" ]; then
 | 
			
		||||
        while read -r pair; do
 | 
			
		||||
            start=$(echo "${pair}" | cut -d':' -f1)
 | 
			
		||||
            end=$(echo "${pair}" | cut -d':' -f2)
 | 
			
		||||
      while read -r pair; do
 | 
			
		||||
        start=$(echo "${pair}" | cut -d':' -f1)
 | 
			
		||||
        end=$(echo "${pair}" | cut -d':' -f2)
 | 
			
		||||
 | 
			
		||||
            if awk "NR >= ${start} && NR <= ${end}" "${iface_filepath}" | grep -qP '^\s*bridge[-_](ports|stp|fd|vlan-aware|vids)\s+'; then
 | 
			
		||||
                iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}')
 | 
			
		||||
                BRIDGES="${iface_name}"$'\n'"${BRIDGES}"
 | 
			
		||||
            fi
 | 
			
		||||
        if awk "NR >= ${start} && NR <= ${end}" "${iface_filepath}" | grep -qP '^\s*(bridge[-_](ports|stp|fd|vlan-aware|vids)|ovs_type\s+OVSBridge)\b'; then
 | 
			
		||||
          iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}')
 | 
			
		||||
          BRIDGES="${iface_name}"$'\n'"${BRIDGES}"
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        done < "${iface_indexes_tmpfile}"
 | 
			
		||||
        rm -f "${iface_indexes_tmpfile}"
 | 
			
		||||
      done <"${iface_indexes_tmpfile}"
 | 
			
		||||
      rm -f "${iface_indexes_tmpfile}"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
  done
 | 
			
		||||
@@ -564,11 +565,11 @@ advanced_settings() {
 | 
			
		||||
    echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
 | 
			
		||||
  else
 | 
			
		||||
    BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --menu "Select network bridge:" 15 40 6 $(echo "$BRIDGES" | awk '{print $0, "Bridge"}') 3>&1 1>&2 2>&3)
 | 
			
		||||
      if [ -z "$BRG" ]; then
 | 
			
		||||
        exit_script
 | 
			
		||||
      else
 | 
			
		||||
        echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
 | 
			
		||||
      fi
 | 
			
		||||
    if [ -z "$BRG" ]; then
 | 
			
		||||
      exit_script
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
@@ -963,18 +964,17 @@ config_file() {
 | 
			
		||||
        else
 | 
			
		||||
          msg_error "Invalid IP Address format for Gateway. Needs to be 0.0.0.0, was ${GATE}"
 | 
			
		||||
          exit
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        msg_error "Gateway IP Address cannot be empty"
 | 
			
		||||
        exit
 | 
			
		||||
      fi
 | 
			
		||||
  else
 | 
			
		||||
    msg_error "Gateway IP Address cannot be empty"
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
    else
 | 
			
		||||
      msg_error "Invalid IP Address format. Needs to be 0.0.0.0/0, was ${NET}"
 | 
			
		||||
      exit
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  if [[ ! -z "$APT_CACHER_IP" ]]; then
 | 
			
		||||
    if [[ "$APT_CACHER_IP" =~ $ip_regex ]]; then
 | 
			
		||||
      APT_CACHER="yes"
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ color() {
 | 
			
		||||
  BOLD=$(echo "\033[1m")
 | 
			
		||||
  HOLD=" "
 | 
			
		||||
  TAB="  "
 | 
			
		||||
  TAB3="      "
 | 
			
		||||
 | 
			
		||||
  # System
 | 
			
		||||
  RETRY_NUM=10
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										337
									
								
								misc/tools.func
									
									
									
									
									
								
							
							
						
						
									
										337
									
								
								misc/tools.func
									
									
									
									
									
								
							@@ -1,4 +1,17 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs Node.js and optional global modules.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Installs specified Node.js version using NodeSource APT repo
 | 
			
		||||
#   - Optionally installs or updates global npm modules
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   NODE_VERSION   - Node.js version to install (default: 22)
 | 
			
		||||
#   NODE_MODULE    - Comma-separated list of global modules (e.g. "yarn,@vue/cli@5.0.0")
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
install_node_and_modules() {
 | 
			
		||||
  local NODE_VERSION="${NODE_VERSION:-22}"
 | 
			
		||||
  local NODE_MODULE="${NODE_MODULE:-}"
 | 
			
		||||
@@ -99,6 +112,19 @@ install_node_and_modules() {
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs or upgrades PostgreSQL and performs data migration.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Detects existing PostgreSQL version
 | 
			
		||||
#   - Dumps all databases before upgrade
 | 
			
		||||
#   - Adds PGDG repo and installs specified version
 | 
			
		||||
#   - Restores dumped data post-upgrade
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   PG_VERSION     - Major PostgreSQL version (e.g. 15, 16) (default: 16)
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
install_postgresql() {
 | 
			
		||||
  local PG_VERSION="${PG_VERSION:-16}"
 | 
			
		||||
  local CURRENT_PG_VERSION=""
 | 
			
		||||
@@ -115,7 +141,7 @@ install_postgresql() {
 | 
			
		||||
    msg_info "Detected PostgreSQL $CURRENT_PG_VERSION, preparing upgrade to $PG_VERSION"
 | 
			
		||||
    NEED_PG_INSTALL=true
 | 
			
		||||
  else
 | 
			
		||||
    msg_info "PostgreSQL not installed, proceeding with fresh install of $PG_VERSION"
 | 
			
		||||
    msg_info "Setup PostgreSQL $PG_VERSION"
 | 
			
		||||
    NEED_PG_INSTALL=true
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
@@ -123,10 +149,10 @@ install_postgresql() {
 | 
			
		||||
    if [[ -n "$CURRENT_PG_VERSION" ]]; then
 | 
			
		||||
      msg_info "Dumping all PostgreSQL data from version $CURRENT_PG_VERSION"
 | 
			
		||||
      su - postgres -c "pg_dumpall > /var/lib/postgresql/backup_$(date +%F)_v${CURRENT_PG_VERSION}.sql"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    msg_info "Stopping PostgreSQL service"
 | 
			
		||||
    systemctl stop postgresql || true
 | 
			
		||||
      msg_info "Stopping PostgreSQL service"
 | 
			
		||||
      systemctl stop postgresql
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    msg_info "Removing pgdg repo and old GPG key"
 | 
			
		||||
    rm -f /etc/apt/sources.list.d/pgdg.list /etc/apt/trusted.gpg.d/postgresql.gpg
 | 
			
		||||
@@ -149,7 +175,7 @@ install_postgresql() {
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    $STD msg_info "Starting PostgreSQL $PG_VERSION"
 | 
			
		||||
    systemctl enable --now postgresql
 | 
			
		||||
    systemctl enable -q --now postgresql
 | 
			
		||||
 | 
			
		||||
    if [[ -n "$CURRENT_PG_VERSION" ]]; then
 | 
			
		||||
      $STD msg_info "Restoring dumped data"
 | 
			
		||||
@@ -160,6 +186,18 @@ install_postgresql() {
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs or updates MariaDB from official repo.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Detects current MariaDB version and replaces it if necessary
 | 
			
		||||
#   - Preserves existing database data
 | 
			
		||||
#   - Dynamically determines latest GA version if "latest" is given
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   MARIADB_VERSION - MariaDB version to install (e.g. 10.11, latest) (default: latest)
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
install_mariadb() {
 | 
			
		||||
  local MARIADB_VERSION="${MARIADB_VERSION:-latest}"
 | 
			
		||||
  local DISTRO_CODENAME
 | 
			
		||||
@@ -167,13 +205,18 @@ install_mariadb() {
 | 
			
		||||
 | 
			
		||||
  # grab dynamic latest LTS version
 | 
			
		||||
  if [[ "$MARIADB_VERSION" == "latest" ]]; then
 | 
			
		||||
    msg_info "Resolving latest MariaDB version"
 | 
			
		||||
    MARIADB_VERSION=$(curl -fsSL https://mariadb.org | grep -oP 'MariaDB \K10\.[0-9]+' | head -n1)
 | 
			
		||||
    $STD msg_info "Resolving latest GA MariaDB version"
 | 
			
		||||
    MARIADB_VERSION=$(curl -fsSL http://mirror.mariadb.org/repo/ |
 | 
			
		||||
      grep -Eo '[0-9]+\.[0-9]+\.[0-9]+/' |
 | 
			
		||||
      grep -vE 'rc/|rolling/' |
 | 
			
		||||
      sed 's|/||' |
 | 
			
		||||
      sort -Vr |
 | 
			
		||||
      head -n1)
 | 
			
		||||
    if [[ -z "$MARIADB_VERSION" ]]; then
 | 
			
		||||
      msg_error "Could not determine latest MariaDB version"
 | 
			
		||||
      msg_error "Could not determine latest GA MariaDB version"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    msg_ok "Latest MariaDB version is $MARIADB_VERSION"
 | 
			
		||||
    $STD msg_ok "Latest GA MariaDB version is $MARIADB_VERSION"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  local CURRENT_VERSION=""
 | 
			
		||||
@@ -182,23 +225,23 @@ install_mariadb() {
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ "$CURRENT_VERSION" == "$MARIADB_VERSION" ]]; then
 | 
			
		||||
    msg_info "MariaDB $MARIADB_VERSION already installed, checking for upgrade"
 | 
			
		||||
    $STD msg_info "MariaDB $MARIADB_VERSION, upgrading"
 | 
			
		||||
    $STD apt-get update
 | 
			
		||||
    $STD apt-get install --only-upgrade -y mariadb-server mariadb-client
 | 
			
		||||
    msg_ok "MariaDB $MARIADB_VERSION upgraded if applicable"
 | 
			
		||||
    $STD msg_ok "MariaDB upgraded to $MARIADB_VERSION"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ -n "$CURRENT_VERSION" ]]; then
 | 
			
		||||
    msg_info "Replacing MariaDB $CURRENT_VERSION with $MARIADB_VERSION (data will be preserved)"
 | 
			
		||||
    $STD msg_info "Replacing MariaDB $CURRENT_VERSION with $MARIADB_VERSION (data will be preserved)"
 | 
			
		||||
    $STD systemctl stop mariadb >/dev/null 2>&1 || true
 | 
			
		||||
    $STD apt-get purge -y 'mariadb*' || true
 | 
			
		||||
    rm -f /etc/apt/sources.list.d/mariadb.list /etc/apt/trusted.gpg.d/mariadb.gpg
 | 
			
		||||
  else
 | 
			
		||||
    msg_info "Installing MariaDB $MARIADB_VERSION"
 | 
			
		||||
    msg_info "Setup MariaDB $MARIADB_VERSION"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  msg_info "Setting up MariaDB Repository"
 | 
			
		||||
  $STD msg_info "Setting up MariaDB Repository"
 | 
			
		||||
  curl -fsSL "https://mariadb.org/mariadb_release_signing_key.asc" |
 | 
			
		||||
    gpg --dearmor -o /etc/apt/trusted.gpg.d/mariadb.gpg
 | 
			
		||||
 | 
			
		||||
@@ -208,9 +251,21 @@ install_mariadb() {
 | 
			
		||||
  $STD apt-get update
 | 
			
		||||
  $STD apt-get install -y mariadb-server mariadb-client
 | 
			
		||||
 | 
			
		||||
  msg_ok "Installed MariaDB $MARIADB_VERSION"
 | 
			
		||||
  msg_ok "Setup MariaDB $MARIADB_VERSION"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs or upgrades MySQL and configures APT repo.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Detects existing MySQL installation
 | 
			
		||||
#   - Purges conflicting packages before installation
 | 
			
		||||
#   - Supports clean upgrade
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   MYSQL_VERSION  - MySQL version to install (e.g. 5.7, 8.0) (default: 8.0)
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
install_mysql() {
 | 
			
		||||
  local MYSQL_VERSION="${MYSQL_VERSION:-8.0}"
 | 
			
		||||
  local CURRENT_VERSION=""
 | 
			
		||||
@@ -248,11 +303,33 @@ install_mysql() {
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs PHP with selected modules and configures Apache/FPM support.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Adds Sury PHP repo if needed
 | 
			
		||||
#   - Installs default and user-defined modules
 | 
			
		||||
#   - Patches php.ini for CLI, Apache, and FPM as needed
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   PHP_VERSION                - PHP version to install (default: 8.4)
 | 
			
		||||
#   PHP_MODULE                 - Additional comma-separated modules
 | 
			
		||||
#   PHP_APACHE                 - Set YES to enable PHP with Apache
 | 
			
		||||
#   PHP_FPM                    - Set YES to enable PHP-FPM
 | 
			
		||||
#   PHP_MEMORY_LIMIT           - (default: 512M)
 | 
			
		||||
#   PHP_UPLOAD_MAX_FILESIZE    - (default: 128M)
 | 
			
		||||
#   PHP_POST_MAX_SIZE          - (default: 128M)
 | 
			
		||||
#   PHP_MAX_EXECUTION_TIME     - (default: 300)
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
install_php() {
 | 
			
		||||
  local PHP_VERSION="${PHP_VERSION:-8.4}"
 | 
			
		||||
  local PHP_MODULE="${PHP_MODULE:-}"
 | 
			
		||||
  local PHP_APACHE="${PHP_APACHE:-NO}"
 | 
			
		||||
  local PHP_FPM="${PHP_FPM:-NO}"
 | 
			
		||||
  local DISTRO_CODENAME
 | 
			
		||||
  DISTRO_CODENAME=$(awk -F= '/VERSION_CODENAME/ { print $2 }' /etc/os-release)
 | 
			
		||||
 | 
			
		||||
  local DEFAULT_MODULES="bcmath,cli,curl,gd,intl,mbstring,opcache,readline,xml,zip"
 | 
			
		||||
  local COMBINED_MODULES
 | 
			
		||||
 | 
			
		||||
@@ -279,11 +356,11 @@ install_php() {
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
 | 
			
		||||
    $STD echo "PHP $CURRENT_PHP detected, migrating to PHP $PHP_VERSION"
 | 
			
		||||
    $STD msg_info "PHP $CURRENT_PHP detected, migrating to PHP $PHP_VERSION"
 | 
			
		||||
    if [[ ! -f /etc/apt/sources.list.d/php.list ]]; then
 | 
			
		||||
      $STD curl -fsSLo /tmp/debsuryorg-archive-keyring.deb https://packages.sury.org/debsuryorg-archive-keyring.deb
 | 
			
		||||
      $STD dpkg -i /tmp/debsuryorg-archive-keyring.deb
 | 
			
		||||
      echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" \
 | 
			
		||||
      echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ ${DISTRO_CODENAME} main" \
 | 
			
		||||
        >/etc/apt/sources.list.d/php.list
 | 
			
		||||
      $STD apt-get update
 | 
			
		||||
    fi
 | 
			
		||||
@@ -329,16 +406,24 @@ install_php() {
 | 
			
		||||
 | 
			
		||||
  for ini in "${PHP_INI_PATHS[@]}"; do
 | 
			
		||||
    if [[ -f "$ini" ]]; then
 | 
			
		||||
      msg_info "Patching $ini"
 | 
			
		||||
      $STD msg_info "Patching $ini"
 | 
			
		||||
      sed -i "s|^memory_limit = .*|memory_limit = ${PHP_MEMORY_LIMIT}|" "$ini"
 | 
			
		||||
      sed -i "s|^upload_max_filesize = .*|upload_max_filesize = ${PHP_UPLOAD_MAX_FILESIZE}|" "$ini"
 | 
			
		||||
      sed -i "s|^post_max_size = .*|post_max_size = ${PHP_POST_MAX_SIZE}|" "$ini"
 | 
			
		||||
      sed -i "s|^max_execution_time = .*|max_execution_time = ${PHP_MAX_EXECUTION_TIME}|" "$ini"
 | 
			
		||||
      msg_ok "Patched $ini"
 | 
			
		||||
      $STD msg_ok "Patched $ini"
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs or updates Composer globally.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Downloads latest version from getcomposer.org
 | 
			
		||||
#   - Installs to /usr/local/bin/composer
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
install_composer() {
 | 
			
		||||
  local COMPOSER_BIN="/usr/local/bin/composer"
 | 
			
		||||
  export COMPOSER_ALLOW_SUPERUSER=1
 | 
			
		||||
@@ -347,14 +432,14 @@ install_composer() {
 | 
			
		||||
  if [[ -x "$COMPOSER_BIN" ]]; then
 | 
			
		||||
    local CURRENT_VERSION
 | 
			
		||||
    CURRENT_VERSION=$("$COMPOSER_BIN" --version | awk '{print $3}')
 | 
			
		||||
    msg_info "Composer $CURRENT_VERSION found, updating to latest"
 | 
			
		||||
    $STD msg_info "Composer $CURRENT_VERSION found, updating to latest"
 | 
			
		||||
  else
 | 
			
		||||
    msg_info "Composer not found, installing latest version"
 | 
			
		||||
    msg_info "Setup Composer"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Download and install latest composer
 | 
			
		||||
  curl -fsSL https://getcomposer.org/installer -o /tmp/composer-setup.php
 | 
			
		||||
  php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer >/dev/null 2>&1
 | 
			
		||||
  php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer &>/dev/null
 | 
			
		||||
 | 
			
		||||
  if [[ $? -ne 0 ]]; then
 | 
			
		||||
    msg_error "Failed to install Composer"
 | 
			
		||||
@@ -365,6 +450,17 @@ install_composer() {
 | 
			
		||||
  msg_ok "Installed Composer $($COMPOSER_BIN --version | awk '{print $3}')"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs Go (Golang) from official tarball.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Determines system architecture
 | 
			
		||||
#   - Downloads latest version if GO_VERSION not set
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   GO_VERSION     - Version to install (e.g. 1.22.2 or latest)
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
install_go() {
 | 
			
		||||
  local ARCH
 | 
			
		||||
  case "$(uname -m)" in
 | 
			
		||||
@@ -420,6 +516,17 @@ install_go() {
 | 
			
		||||
  msg_ok "Installed Go $GO_VERSION"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs Temurin JDK via Adoptium APT repository.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Removes previous JDK if version mismatch
 | 
			
		||||
#   - Installs or upgrades to specified JAVA_VERSION
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   JAVA_VERSION   - Temurin JDK version to install (e.g. 17, 21)
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
install_java() {
 | 
			
		||||
  local JAVA_VERSION="${JAVA_VERSION:-21}"
 | 
			
		||||
  local DISTRO_CODENAME
 | 
			
		||||
@@ -460,6 +567,17 @@ install_java() {
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs or updates MongoDB to specified major version.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Preserves data across installations
 | 
			
		||||
#   - Adds official MongoDB repo
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   MONGO_VERSION  - MongoDB major version to install (e.g. 7.0, 8.0)
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
install_mongodb() {
 | 
			
		||||
  local MONGO_VERSION="${MONGO_VERSION:-8.0}"
 | 
			
		||||
  local DISTRO_CODENAME
 | 
			
		||||
@@ -508,6 +626,19 @@ install_mongodb() {
 | 
			
		||||
  msg_ok "MongoDB $MONGO_VERSION installed and started"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Downloads and deploys latest GitHub release tarball.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Fetches latest release from GitHub API
 | 
			
		||||
#   - Detects matching asset by architecture
 | 
			
		||||
#   - Extracts to /opt/<app> and saves version
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   APP            - Override default application name (optional)
 | 
			
		||||
#   GITHUB_TOKEN   - (optional) GitHub token for private rate limits
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
fetch_and_deploy_gh_release() {
 | 
			
		||||
  local repo="$1"
 | 
			
		||||
  local app=${APP:-$(echo "${APPLICATION,,}" | tr -d ' ')}
 | 
			
		||||
@@ -518,13 +649,11 @@ fetch_and_deploy_gh_release() {
 | 
			
		||||
  local api_response tag http_code
 | 
			
		||||
  local current_version=""
 | 
			
		||||
  local curl_timeout="--connect-timeout 10 --max-time 30"
 | 
			
		||||
 | 
			
		||||
  # Check if the app directory exists and if there's a version file
 | 
			
		||||
  if [[ -f "/opt/${app}_version.txt" ]]; then
 | 
			
		||||
    current_version=$(cat "/opt/${app}_version.txt")
 | 
			
		||||
    $STD msg_info "Current version: $current_version"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # ensure that jq is installed
 | 
			
		||||
  if ! command -v jq &>/dev/null; then
 | 
			
		||||
    $STD msg_info "Installing jq..."
 | 
			
		||||
@@ -534,58 +663,45 @@ fetch_and_deploy_gh_release() {
 | 
			
		||||
      return 1
 | 
			
		||||
    }
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  [[ -n "${GITHUB_TOKEN:-}" ]] && header=(-H "Authorization: token $GITHUB_TOKEN")
 | 
			
		||||
 | 
			
		||||
  until [[ $attempt -ge $max_attempts ]]; do
 | 
			
		||||
    ((attempt++)) || true
 | 
			
		||||
    $STD msg_info "[$attempt/$max_attempts] Fetching GitHub release for $repo...\n"
 | 
			
		||||
 | 
			
		||||
    api_response=$(curl $curl_timeout -fsSL -w "%{http_code}" -o /tmp/gh_resp.json "${header[@]}" "$api_url")
 | 
			
		||||
    http_code="${api_response:(-3)}"
 | 
			
		||||
 | 
			
		||||
    if [[ "$http_code" == "404" ]]; then
 | 
			
		||||
      msg_error "Repository $repo has no Release candidate (404)"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ "$http_code" != "200" ]]; then
 | 
			
		||||
      $STD msg_info "Request failed with HTTP $http_code, retrying...\n"
 | 
			
		||||
      sleep $((attempt * 2))
 | 
			
		||||
      continue
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    api_response=$(</tmp/gh_resp.json)
 | 
			
		||||
 | 
			
		||||
    if echo "$api_response" | grep -q "API rate limit exceeded"; then
 | 
			
		||||
      msg_error "GitHub API rate limit exceeded."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if echo "$api_response" | jq -e '.message == "Not Found"' &>/dev/null; then
 | 
			
		||||
      msg_error "Repository not found: $repo"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    tag=$(echo "$api_response" | jq -r '.tag_name // .name // empty')
 | 
			
		||||
    [[ "$tag" =~ ^v[0-9] ]] && tag="${tag:1}"
 | 
			
		||||
    version="${tag#v}"
 | 
			
		||||
 | 
			
		||||
    if [[ -z "$tag" ]]; then
 | 
			
		||||
      $STD msg_info "Empty tag received, retrying...\n"
 | 
			
		||||
      sleep $((attempt * 2))
 | 
			
		||||
      continue
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    $STD msg_ok "Found release: $tag for $repo"
 | 
			
		||||
    break
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  if [[ -z "$tag" ]]; then
 | 
			
		||||
    msg_error "Failed to fetch release for $repo after $max_attempts attempts."
 | 
			
		||||
    exit 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Version comparison (if we already have this version, skip)
 | 
			
		||||
  if [[ "$current_version" == "$tag" ]]; then
 | 
			
		||||
    $STD msg_info "Already running the latest version ($tag). Skipping update."
 | 
			
		||||
@@ -595,11 +711,9 @@ fetch_and_deploy_gh_release() {
 | 
			
		||||
  local base_url="https://github.com/$repo/releases/download/v$tag"
 | 
			
		||||
  local tmpdir
 | 
			
		||||
  tmpdir=$(mktemp -d) || return 1
 | 
			
		||||
 | 
			
		||||
  # Extract list of assets from the Release API
 | 
			
		||||
  local assets urls
 | 
			
		||||
  assets=$(echo "$api_response" | jq -r '.assets[].browser_download_url') || true
 | 
			
		||||
 | 
			
		||||
  # Detect current architecture
 | 
			
		||||
  local arch
 | 
			
		||||
  if command -v dpkg &>/dev/null; then
 | 
			
		||||
@@ -616,7 +730,6 @@ fetch_and_deploy_gh_release() {
 | 
			
		||||
    arch="unknown"
 | 
			
		||||
  fi
 | 
			
		||||
  $STD msg_info "Detected system architecture: $arch"
 | 
			
		||||
 | 
			
		||||
  # Try to find a matching asset for our architecture
 | 
			
		||||
  local url=""
 | 
			
		||||
  for u in $assets; do
 | 
			
		||||
@@ -626,7 +739,6 @@ fetch_and_deploy_gh_release() {
 | 
			
		||||
      break
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  # Fallback to other architectures if our specific one isn't found
 | 
			
		||||
  if [[ -z "$url" ]]; then
 | 
			
		||||
    for u in $assets; do
 | 
			
		||||
@@ -637,7 +749,6 @@ fetch_and_deploy_gh_release() {
 | 
			
		||||
      fi
 | 
			
		||||
    done
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Fallback to any tar.gz
 | 
			
		||||
  if [[ -z "$url" ]]; then
 | 
			
		||||
    for u in $assets; do
 | 
			
		||||
@@ -648,7 +759,6 @@ fetch_and_deploy_gh_release() {
 | 
			
		||||
      fi
 | 
			
		||||
    done
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Final fallback to GitHub source tarball
 | 
			
		||||
  if [[ -z "$url" ]]; then
 | 
			
		||||
    # Use tarball_url directly from API response instead of constructing our own URL
 | 
			
		||||
@@ -661,18 +771,14 @@ fetch_and_deploy_gh_release() {
 | 
			
		||||
 | 
			
		||||
    $STD msg_info "Using GitHub source tarball: $url"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  local filename="${url##*/}"
 | 
			
		||||
  $STD msg_info "Downloading $url"
 | 
			
		||||
 | 
			
		||||
  if ! curl $curl_timeout -fsSL -o "$tmpdir/$filename" "$url"; then
 | 
			
		||||
    msg_error "Failed to download release asset from $url"
 | 
			
		||||
    rm -rf "$tmpdir"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  mkdir -p "/opt/$app"
 | 
			
		||||
 | 
			
		||||
  tar -xzf "$tmpdir/$filename" -C "$tmpdir"
 | 
			
		||||
  local content_root
 | 
			
		||||
  content_root=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d)
 | 
			
		||||
@@ -681,12 +787,19 @@ fetch_and_deploy_gh_release() {
 | 
			
		||||
  else
 | 
			
		||||
    cp -r "$tmpdir"/* "/opt/$app/"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  echo "$version" >"/opt/${app}_version.txt"
 | 
			
		||||
  $STD msg_ok "Deployed $app v$version to /opt/$app"
 | 
			
		||||
  rm -rf "$tmpdir"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs a local IP updater script using networkd-dispatcher.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Stores current IP in /run/local-ip.env
 | 
			
		||||
#   - Automatically runs on network changes
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
setup_local_ip_helper() {
 | 
			
		||||
  local BASE_DIR="/usr/local/community-scripts/ip-management"
 | 
			
		||||
  local SCRIPT_PATH="$BASE_DIR/update_local_ip.sh"
 | 
			
		||||
@@ -759,6 +872,13 @@ EOF
 | 
			
		||||
  $STD msg_ok "LOCAL_IP helper installed using networkd-dispatcher"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Loads LOCAL_IP from persistent store or detects if missing.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Loads from /run/local-ip.env or performs runtime lookup
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
import_local_ip() {
 | 
			
		||||
  local IP_FILE="/run/local-ip.env"
 | 
			
		||||
  if [[ -f "$IP_FILE" ]]; then
 | 
			
		||||
@@ -796,6 +916,14 @@ import_local_ip() {
 | 
			
		||||
  export LOCAL_IP
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Downloads file with optional progress indicator using pv.
 | 
			
		||||
#
 | 
			
		||||
# Arguments:
 | 
			
		||||
#   $1 - URL
 | 
			
		||||
#   $2 - Destination path
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function download_with_progress() {
 | 
			
		||||
  local url="$1"
 | 
			
		||||
  local output="$2"
 | 
			
		||||
@@ -824,6 +952,14 @@ function download_with_progress() {
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs or upgrades uv (Python package manager) from GitHub releases.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Downloads architecture-specific tarball
 | 
			
		||||
#   - Places binary in /usr/local/bin
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function setup_uv() {
 | 
			
		||||
  $STD msg_info "Checking uv installation..."
 | 
			
		||||
  UV_BIN="/usr/local/bin/uv"
 | 
			
		||||
@@ -877,6 +1013,13 @@ function setup_uv() {
 | 
			
		||||
  msg_ok "uv installed/updated to $LATEST_VERSION"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Ensures /usr/local/bin is permanently in system PATH.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Adds to /etc/profile.d if not present
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function ensure_usr_local_bin_persist() {
 | 
			
		||||
  local PROFILE_FILE="/etc/profile.d/custom_path.sh"
 | 
			
		||||
 | 
			
		||||
@@ -886,6 +1029,14 @@ function ensure_usr_local_bin_persist() {
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs or updates Ghostscript (gs) from source.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Fetches latest release
 | 
			
		||||
#   - Builds and installs system-wide
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function setup_gs() {
 | 
			
		||||
  msg_info "Setup Ghostscript"
 | 
			
		||||
  mkdir -p /tmp
 | 
			
		||||
@@ -939,3 +1090,93 @@ function setup_gs() {
 | 
			
		||||
    msg_error "Ghostscript installation failed"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
# Installs rbenv and ruby-build, installs Ruby and optionally Rails.
 | 
			
		||||
#
 | 
			
		||||
# Description:
 | 
			
		||||
#   - Downloads rbenv and ruby-build from GitHub
 | 
			
		||||
#   - Compiles and installs target Ruby version
 | 
			
		||||
#   - Optionally installs Rails via gem
 | 
			
		||||
#
 | 
			
		||||
# Variables:
 | 
			
		||||
#   RUBY_VERSION         - Ruby version to install (default: 3.4.4)
 | 
			
		||||
#   RUBY_INSTALL_RAILS   - true/false to install Rails (default: true)
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
setup_rbenv_stack() {
 | 
			
		||||
  local RUBY_VERSION="${RUBY_VERSION:-3.4.4}"
 | 
			
		||||
  local RUBY_INSTALL_RAILS="${RUBY_INSTALL_RAILS:-true}"
 | 
			
		||||
 | 
			
		||||
  local RBENV_DIR="$HOME/.rbenv"
 | 
			
		||||
  local RBENV_BIN="$RBENV_DIR/bin/rbenv"
 | 
			
		||||
  local PROFILE_FILE="$HOME/.profile"
 | 
			
		||||
  local TMP_DIR
 | 
			
		||||
  TMP_DIR=$(mktemp -d)
 | 
			
		||||
 | 
			
		||||
  $STD msg_info "Installing rbenv + ruby-build + Ruby $RUBY_VERSION"
 | 
			
		||||
 | 
			
		||||
  # Fetch latest rbenv release tag from GitHub (e.g. v1.3.2 → 1.3.2)
 | 
			
		||||
  local RBENV_RELEASE
 | 
			
		||||
  RBENV_RELEASE=$(curl -fsSL https://api.github.com/repos/rbenv/rbenv/releases/latest | grep '"tag_name":' | cut -d '"' -f4 | sed 's/^v//')
 | 
			
		||||
  if [[ -z "$RBENV_RELEASE" ]]; then
 | 
			
		||||
    msg_error "Failed to fetch latest rbenv version"
 | 
			
		||||
    rm -rf "$TMP_DIR"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Download and extract rbenv release
 | 
			
		||||
  curl -fsSL "https://github.com/rbenv/rbenv/archive/refs/tags/v${RBENV_RELEASE}.tar.gz" -o "$TMP_DIR/rbenv.tar.gz"
 | 
			
		||||
  tar -xzf "$TMP_DIR/rbenv.tar.gz" -C "$TMP_DIR"
 | 
			
		||||
  mkdir -p "$RBENV_DIR"
 | 
			
		||||
  cp -r "$TMP_DIR/rbenv-${RBENV_RELEASE}/." "$RBENV_DIR/"
 | 
			
		||||
  cd "$RBENV_DIR" && src/configure && make -C src
 | 
			
		||||
 | 
			
		||||
  # Fetch latest ruby-build plugin release tag (e.g. v20250507 → 20250507)
 | 
			
		||||
  local RUBY_BUILD_RELEASE
 | 
			
		||||
  RUBY_BUILD_RELEASE=$(curl -fsSL https://api.github.com/repos/rbenv/ruby-build/releases/latest | grep '"tag_name":' | cut -d '"' -f4 | sed 's/^v//')
 | 
			
		||||
  if [[ -z "$RUBY_BUILD_RELEASE" ]]; then
 | 
			
		||||
    msg_error "Failed to fetch latest ruby-build version"
 | 
			
		||||
    rm -rf "$TMP_DIR"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Download and install ruby-build plugin
 | 
			
		||||
  curl -fsSL "https://github.com/rbenv/ruby-build/archive/refs/tags/v${RUBY_BUILD_RELEASE}.tar.gz" -o "$TMP_DIR/ruby-build.tar.gz"
 | 
			
		||||
  tar -xzf "$TMP_DIR/ruby-build.tar.gz" -C "$TMP_DIR"
 | 
			
		||||
  mkdir -p "$RBENV_DIR/plugins/ruby-build"
 | 
			
		||||
  cp -r "$TMP_DIR/ruby-build-${RUBY_BUILD_RELEASE}/." "$RBENV_DIR/plugins/ruby-build/"
 | 
			
		||||
  echo "$RUBY_BUILD_RELEASE" >"$RBENV_DIR/plugins/ruby-build/RUBY_BUILD_version.txt"
 | 
			
		||||
 | 
			
		||||
  # Persist rbenv init to user's profile
 | 
			
		||||
  if ! grep -q 'rbenv init' "$PROFILE_FILE"; then
 | 
			
		||||
    echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >>"$PROFILE_FILE"
 | 
			
		||||
    echo 'eval "$(rbenv init -)"' >>"$PROFILE_FILE"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Activate rbenv in current shell
 | 
			
		||||
  export PATH="$RBENV_DIR/bin:$PATH"
 | 
			
		||||
  eval "$("$RBENV_BIN" init - bash)"
 | 
			
		||||
 | 
			
		||||
  # Install Ruby version if not already present
 | 
			
		||||
  if "$RBENV_BIN" versions --bare | grep -qx "$RUBY_VERSION"; then
 | 
			
		||||
    msg_ok "Ruby $RUBY_VERSION already installed"
 | 
			
		||||
  else
 | 
			
		||||
    $STD msg_info "Installing Ruby $RUBY_VERSION"
 | 
			
		||||
    $STD "$RBENV_BIN" install "$RUBY_VERSION"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Set Ruby version globally
 | 
			
		||||
  "$RBENV_BIN" global "$RUBY_VERSION"
 | 
			
		||||
  hash -r
 | 
			
		||||
 | 
			
		||||
  # Optionally install Rails via gem
 | 
			
		||||
  if [[ "$RUBY_INSTALL_RAILS" == "true" ]]; then
 | 
			
		||||
    $STD msg_info "Installing latest Rails via gem"
 | 
			
		||||
    gem install rails
 | 
			
		||||
    msg_ok "Rails $(rails -v) installed"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  rm -rf "$TMP_DIR"
 | 
			
		||||
  msg_ok "rbenv stack ready (Ruby $RUBY_VERSION)"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user