mirror of
				https://github.com/community-scripts/ProxmoxVE.git
				synced 2025-11-04 02:12:49 +00:00 
			
		
		
		
	Compare commits
	
		
			58 Commits
		
	
	
		
			2025-06-18
			...
			2025-06-20
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a8deff54d8 | ||
| 
						 | 
					e33cf652a1 | ||
| 
						 | 
					b35eadfc36 | ||
| 
						 | 
					74a073e8bd | ||
| 
						 | 
					ce9c1e63a8 | ||
| 
						 | 
					25f6245d31 | ||
| 
						 | 
					074d6fa31b | ||
| 
						 | 
					8dfacb9e7d | ||
| 
						 | 
					12a6055ea3 | ||
| 
						 | 
					637f9a1f44 | ||
| 
						 | 
					a7ed02160b | ||
| 
						 | 
					03551e23e4 | ||
| 
						 | 
					1f7d85ac60 | ||
| 
						 | 
					4e46fd739d | ||
| 
						 | 
					ea5eca83fe | ||
| 
						 | 
					b49b902d64 | ||
| 
						 | 
					f81f7fb1c0 | ||
| 
						 | 
					bcdeeaafb3 | ||
| 
						 | 
					92f631b628 | ||
| 
						 | 
					9133782289 | ||
| 
						 | 
					e343c7b5aa | ||
| 
						 | 
					3e47e39633 | ||
| 
						 | 
					43a90bf9e6 | ||
| 
						 | 
					cd45ccfb70 | ||
| 
						 | 
					b52cba817f | ||
| 
						 | 
					ac203f4e79 | ||
| 
						 | 
					b019991ee6 | ||
| 
						 | 
					6bc17a0031 | ||
| 
						 | 
					69d9394840 | ||
| 
						 | 
					ad8462bc10 | ||
| 
						 | 
					39b18ea011 | ||
| 
						 | 
					76c99518b1 | ||
| 
						 | 
					8fb0a16568 | ||
| 
						 | 
					9bbc0c90e3 | ||
| 
						 | 
					b5012c4225 | ||
| 
						 | 
					204ec64f14 | ||
| 
						 | 
					451608b445 | ||
| 
						 | 
					94ad4f2e40 | ||
| 
						 | 
					5db3d92286 | ||
| 
						 | 
					796aaaa1d4 | ||
| 
						 | 
					5042f6edb0 | ||
| 
						 | 
					0c1fad54b6 | ||
| 
						 | 
					fe1df0b344 | ||
| 
						 | 
					3ca014b757 | ||
| 
						 | 
					db7a13fced | ||
| 
						 | 
					ab1f4c1196 | ||
| 
						 | 
					14ffff4c6a | ||
| 
						 | 
					bada204f64 | ||
| 
						 | 
					1c42a2016e | ||
| 
						 | 
					0cd347d3b6 | ||
| 
						 | 
					63713c6489 | ||
| 
						 | 
					49153887dc | ||
| 
						 | 
					c46d543c43 | ||
| 
						 | 
					dbd2af91b5 | ||
| 
						 | 
					86183c638d | ||
| 
						 | 
					aec9af49a0 | ||
| 
						 | 
					791eca99b9 | ||
| 
						 | 
					4190582659 | 
							
								
								
									
										
											BIN
										
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										4
									
								
								.github/CONTRIBUTOR_AND_GUIDES/CODE-AUDIT.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/CONTRIBUTOR_AND_GUIDES/CODE-AUDIT.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -5,10 +5,10 @@
 | 
			
		||||
 | 
			
		||||
1) [adguard.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/adguard.sh): This script collects system parameters. (Also holds the function to update the application.)
 | 
			
		||||
2) [build.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/build.func): Adds user settings and integrates collected information.
 | 
			
		||||
3) [create_lxc.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/create_lxc.sh): Constructs the LXC container.
 | 
			
		||||
3) [create_lxc.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/create_lxc.sh): Constructs the LXC container.
 | 
			
		||||
4) [adguard-install.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/install/adguard-install.sh): Executes functions from [install.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/install.func), and installs the application.
 | 
			
		||||
5) [adguard.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/adguard.sh) (again): To display the completion message.
 | 
			
		||||
 | 
			
		||||
The installation process uses reusable scripts: [build.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/build.func), [create_lxc.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/create_lxc.sh), and [install.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/install.func), which are not specific to any particular application.
 | 
			
		||||
The installation process uses reusable scripts: [build.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/build.func), [create_lxc.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/create_lxc.sh), and [install.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/install.func), which are not specific to any particular application.
 | 
			
		||||
 | 
			
		||||
To gain a better understanding, focus on reviewing [adguard-install.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/install/adguard-install.sh). This script contains the commands and configurations for installing and configuring AdGuard Home within the LXC container.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										61
									
								
								.github/autolabeler-config.json
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										61
									
								
								.github/autolabeler-config.json
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,21 +2,43 @@
 | 
			
		||||
  "new script": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": "added",
 | 
			
		||||
      "includeGlobs": ["ct/**", "install/**", "misc/**", "turnkey/**", "vm/**"],
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        "ct/**",
 | 
			
		||||
        "install/**",
 | 
			
		||||
        "misc/**",
 | 
			
		||||
        "turnkey/**",
 | 
			
		||||
        "vm/**"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "update script": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": "modified",
 | 
			
		||||
      "includeGlobs": ["ct/**", "install/**", "misc/**", "turnkey/**", "vm/**"],
 | 
			
		||||
      "excludeGlobs": ["misc/build.func", "misc/install.func", "misc/api.func"]
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        "ct/**",
 | 
			
		||||
        "install/**",
 | 
			
		||||
        "misc/**",
 | 
			
		||||
        "turnkey/**",
 | 
			
		||||
        "vm/**"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": [
 | 
			
		||||
        "misc/build.func",
 | 
			
		||||
        "misc/install.func",
 | 
			
		||||
        "misc/api.func"
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "delete script": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": "removed",
 | 
			
		||||
      "includeGlobs": ["ct/**", "install/**", "misc/**", "turnkey/**", "vm/**"],
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        "ct/**",
 | 
			
		||||
        "install/**",
 | 
			
		||||
        "misc/**",
 | 
			
		||||
        "turnkey/**",
 | 
			
		||||
        "vm/**"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
@@ -27,7 +49,7 @@
 | 
			
		||||
        "*.md",
 | 
			
		||||
        ".github/**",
 | 
			
		||||
        "misc/*.func",
 | 
			
		||||
        "ct/create_lxc.sh",
 | 
			
		||||
        "misc/create_lxc.sh",
 | 
			
		||||
        "api/**"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
@@ -36,46 +58,57 @@
 | 
			
		||||
  "core": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": null,
 | 
			
		||||
      "includeGlobs": ["misc/*.func", "ct/create_lxc.sh"],
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        "misc/*.func",
 | 
			
		||||
        "misc/create_lxc.sh"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "website": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": null,
 | 
			
		||||
      "includeGlobs": ["frontend/**"],
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        "frontend/**"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "api": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": null,
 | 
			
		||||
      "includeGlobs": ["api/**", "misc/api.func"],
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        "api/**",
 | 
			
		||||
        "misc/api.func"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "github": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": null,
 | 
			
		||||
      "includeGlobs": [".github/**"],
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        ".github/**"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "json": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": "modified",
 | 
			
		||||
      "includeGlobs": ["frontend/public/json/**"],
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        "frontend/public/json/**"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
 | 
			
		||||
  "high risk": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": null,
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        "misc/build.func",
 | 
			
		||||
        "misc/install.func",
 | 
			
		||||
        "ct/create_lxc.sh"
 | 
			
		||||
        "misc/create_lxc.sh"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
    }
 | 
			
		||||
@@ -83,7 +116,9 @@
 | 
			
		||||
  "documentation": [
 | 
			
		||||
    {
 | 
			
		||||
      "fileStatus": null,
 | 
			
		||||
      "includeGlobs": ["*.md"],
 | 
			
		||||
      "includeGlobs": [
 | 
			
		||||
        "*.md"
 | 
			
		||||
      ],
 | 
			
		||||
      "excludeGlobs": []
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								.github/workflows/validate-filenames.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/validate-filenames.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -51,8 +51,8 @@ jobs:
 | 
			
		||||
 | 
			
		||||
          NON_COMPLIANT_FILES=""
 | 
			
		||||
          for FILE in $CHANGED_FILES; do
 | 
			
		||||
            # Datei "ct/create_lxc.sh" explizit überspringen
 | 
			
		||||
            if [[ "$FILE" == "ct/create_lxc.sh" ]]; then
 | 
			
		||||
            # Skip File "misc/create_lxc.sh"
 | 
			
		||||
            if [[ "$FILE" == "misc/create_lxc.sh" ]]; then
 | 
			
		||||
              continue
 | 
			
		||||
            fi
 | 
			
		||||
            BASENAME=$(echo "$(basename "${FILE%.*}")")
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -14,8 +14,65 @@ 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-06-21
 | 
			
		||||
 | 
			
		||||
## 2025-06-20
 | 
			
		||||
 | 
			
		||||
### 🚀 Updated Scripts
 | 
			
		||||
 | 
			
		||||
  - #### 🐞 Bug Fixes
 | 
			
		||||
 | 
			
		||||
    - Immich: remove unneeded tmp_file [@MickLesk](https://github.com/MickLesk) ([#5332](https://github.com/community-scripts/ProxmoxVE/pull/5332))
 | 
			
		||||
    - Huntarr: Fix duplicate update status messages [@tremor021](https://github.com/tremor021) ([#5336](https://github.com/community-scripts/ProxmoxVE/pull/5336))
 | 
			
		||||
    - fix planka Tags [@CrazyWolf13](https://github.com/CrazyWolf13) ([#5311](https://github.com/community-scripts/ProxmoxVE/pull/5311))
 | 
			
		||||
    - PLANKA: Better DB password generate [@tremor021](https://github.com/tremor021) ([#5313](https://github.com/community-scripts/ProxmoxVE/pull/5313))
 | 
			
		||||
    - Immich: Hotfix for #5299 [@vhsdream](https://github.com/vhsdream) ([#5300](https://github.com/community-scripts/ProxmoxVE/pull/5300))
 | 
			
		||||
    - changedetection: add msedge as Browser dependency [@Niklas04](https://github.com/Niklas04) ([#5301](https://github.com/community-scripts/ProxmoxVE/pull/5301))
 | 
			
		||||
 | 
			
		||||
  - #### ✨ New Features
 | 
			
		||||
 | 
			
		||||
    - (turnkey) Add OpenLDAP as a TurnKey option [@mhaligowski](https://github.com/mhaligowski) ([#5305](https://github.com/community-scripts/ProxmoxVE/pull/5305))
 | 
			
		||||
 | 
			
		||||
  - #### 🔧 Refactor
 | 
			
		||||
 | 
			
		||||
    - [core]: unify misc/*.func scripts with centralized logic from core.func [@MickLesk](https://github.com/MickLesk) ([#5316](https://github.com/community-scripts/ProxmoxVE/pull/5316))
 | 
			
		||||
    - Refactor: migrate AdventureLog update to uv and GitHub release logic [@MickLesk](https://github.com/MickLesk) ([#5318](https://github.com/community-scripts/ProxmoxVE/pull/5318))
 | 
			
		||||
    - Refactor: migrate Jupyter Notebook to uv-based installation with update support [@MickLesk](https://github.com/MickLesk) ([#5320](https://github.com/community-scripts/ProxmoxVE/pull/5320))
 | 
			
		||||
 | 
			
		||||
### 🌐 Website
 | 
			
		||||
 | 
			
		||||
  - #### 📝 Script Information
 | 
			
		||||
 | 
			
		||||
    - Argus: fix wrong port on website [@MickLesk](https://github.com/MickLesk) ([#5322](https://github.com/community-scripts/ProxmoxVE/pull/5322))
 | 
			
		||||
 | 
			
		||||
## 2025-06-19
 | 
			
		||||
 | 
			
		||||
### 🆕 New Scripts
 | 
			
		||||
 | 
			
		||||
  - Ubuntu 25.04 VM [@MickLesk](https://github.com/MickLesk) ([#5284](https://github.com/community-scripts/ProxmoxVE/pull/5284))
 | 
			
		||||
- PLANKA ([#5277](https://github.com/community-scripts/ProxmoxVE/pull/5277))
 | 
			
		||||
- Wizarr ([#5273](https://github.com/community-scripts/ProxmoxVE/pull/5273))
 | 
			
		||||
 | 
			
		||||
### 🚀 Updated Scripts
 | 
			
		||||
 | 
			
		||||
  - #### 🐞 Bug Fixes
 | 
			
		||||
 | 
			
		||||
    - immich-install.sh: restore pgvector module install [@vhsdream](https://github.com/vhsdream) ([#5286](https://github.com/community-scripts/ProxmoxVE/pull/5286))
 | 
			
		||||
    - Immich: prepare for v1.135.0 [@vhsdream](https://github.com/vhsdream) ([#5025](https://github.com/community-scripts/ProxmoxVE/pull/5025))
 | 
			
		||||
 | 
			
		||||
### 🧰 Maintenance
 | 
			
		||||
 | 
			
		||||
  - #### ✨ New Features
 | 
			
		||||
 | 
			
		||||
    - [core]: Feature - Check Quorum Status in create_lxc to prevent issues [@MickLesk](https://github.com/MickLesk) ([#5278](https://github.com/community-scripts/ProxmoxVE/pull/5278))
 | 
			
		||||
    - [core]: add validation and replace recursion for invalid inputs in adv. settings [@MickLesk](https://github.com/MickLesk) ([#5291](https://github.com/community-scripts/ProxmoxVE/pull/5291))
 | 
			
		||||
 | 
			
		||||
### 🌐 Website
 | 
			
		||||
 | 
			
		||||
  - #### 📝 Script Information
 | 
			
		||||
 | 
			
		||||
    - cloudflare-ddns: fix typo in info-text [@LukaZagar](https://github.com/LukaZagar) ([#5263](https://github.com/community-scripts/ProxmoxVE/pull/5263))
 | 
			
		||||
 | 
			
		||||
## 2025-06-18
 | 
			
		||||
 | 
			
		||||
### 🆕 New Scripts
 | 
			
		||||
 
 | 
			
		||||
@@ -27,43 +27,51 @@ function update_script() {
 | 
			
		||||
    msg_error "No ${APP} Installation Found!"
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  RELEASE=$(curl -fsSL https://api.github.com/repos/seanmorley15/AdventureLog/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
 | 
			
		||||
  if [[ "${RELEASE}" != "$(cat ~/.adventurelog 2>/dev/null)" ]] || [[ ! -f ~/.adventurelog ]]; then
 | 
			
		||||
    msg_info "Stopping Services"
 | 
			
		||||
    systemctl stop adventurelog-backend
 | 
			
		||||
    systemctl stop adventurelog-frontend
 | 
			
		||||
    msg_ok "Services Stopped"
 | 
			
		||||
 | 
			
		||||
    msg_info "Updating ${APP} to ${RELEASE}"
 | 
			
		||||
    mv /opt/adventurelog/ /opt/adventurelog-backup/
 | 
			
		||||
    curl -fsSL -o /opt/v${RELEASE}.zip "https://github.com/seanmorley15/AdventureLog/archive/refs/tags/v${RELEASE}.zip"
 | 
			
		||||
    $STD unzip /opt/v${RELEASE}.zip -d /opt/
 | 
			
		||||
    mv /opt/AdventureLog-${RELEASE} /opt/adventurelog
 | 
			
		||||
    fetch_and_deploy_gh_release "adventurelog" "seanmorley15/adventurelog"
 | 
			
		||||
    PYTHON_VERSION="3.12" setup_uv
 | 
			
		||||
 | 
			
		||||
    msg_info "Updating ${APP} to v${RELEASE}"
 | 
			
		||||
    # Backend Migration
 | 
			
		||||
    cp /opt/adventurelog-backup/backend/server/.env /opt/adventurelog/backend/server/.env
 | 
			
		||||
    cp -r /opt/adventurelog-backup/backend/server/media /opt/adventurelog/backend/server/media
 | 
			
		||||
 | 
			
		||||
    mv /opt/adventurelog-backup/backend/server/.env /opt/adventurelog/backend/server/.env
 | 
			
		||||
    mv /opt/adventurelog-backup/backend/server/media /opt/adventurelog/backend/server/media
 | 
			
		||||
    cd /opt/adventurelog/backend/server
 | 
			
		||||
    $STD pip install --upgrade pip
 | 
			
		||||
    $STD pip install -r requirements.txt
 | 
			
		||||
    $STD python3 manage.py collectstatic --noinput
 | 
			
		||||
    $STD python3 manage.py migrate
 | 
			
		||||
    if [[ ! -x .venv/bin/python ]]; then
 | 
			
		||||
      $STD uv venv .venv
 | 
			
		||||
      $STD .venv/bin/python -m ensurepip --upgrade
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    mv /opt/adventurelog-backup/frontend/.env /opt/adventurelog/frontend/.env
 | 
			
		||||
    $STD .venv/bin/python -m pip install --upgrade pip
 | 
			
		||||
    $STD .venv/bin/python -m pip install -r requirements.txt
 | 
			
		||||
    $STD .venv/bin/python -m manage collectstatic --noinput
 | 
			
		||||
    $STD .venv/bin/python -m manage migrate
 | 
			
		||||
 | 
			
		||||
    # Frontend Migration
 | 
			
		||||
    cp /opt/adventurelog-backup/frontend/.env /opt/adventurelog/frontend/.env
 | 
			
		||||
    cd /opt/adventurelog/frontend
 | 
			
		||||
    $STD pnpm install
 | 
			
		||||
    $STD pnpm run build
 | 
			
		||||
    echo "${RELEASE}" >/opt/${APP}_version.txt
 | 
			
		||||
    $STD pnpm i
 | 
			
		||||
    $STD pnpm build
 | 
			
		||||
    msg_ok "Updated ${APP}"
 | 
			
		||||
 | 
			
		||||
    msg_info "Starting Services"
 | 
			
		||||
    systemctl daemon-reexec
 | 
			
		||||
    systemctl start adventurelog-backend
 | 
			
		||||
    systemctl start adventurelog-frontend
 | 
			
		||||
    msg_ok "Started Services"
 | 
			
		||||
    msg_ok "Services Started"
 | 
			
		||||
 | 
			
		||||
    msg_info "Cleaning Up"
 | 
			
		||||
    rm -rf /opt/v${RELEASE}.zip
 | 
			
		||||
    rm -rf /opt/adventurelog-backup
 | 
			
		||||
    msg_ok "Cleaned"
 | 
			
		||||
 | 
			
		||||
    msg_ok "Updated Successfully"
 | 
			
		||||
  else
 | 
			
		||||
    msg_ok "No update required. ${APP} is already at ${RELEASE}"
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ function update_script() {
 | 
			
		||||
    $STD /opt/browserless/node_modules/playwright-core/cli.js install --with-deps
 | 
			
		||||
    # Update Chrome separately, as it has to be done with the force option. Otherwise the installation of other browsers will not be done if Chrome is already installed.
 | 
			
		||||
    $STD /opt/browserless/node_modules/playwright-core/cli.js install --force chrome
 | 
			
		||||
    $STD /opt/browserless/node_modules/playwright-core/cli.js install chromium firefox webkit
 | 
			
		||||
    $STD /opt/browserless/node_modules/playwright-core/cli.js install chromium firefox webkit msedge
 | 
			
		||||
    $STD npm run build --prefix /opt/browserless
 | 
			
		||||
    $STD npm run build:function --prefix /opt/browserless
 | 
			
		||||
    $STD npm prune production --prefix /opt/browserless
 | 
			
		||||
@@ -74,4 +74,4 @@ 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}:5000${CL}"
 | 
			
		||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:5000${CL}"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										282
									
								
								ct/create_lxc.sh
									
									
									
									
									
								
							
							
						
						
									
										282
									
								
								ct/create_lxc.sh
									
									
									
									
									
								
							@@ -1,282 +0,0 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2021-2025 tteck
 | 
			
		||||
# Author: tteck (tteckster)
 | 
			
		||||
# Co-Author: MickLesk
 | 
			
		||||
# License: MIT
 | 
			
		||||
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
 | 
			
		||||
# This sets verbose mode if the global variable is set to "yes"
 | 
			
		||||
# if [ "$VERBOSE" == "yes" ]; then set -x; fi
 | 
			
		||||
 | 
			
		||||
# This function sets color variables for formatting output in the terminal
 | 
			
		||||
# Colors
 | 
			
		||||
YW=$(echo "\033[33m")
 | 
			
		||||
YWB=$(echo "\033[93m")
 | 
			
		||||
BL=$(echo "\033[36m")
 | 
			
		||||
RD=$(echo "\033[01;31m")
 | 
			
		||||
GN=$(echo "\033[1;92m")
 | 
			
		||||
 | 
			
		||||
# Formatting
 | 
			
		||||
CL=$(echo "\033[m")
 | 
			
		||||
UL=$(echo "\033[4m")
 | 
			
		||||
BOLD=$(echo "\033[1m")
 | 
			
		||||
BFR="\\r\\033[K"
 | 
			
		||||
HOLD=" "
 | 
			
		||||
TAB="  "
 | 
			
		||||
 | 
			
		||||
# Icons
 | 
			
		||||
CM="${TAB}✔️${TAB}${CL}"
 | 
			
		||||
CROSS="${TAB}✖️${TAB}${CL}"
 | 
			
		||||
INFO="${TAB}💡${TAB}${CL}"
 | 
			
		||||
 | 
			
		||||
# This sets error handling options and defines the error_handler function to handle errors
 | 
			
		||||
set -Eeuo pipefail
 | 
			
		||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
 | 
			
		||||
 | 
			
		||||
# This function handles errors
 | 
			
		||||
function error_handler() {
 | 
			
		||||
  if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
 | 
			
		||||
  printf "\e[?25h"
 | 
			
		||||
  local exit_code="$?"
 | 
			
		||||
  local line_number="$1"
 | 
			
		||||
  local command="$2"
 | 
			
		||||
  local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
 | 
			
		||||
  echo -e "\n$error_message\n"
 | 
			
		||||
  exit 200
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays a spinner.
 | 
			
		||||
function spinner() {
 | 
			
		||||
  local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
 | 
			
		||||
  local spin_i=0
 | 
			
		||||
  local interval=0.1
 | 
			
		||||
  printf "\e[?25l"
 | 
			
		||||
 | 
			
		||||
  local color="${YWB}"
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    printf "\r ${color}%s${CL}" "${frames[spin_i]}"
 | 
			
		||||
    spin_i=$(((spin_i + 1) % ${#frames[@]}))
 | 
			
		||||
    sleep "$interval"
 | 
			
		||||
  done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays an informational message with a yellow color.
 | 
			
		||||
function msg_info() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
 | 
			
		||||
  spinner &
 | 
			
		||||
  SPINNER_PID=$!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function msg_warn() {
 | 
			
		||||
  if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
 | 
			
		||||
  printf "\e[?25h"
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -e "${BFR}${INFO}${YWB}${msg}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays a success message with a green color.
 | 
			
		||||
function msg_ok() {
 | 
			
		||||
  if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
 | 
			
		||||
  printf "\e[?25h"
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -e "${BFR}${CM}${GN}${msg}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays a error message with a red color.
 | 
			
		||||
function msg_error() {
 | 
			
		||||
  if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
 | 
			
		||||
  printf "\e[?25h"
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This checks for the presence of valid Container Storage and Template Storage locations
 | 
			
		||||
msg_info "Validating Storage"
 | 
			
		||||
VALIDCT=$(pvesm status -content rootdir | awk 'NR>1')
 | 
			
		||||
if [ -z "$VALIDCT" ]; then
 | 
			
		||||
  msg_error "Unable to detect a valid Container Storage location."
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
VALIDTMP=$(pvesm status -content vztmpl | awk 'NR>1')
 | 
			
		||||
if [ -z "$VALIDTMP" ]; then
 | 
			
		||||
  msg_error "Unable to detect a valid Template Storage location."
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# This function is used to select the storage class and determine the corresponding storage content type and label.
 | 
			
		||||
function select_storage() {
 | 
			
		||||
  local CLASS=$1
 | 
			
		||||
  local CONTENT
 | 
			
		||||
  local CONTENT_LABEL
 | 
			
		||||
  case $CLASS in
 | 
			
		||||
  container)
 | 
			
		||||
    CONTENT='rootdir'
 | 
			
		||||
    CONTENT_LABEL='Container'
 | 
			
		||||
    ;;
 | 
			
		||||
  template)
 | 
			
		||||
    CONTENT='vztmpl'
 | 
			
		||||
    CONTENT_LABEL='Container template'
 | 
			
		||||
    ;;
 | 
			
		||||
  *) false || {
 | 
			
		||||
    msg_error "Invalid storage class."
 | 
			
		||||
    exit 201
 | 
			
		||||
  } ;;
 | 
			
		||||
  esac
 | 
			
		||||
 | 
			
		||||
  # This Queries all storage locations
 | 
			
		||||
  local -a MENU
 | 
			
		||||
  while read -r line; do
 | 
			
		||||
    local TAG=$(echo $line | awk '{print $1}')
 | 
			
		||||
    local TYPE=$(echo $line | awk '{printf "%-10s", $2}')
 | 
			
		||||
    local FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
 | 
			
		||||
    local ITEM="Type: $TYPE Free: $FREE "
 | 
			
		||||
    local OFFSET=2
 | 
			
		||||
    if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
 | 
			
		||||
      local MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
 | 
			
		||||
    fi
 | 
			
		||||
    MENU+=("$TAG" "$ITEM" "OFF")
 | 
			
		||||
  done < <(pvesm status -content $CONTENT | awk 'NR>1')
 | 
			
		||||
 | 
			
		||||
  # Select storage location
 | 
			
		||||
  if [ $((${#MENU[@]} / 3)) -eq 1 ]; then
 | 
			
		||||
    printf ${MENU[0]}
 | 
			
		||||
  else
 | 
			
		||||
    local STORAGE
 | 
			
		||||
    while [ -z "${STORAGE:+x}" ]; do
 | 
			
		||||
      STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
 | 
			
		||||
        "Which storage pool would you like to use for the ${CONTENT_LABEL,,}?\nTo make a selection, use the Spacebar.\n" \
 | 
			
		||||
        16 $(($MSG_MAX_LENGTH + 23)) 6 \
 | 
			
		||||
        "${MENU[@]}" 3>&1 1>&2 2>&3) || {
 | 
			
		||||
        msg_error "Menu aborted."
 | 
			
		||||
        exit 202
 | 
			
		||||
      }
 | 
			
		||||
      if [ $? -ne 0 ]; then
 | 
			
		||||
        echo -e "${CROSS}${RD} Menu aborted by user.${CL}"
 | 
			
		||||
        exit 0
 | 
			
		||||
      fi
 | 
			
		||||
    done
 | 
			
		||||
    printf "%s" "$STORAGE"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
# Test if required variables are set
 | 
			
		||||
[[ "${CTID:-}" ]] || {
 | 
			
		||||
  msg_error "You need to set 'CTID' variable."
 | 
			
		||||
  exit 203
 | 
			
		||||
}
 | 
			
		||||
[[ "${PCT_OSTYPE:-}" ]] || {
 | 
			
		||||
  msg_error "You need to set 'PCT_OSTYPE' variable."
 | 
			
		||||
  exit 204
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Test if ID is valid
 | 
			
		||||
[ "$CTID" -ge "100" ] || {
 | 
			
		||||
  msg_error "ID cannot be less than 100."
 | 
			
		||||
  exit 205
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Check for network connectivity (IPv4 & IPv6)
 | 
			
		||||
#function check_network() {
 | 
			
		||||
#  local CHECK_URLS=("8.8.8.8" "1.1.1.1" "9.9.9.9" "2606:4700:4700::1111" "2001:4860:4860::8888" "2620:fe::fe")
 | 
			
		||||
#
 | 
			
		||||
#  for url in "${CHECK_URLS[@]}"; do
 | 
			
		||||
#    if ping -c 1 -W 2 "$url" &>/dev/null; then
 | 
			
		||||
#      return 0 # Success: At least one connection works
 | 
			
		||||
#    fi
 | 
			
		||||
#  done
 | 
			
		||||
#
 | 
			
		||||
#  msg_error "No network connection detected. Check your internet connection."
 | 
			
		||||
#  exit 101
 | 
			
		||||
#}
 | 
			
		||||
 | 
			
		||||
# Test if ID is in use
 | 
			
		||||
if qm status "$CTID" &>/dev/null || pct status "$CTID" &>/dev/null; then
 | 
			
		||||
  echo -e "ID '$CTID' is already in use."
 | 
			
		||||
  unset CTID
 | 
			
		||||
  msg_error "Cannot use ID that is already in use."
 | 
			
		||||
  exit 206
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Get template storage
 | 
			
		||||
TEMPLATE_STORAGE=$(select_storage template)
 | 
			
		||||
msg_ok "Using ${BL}$TEMPLATE_STORAGE${CL} ${GN}for Template Storage."
 | 
			
		||||
 | 
			
		||||
# Get container storage
 | 
			
		||||
CONTAINER_STORAGE=$(select_storage container)
 | 
			
		||||
msg_ok "Using ${BL}$CONTAINER_STORAGE${CL} ${GN}for Container Storage."
 | 
			
		||||
 | 
			
		||||
# Update LXC template list
 | 
			
		||||
msg_info "Updating LXC Template List"
 | 
			
		||||
#check_network
 | 
			
		||||
pveam update >/dev/null
 | 
			
		||||
msg_ok "Updated LXC Template List"
 | 
			
		||||
 | 
			
		||||
# Get LXC template string
 | 
			
		||||
TEMPLATE_SEARCH=${PCT_OSTYPE}-${PCT_OSVERSION:-}
 | 
			
		||||
mapfile -t TEMPLATES < <(pveam available -section system | sed -n "s/.*\($TEMPLATE_SEARCH.*\)/\1/p" | sort -t - -k 2 -V)
 | 
			
		||||
[ ${#TEMPLATES[@]} -gt 0 ] || {
 | 
			
		||||
  msg_error "Unable to find a template when searching for '$TEMPLATE_SEARCH'."
 | 
			
		||||
  exit 207
 | 
			
		||||
}
 | 
			
		||||
TEMPLATE="${TEMPLATES[-1]}"
 | 
			
		||||
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE)"
 | 
			
		||||
# Without NAS/Mount: TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
 | 
			
		||||
# Check if template exists, if corrupt remove and redownload
 | 
			
		||||
if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE" || ! zstdcat "$TEMPLATE_PATH" | tar -tf - >/dev/null 2>&1; then
 | 
			
		||||
  msg_warn "Template $TEMPLATE not found in storage or seems to be corrupted. Redownloading."
 | 
			
		||||
  [[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
 | 
			
		||||
 | 
			
		||||
  # Download with 3 attempts
 | 
			
		||||
  for attempt in {1..3}; do
 | 
			
		||||
    msg_info "Attempt $attempt: Downloading LXC template..."
 | 
			
		||||
 | 
			
		||||
    if timeout 120 pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null; then
 | 
			
		||||
      msg_ok "Template download successful."
 | 
			
		||||
      break
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ $attempt -eq 3 ]; then
 | 
			
		||||
      msg_error "Three failed attempts. Aborting."
 | 
			
		||||
      exit 208
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    sleep $((attempt * 5))
 | 
			
		||||
  done
 | 
			
		||||
fi
 | 
			
		||||
msg_ok "LXC Template is ready to use."
 | 
			
		||||
 | 
			
		||||
# Check and fix subuid/subgid
 | 
			
		||||
grep -q "root:100000:65536" /etc/subuid || echo "root:100000:65536" >>/etc/subuid
 | 
			
		||||
grep -q "root:100000:65536" /etc/subgid || echo "root:100000:65536" >>/etc/subgid
 | 
			
		||||
 | 
			
		||||
# Combine all options
 | 
			
		||||
PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}})
 | 
			
		||||
[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "$CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}")
 | 
			
		||||
 | 
			
		||||
msg_info "Creating LXC Container"
 | 
			
		||||
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
 | 
			
		||||
  msg_error "Container creation failed. Checking if template is corrupted."
 | 
			
		||||
 | 
			
		||||
  if ! zstdcat "$TEMPLATE_PATH" | tar -tf - >/dev/null 2>&1; then
 | 
			
		||||
    msg_error "Template appears to be corrupted. Removing and re-downloading."
 | 
			
		||||
    rm -f "$TEMPLATE_PATH"
 | 
			
		||||
 | 
			
		||||
    if ! timeout 120 pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null; then
 | 
			
		||||
      msg_error "Failed to re-download template."
 | 
			
		||||
      exit 208
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    msg_ok "Re-downloaded LXC Template"
 | 
			
		||||
 | 
			
		||||
    if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
 | 
			
		||||
      msg_error "Container creation failed after re-downloading template."
 | 
			
		||||
      exit 200
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    msg_error "Container creation failed, but template is not corrupted."
 | 
			
		||||
    exit 209
 | 
			
		||||
  fi
 | 
			
		||||
fi
 | 
			
		||||
msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created."
 | 
			
		||||
							
								
								
									
										6
									
								
								ct/headers/planka
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								ct/headers/planka
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
    ____  __    ___    _   ____ __ ___ 
 | 
			
		||||
   / __ \/ /   /   |  / | / / //_//   |
 | 
			
		||||
  / /_/ / /   / /| | /  |/ / ,<  / /| |
 | 
			
		||||
 / ____/ /___/ ___ |/ /|  / /| |/ ___ |
 | 
			
		||||
/_/   /_____/_/  |_/_/ |_/_/ |_/_/  |_|
 | 
			
		||||
                                       
 | 
			
		||||
							
								
								
									
										6
									
								
								ct/headers/wizarr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								ct/headers/wizarr
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
 _       ___                      
 | 
			
		||||
| |     / (_)___  ____ ___________
 | 
			
		||||
| | /| / / /_  / / __ `/ ___/ ___/
 | 
			
		||||
| |/ |/ / / / /_/ /_/ / /  / /    
 | 
			
		||||
|__/|__/_/ /___/\__,_/_/  /_/     
 | 
			
		||||
                                  
 | 
			
		||||
@@ -40,10 +40,10 @@ function update_script() {
 | 
			
		||||
  msg_ok "Stopped huntarr service"
 | 
			
		||||
 | 
			
		||||
  fetch_and_deploy_gh_release "huntarr" "plexguide/Huntarr.io"
 | 
			
		||||
  msg_info "Updating $APP to v${RELEASE}"
 | 
			
		||||
  msg_info "Configuring $APP"
 | 
			
		||||
  cd /opt/huntarr
 | 
			
		||||
  $STD uv pip install -r requirements.txt --python /opt/huntarr/.venv/bin/python
 | 
			
		||||
  msg_ok "Updated $APP to v${RELEASE}"
 | 
			
		||||
  msg_ok "Configured $APP"
 | 
			
		||||
 | 
			
		||||
  msg_info "Starting $APP"
 | 
			
		||||
  systemctl start huntarr
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										91
									
								
								ct/immich.sh
									
									
									
									
									
								
							
							
						
						
									
										91
									
								
								ct/immich.sh
									
									
									
									
									
								
							@@ -27,6 +27,9 @@ function update_script() {
 | 
			
		||||
    msg_error "No ${APP} Installation Found!"
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  setup_uv
 | 
			
		||||
 | 
			
		||||
  STAGING_DIR=/opt/staging
 | 
			
		||||
  BASE_DIR=${STAGING_DIR}/base-images
 | 
			
		||||
  SOURCE_DIR=${STAGING_DIR}/image-source
 | 
			
		||||
@@ -40,7 +43,7 @@ function update_script() {
 | 
			
		||||
      for url in "${INTEL_URLS[@]}"; do
 | 
			
		||||
        curl -fsSLO "$url"
 | 
			
		||||
      done
 | 
			
		||||
      $STD dpkg -i ./*.deb
 | 
			
		||||
      $STD apt install -y ./*.deb
 | 
			
		||||
      rm ./*.deb
 | 
			
		||||
      msg_ok "Intel iGPU dependencies updated"
 | 
			
		||||
    fi
 | 
			
		||||
@@ -177,54 +180,42 @@ function update_script() {
 | 
			
		||||
      msg_ok "Image-processing libraries compiled"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
  RELEASE=$(curl -s https://api.github.com/repos/immich-app/immich/releases?per_page=1 | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
  RELEASE=$(curl -fsSL https://api.github.com/repos/immich-app/immich/releases?per_page=1 | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
  if [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]] || [[ ! -f /opt/${APP}_version.txt ]]; then
 | 
			
		||||
    msg_info "Stopping ${APP} services"
 | 
			
		||||
    systemctl stop immich-web
 | 
			
		||||
    systemctl stop immich-ml
 | 
			
		||||
    msg_ok "Stopped ${APP}"
 | 
			
		||||
    if [[ "$(cat /opt/${APP}_version.txt)" < "1.133.0" ]]; then
 | 
			
		||||
      msg_info "Upgrading to the VectorChord PostgreSQL extension"
 | 
			
		||||
      NUMBER="$(
 | 
			
		||||
        sed -n '2p' <(
 | 
			
		||||
          sudo -u postgres psql -A -d immich <<EOF
 | 
			
		||||
        SELECT atttypmod as dimsize
 | 
			
		||||
          FROM pg_attribute f
 | 
			
		||||
          JOIN pg_class c ON c.oid = f.attrelid
 | 
			
		||||
          WHERE c.relkind = 'r'::char
 | 
			
		||||
          AND f.attnum > 0
 | 
			
		||||
          AND c.relname = 'smart_search'::text
 | 
			
		||||
          AND f.attname = 'embedding'::text;
 | 
			
		||||
EOF
 | 
			
		||||
        )
 | 
			
		||||
      )"
 | 
			
		||||
      $STD sudo -u postgres psql -d immich <<EOF
 | 
			
		||||
      DROP INDEX IF EXISTS clip_index;
 | 
			
		||||
      DROP INDEX IF EXISTS face_index;
 | 
			
		||||
      ALTER TABLE smart_search ALTER COLUMN embedding SET DATA TYPE real[];
 | 
			
		||||
      ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE real[];
 | 
			
		||||
EOF
 | 
			
		||||
      $STD apt-get update
 | 
			
		||||
      $STD apt-get install postgresql-16-pgvector -y
 | 
			
		||||
      curl -fsSL https://github.com/tensorchord/VectorChord/releases/download/0.3.0/postgresql-16-vchord_0.3.0-1_amd64.deb -o vchord.deb
 | 
			
		||||
      $STD dpkg -i vchord.deb
 | 
			
		||||
      rm vchord.deb
 | 
			
		||||
      sed -i "s|vectors.so|vchord.so|" /etc/postgresql/16/main/postgresql.conf
 | 
			
		||||
      systemctl restart postgresql.service
 | 
			
		||||
      $STD sudo -u postgres psql -d immich <<EOF
 | 
			
		||||
      CREATE EXTENSION IF NOT EXISTS vchord CASCADE;
 | 
			
		||||
      ALTER TABLE smart_search ALTER COLUMN embedding SET DATA TYPE vector($NUMBER);
 | 
			
		||||
      ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE vector(512);
 | 
			
		||||
EOF
 | 
			
		||||
      $STD apt purge vectors-pg16 -y
 | 
			
		||||
      msg_ok "Database upgrade complete"
 | 
			
		||||
    fi
 | 
			
		||||
    INSTALL_DIR="/opt/${APP}"
 | 
			
		||||
    UPLOAD_DIR="$(sed -n '/^IMMICH_MEDIA_LOCATION/s/[^=]*=//p' /opt/immich/.env)"
 | 
			
		||||
    SRC_DIR="${INSTALL_DIR}/source"
 | 
			
		||||
    APP_DIR="${INSTALL_DIR}/app"
 | 
			
		||||
    ML_DIR="${APP_DIR}/machine-learning"
 | 
			
		||||
    GEO_DIR="${INSTALL_DIR}/geodata"
 | 
			
		||||
    VCHORD_RELEASE="$(curl -fsSL https://api.github.com/repos/tensorchord/vectorchord/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')"
 | 
			
		||||
 | 
			
		||||
    if [[ ! -f ~/.vchord_version ]] || [[ "$VCHORD_RELEASE" != "$(cat ~/.vchord_version)" ]]; then
 | 
			
		||||
      msg_info "Updating VectorChord"
 | 
			
		||||
      if [[ ! -f ~/.vchord_version ]] || [[ ! "$(cat ~/.vchord_version)" > "0.3.0" ]]; then
 | 
			
		||||
        $STD sudo -u postgres pg_dumpall --clean --if-exists --username=postgres | gzip >/etc/postgresql/immich-db-vchord0.3.0.sql.gz
 | 
			
		||||
        chown postgres /etc/postgresql/immich-db-vchord0.3.0.sql.gz
 | 
			
		||||
        $STD sudo -u postgres gunzip --stdout /etc/postgresql/immich-db-vchord0.3.0.sql.gz |
 | 
			
		||||
          sed -e "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" \
 | 
			
		||||
            -e "/vchordrq.prewarm_dim/d" |
 | 
			
		||||
          sudo -u postgres psql
 | 
			
		||||
      fi
 | 
			
		||||
      curl -fsSL "https://github.com/tensorchord/vectorchord/releases/download/${VCHORD_RELEASE}/postgresql-16-vchord_${VCHORD_RELEASE}-1_amd64.deb" -o vchord.deb
 | 
			
		||||
      $STD apt install -y ./vchord.deb
 | 
			
		||||
      $STD sudo -u postgres psql -d immich -c "ALTER EXTENSION vchord UPDATE;"
 | 
			
		||||
      systemctl restart postgresql
 | 
			
		||||
      if [[ ! -f ~/.vchord_version ]] || [[ ! "$(cat ~/.vchord_version)" > "0.3.0" ]]; then
 | 
			
		||||
        $STD sudo -u postgres psql -d immich -c "REINDEX DATABASE;"
 | 
			
		||||
      fi
 | 
			
		||||
      echo "$VCHORD_RELEASE" >~/.vchord_version
 | 
			
		||||
      rm ./vchord.deb
 | 
			
		||||
      msg_ok "Updated VectorChord to v${VCHORD_RELEASE}"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    cp "$ML_DIR"/ml_start.sh "$INSTALL_DIR"
 | 
			
		||||
    rm -rf "${APP_DIR:?}"/*
 | 
			
		||||
    rm -rf "$SRC_DIR"
 | 
			
		||||
@@ -235,6 +226,9 @@ EOF
 | 
			
		||||
    mv "$APP-$RELEASE"/ "$SRC_DIR"
 | 
			
		||||
    mkdir -p "$ML_DIR"
 | 
			
		||||
    cd "$SRC_DIR"/server
 | 
			
		||||
    if [[ "$RELEASE" == "1.135.1" ]]; then
 | 
			
		||||
      rm ./src/schema/migrations/1750323941566-UnsetPrewarmDimParameter.ts
 | 
			
		||||
    fi
 | 
			
		||||
    $STD npm install -g node-gyp node-pre-gyp
 | 
			
		||||
    $STD npm ci
 | 
			
		||||
    $STD npm run build
 | 
			
		||||
@@ -252,28 +246,21 @@ EOF
 | 
			
		||||
    msg_ok "Updated ${APP} web and microservices"
 | 
			
		||||
 | 
			
		||||
    cd "$SRC_DIR"/machine-learning
 | 
			
		||||
    $STD python3 -m venv "$ML_DIR"/ml-venv
 | 
			
		||||
    export VIRTUAL_ENV="${ML_DIR}"/ml-venv
 | 
			
		||||
    $STD /usr/local/bin/uv venv "$VIRTUAL_ENV"
 | 
			
		||||
    if [[ -f ~/.openvino ]]; then
 | 
			
		||||
      msg_info "Updating HW-accelerated machine-learning"
 | 
			
		||||
      (
 | 
			
		||||
        source "$ML_DIR"/ml-venv/bin/activate
 | 
			
		||||
        $STD pip3 install -U uv
 | 
			
		||||
        uv -q sync --extra openvino --no-cache --active
 | 
			
		||||
      )
 | 
			
		||||
      patchelf --clear-execstack "$ML_DIR"/ml-venv/lib/python3.11/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-311-x86_64-linux-gnu.so
 | 
			
		||||
      /usr/local/bin/uv -q sync --extra openvino --no-cache --active
 | 
			
		||||
      patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.11/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-311-x86_64-linux-gnu.so"
 | 
			
		||||
      msg_ok "Updated HW-accelerated machine-learning"
 | 
			
		||||
    else
 | 
			
		||||
      msg_info "Updating machine-learning"
 | 
			
		||||
      (
 | 
			
		||||
        source "$ML_DIR"/ml-venv/bin/activate
 | 
			
		||||
        $STD pip3 install -U uv
 | 
			
		||||
        uv -q sync --extra cpu --no-cache --active
 | 
			
		||||
      )
 | 
			
		||||
      /usr/local/bin/uv -q sync --extra cpu --no-cache --active
 | 
			
		||||
      msg_ok "Updated machine-learning"
 | 
			
		||||
    fi
 | 
			
		||||
    cd "$SRC_DIR"
 | 
			
		||||
    cp -a machine-learning/{ann,immich_ml} "$ML_DIR"
 | 
			
		||||
    cp "$INSTALL_DIR"/ml_start.sh "$ML_DIR"
 | 
			
		||||
    mv "$INSTALL_DIR"/ml_start.sh "$ML_DIR"
 | 
			
		||||
    if [[ -f ~/.openvino ]]; then
 | 
			
		||||
      sed -i "/intra_op/s/int = 0/int = os.cpu_count() or 0/" "$ML_DIR"/immich_ml/config.py
 | 
			
		||||
    fi
 | 
			
		||||
@@ -292,8 +279,6 @@ EOF
 | 
			
		||||
    $STD npm i -g @immich/cli
 | 
			
		||||
    msg_ok "Updated Immich CLI"
 | 
			
		||||
 | 
			
		||||
    sed -i "s|pgvecto.rs|vectorchord|" /opt/"${APP}"/.env
 | 
			
		||||
 | 
			
		||||
    chown -R immich:immich "$INSTALL_DIR"
 | 
			
		||||
    echo "$RELEASE" >/opt/"${APP}"_version.txt
 | 
			
		||||
    msg_ok "Updated ${APP} to v${RELEASE}"
 | 
			
		||||
 
 | 
			
		||||
@@ -20,16 +20,53 @@ color
 | 
			
		||||
catch_errors
 | 
			
		||||
 | 
			
		||||
function update_script() {
 | 
			
		||||
    header_info
 | 
			
		||||
    check_container_storage
 | 
			
		||||
    check_container_resources
 | 
			
		||||
  header_info
 | 
			
		||||
  check_container_storage
 | 
			
		||||
  check_container_resources
 | 
			
		||||
 | 
			
		||||
    msg_info "Updating ${APP} LXC"
 | 
			
		||||
    $STD apt-get update
 | 
			
		||||
    $STD apt-get install -y upgrade
 | 
			
		||||
    $STD pip3 install jupyter --upgrade
 | 
			
		||||
    msg_ok "Updated Successfully"
 | 
			
		||||
    exit
 | 
			
		||||
  INSTALL_DIR="/opt/jupyter"
 | 
			
		||||
  VENV_PYTHON="${INSTALL_DIR}/.venv/bin/python"
 | 
			
		||||
  VENV_JUPYTER="${INSTALL_DIR}/.venv/bin/jupyter"
 | 
			
		||||
  SERVICE_FILE="/etc/systemd/system/jupyternotebook.service"
 | 
			
		||||
 | 
			
		||||
  if [[ ! -x "$VENV_JUPYTER" ]]; then
 | 
			
		||||
    msg_info "Migrating to uv venv"
 | 
			
		||||
    PYTHON_VERSION="3.12" setup_uv
 | 
			
		||||
    mkdir -p "$INSTALL_DIR"
 | 
			
		||||
    cd "$INSTALL_DIR"
 | 
			
		||||
    $STD uv venv .venv
 | 
			
		||||
    $STD "$VENV_PYTHON" -m ensurepip --upgrade
 | 
			
		||||
    $STD "$VENV_PYTHON" -m pip install --upgrade pip
 | 
			
		||||
    $STD "$VENV_PYTHON" -m pip install jupyter
 | 
			
		||||
    msg_ok "Migrated to uv and installed Jupyter"
 | 
			
		||||
  else
 | 
			
		||||
    msg_info "Updating Jupyter"
 | 
			
		||||
    $STD "$VENV_PYTHON" -m pip install --upgrade pip
 | 
			
		||||
    $STD "$VENV_PYTHON" -m pip install --upgrade jupyter
 | 
			
		||||
    msg_ok "Jupyter updated"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ -f "$SERVICE_FILE" && "$(grep ExecStart "$SERVICE_FILE")" != *".venv/bin/jupyter"* ]]; then
 | 
			
		||||
    msg_info "Updating systemd service to use .venv"
 | 
			
		||||
    cat <<EOF >"$SERVICE_FILE"
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=Jupyter Notebook Server
 | 
			
		||||
After=network.target
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
WorkingDirectory=${INSTALL_DIR}
 | 
			
		||||
ExecStart=${VENV_JUPYTER} notebook --ip=0.0.0.0 --port=8888 --allow-root
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=10
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
EOF
 | 
			
		||||
    systemctl daemon-reexec
 | 
			
		||||
    systemctl restart jupyternotebook
 | 
			
		||||
    msg_ok "Service updated and restarted"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  exit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
start
 | 
			
		||||
@@ -39,4 +76,4 @@ 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}:8888${CL}"
 | 
			
		||||
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8888${CL}"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										77
									
								
								ct/planka.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								ct/planka.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/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/plankanban/planka
 | 
			
		||||
 | 
			
		||||
APP="PLANKA"
 | 
			
		||||
var_tags="${var_tags:-Todo,kanban}"
 | 
			
		||||
var_cpu="${var_cpu:-1}"
 | 
			
		||||
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 [[ ! -f /etc/systemd/system/planka.service ]]; then
 | 
			
		||||
    msg_error "No ${APP} Installation Found!"
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
  RELEASE=$(curl -s https://api.github.com/repos/plankanban/planka/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
 | 
			
		||||
  if [[ "${RELEASE}" != "$(cat ~/.planka 2>/dev/null)" ]] || [[ ! -f ~/.planka ]]; then
 | 
			
		||||
    msg_info "Stopping $APP"
 | 
			
		||||
    systemctl stop planka
 | 
			
		||||
    msg_ok "Stopped $APP"
 | 
			
		||||
 | 
			
		||||
    msg_info "Updating $APP to ${RELEASE}"
 | 
			
		||||
    mkdir -p /opt/planka-backup
 | 
			
		||||
    mkdir -p /opt/planka-backup/favicons
 | 
			
		||||
    mkdir -p /opt/planka-backup/user-avatars
 | 
			
		||||
    mkdir -p /opt/planka-backup/background-images
 | 
			
		||||
    mkdir -p /opt/planka-backup/attachments
 | 
			
		||||
    mv /opt/planka/planka/.env /opt/planka-backup
 | 
			
		||||
    mv /opt/planka/planka/public/favicons/* /opt/planka-backup/favicons/
 | 
			
		||||
    mv /opt/planka/planka/public/user-avatars/* /opt/planka-backup/user-avatars/
 | 
			
		||||
    mv /opt/planka/planka/public/background-images/* /opt/planka-backup/background-images/
 | 
			
		||||
    mv /opt/planka/planka/private/attachments/* /opt/planka-backup/attachments/
 | 
			
		||||
    rm -rf /opt/planka
 | 
			
		||||
    fetch_and_deploy_gh_release "planka" "plankanban/planka" "prebuild" "latest" "/opt/planka" "planka-prebuild.zip"
 | 
			
		||||
    cd /opt/planka/planka
 | 
			
		||||
    $STD npm install
 | 
			
		||||
    mv /opt/planka-backup/.env /opt/planka/planka/
 | 
			
		||||
    mv /opt/planka-backup/favicons/* /opt/planka/planka/public/favicons/
 | 
			
		||||
    mv /opt/planka-backup/user-avatars/* /opt/planka/planka/public/user-avatars/
 | 
			
		||||
    mv /opt/planka-backup/background-images/* /opt/planka/planka/public/background-images/
 | 
			
		||||
    mv /opt/planka-backup/attachments/* /opt/planka/planka/private/attachments/
 | 
			
		||||
    msg_ok "Updated $APP to ${RELEASE}"
 | 
			
		||||
 | 
			
		||||
    msg_info "Starting $APP"
 | 
			
		||||
    systemctl start planka
 | 
			
		||||
    msg_ok "Started $APP"
 | 
			
		||||
 | 
			
		||||
    msg_ok "Update Successful"
 | 
			
		||||
  else
 | 
			
		||||
    msg_ok "No update required. ${APP} is already at ${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}:1337${CL}"
 | 
			
		||||
							
								
								
									
										79
									
								
								ct/wizarr.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								ct/wizarr.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
#!/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: vhsdream
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
# Source: https://github.com/wizarrrr/wizarr
 | 
			
		||||
 | 
			
		||||
APP="Wizarr"
 | 
			
		||||
var_tags="${var_tags:-media;arr}"
 | 
			
		||||
var_cpu="${var_cpu:-1}"
 | 
			
		||||
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/wizarr ]]; then
 | 
			
		||||
    msg_error "No ${APP} Installation Found!"
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  RELEASE=$(curl -fsSL https://api.github.com/repos/wizarrrr/wizarr/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
 | 
			
		||||
  if [[ "${RELEASE}" != "$(cat ~/.wizarr 2>/dev/null)" ]] || [[ ! -f ~/.wizarr ]]; then
 | 
			
		||||
    msg_info "Stopping $APP"
 | 
			
		||||
    systemctl stop wizarr
 | 
			
		||||
    msg_ok "Stopped $APP"
 | 
			
		||||
 | 
			
		||||
    msg_info "Creating Backup"
 | 
			
		||||
    BACKUP_FILE="/opt/wizarr_backup_$(date +%F).tar.gz"
 | 
			
		||||
    $STD tar -czf "$BACKUP_FILE" /opt/wizarr/{.env,start.sh} /opt/wizarr/database/ &>/dev/null
 | 
			
		||||
    msg_ok "Backup Created"
 | 
			
		||||
 | 
			
		||||
    setup_uv
 | 
			
		||||
    fetch_and_deploy_gh_release "wizarr" "wizarrrr/wizarr"
 | 
			
		||||
 | 
			
		||||
    msg_info "Updating $APP to v${RELEASE}"
 | 
			
		||||
    cd /opt/wizarr
 | 
			
		||||
    uv -q sync --locked
 | 
			
		||||
    $STD uv -q run pybabel compile -d app/translations
 | 
			
		||||
    $STD npm --prefix app/static install
 | 
			
		||||
    $STD npm --prefix app/static run build:css
 | 
			
		||||
    mkdir -p ./.cache
 | 
			
		||||
    $STD tar -xf "$BACKUP_FILE" --directory=/
 | 
			
		||||
    $STD uv -q run flask db upgrade
 | 
			
		||||
    msg_ok "Updated $APP to v${RELEASE}"
 | 
			
		||||
 | 
			
		||||
    msg_info "Starting $APP"
 | 
			
		||||
    systemctl start wizarr
 | 
			
		||||
    msg_ok "Started $APP"
 | 
			
		||||
 | 
			
		||||
    msg_info "Cleaning Up"
 | 
			
		||||
    rm -rf "$BACKUP_FILE"
 | 
			
		||||
    rm /tmp/"$RELEASE".zip
 | 
			
		||||
    msg_ok "Cleanup Completed"
 | 
			
		||||
    msg_ok "Update Successful"
 | 
			
		||||
  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}:5690${CL}"
 | 
			
		||||
							
								
								
									
										2
									
								
								frontend/public/json/argus.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								frontend/public/json/argus.json
									
									
									
										generated
									
									
									
								
							@@ -8,7 +8,7 @@
 | 
			
		||||
  "type": "ct",
 | 
			
		||||
  "updateable": true,
 | 
			
		||||
  "privileged": false,
 | 
			
		||||
  "interface_port": 3000,
 | 
			
		||||
  "interface_port": 8080,
 | 
			
		||||
  "documentation": "https://release-argus.io/docs/overview/",
 | 
			
		||||
  "website": "https://release-argus.io/",
 | 
			
		||||
  "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/argus.webp",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								frontend/public/json/cloudflare-ddns.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								frontend/public/json/cloudflare-ddns.json
									
									
									
										generated
									
									
									
								
							@@ -37,7 +37,7 @@
 | 
			
		||||
      "type": "warning"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "text": "To update the configuration edit `/etc/systemd/system/cloudflare-ddns.service`. After edit please restard with `systemctl restart cloudflare-ddns`",
 | 
			
		||||
      "text": "To update the configuration edit `/etc/systemd/system/cloudflare-ddns.service`. After edit please restart with `systemctl restart cloudflare-ddns`",
 | 
			
		||||
      "type": "info"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								frontend/public/json/immich.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								frontend/public/json/immich.json
									
									
									
										generated
									
									
									
								
							@@ -43,6 +43,10 @@
 | 
			
		||||
    {
 | 
			
		||||
      "text": "To change upload location, edit 'IMMICH_MEDIA_LOCATION' in `/opt/immich/.env`, and create the symlink 'upload' in /opt/immich/app & /opt/immich/app/machine-learning to your new upload location",
 | 
			
		||||
      "type": "info"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "text": "Logs: `/var/log/immich`",
 | 
			
		||||
      "type": "info"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								frontend/public/json/planka.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								frontend/public/json/planka.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "PLANKA",
 | 
			
		||||
  "slug": "planka",
 | 
			
		||||
  "categories": [
 | 
			
		||||
    12
 | 
			
		||||
  ],
 | 
			
		||||
  "date_created": "2025-06-19",
 | 
			
		||||
  "type": "ct",
 | 
			
		||||
  "updateable": true,
 | 
			
		||||
  "privileged": false,
 | 
			
		||||
  "interface_port": 1337,
 | 
			
		||||
  "documentation": "https://docs.planka.cloud/",
 | 
			
		||||
  "website": "https://planka.app/",
 | 
			
		||||
  "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/planka.webp",
 | 
			
		||||
  "config_path": "/opt/planka/planka/.env",
 | 
			
		||||
  "description": "Planka is a powerful, project management platform that transforms how teams collaborate. Create projects with multiple boards, organize tasks with intuitive drag-and-drop cards, attach files, write rich markdown descriptions, set due dates, assign team members, and keep conversations flowing with comments and labels—all with seamless real-time updates and smart notifications.",
 | 
			
		||||
  "install_methods": [
 | 
			
		||||
    {
 | 
			
		||||
      "type": "default",
 | 
			
		||||
      "script": "ct/planka.sh",
 | 
			
		||||
      "resources": {
 | 
			
		||||
        "cpu": 1,
 | 
			
		||||
        "ram": 1024,
 | 
			
		||||
        "hdd": 4,
 | 
			
		||||
        "os": "debian",
 | 
			
		||||
        "version": "12"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "default_credentials": {
 | 
			
		||||
    "username": null,
 | 
			
		||||
    "password": null
 | 
			
		||||
  },
 | 
			
		||||
  "notes": [
 | 
			
		||||
    {
 | 
			
		||||
      "text": "Type `cat ~/planka.creds` inside LXC to see admin user and database credentials.",
 | 
			
		||||
      "type": "info"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								frontend/public/json/ubuntu2504-vm.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								frontend/public/json/ubuntu2504-vm.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "Ubuntu 25.04",
 | 
			
		||||
  "slug": "ubuntu2504-vm",
 | 
			
		||||
  "categories": [
 | 
			
		||||
    2
 | 
			
		||||
  ],
 | 
			
		||||
  "date_created": "2025-06-19",
 | 
			
		||||
  "type": "vm",
 | 
			
		||||
  "updateable": false,
 | 
			
		||||
  "privileged": false,
 | 
			
		||||
  "interface_port": null,
 | 
			
		||||
  "documentation": null,
 | 
			
		||||
  "website": "https://ubuntu.com/",
 | 
			
		||||
  "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/ubuntu.webp",
 | 
			
		||||
  "config_path": "",
 | 
			
		||||
  "description": "Ubuntu is a distribution based on Debian, designed to have regular releases and a consistent user experience.",
 | 
			
		||||
  "install_methods": [
 | 
			
		||||
    {
 | 
			
		||||
      "type": "default",
 | 
			
		||||
      "script": "vm/ubuntu2504-vm.sh",
 | 
			
		||||
      "resources": {
 | 
			
		||||
        "cpu": 2,
 | 
			
		||||
        "ram": 2048,
 | 
			
		||||
        "hdd": 8,
 | 
			
		||||
        "os": null,
 | 
			
		||||
        "version": null
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "default_credentials": {
 | 
			
		||||
    "username": null,
 | 
			
		||||
    "password": null
 | 
			
		||||
  },
 | 
			
		||||
  "notes": [
 | 
			
		||||
    {
 | 
			
		||||
      "text": "after installation, checkout: ´https://github.com/community-scripts/ProxmoxVE/discussions/272´",
 | 
			
		||||
      "type": "info"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										296
									
								
								frontend/public/json/versions.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										296
									
								
								frontend/public/json/versions.json
									
									
									
										generated
									
									
									
								
							@@ -1,34 +1,169 @@
 | 
			
		||||
[
 | 
			
		||||
  {
 | 
			
		||||
    "name": "docmost/docmost",
 | 
			
		||||
    "version": "v0.21.0",
 | 
			
		||||
    "date": "2025-06-18T21:43:27Z"
 | 
			
		||||
    "name": "fallenbagel/jellyseerr",
 | 
			
		||||
    "version": "preview-dns-cache-manager",
 | 
			
		||||
    "date": "2025-06-20T23:03:23Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "go-gitea/gitea",
 | 
			
		||||
    "version": "v1.24.2",
 | 
			
		||||
    "date": "2025-06-20T20:37:55Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "coder/code-server",
 | 
			
		||||
    "version": "v4.101.0",
 | 
			
		||||
    "date": "2025-06-20T20:21:50Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "immich-app/immich",
 | 
			
		||||
    "version": "v1.135.0",
 | 
			
		||||
    "date": "2025-06-18T20:37:30Z"
 | 
			
		||||
    "version": "v1.135.3",
 | 
			
		||||
    "date": "2025-06-20T20:19:20Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "ipfs/kubo",
 | 
			
		||||
    "version": "v0.35.0",
 | 
			
		||||
    "date": "2025-05-21T18:00:32Z"
 | 
			
		||||
    "name": "apache/tika",
 | 
			
		||||
    "version": "3.2.1-rc1",
 | 
			
		||||
    "date": "2025-06-20T19:41:10Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "VictoriaMetrics/VictoriaMetrics",
 | 
			
		||||
    "version": "v1.24.0-victorialogs",
 | 
			
		||||
    "date": "2025-06-20T19:31:31Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "homarr-labs/homarr",
 | 
			
		||||
    "version": "v1.25.0",
 | 
			
		||||
    "date": "2025-06-20T19:15:43Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "msgbyte/tianji",
 | 
			
		||||
    "version": "v1.22.1",
 | 
			
		||||
    "date": "2025-06-20T18:12:20Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "mongodb/mongo",
 | 
			
		||||
    "version": "r8.1.2-rc0",
 | 
			
		||||
    "date": "2025-06-20T17:35:38Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "nzbgetcom/nzbget",
 | 
			
		||||
    "version": "v25.0",
 | 
			
		||||
    "date": "2025-05-12T09:12:04Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Sonarr/Sonarr",
 | 
			
		||||
    "version": "v4.0.15.2941",
 | 
			
		||||
    "date": "2025-06-20T17:20:54Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "bunkerity/bunkerweb",
 | 
			
		||||
    "version": "testing",
 | 
			
		||||
    "date": "2025-06-16T18:10:42Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "plexguide/Huntarr.io",
 | 
			
		||||
    "version": "8.1.6",
 | 
			
		||||
    "date": "2025-06-20T14:50:59Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "docker/compose",
 | 
			
		||||
    "version": "v2.37.2",
 | 
			
		||||
    "date": "2025-06-20T13:25:03Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "zabbix/zabbix",
 | 
			
		||||
    "version": "7.2.9",
 | 
			
		||||
    "date": "2025-06-20T10:58:45Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "syncthing/syncthing",
 | 
			
		||||
    "version": "2.0.0-rc.19",
 | 
			
		||||
    "date": "2025-06-02T17:56:25Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "benzino77/tasmocompiler",
 | 
			
		||||
    "version": "v12.7.0",
 | 
			
		||||
    "date": "2025-06-20T08:31:16Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Jackett/Jackett",
 | 
			
		||||
    "version": "v0.22.2032",
 | 
			
		||||
    "date": "2025-06-20T05:57:27Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "arunavo4/gitea-mirror",
 | 
			
		||||
    "version": "v2.16.3",
 | 
			
		||||
    "date": "2025-06-20T05:49:06Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "firefly-iii/firefly-iii",
 | 
			
		||||
    "version": "v6.2.18",
 | 
			
		||||
    "date": "2025-06-20T04:45:37Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "paperless-ngx/paperless-ngx",
 | 
			
		||||
    "version": "v2.17.1",
 | 
			
		||||
    "date": "2025-06-19T19:35:01Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "pocket-id/pocket-id",
 | 
			
		||||
    "version": "v1.4.0",
 | 
			
		||||
    "date": "2025-06-19T18:30:11Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "keycloak/keycloak",
 | 
			
		||||
    "version": "26.2.5",
 | 
			
		||||
    "date": "2025-05-28T06:49:43Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "rclone/rclone",
 | 
			
		||||
    "version": "v1.70.1",
 | 
			
		||||
    "date": "2025-06-19T13:19:02Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "icereed/paperless-gpt",
 | 
			
		||||
    "version": "v0.21.0",
 | 
			
		||||
    "date": "2025-06-19T11:54:59Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "neo4j/neo4j",
 | 
			
		||||
    "version": "2025.05.1",
 | 
			
		||||
    "date": "2025-06-19T11:28:36Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "mattermost/mattermost",
 | 
			
		||||
    "version": "v9.11.17",
 | 
			
		||||
    "date": "2025-06-18T08:12:05Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "n8n-io/n8n",
 | 
			
		||||
    "version": "n8n@1.98.2",
 | 
			
		||||
    "date": "2025-06-18T18:20:16Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "redis/redis",
 | 
			
		||||
    "version": "8.2-m01-int2",
 | 
			
		||||
    "date": "2025-06-12T08:52:10Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "prometheus-pve/prometheus-pve-exporter",
 | 
			
		||||
    "version": "v3.5.5",
 | 
			
		||||
    "date": "2025-06-19T05:43:47Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "docmost/docmost",
 | 
			
		||||
    "version": "v0.21.0",
 | 
			
		||||
    "date": "2025-06-18T21:43:27Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "ipfs/kubo",
 | 
			
		||||
    "version": "v0.35.0",
 | 
			
		||||
    "date": "2025-05-21T18:00:32Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "pterodactyl/panel",
 | 
			
		||||
    "version": "v1.11.11",
 | 
			
		||||
    "date": "2025-06-18T18:04:50Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "msgbyte/tianji",
 | 
			
		||||
    "version": "v1.22.0",
 | 
			
		||||
    "date": "2025-06-18T16:21:38Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "ollama/ollama",
 | 
			
		||||
    "version": "v0.9.2",
 | 
			
		||||
@@ -49,16 +184,6 @@
 | 
			
		||||
    "version": "5.0.0.M3",
 | 
			
		||||
    "date": "2025-06-18T14:18:12Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "zabbix/zabbix",
 | 
			
		||||
    "version": "7.2.8",
 | 
			
		||||
    "date": "2025-06-18T13:46:00Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "plexguide/Huntarr.io",
 | 
			
		||||
    "version": "8.0.9",
 | 
			
		||||
    "date": "2025-06-18T13:12:23Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Bubka/2FAuth",
 | 
			
		||||
    "version": "v5.6.0",
 | 
			
		||||
@@ -69,11 +194,6 @@
 | 
			
		||||
    "version": "v10.7.0",
 | 
			
		||||
    "date": "2025-06-18T11:57:05Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "rclone/rclone",
 | 
			
		||||
    "version": "v1.70.0",
 | 
			
		||||
    "date": "2025-06-18T10:31:28Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "esphome/esphome",
 | 
			
		||||
    "version": "2025.6.0",
 | 
			
		||||
@@ -94,16 +214,6 @@
 | 
			
		||||
    "version": "2.0.0-pre3",
 | 
			
		||||
    "date": "2025-06-18T08:01:24Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "mattermost/mattermost",
 | 
			
		||||
    "version": "v9.11.17",
 | 
			
		||||
    "date": "2025-06-18T08:12:05Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Jackett/Jackett",
 | 
			
		||||
    "version": "v0.22.2026",
 | 
			
		||||
    "date": "2025-06-18T05:51:39Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "cross-seed/cross-seed",
 | 
			
		||||
    "version": "v6.12.7",
 | 
			
		||||
@@ -119,21 +229,11 @@
 | 
			
		||||
    "version": "v11.5.6",
 | 
			
		||||
    "date": "2025-06-17T22:00:40Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "keycloak/keycloak",
 | 
			
		||||
    "version": "26.2.5",
 | 
			
		||||
    "date": "2025-05-28T06:49:43Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "jenkinsci/jenkins",
 | 
			
		||||
    "version": "jenkins-2.515",
 | 
			
		||||
    "date": "2025-06-17T19:17:56Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "coder/code-server",
 | 
			
		||||
    "version": "v4.100.3",
 | 
			
		||||
    "date": "2025-06-03T21:06:41Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "HabitRPG/habitica",
 | 
			
		||||
    "version": "v5.36.6",
 | 
			
		||||
@@ -144,11 +244,6 @@
 | 
			
		||||
    "version": "v2.1.5",
 | 
			
		||||
    "date": "2025-06-17T18:04:11Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "fallenbagel/jellyseerr",
 | 
			
		||||
    "version": "preview-sort-userlist",
 | 
			
		||||
    "date": "2025-06-17T18:02:25Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "BookStackApp/BookStack",
 | 
			
		||||
    "version": "v25.05.1",
 | 
			
		||||
@@ -169,11 +264,6 @@
 | 
			
		||||
    "version": "4.5.1",
 | 
			
		||||
    "date": "2025-04-11T09:57:47Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "arunavo4/gitea-mirror",
 | 
			
		||||
    "version": "v2.16.2",
 | 
			
		||||
    "date": "2025-06-17T11:59:34Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "crowdsecurity/crowdsec",
 | 
			
		||||
    "version": "v1.6.9",
 | 
			
		||||
@@ -204,11 +294,6 @@
 | 
			
		||||
    "version": "2.36.1",
 | 
			
		||||
    "date": "2025-06-16T19:20:54Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "bunkerity/bunkerweb",
 | 
			
		||||
    "version": "testing",
 | 
			
		||||
    "date": "2025-06-16T18:10:42Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "goauthentik/authentik",
 | 
			
		||||
    "version": "version/2025.6.2",
 | 
			
		||||
@@ -254,11 +339,6 @@
 | 
			
		||||
    "version": "v1.18.3",
 | 
			
		||||
    "date": "2025-06-16T07:03:46Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "firefly-iii/firefly-iii",
 | 
			
		||||
    "version": "v6.2.17",
 | 
			
		||||
    "date": "2025-06-11T12:07:38Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "jellyfin/jellyfin",
 | 
			
		||||
    "version": "v10.10.7",
 | 
			
		||||
@@ -284,11 +364,6 @@
 | 
			
		||||
    "version": "v3.1.9",
 | 
			
		||||
    "date": "2025-03-01T02:24:33Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "syncthing/syncthing",
 | 
			
		||||
    "version": "2.0.0-rc.19",
 | 
			
		||||
    "date": "2025-06-02T17:56:25Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Prowlarr/Prowlarr",
 | 
			
		||||
    "version": "v1.37.0.5076",
 | 
			
		||||
@@ -324,11 +399,6 @@
 | 
			
		||||
    "version": "v2.25.1",
 | 
			
		||||
    "date": "2025-06-14T23:32:15Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "nzbgetcom/nzbget",
 | 
			
		||||
    "version": "v25.0",
 | 
			
		||||
    "date": "2025-05-12T09:12:04Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "theonedev/onedev",
 | 
			
		||||
    "version": "v11.11.0",
 | 
			
		||||
@@ -349,11 +419,6 @@
 | 
			
		||||
    "version": "2025.6.1",
 | 
			
		||||
    "date": "2025-06-13T20:16:18Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "homarr-labs/homarr",
 | 
			
		||||
    "version": "v1.24.0",
 | 
			
		||||
    "date": "2025-06-13T19:15:36Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Luligu/matterbridge",
 | 
			
		||||
    "version": "3.0.6",
 | 
			
		||||
@@ -384,16 +449,6 @@
 | 
			
		||||
    "version": "v2.3.0p34",
 | 
			
		||||
    "date": "2025-06-12T12:15:44Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "docker/compose",
 | 
			
		||||
    "version": "v2.37.1",
 | 
			
		||||
    "date": "2025-06-12T09:00:21Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "redis/redis",
 | 
			
		||||
    "version": "8.2-m01-int2",
 | 
			
		||||
    "date": "2025-06-12T08:52:10Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "zitadel/zitadel",
 | 
			
		||||
    "version": "v3.3.0",
 | 
			
		||||
@@ -449,36 +504,16 @@
 | 
			
		||||
    "version": "1.11.2",
 | 
			
		||||
    "date": "2025-06-10T11:07:14Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "VictoriaMetrics/VictoriaMetrics",
 | 
			
		||||
    "version": "v1.110.11",
 | 
			
		||||
    "date": "2025-06-10T10:00:25Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "glanceapp/glance",
 | 
			
		||||
    "version": "v0.8.4",
 | 
			
		||||
    "date": "2025-06-10T07:57:14Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "go-gitea/gitea",
 | 
			
		||||
    "version": "v1.24.0",
 | 
			
		||||
    "date": "2025-06-10T02:00:38Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Sonarr/Sonarr",
 | 
			
		||||
    "version": "v4.0.14.2939",
 | 
			
		||||
    "date": "2025-03-17T19:12:37Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "tailscale/tailscale",
 | 
			
		||||
    "version": "v1.84.2",
 | 
			
		||||
    "date": "2025-06-09T23:43:27Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "pocket-id/pocket-id",
 | 
			
		||||
    "version": "v1.3.1",
 | 
			
		||||
    "date": "2025-06-09T21:07:27Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "pocketbase/pocketbase",
 | 
			
		||||
    "version": "v0.28.3",
 | 
			
		||||
@@ -499,11 +534,6 @@
 | 
			
		||||
    "version": "v0.10.0",
 | 
			
		||||
    "date": "2025-06-09T13:37:07Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "neo4j/neo4j",
 | 
			
		||||
    "version": "5.26.8",
 | 
			
		||||
    "date": "2025-06-08T22:50:58Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Forceu/Gokapi",
 | 
			
		||||
    "version": "v2.0.1",
 | 
			
		||||
@@ -549,11 +579,6 @@
 | 
			
		||||
    "version": "10.1.42",
 | 
			
		||||
    "date": "2025-06-05T22:39:40Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "paperless-ngx/paperless-ngx",
 | 
			
		||||
    "version": "v2.16.3",
 | 
			
		||||
    "date": "2025-06-05T21:16:59Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "netbox-community/netbox",
 | 
			
		||||
    "version": "v4.3.2",
 | 
			
		||||
@@ -649,11 +674,6 @@
 | 
			
		||||
    "version": "v0.14.1",
 | 
			
		||||
    "date": "2024-08-29T22:32:51Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "icereed/paperless-gpt",
 | 
			
		||||
    "version": "v0.20.0",
 | 
			
		||||
    "date": "2025-05-30T14:39:51Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "binwiederhier/ntfy",
 | 
			
		||||
    "version": "v2.12.0",
 | 
			
		||||
@@ -689,11 +709,6 @@
 | 
			
		||||
    "version": "cassandra-4.0.18",
 | 
			
		||||
    "date": "2025-05-28T21:45:55Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "mongodb/mongo",
 | 
			
		||||
    "version": "r6.0.24",
 | 
			
		||||
    "date": "2025-05-28T21:25:03Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Athou/commafeed",
 | 
			
		||||
    "version": "5.10.0",
 | 
			
		||||
@@ -759,11 +774,6 @@
 | 
			
		||||
    "version": "0.5",
 | 
			
		||||
    "date": "2025-05-21T20:19:14Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "apache/tika",
 | 
			
		||||
    "version": "3.2.0-rc2",
 | 
			
		||||
    "date": "2025-05-21T20:09:07Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "Stirling-Tools/Stirling-PDF",
 | 
			
		||||
    "version": "v0.46.2",
 | 
			
		||||
@@ -899,11 +909,6 @@
 | 
			
		||||
    "version": "v0.9.80",
 | 
			
		||||
    "date": "2025-05-02T16:48:15Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "prometheus-pve/prometheus-pve-exporter",
 | 
			
		||||
    "version": "v3.5.4",
 | 
			
		||||
    "date": "2025-05-02T13:42:06Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "WordPress/WordPress",
 | 
			
		||||
    "version": "6.8.1",
 | 
			
		||||
@@ -989,11 +994,6 @@
 | 
			
		||||
    "version": "v2.10.0",
 | 
			
		||||
    "date": "2025-04-18T20:46:28Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "benzino77/tasmocompiler",
 | 
			
		||||
    "version": "v12.6.1",
 | 
			
		||||
    "date": "2025-04-17T17:35:02Z"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "name": "IceWhaleTech/CasaOS",
 | 
			
		||||
    "version": "v0.4.15",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								frontend/public/json/wizarr.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								frontend/public/json/wizarr.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "Wizarr",
 | 
			
		||||
  "slug": "wizarr",
 | 
			
		||||
  "categories": [
 | 
			
		||||
    14,
 | 
			
		||||
    13
 | 
			
		||||
  ],
 | 
			
		||||
  "date_created": "2025-06-19",
 | 
			
		||||
  "type": "ct",
 | 
			
		||||
  "updateable": true,
 | 
			
		||||
  "privileged": false,
 | 
			
		||||
  "interface_port": 5690,
 | 
			
		||||
  "documentation": "https://docs.wizarr.dev/",
 | 
			
		||||
  "website": "https://docs.wizarr.dev/",
 | 
			
		||||
  "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/webp/wizarr.webp",
 | 
			
		||||
  "config_path": "/opt/wizarr/.env",
 | 
			
		||||
  "description": "Wizarr is an automatic user invitation system for Plex, Jellyfin and Emby. Create a unique link and share it to a user and they will automatically be invited to your media Server",
 | 
			
		||||
  "install_methods": [
 | 
			
		||||
    {
 | 
			
		||||
      "type": "default",
 | 
			
		||||
      "script": "ct/wizarr.sh",
 | 
			
		||||
      "resources": {
 | 
			
		||||
        "cpu": 1,
 | 
			
		||||
        "ram": 1024,
 | 
			
		||||
        "hdd": 4,
 | 
			
		||||
        "os": "debian",
 | 
			
		||||
        "version": "12"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "default_credentials": {
 | 
			
		||||
    "username": null,
 | 
			
		||||
    "password": null
 | 
			
		||||
  },
 | 
			
		||||
  "notes": []
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,7 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2021-2025 tteck
 | 
			
		||||
# Author: tteck
 | 
			
		||||
# Co-Author: MickLesk (Canbiz)
 | 
			
		||||
# Author: MickLesk (CanbiZ)
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
# Source: https://github.com/seanmorley15/AdventureLog
 | 
			
		||||
 | 
			
		||||
@@ -18,13 +17,12 @@ msg_info "Installing Dependencies"
 | 
			
		||||
$STD apt-get install -y \
 | 
			
		||||
  gdal-bin \
 | 
			
		||||
  libgdal-dev \
 | 
			
		||||
  git \
 | 
			
		||||
  python3-venv \
 | 
			
		||||
  python3-pip
 | 
			
		||||
  git
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
NODE_VERSION="22" NODE_MODULE="pnpm@latest" setup_nodejs
 | 
			
		||||
PG_VERSION="16" PG_MODULES="postgis" setup_postgresql
 | 
			
		||||
PYTHON_VERSION="3.12" setup_uv
 | 
			
		||||
NODE_VERSION="22" NODE_MODULE="pnpm@latest" install_node_and_modules
 | 
			
		||||
PG_VERSION="16" PG_MODULES="postgis" install_postgresql
 | 
			
		||||
 | 
			
		||||
msg_info "Set up PostgreSQL Database"
 | 
			
		||||
DB_NAME="adventurelog_db"
 | 
			
		||||
@@ -46,15 +44,12 @@ $STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';"
 | 
			
		||||
} >>~/adventurelog.creds
 | 
			
		||||
msg_ok "Set up PostgreSQL"
 | 
			
		||||
 | 
			
		||||
fetch_and_deploy_gh_release "adventurelog" "seanmorley15/adventurelog"
 | 
			
		||||
 | 
			
		||||
msg_info "Installing AdventureLog (Patience)"
 | 
			
		||||
DJANGO_ADMIN_USER="djangoadmin"
 | 
			
		||||
DJANGO_ADMIN_PASS="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)"
 | 
			
		||||
LOCAL_IP="$(hostname -I | awk '{print $1}')"
 | 
			
		||||
cd /opt
 | 
			
		||||
RELEASE=$(curl -fsSL https://api.github.com/repos/seanmorley15/AdventureLog/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
curl -fsSL "https://github.com/seanmorley15/AdventureLog/archive/refs/tags/v${RELEASE}.zip" -o "v${RELEASE}.zip"
 | 
			
		||||
$STD unzip v${RELEASE}.zip
 | 
			
		||||
mv AdventureLog-${RELEASE} /opt/adventurelog
 | 
			
		||||
cat <<EOF >/opt/adventurelog/backend/server/.env
 | 
			
		||||
PGHOST='localhost'
 | 
			
		||||
PGDATABASE='${DB_NAME}'
 | 
			
		||||
@@ -79,11 +74,13 @@ DISABLE_REGISTRATION=False
 | 
			
		||||
EOF
 | 
			
		||||
cd /opt/adventurelog/backend/server
 | 
			
		||||
mkdir -p /opt/adventurelog/backend/server/media
 | 
			
		||||
$STD pip install --upgrade pip
 | 
			
		||||
$STD pip install -r requirements.txt
 | 
			
		||||
$STD python3 manage.py collectstatic --noinput
 | 
			
		||||
$STD python3 manage.py migrate
 | 
			
		||||
$STD python3 manage.py download-countries
 | 
			
		||||
$STD uv venv /opt/adventurelog/backend/server/.venv
 | 
			
		||||
$STD /opt/adventurelog/backend/server/.venv/bin/python -m ensurepip --upgrade
 | 
			
		||||
$STD /opt/adventurelog/backend/server/.venv/bin/python -m pip install --upgrade pip
 | 
			
		||||
$STD /opt/adventurelog/backend/server/.venv/bin/python -m pip install -r requirements.txt
 | 
			
		||||
$STD /opt/adventurelog/backend/server/.venv/bin/python -m manage collectstatic --noinput
 | 
			
		||||
$STD /opt/adventurelog/backend/server/.venv/bin/python -m manage migrate
 | 
			
		||||
$STD /opt/adventurelog/backend/server/.venv/bin/python -m manage download-countries
 | 
			
		||||
cat <<EOF >/opt/adventurelog/frontend/.env
 | 
			
		||||
PUBLIC_SERVER_URL=http://$LOCAL_IP:8000
 | 
			
		||||
BODY_SIZE_LIMIT=Infinity
 | 
			
		||||
@@ -96,7 +93,8 @@ echo "${RELEASE}" >"/opt/${APPLICATION}_version.txt"
 | 
			
		||||
msg_ok "Installed AdventureLog"
 | 
			
		||||
 | 
			
		||||
msg_info "Setting up Django Admin"
 | 
			
		||||
$STD python3 /opt/adventurelog/backend/server/manage.py shell <<EOF
 | 
			
		||||
cd /opt/adventurelog/backend/server
 | 
			
		||||
$STD .venv/bin/python -m manage shell <<EOF
 | 
			
		||||
from django.contrib.auth import get_user_model
 | 
			
		||||
UserModel = get_user_model()
 | 
			
		||||
user = UserModel.objects.create_user('$DJANGO_ADMIN_USER', password='$DJANGO_ADMIN_PASS')
 | 
			
		||||
@@ -120,7 +118,7 @@ After=network.target postgresql.service
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
WorkingDirectory=/opt/adventurelog/backend/server
 | 
			
		||||
ExecStart=python3 manage.py runserver 0.0.0.0:8000
 | 
			
		||||
ExecStart=/opt/adventurelog/backend/server/.venv/bin/python -m manage runserver 0.0.0.0:8000
 | 
			
		||||
Restart=always
 | 
			
		||||
EnvironmentFile=/opt/adventurelog/backend/server/.env
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,8 @@ setting_up_container
 | 
			
		||||
network_check
 | 
			
		||||
update_os
 | 
			
		||||
 | 
			
		||||
setup_uv
 | 
			
		||||
 | 
			
		||||
msg_info "Configuring apt and installing dependencies"
 | 
			
		||||
echo "deb http://deb.debian.org/debian testing main contrib" >/etc/apt/sources.list.d/immich.list
 | 
			
		||||
cat <<EOF >/etc/apt/preferences.d/immich
 | 
			
		||||
@@ -27,7 +29,6 @@ $STD apt-get install --no-install-recommends -y \
 | 
			
		||||
  redis \
 | 
			
		||||
  autoconf \
 | 
			
		||||
  build-essential \
 | 
			
		||||
  python3-venv \
 | 
			
		||||
  python3-dev \
 | 
			
		||||
  cmake \
 | 
			
		||||
  jq \
 | 
			
		||||
@@ -63,6 +64,7 @@ $STD apt-get install --no-install-recommends -y \
 | 
			
		||||
  mesa-utils \
 | 
			
		||||
  mesa-va-drivers \
 | 
			
		||||
  mesa-vulkan-drivers \
 | 
			
		||||
  ocl-icd-libopencl1 \
 | 
			
		||||
  tini \
 | 
			
		||||
  zlib1g
 | 
			
		||||
$STD apt-get install -y \
 | 
			
		||||
@@ -88,14 +90,13 @@ read -r -p "Install OpenVINO dependencies for Intel HW-accelerated machine-learn
 | 
			
		||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
  msg_info "Installing OpenVINO dependencies"
 | 
			
		||||
  touch ~/.openvino
 | 
			
		||||
  $STD apt-get -y install --no-install-recommends ocl-icd-libopencl1
 | 
			
		||||
  tmp_dir=$(mktemp -d)
 | 
			
		||||
  $STD pushd "$tmp_dir"
 | 
			
		||||
  curl -fsSL https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17384.11/intel-igc-core_1.0.17384.11_amd64.deb -O
 | 
			
		||||
  curl -fsSL https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17384.11/intel-igc-opencl_1.0.17384.11_amd64.deb -O
 | 
			
		||||
  curl -fsSL https://github.com/intel/compute-runtime/releases/download/24.31.30508.7/intel-opencl-icd_24.31.30508.7_amd64.deb -O
 | 
			
		||||
  curl -fsSL https://github.com/intel/compute-runtime/releases/download/24.31.30508.7/libigdgmm12_22.4.1_amd64.deb -O
 | 
			
		||||
  $STD dpkg -i ./*.deb
 | 
			
		||||
  curl -fsSLO https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17384.11/intel-igc-core_1.0.17384.11_amd64.deb
 | 
			
		||||
  curl -fsSLO https://github.com/intel/intel-graphics-compiler/releases/download/igc-1.0.17384.11/intel-igc-opencl_1.0.17384.11_amd64.deb
 | 
			
		||||
  curl -fsSLO https://github.com/intel/compute-runtime/releases/download/24.31.30508.7/intel-opencl-icd_24.31.30508.7_amd64.deb
 | 
			
		||||
  curl -fsSLO https://github.com/intel/compute-runtime/releases/download/24.31.30508.7/libigdgmm12_22.4.1_amd64.deb
 | 
			
		||||
  $STD apt install -y ./*.deb
 | 
			
		||||
  $STD popd
 | 
			
		||||
  rm -rf "$tmp_dir"
 | 
			
		||||
  dpkg -l | grep "intel-opencl-icd" | awk '{print $3}' >~/.intel_version
 | 
			
		||||
@@ -110,13 +111,14 @@ if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
NODE_VERSION="22" setup_nodejs
 | 
			
		||||
PG_VERSION="16" setup_postgresql
 | 
			
		||||
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
 | 
			
		||||
 | 
			
		||||
msg_info "Setting up Postgresql Database"
 | 
			
		||||
$STD apt-get install postgresql-16-pgvector
 | 
			
		||||
curl -fsSL https://github.com/tensorchord/VectorChord/releases/download/0.3.0/postgresql-16-vchord_0.3.0-1_amd64.deb -o vchord.deb
 | 
			
		||||
$STD dpkg -i vchord.deb
 | 
			
		||||
VCHORD_RELEASE="$(curl -fsSL https://api.github.com/repos/tensorchord/vectorchord/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')"
 | 
			
		||||
curl -fsSL "https://github.com/tensorchord/VectorChord/releases/download/${VCHORD_RELEASE}/postgresql-16-vchord_${VCHORD_RELEASE}-1_amd64.deb" -o vchord.deb
 | 
			
		||||
$STD apt install -y ./vchord.deb
 | 
			
		||||
rm vchord.deb
 | 
			
		||||
echo "$VCHORD_RELEASE" >~/.vchord_version
 | 
			
		||||
DB_NAME="immich"
 | 
			
		||||
DB_USER="immich"
 | 
			
		||||
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c18)
 | 
			
		||||
@@ -271,11 +273,6 @@ rm -rf "$SOURCE"/build
 | 
			
		||||
} >~/.immich_library_revisions
 | 
			
		||||
msg_ok "Custom Photo-processing Library Compiled"
 | 
			
		||||
 | 
			
		||||
msg_info "Installing ${APPLICATION} (more patience please)"
 | 
			
		||||
tmp_file=$(mktemp)
 | 
			
		||||
RELEASE=$(curl -s https://api.github.com/repos/immich-app/immich/releases?per_page=1 | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
 | 
			
		||||
curl -fsSL "https://github.com/immich-app/immich/archive/refs/tags/v${RELEASE}.zip" -o "$tmp_file"
 | 
			
		||||
unzip -q "$tmp_file"
 | 
			
		||||
INSTALL_DIR="/opt/${APPLICATION}"
 | 
			
		||||
UPLOAD_DIR="${INSTALL_DIR}/upload"
 | 
			
		||||
SRC_DIR="${INSTALL_DIR}/source"
 | 
			
		||||
@@ -283,9 +280,12 @@ APP_DIR="${INSTALL_DIR}/app"
 | 
			
		||||
ML_DIR="${APP_DIR}/machine-learning"
 | 
			
		||||
GEO_DIR="${INSTALL_DIR}/geodata"
 | 
			
		||||
mkdir -p "$INSTALL_DIR"
 | 
			
		||||
mv "$APPLICATION-$RELEASE"/ "$SRC_DIR"
 | 
			
		||||
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${ML_DIR}","${INSTALL_DIR}"/cache}
 | 
			
		||||
 | 
			
		||||
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v1.135.0" "$SRC_DIR"
 | 
			
		||||
 | 
			
		||||
msg_info "Installing ${APPLICATION} (more patience please)"
 | 
			
		||||
 | 
			
		||||
cd "$SRC_DIR"/server
 | 
			
		||||
$STD npm install -g node-gyp node-pre-gyp
 | 
			
		||||
$STD npm ci
 | 
			
		||||
@@ -304,23 +304,16 @@ cp LICENSE "$APP_DIR"
 | 
			
		||||
msg_ok "Installed Immich Web Components"
 | 
			
		||||
 | 
			
		||||
cd "$SRC_DIR"/machine-learning
 | 
			
		||||
$STD python3 -m venv "$ML_DIR/ml-venv"
 | 
			
		||||
export VIRTUAL_ENV="${ML_DIR}/ml-venv"
 | 
			
		||||
$STD uv venv "$VIRTUAL_ENV"
 | 
			
		||||
if [[ -f ~/.openvino ]]; then
 | 
			
		||||
  msg_info "Installing HW-accelerated machine-learning"
 | 
			
		||||
  (
 | 
			
		||||
    source "$ML_DIR"/ml-venv/bin/activate
 | 
			
		||||
    $STD pip3 install uv
 | 
			
		||||
    uv -q sync --extra openvino --no-cache --active
 | 
			
		||||
  )
 | 
			
		||||
  patchelf --clear-execstack "$ML_DIR"/ml-venv/lib/python3.11/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-311-x86_64-linux-gnu.so
 | 
			
		||||
  uv -q sync --extra openvino --no-cache --active
 | 
			
		||||
  patchelf --clear-execstack "${VIRTUAL_ENV}/lib/python3.11/site-packages/onnxruntime/capi/onnxruntime_pybind11_state.cpython-311-x86_64-linux-gnu.so"
 | 
			
		||||
  msg_ok "Installed HW-accelerated machine-learning"
 | 
			
		||||
else
 | 
			
		||||
  msg_info "Installing machine-learning"
 | 
			
		||||
  (
 | 
			
		||||
    source "$ML_DIR"/ml-venv/bin/activate
 | 
			
		||||
    $STD pip3 install uv
 | 
			
		||||
    uv -q sync --extra cpu --no-cache --active
 | 
			
		||||
  )
 | 
			
		||||
  uv -q sync --extra cpu --no-cache --active
 | 
			
		||||
  msg_ok "Installed machine-learning"
 | 
			
		||||
fi
 | 
			
		||||
cd "$SRC_DIR"
 | 
			
		||||
@@ -351,7 +344,9 @@ URL_LIST=(
 | 
			
		||||
  https://download.geonames.org/export/dump/cities500.zip
 | 
			
		||||
  https://raw.githubusercontent.com/nvkelso/natural-earth-vector/v5.1.2/geojson/ne_10m_admin_0_countries.geojson
 | 
			
		||||
)
 | 
			
		||||
echo "${URL_LIST[@]}" | xargs -n1 -P 8 wget -q
 | 
			
		||||
for geo in "${URL_LIST[@]}"; do
 | 
			
		||||
  curl -fsSLO "$geo"
 | 
			
		||||
done
 | 
			
		||||
unzip -q cities500.zip
 | 
			
		||||
date --iso-8601=seconds | tr -d "\n" >geodata-date.txt
 | 
			
		||||
rm cities500.zip
 | 
			
		||||
@@ -361,7 +356,6 @@ msg_ok "Installed GeoNames data"
 | 
			
		||||
 | 
			
		||||
mkdir -p /var/log/immich
 | 
			
		||||
touch /var/log/immich/{web.log,ml.log}
 | 
			
		||||
echo "$RELEASE" >/opt/"${APPLICATION}"_version.txt
 | 
			
		||||
msg_ok "Installed ${APPLICATION}"
 | 
			
		||||
 | 
			
		||||
msg_info "Creating user, env file, scripts & services"
 | 
			
		||||
@@ -390,13 +384,13 @@ cat <<EOF >"${ML_DIR}"/ml_start.sh
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
cd ${ML_DIR}
 | 
			
		||||
. ml-venv/bin/activate
 | 
			
		||||
. ${VIRTUAL_ENV}/bin/activate
 | 
			
		||||
 | 
			
		||||
set -a
 | 
			
		||||
. ${INSTALL_DIR}/.env
 | 
			
		||||
set +a
 | 
			
		||||
 | 
			
		||||
python -m immich_ml
 | 
			
		||||
python3 -m immich_ml
 | 
			
		||||
EOF
 | 
			
		||||
chmod +x "$ML_DIR"/ml_start.sh
 | 
			
		||||
cat <<EOF >/etc/systemd/system/"${APPLICATION}"-web.service
 | 
			
		||||
@@ -453,7 +447,6 @@ motd_ssh
 | 
			
		||||
customize
 | 
			
		||||
 | 
			
		||||
msg_info "Cleaning up"
 | 
			
		||||
rm -f "$tmp_file"
 | 
			
		||||
$STD apt-get -y autoremove
 | 
			
		||||
$STD apt-get -y autoclean
 | 
			
		||||
msg_ok "Cleaned"
 | 
			
		||||
 
 | 
			
		||||
@@ -13,15 +13,19 @@ setting_up_container
 | 
			
		||||
network_check
 | 
			
		||||
update_os
 | 
			
		||||
 | 
			
		||||
msg_info "Installing Dependencies"
 | 
			
		||||
$STD apt-get install -y \
 | 
			
		||||
    python3 \
 | 
			
		||||
    python3-pip
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
PYTHON_VERSION="3.12" setup_uv
 | 
			
		||||
 | 
			
		||||
msg_info "Setting up Jupyter Notebook"
 | 
			
		||||
$STD pip3 install jupyter
 | 
			
		||||
msg_ok "Setup Jupyter Notebook"
 | 
			
		||||
msg_info "Installing Jupyter"
 | 
			
		||||
mkdir -p /opt/jupyter
 | 
			
		||||
cd /opt/jupyter
 | 
			
		||||
$STD uv venv /opt/jupyter/.venv
 | 
			
		||||
$STD /opt/jupyter/.venv/bin/python -m ensurepip --upgrade
 | 
			
		||||
$STD /opt/jupyter/.venv/bin/python -m pip install --upgrade pip
 | 
			
		||||
$STD /opt/jupyter/.venv/bin/python -m pip install jupyter
 | 
			
		||||
ln -s /opt/jupyter/.venv/bin/jupyter /usr/local/bin/jupyter
 | 
			
		||||
ln -s /opt/jupyter/.venv/bin/jupyter-lab /usr/local/bin/jupyter-lab
 | 
			
		||||
ln -s /opt/jupyter/.venv/bin/jupyter-notebook /usr/local/bin/jupyter-notebook
 | 
			
		||||
msg_ok "Installed Jupyter"
 | 
			
		||||
 | 
			
		||||
msg_info "Creating Service"
 | 
			
		||||
cat <<EOF >/etc/systemd/system/jupyternotebook.service
 | 
			
		||||
@@ -31,7 +35,8 @@ After=network.target
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
ExecStart=jupyter notebook --ip=0.0.0.0 --port=8888 --allow-root
 | 
			
		||||
WorkingDirectory=/opt/jupyter
 | 
			
		||||
ExecStart=/opt/jupyter/.venv/bin/jupyter notebook --ip=0.0.0.0 --port=8888 --allow-root
 | 
			
		||||
Restart=always
 | 
			
		||||
RestartSec=10
 | 
			
		||||
 | 
			
		||||
@@ -39,6 +44,7 @@ RestartSec=10
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
EOF
 | 
			
		||||
systemctl enable -q --now jupyternotebook
 | 
			
		||||
msg_ok "Created Service"
 | 
			
		||||
 | 
			
		||||
motd_ssh
 | 
			
		||||
customize
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										103
									
								
								install/planka-install.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								install/planka-install.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
#!/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/plankanban/planka
 | 
			
		||||
 | 
			
		||||
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 \
 | 
			
		||||
  unzip \
 | 
			
		||||
  build-essential \
 | 
			
		||||
  python3-venv
 | 
			
		||||
msg_ok "Installed dependencies"
 | 
			
		||||
 | 
			
		||||
NODE_VERSION="22" setup_nodejs
 | 
			
		||||
PG_VERSION="16" setup_postgresql
 | 
			
		||||
 | 
			
		||||
msg_info "Setting up PostgreSQL Database"
 | 
			
		||||
DB_NAME=planka
 | 
			
		||||
DB_USER=planka
 | 
			
		||||
DB_PASS=$(openssl rand -base64 16 | tr -d '/+=')
 | 
			
		||||
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
 | 
			
		||||
$STD sudo -u postgres psql -c "CREATE DATABASE $DB_NAME WITH OWNER $DB_USER ENCODING 'UTF8' TEMPLATE template0;"
 | 
			
		||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
 | 
			
		||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
 | 
			
		||||
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC'"
 | 
			
		||||
{
 | 
			
		||||
  echo "PLANKA DB Credentials"
 | 
			
		||||
  echo "PLANKA Database User: $DB_USER"
 | 
			
		||||
  echo "PLANKA Database Password: $DB_PASS"
 | 
			
		||||
  echo "PLANKA Database Name: $DB_NAME"
 | 
			
		||||
} >>~/planka.creds
 | 
			
		||||
msg_ok "Set up PostgreSQL Database"
 | 
			
		||||
 | 
			
		||||
fetch_and_deploy_gh_release "planka" "plankanban/planka" "prebuild" "latest" "/opt/planka" "planka-prebuild.zip"
 | 
			
		||||
 | 
			
		||||
msg_info "Configuring PLANKA"
 | 
			
		||||
LOCAL_IP=$(hostname -I | awk '{print $1}')
 | 
			
		||||
SECRET_KEY=$(openssl rand -hex 64)
 | 
			
		||||
cd /opt/planka/planka
 | 
			
		||||
$STD npm install
 | 
			
		||||
cp .env.sample .env
 | 
			
		||||
sed -i "s#http://localhost:1337#http://$LOCAL_IP:1337#g" /opt/planka/planka/.env
 | 
			
		||||
sed -i "s#postgres@localhost#planka:$DB_PASS@localhost#g" /opt/planka/planka/.env
 | 
			
		||||
sed -i "s#notsecretkey#$SECRET_KEY#g" /opt/planka/planka/.env
 | 
			
		||||
$STD npm run db:init
 | 
			
		||||
msg_ok "Configured PLANKA"
 | 
			
		||||
 | 
			
		||||
msg_info "Creating Admin User"
 | 
			
		||||
ADMIN_EMAIL="admin@planka.local"
 | 
			
		||||
ADMIN_PASSWORD="$(openssl rand -base64 12)"
 | 
			
		||||
ADMIN_NAME="Administrator"
 | 
			
		||||
ADMIN_USERNAME="admin"
 | 
			
		||||
echo "" >>.env
 | 
			
		||||
echo "# Temporary admin user creation settings" >>.env
 | 
			
		||||
echo "DEFAULT_ADMIN_EMAIL=$ADMIN_EMAIL" >>.env
 | 
			
		||||
echo "DEFAULT_ADMIN_PASSWORD=$ADMIN_PASSWORD" >>.env
 | 
			
		||||
echo "DEFAULT_ADMIN_NAME=$ADMIN_NAME" >>.env
 | 
			
		||||
echo "DEFAULT_ADMIN_USERNAME=$ADMIN_USERNAME" >>.env
 | 
			
		||||
$STD npm run db:seed
 | 
			
		||||
sed -i '/# Temporary admin user creation settings/,$d' .env
 | 
			
		||||
{
 | 
			
		||||
  echo ""
 | 
			
		||||
  echo "PLANKA Admin Credentials"
 | 
			
		||||
  echo "Admin Email: $ADMIN_EMAIL"
 | 
			
		||||
  echo "Admin Password: $ADMIN_PASSWORD"
 | 
			
		||||
  echo "Admin Name: $ADMIN_NAME"
 | 
			
		||||
  echo "Admin Username: $ADMIN_USERNAME"
 | 
			
		||||
} >>~/planka.creds
 | 
			
		||||
msg_ok "Created Admin User"
 | 
			
		||||
 | 
			
		||||
msg_info "Creating Service"
 | 
			
		||||
cat <<EOF >/etc/systemd/system/planka.service
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=planka Service
 | 
			
		||||
After=network.target
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
WorkingDirectory=/opt/planka/planka
 | 
			
		||||
ExecStart=/usr/bin/npm start --prod
 | 
			
		||||
Restart=always
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
EOF
 | 
			
		||||
systemctl enable -q --now planka
 | 
			
		||||
msg_ok "Created Service"
 | 
			
		||||
 | 
			
		||||
motd_ssh
 | 
			
		||||
customize
 | 
			
		||||
 | 
			
		||||
msg_info "Cleaning up"
 | 
			
		||||
$STD apt-get -y autoremove
 | 
			
		||||
$STD apt-get -y autoclean
 | 
			
		||||
msg_ok "Cleaned"
 | 
			
		||||
							
								
								
									
										79
									
								
								install/wizarr-install.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								install/wizarr-install.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2021-2025 community-scripts ORG
 | 
			
		||||
# Author: vhsdream
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
# Source: https://github.com/wizarrrr/wizarr
 | 
			
		||||
 | 
			
		||||
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 sqlite3
 | 
			
		||||
msg_ok "Installed Dependencies"
 | 
			
		||||
 | 
			
		||||
setup_uv
 | 
			
		||||
NODE_VERSION="22" setup_nodejs
 | 
			
		||||
fetch_and_deploy_gh_release "wizarr" "wizarrrr/wizarr"
 | 
			
		||||
 | 
			
		||||
msg_info "Configure ${APPLICATION}"
 | 
			
		||||
cd /opt/wizarr
 | 
			
		||||
uv -q sync --locked
 | 
			
		||||
$STD uv -q run pybabel compile -d app/translations
 | 
			
		||||
$STD npm --prefix app/static install
 | 
			
		||||
$STD npm --prefix app/static run build:css
 | 
			
		||||
mkdir -p ./.cache
 | 
			
		||||
$STD uv -q run flask db upgrade
 | 
			
		||||
msg_ok "Configure ${APPLICATION}"
 | 
			
		||||
 | 
			
		||||
msg_info "Creating env, start script and service"
 | 
			
		||||
LOCAL_IP="$(hostname -I | awk '{print $1}')"
 | 
			
		||||
cat <<EOF >/opt/wizarr/.env
 | 
			
		||||
APP_URL=http://${LOCAL_IP}
 | 
			
		||||
DISABLE_BUILTIN_AUTH=false
 | 
			
		||||
LOG_LEVEL=INFO
 | 
			
		||||
EOF
 | 
			
		||||
 | 
			
		||||
cat <<EOF >/opt/wizarr/start.sh
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
uv run gunicorn \
 | 
			
		||||
    --config gunicorn.conf.py \
 | 
			
		||||
    --preload \
 | 
			
		||||
    --workers 4 \
 | 
			
		||||
    --bind 0.0.0.0:5690 \
 | 
			
		||||
    --umask 007 \
 | 
			
		||||
    run:app
 | 
			
		||||
EOF
 | 
			
		||||
chmod u+x /opt/wizarr/start.sh
 | 
			
		||||
 | 
			
		||||
cat <<EOF >/etc/systemd/system/wizarr.service
 | 
			
		||||
[Unit]
 | 
			
		||||
Description=${APPLICATION} Service
 | 
			
		||||
After=network.target
 | 
			
		||||
 | 
			
		||||
[Service]
 | 
			
		||||
Type=simple
 | 
			
		||||
WorkingDirectory=/opt/wizarr
 | 
			
		||||
EnvironmentFile=/opt/wizarr/.env
 | 
			
		||||
ExecStart=/opt/wizarr/start.sh
 | 
			
		||||
Restart=on-abnormal
 | 
			
		||||
 | 
			
		||||
[Install]
 | 
			
		||||
WantedBy=multi-user.target
 | 
			
		||||
EOF
 | 
			
		||||
systemctl enable -q --now wizarr
 | 
			
		||||
msg_ok "Created env, start script and service"
 | 
			
		||||
 | 
			
		||||
motd_ssh
 | 
			
		||||
customize
 | 
			
		||||
 | 
			
		||||
msg_info "Cleaning up"
 | 
			
		||||
$STD apt-get -y autoremove
 | 
			
		||||
$STD apt-get -y autoclean
 | 
			
		||||
msg_ok "Cleaned"
 | 
			
		||||
@@ -1,52 +1,13 @@
 | 
			
		||||
# Copyright (c) 2021-2025 tteck
 | 
			
		||||
# Copyright (c) 2021-2025 community-scripts ORG
 | 
			
		||||
# Author: tteck (tteckster)
 | 
			
		||||
# Co-Author: MickLesk
 | 
			
		||||
# License: MIT
 | 
			
		||||
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
 | 
			
		||||
# This function sets color variables for formatting output in the terminal
 | 
			
		||||
color() {
 | 
			
		||||
  # Colors
 | 
			
		||||
  YW=$(echo "\033[33m")
 | 
			
		||||
  BL=$(echo "\033[36m")
 | 
			
		||||
  RD=$(echo "\033[01;31m")
 | 
			
		||||
  GN=$(echo "\033[1;92m")
 | 
			
		||||
 | 
			
		||||
  # Formatting
 | 
			
		||||
  CL=$(echo "\033[m")
 | 
			
		||||
  BFR="\\r\\033[K"
 | 
			
		||||
  BOLD=$(echo "\033[1m")
 | 
			
		||||
  TAB="  "
 | 
			
		||||
  TAB3="      "
 | 
			
		||||
 | 
			
		||||
  # System
 | 
			
		||||
  RETRY_NUM=10
 | 
			
		||||
  RETRY_EVERY=3
 | 
			
		||||
  i=$RETRY_NUM
 | 
			
		||||
 | 
			
		||||
  # Icons
 | 
			
		||||
  CM="${TAB}✔️${TAB}${CL}"
 | 
			
		||||
  CROSS="${TAB}✖️${TAB}${CL}"
 | 
			
		||||
  INFO="${TAB}💡${TAB}${CL}"
 | 
			
		||||
  NETWORK="${TAB}📡${TAB}${CL}"
 | 
			
		||||
  OS="${TAB}🖥️${TAB}${CL}"
 | 
			
		||||
  HOSTNAME="${TAB}🏠${TAB}${CL}"
 | 
			
		||||
  GATEWAY="${TAB}🌐${TAB}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Function to set STD mode based on verbosity
 | 
			
		||||
set_std_mode() {
 | 
			
		||||
  if [ "$VERBOSE" = "yes" ]; then
 | 
			
		||||
    STD=""
 | 
			
		||||
  else
 | 
			
		||||
    STD="silent"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Silent execution function
 | 
			
		||||
silent() {
 | 
			
		||||
  "$@" >/dev/null 2>&1
 | 
			
		||||
}
 | 
			
		||||
if ! command -v curl >/dev/null 2>&1; then
 | 
			
		||||
  apk update && apk add curl >/dev/null 2>&1
 | 
			
		||||
fi
 | 
			
		||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
 | 
			
		||||
load_functions
 | 
			
		||||
 | 
			
		||||
# This function enables IPv6 if it's not disabled and sets verbose mode
 | 
			
		||||
verb_ip6() {
 | 
			
		||||
@@ -74,33 +35,15 @@ error_handler() {
 | 
			
		||||
  echo -e "\n$error_message\n"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays an informational message with a yellow color.
 | 
			
		||||
msg_info() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -ne " ${TAB}${YW}${msg}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays a success message with a green color.
 | 
			
		||||
msg_ok() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -e "${BFR}${CM}${GN}${msg}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays a error message with a red color.
 | 
			
		||||
msg_error() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
 | 
			
		||||
setting_up_container() {
 | 
			
		||||
  msg_info "Setting up Container OS"
 | 
			
		||||
  while [ "$i" -gt 0 ]; do
 | 
			
		||||
  while [ $i -gt 0 ]; do
 | 
			
		||||
    if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
 | 
			
		||||
      break
 | 
			
		||||
    fi
 | 
			
		||||
    echo 1>&2 -en "${CROSS}${RD} No Network! "
 | 
			
		||||
    sleep "$RETRY_EVERY"
 | 
			
		||||
    sleep $RETRY_EVERY
 | 
			
		||||
    i=$((i - 1))
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
@@ -149,10 +92,9 @@ update_os() {
 | 
			
		||||
 | 
			
		||||
# This function modifies the message of the day (motd) and SSH settings
 | 
			
		||||
motd_ssh() {
 | 
			
		||||
  # Set terminal to 256-color mode
 | 
			
		||||
  echo "export TERM='xterm-256color'" >>/root/.bashrc
 | 
			
		||||
  IP=$(ip -4 addr show eth0 | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1)
 | 
			
		||||
  # Get OS information
 | 
			
		||||
 | 
			
		||||
  if [ -f "/etc/os-release" ]; then
 | 
			
		||||
    OS_NAME=$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '"')
 | 
			
		||||
    OS_VERSION=$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"')
 | 
			
		||||
@@ -213,6 +155,6 @@ EOF
 | 
			
		||||
    msg_ok "Customized Container"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVE/raw/main/ct/${app}.sh)\"" >/usr/bin/update
 | 
			
		||||
  echo "bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)\"" >/usr/bin/update
 | 
			
		||||
  chmod +x /usr/bin/update
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
post_to_api() {
 | 
			
		||||
 | 
			
		||||
  if ! command -v curl &> /dev/null; then
 | 
			
		||||
  if ! command -v curl &>/dev/null; then
 | 
			
		||||
    return
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
@@ -20,7 +20,8 @@ post_to_api() {
 | 
			
		||||
  local pve_version="not found"
 | 
			
		||||
  pve_version=$(pveversion | awk -F'[/ ]' '{print $2}')
 | 
			
		||||
 | 
			
		||||
  JSON_PAYLOAD=$(cat <<EOF
 | 
			
		||||
  JSON_PAYLOAD=$(
 | 
			
		||||
    cat <<EOF
 | 
			
		||||
{
 | 
			
		||||
    "ct_type": $CT_TYPE,
 | 
			
		||||
    "type":"lxc",
 | 
			
		||||
@@ -37,12 +38,12 @@ post_to_api() {
 | 
			
		||||
    "random_id": "$RANDOM_UUID"
 | 
			
		||||
}
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  if [[ "$DIAGNOSTICS" == "yes" ]]; then
 | 
			
		||||
    RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
 | 
			
		||||
    -H "Content-Type: application/json" \
 | 
			
		||||
    -d "$JSON_PAYLOAD") || true
 | 
			
		||||
      -H "Content-Type: application/json" \
 | 
			
		||||
      -d "$JSON_PAYLOAD") || true
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -52,7 +53,7 @@ post_to_api_vm() {
 | 
			
		||||
    return
 | 
			
		||||
  fi
 | 
			
		||||
  DIAGNOSTICS=$(grep -i "^DIAGNOSTICS=" /usr/local/community-scripts/diagnostics | awk -F'=' '{print $2}')
 | 
			
		||||
  if ! command -v curl &> /dev/null; then
 | 
			
		||||
  if ! command -v curl &>/dev/null; then
 | 
			
		||||
    return
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
@@ -70,7 +71,8 @@ post_to_api_vm() {
 | 
			
		||||
 | 
			
		||||
  DISK_SIZE_API=${DISK_SIZE%G}
 | 
			
		||||
 | 
			
		||||
  JSON_PAYLOAD=$(cat <<EOF
 | 
			
		||||
  JSON_PAYLOAD=$(
 | 
			
		||||
    cat <<EOF
 | 
			
		||||
{
 | 
			
		||||
    "ct_type": 2,
 | 
			
		||||
    "type":"vm",
 | 
			
		||||
@@ -87,42 +89,43 @@ post_to_api_vm() {
 | 
			
		||||
    "random_id": "$RANDOM_UUID"
 | 
			
		||||
}
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  if [[ "$DIAGNOSTICS" == "yes" ]]; then
 | 
			
		||||
    RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
 | 
			
		||||
    -H "Content-Type: application/json" \
 | 
			
		||||
    -d "$JSON_PAYLOAD") || true
 | 
			
		||||
      -H "Content-Type: application/json" \
 | 
			
		||||
      -d "$JSON_PAYLOAD") || true
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
POST_UPDATE_DONE=false
 | 
			
		||||
post_update_to_api() {
 | 
			
		||||
 | 
			
		||||
    if ! command -v curl &> /dev/null; then
 | 
			
		||||
      return
 | 
			
		||||
    fi
 | 
			
		||||
  if ! command -v curl &>/dev/null; then
 | 
			
		||||
    return
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
    if [ "$POST_UPDATE_DONE" = true ]; then
 | 
			
		||||
        return 0
 | 
			
		||||
    fi
 | 
			
		||||
    local API_URL="http://api.community-scripts.org/upload/updatestatus"    
 | 
			
		||||
    local status="${1:-failed}"
 | 
			
		||||
    local error="${2:-No error message}"
 | 
			
		||||
  if [ "$POST_UPDATE_DONE" = true ]; then
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
  local API_URL="http://api.community-scripts.org/upload/updatestatus"
 | 
			
		||||
  local status="${1:-failed}"
 | 
			
		||||
  local error="${2:-No error message}"
 | 
			
		||||
 | 
			
		||||
    JSON_PAYLOAD=$(cat <<EOF
 | 
			
		||||
  JSON_PAYLOAD=$(
 | 
			
		||||
    cat <<EOF
 | 
			
		||||
{
 | 
			
		||||
    "status": "$status",
 | 
			
		||||
    "error": "$error",
 | 
			
		||||
    "random_id": "$RANDOM_UUID"
 | 
			
		||||
}
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
   
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  if [[ "$DIAGNOSTICS" == "yes" ]]; then
 | 
			
		||||
    RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
 | 
			
		||||
    -H "Content-Type: application/json" \
 | 
			
		||||
    -d "$JSON_PAYLOAD") || true
 | 
			
		||||
      -H "Content-Type: application/json" \
 | 
			
		||||
      -d "$JSON_PAYLOAD") || true
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  POST_UPDATE_DONE=true
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										383
									
								
								misc/build.func
									
									
									
									
									
								
							
							
						
						
									
										383
									
								
								misc/build.func
									
									
									
									
									
								
							@@ -12,56 +12,20 @@ variables() {
 | 
			
		||||
  DIAGNOSTICS="yes"                                 # sets the DIAGNOSTICS variable to "yes", used for the API call.
 | 
			
		||||
  METHOD="default"                                  # sets the METHOD variable to "default", used for the API call.
 | 
			
		||||
  RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable.
 | 
			
		||||
  CT_TYPE=${var_unprivileged:-$CT_TYPE}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
 | 
			
		||||
 | 
			
		||||
# This function sets various color variables using ANSI escape codes for formatting text in the terminal.
 | 
			
		||||
color() {
 | 
			
		||||
  # Colors
 | 
			
		||||
  YW=$(echo "\033[33m")
 | 
			
		||||
  YWB=$(echo "\033[93m")
 | 
			
		||||
  BL=$(echo "\033[36m")
 | 
			
		||||
  RD=$(echo "\033[01;31m")
 | 
			
		||||
  BGN=$(echo "\033[4;92m")
 | 
			
		||||
  GN=$(echo "\033[1;92m")
 | 
			
		||||
  DGN=$(echo "\033[32m")
 | 
			
		||||
 | 
			
		||||
  # Formatting
 | 
			
		||||
  CL=$(echo "\033[m")
 | 
			
		||||
  BOLD=$(echo "\033[1m")
 | 
			
		||||
  HOLD=" "
 | 
			
		||||
  TAB="  "
 | 
			
		||||
  TAB3="      "
 | 
			
		||||
 | 
			
		||||
  # Icons
 | 
			
		||||
  CM="${TAB}✔️${TAB}"
 | 
			
		||||
  CROSS="${TAB}✖️${TAB}"
 | 
			
		||||
  INFO="${TAB}💡${TAB}${CL}"
 | 
			
		||||
  OS="${TAB}🖥️${TAB}${CL}"
 | 
			
		||||
  OSVERSION="${TAB}🌟${TAB}${CL}"
 | 
			
		||||
  CONTAINERTYPE="${TAB}📦${TAB}${CL}"
 | 
			
		||||
  DISKSIZE="${TAB}💾${TAB}${CL}"
 | 
			
		||||
  CPUCORE="${TAB}🧠${TAB}${CL}"
 | 
			
		||||
  RAMSIZE="${TAB}🛠️${TAB}${CL}"
 | 
			
		||||
  SEARCH="${TAB}🔍${TAB}${CL}"
 | 
			
		||||
  VERBOSE_CROPPED="🔍${TAB}"
 | 
			
		||||
  VERIFYPW="${TAB}🔐${TAB}${CL}"
 | 
			
		||||
  CONTAINERID="${TAB}🆔${TAB}${CL}"
 | 
			
		||||
  HOSTNAME="${TAB}🏠${TAB}${CL}"
 | 
			
		||||
  BRIDGE="${TAB}🌉${TAB}${CL}"
 | 
			
		||||
  NETWORK="${TAB}📡${TAB}${CL}"
 | 
			
		||||
  GATEWAY="${TAB}🌐${TAB}${CL}"
 | 
			
		||||
  DISABLEIPV6="${TAB}🚫${TAB}${CL}"
 | 
			
		||||
  DEFAULT="${TAB}⚙️${TAB}${CL}"
 | 
			
		||||
  MACADDRESS="${TAB}🔗${TAB}${CL}"
 | 
			
		||||
  VLANTAG="${TAB}🏷️${TAB}${CL}"
 | 
			
		||||
  ROOTSSH="${TAB}🔑${TAB}${CL}"
 | 
			
		||||
  CREATING="${TAB}🚀${TAB}${CL}"
 | 
			
		||||
  ADVANCED="${TAB}🧩${TAB}${CL}"
 | 
			
		||||
  FUSE="${TAB}🗂️${TAB}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if command -v curl >/dev/null 2>&1; then
 | 
			
		||||
  source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
 | 
			
		||||
  load_functions
 | 
			
		||||
  #echo "(build.func) Loaded core.func via curl"
 | 
			
		||||
elif command -v wget >/dev/null 2>&1; then
 | 
			
		||||
  source <(wget -qO- https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
 | 
			
		||||
  load_functions
 | 
			
		||||
  #echo "(build.func) Loaded core.func via wget"
 | 
			
		||||
fi
 | 
			
		||||
# This function enables error handling in the script by setting options and defining a trap for the ERR signal.
 | 
			
		||||
catch_errors() {
 | 
			
		||||
  set -Eeuo pipefail
 | 
			
		||||
@@ -71,7 +35,6 @@ catch_errors() {
 | 
			
		||||
# This function is called when an error occurs. It receives the exit code, line number, and command that caused the error, and displays an error message.
 | 
			
		||||
error_handler() {
 | 
			
		||||
  source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
 | 
			
		||||
  if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
 | 
			
		||||
  printf "\e[?25h"
 | 
			
		||||
  local exit_code="$?"
 | 
			
		||||
  local line_number="$1"
 | 
			
		||||
@@ -81,78 +44,6 @@ error_handler() {
 | 
			
		||||
  echo -e "\n$error_message\n"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays an informational message with logging support.
 | 
			
		||||
declare -A MSG_INFO_SHOWN
 | 
			
		||||
SPINNER_ACTIVE=0
 | 
			
		||||
SPINNER_PID=""
 | 
			
		||||
SPINNER_MSG=""
 | 
			
		||||
 | 
			
		||||
trap 'stop_spinner' EXIT INT TERM HUP
 | 
			
		||||
 | 
			
		||||
start_spinner() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  local frames=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
 | 
			
		||||
  local spin_i=0
 | 
			
		||||
  local interval=0.1
 | 
			
		||||
 | 
			
		||||
  SPINNER_MSG="$msg"
 | 
			
		||||
  printf "\r\e[2K" >&2
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do
 | 
			
		||||
      printf "\r\e[2K%s %b" "${frames[spin_i]}" "${YW}${SPINNER_MSG}${CL}" >&2
 | 
			
		||||
      spin_i=$(((spin_i + 1) % ${#frames[@]}))
 | 
			
		||||
      sleep "$interval"
 | 
			
		||||
    done
 | 
			
		||||
  } &
 | 
			
		||||
 | 
			
		||||
  SPINNER_PID=$!
 | 
			
		||||
  disown "$SPINNER_PID"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
stop_spinner() {
 | 
			
		||||
  if [[ ${SPINNER_PID+v} && -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
 | 
			
		||||
    kill "$SPINNER_PID" 2>/dev/null
 | 
			
		||||
    sleep 0.1
 | 
			
		||||
    kill -0 "$SPINNER_PID" 2>/dev/null && kill -9 "$SPINNER_PID" 2>/dev/null
 | 
			
		||||
    wait "$SPINNER_PID" 2>/dev/null || true
 | 
			
		||||
  fi
 | 
			
		||||
  SPINNER_ACTIVE=0
 | 
			
		||||
  unset SPINNER_PID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
spinner_guard() {
 | 
			
		||||
  if [[ "$SPINNER_ACTIVE" -eq 1 ]] && [[ -n "$SPINNER_PID" ]]; then
 | 
			
		||||
    kill "$SPINNER_PID" 2>/dev/null
 | 
			
		||||
    wait "$SPINNER_PID" 2>/dev/null || true
 | 
			
		||||
    SPINNER_ACTIVE=0
 | 
			
		||||
    unset SPINNER_PID
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
msg_info() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  [[ -n "${MSG_INFO_SHOWN["$msg"]+x}" ]] && return
 | 
			
		||||
  MSG_INFO_SHOWN["$msg"]=1
 | 
			
		||||
 | 
			
		||||
  spinner_guard
 | 
			
		||||
  SPINNER_ACTIVE=1
 | 
			
		||||
  start_spinner "$msg"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
msg_ok() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  stop_spinner
 | 
			
		||||
  printf "\r\e[2K%s %b\n" "${CM}" "${GN}${msg}${CL}" >&2
 | 
			
		||||
  unset MSG_INFO_SHOWN["$msg"]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
msg_error() {
 | 
			
		||||
  stop_spinner
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  printf "\r\e[2K%s %b\n" "${CROSS}" "${RD}${msg}${CL}" >&2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Check if the shell is using bash
 | 
			
		||||
shell_check() {
 | 
			
		||||
  if [[ "$(basename "$SHELL")" != "bash" ]]; then
 | 
			
		||||
@@ -273,42 +164,6 @@ update_motd_ip() {
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Function to download & save header files
 | 
			
		||||
get_header() {
 | 
			
		||||
  local app_name=$(echo "${APP,,}" | tr -d ' ')
 | 
			
		||||
  local header_url="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/headers/${app_name}"
 | 
			
		||||
  local local_header_path="/usr/local/community-scripts/headers/${app_name}"
 | 
			
		||||
 | 
			
		||||
  mkdir -p "$(dirname "$local_header_path")"
 | 
			
		||||
 | 
			
		||||
  if [ ! -s "$local_header_path" ]; then
 | 
			
		||||
    if ! curl -fsSL "$header_url" -o "$local_header_path"; then
 | 
			
		||||
      echo -e "Failed to download header for ${app_name}. No header will be displayed."
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  cat "$local_header_path"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function sets the APP-Name into an ASCII Header in Slant, figlet needed on proxmox main node.
 | 
			
		||||
header_info() {
 | 
			
		||||
  local app_name=$(echo "${APP,,}" | tr -d ' ')
 | 
			
		||||
  local header_content
 | 
			
		||||
 | 
			
		||||
  # Download & save Header-File locally
 | 
			
		||||
  header_content=$(get_header "$app_name")
 | 
			
		||||
  if [ $? -ne 0 ]; then
 | 
			
		||||
    # Fallback: Doesn't show Header
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Show ASCII-Header
 | 
			
		||||
  term_width=$(tput cols 2>/dev/null || echo 120)
 | 
			
		||||
  clear
 | 
			
		||||
  echo "$header_content"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function checks if the script is running through SSH and prompts the user to confirm if they want to proceed or exit.
 | 
			
		||||
ssh_check() {
 | 
			
		||||
  if [ -n "${SSH_CLIENT:+x}" ]; then
 | 
			
		||||
@@ -346,8 +201,8 @@ base_settings() {
 | 
			
		||||
  SSH="no"
 | 
			
		||||
  SSH_AUTHORIZED_KEY=""
 | 
			
		||||
  TAGS="community-script;"
 | 
			
		||||
  ENABLE_FUSE="no"
 | 
			
		||||
  ENABLE_TUN="no"
 | 
			
		||||
  ENABLE_FUSE="${1:-no}"
 | 
			
		||||
  ENABLE_TUN="${1:-no}"
 | 
			
		||||
 | 
			
		||||
  # Override default settings with variables from ct script
 | 
			
		||||
  CT_TYPE=${var_unprivileged:-$CT_TYPE}
 | 
			
		||||
@@ -370,7 +225,7 @@ base_settings() {
 | 
			
		||||
write_config() {
 | 
			
		||||
  mkdir -p /opt/community-scripts
 | 
			
		||||
  # This function writes the configuration to a file.
 | 
			
		||||
  if whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "Write configfile" --yesno "Do you want to write the selections to a config file?" 10 60; then
 | 
			
		||||
  if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Write configfile" --yesno "Do you want to write the selections to a config file?" 10 60; then
 | 
			
		||||
    FILEPATH="/opt/community-scripts/${NSAPP}.conf"
 | 
			
		||||
    if [[ ! -f $FILEPATH ]]; then
 | 
			
		||||
      cat <<EOF >"$FILEPATH"
 | 
			
		||||
@@ -403,7 +258,7 @@ EOF
 | 
			
		||||
      echo -e "${INFO}${BOLD}${GN}Writing configuration to ${FILEPATH}${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${INFO}${BOLD}${RD}Configuration file already exists at ${FILEPATH}${CL}"
 | 
			
		||||
      if whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "Overwrite configfile" --yesno "Do you want to overwrite the existing config file?" 10 60; then
 | 
			
		||||
      if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Overwrite configfile" --yesno "Do you want to overwrite the existing config file?" 10 60; then
 | 
			
		||||
        rm -f "$FILEPATH"
 | 
			
		||||
        cat <<EOF >"$FILEPATH"
 | 
			
		||||
# ${NSAPP} Configuration File
 | 
			
		||||
@@ -518,30 +373,38 @@ advanced_settings() {
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nSet Root Password (needed for root ssh access)" 9 58 --title "PASSWORD (leave blank for automatic login)" 3>&1 1>&2 2>&3); then
 | 
			
		||||
      if [[ ! -z "$PW1" ]]; then
 | 
			
		||||
        if [[ "$PW1" == *" "* ]]; then
 | 
			
		||||
          whiptail --msgbox "Password cannot contain spaces. Please try again." 8 58
 | 
			
		||||
        elif [ ${#PW1} -lt 5 ]; then
 | 
			
		||||
          whiptail --msgbox "Password must be at least 5 characters long. Please try again." 8 58
 | 
			
		||||
        else
 | 
			
		||||
          if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then
 | 
			
		||||
            if [[ "$PW1" == "$PW2" ]]; then
 | 
			
		||||
              PW="-password $PW1"
 | 
			
		||||
              echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}"
 | 
			
		||||
              break
 | 
			
		||||
            else
 | 
			
		||||
              whiptail --msgbox "Passwords do not match. Please try again." 8 58
 | 
			
		||||
            fi
 | 
			
		||||
          else
 | 
			
		||||
            exit_script
 | 
			
		||||
          fi
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        PW1="Automatic Login"
 | 
			
		||||
      # Empty = Autologin
 | 
			
		||||
      if [[ -z "$PW1" ]]; then
 | 
			
		||||
        PW=""
 | 
			
		||||
        PW1="Automatic Login"
 | 
			
		||||
        echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}$PW1${CL}"
 | 
			
		||||
        break
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      # Invalid: contains spaces
 | 
			
		||||
      if [[ "$PW1" == *" "* ]]; then
 | 
			
		||||
        whiptail --msgbox "Password cannot contain spaces." 8 58
 | 
			
		||||
        continue
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      # Invalid: too short
 | 
			
		||||
      if ((${#PW1} < 5)); then
 | 
			
		||||
        whiptail --msgbox "Password must be at least 5 characters." 8 58
 | 
			
		||||
        continue
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      # Confirm password
 | 
			
		||||
      if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then
 | 
			
		||||
        if [[ "$PW1" == "$PW2" ]]; then
 | 
			
		||||
          PW="-password $PW1"
 | 
			
		||||
          echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}"
 | 
			
		||||
          break
 | 
			
		||||
        else
 | 
			
		||||
          whiptail --msgbox "Passwords do not match. Please try again." 8 58
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        exit_script
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
@@ -558,53 +421,72 @@ advanced_settings() {
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if CT_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$NSAPP" --title "HOSTNAME" 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z "$CT_NAME" ]; then
 | 
			
		||||
      HN="$NSAPP"
 | 
			
		||||
  while true; do
 | 
			
		||||
    if CT_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$NSAPP" --title "HOSTNAME" 3>&1 1>&2 2>&3); then
 | 
			
		||||
      if [ -z "$CT_NAME" ]; then
 | 
			
		||||
        HN="$NSAPP"
 | 
			
		||||
      else
 | 
			
		||||
        HN=$(echo "${CT_NAME,,}" | tr -d ' ')
 | 
			
		||||
      fi
 | 
			
		||||
      # Hostname validate (RFC 1123)
 | 
			
		||||
      if [[ "$HN" =~ ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ ]]; then
 | 
			
		||||
        echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
 | 
			
		||||
        break
 | 
			
		||||
      else
 | 
			
		||||
        whiptail --backtitle "Proxmox VE Helper Scripts" \
 | 
			
		||||
          --msgbox "❌ Invalid hostname: '$HN'\n\nOnly lowercase letters, digits and hyphens (-) are allowed.\nUnderscores (_) or other characters are not permitted!" 10 70
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      HN=$(echo "${CT_NAME,,}" | tr -d ' ')
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
    echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
 | 
			
		||||
  else
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GB" 8 58 "$var_disk" --title "DISK SIZE" 3>&1 1>&2 2>&3) || exit_script
 | 
			
		||||
 | 
			
		||||
  if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GB" 8 58 "$var_disk" --title "DISK SIZE" 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z "$DISK_SIZE" ]; then
 | 
			
		||||
      DISK_SIZE="$var_disk"
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      if ! [[ $DISK_SIZE =~ $INTEGER ]]; then
 | 
			
		||||
        echo -e "{INFO}${HOLD}${RD} DISK SIZE MUST BE AN INTEGER NUMBER!${CL}"
 | 
			
		||||
        advanced_settings
 | 
			
		||||
      fi
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 "$var_cpu" --title "CORE COUNT" 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [[ "$DISK_SIZE" =~ ^[1-9][0-9]*$ ]]; then
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
 | 
			
		||||
      break
 | 
			
		||||
    else
 | 
			
		||||
      whiptail --msgbox "Disk size must be a positive integer!" 8 58
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
 | 
			
		||||
      --inputbox "Allocate CPU Cores" 8 58 "$var_cpu" --title "CORE COUNT" 3>&1 1>&2 2>&3) || exit_script
 | 
			
		||||
 | 
			
		||||
    if [ -z "$CORE_COUNT" ]; then
 | 
			
		||||
      CORE_COUNT="$var_cpu"
 | 
			
		||||
      echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 "$var_ram" --title "RAM" 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [[ "$CORE_COUNT" =~ ^[1-9][0-9]*$ ]]; then
 | 
			
		||||
      echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
 | 
			
		||||
      break
 | 
			
		||||
    else
 | 
			
		||||
      whiptail --msgbox "CPU core count must be a positive integer!" 8 58
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
 | 
			
		||||
      --inputbox "Allocate RAM in MiB" 8 58 "$var_ram" --title "RAM" 3>&1 1>&2 2>&3) || exit_script
 | 
			
		||||
 | 
			
		||||
    if [ -z "$RAM_SIZE" ]; then
 | 
			
		||||
      RAM_SIZE="$var_ram"
 | 
			
		||||
      echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
    if [[ "$RAM_SIZE" =~ ^[1-9][0-9]*$ ]]; then
 | 
			
		||||
      echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
 | 
			
		||||
      break
 | 
			
		||||
    else
 | 
			
		||||
      whiptail --msgbox "RAM size must be a positive integer!" 8 58
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  BRIDGES=""
 | 
			
		||||
  IFACE_FILEPATH_LIST="/etc/network/interfaces"$'\n'$(find "/etc/network/interfaces.d/" -type f)
 | 
			
		||||
@@ -779,14 +661,14 @@ advanced_settings() {
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  SSH_AUTHORIZED_KEY="$(whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --inputbox "SSH Authorized key for root (leave empty for none)" 8 58 --title "SSH Key" 3>&1 1>&2 2>&3)"
 | 
			
		||||
  SSH_AUTHORIZED_KEY="$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "SSH Authorized key for root (leave empty for none)" 8 58 --title "SSH Key" 3>&1 1>&2 2>&3)"
 | 
			
		||||
 | 
			
		||||
  if [[ -z "${SSH_AUTHORIZED_KEY}" ]]; then
 | 
			
		||||
    SSH_AUTHORIZED_KEY=""
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ "$PW" == -password* || -n "$SSH_AUTHORIZED_KEY" ]]; then
 | 
			
		||||
    if (whiptail --backtitle "[dev] Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable Root SSH Access?" 10 58); then
 | 
			
		||||
    if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH ACCESS" --yesno "Enable Root SSH Access?" 10 58); then
 | 
			
		||||
      SSH="yes"
 | 
			
		||||
    else
 | 
			
		||||
      SSH="no"
 | 
			
		||||
@@ -805,11 +687,11 @@ advanced_settings() {
 | 
			
		||||
  echo -e "${FUSE}${BOLD}${DGN}Enable FUSE Support: ${BGN}$ENABLE_FUSE${CL}"
 | 
			
		||||
 | 
			
		||||
  if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then
 | 
			
		||||
    VERB="yes"
 | 
			
		||||
    VERBOSE="yes"
 | 
			
		||||
  else
 | 
			
		||||
    VERB="no"
 | 
			
		||||
    VERBOSE="no"
 | 
			
		||||
  fi
 | 
			
		||||
  echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERB${CL}"
 | 
			
		||||
  echo -e "${SEARCH}${BOLD}${DGN}Verbose Mode: ${BGN}$VERBOSE${CL}"
 | 
			
		||||
 | 
			
		||||
  if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create ${APP} LXC?" 10 58); then
 | 
			
		||||
    echo -e "${CREATING}${BOLD}${RD}Creating a ${APP} LXC using the above advanced settings${CL}"
 | 
			
		||||
@@ -925,18 +807,18 @@ install_script() {
 | 
			
		||||
    1)
 | 
			
		||||
      header_info
 | 
			
		||||
      echo -e "${DEFAULT}${BOLD}${BL}Using Default Settings on node $PVEHOST_NAME${CL}"
 | 
			
		||||
      VERB="no"
 | 
			
		||||
      VERBOSE="no"
 | 
			
		||||
      METHOD="default"
 | 
			
		||||
      base_settings "$VERB"
 | 
			
		||||
      base_settings "$VERBOSE"
 | 
			
		||||
      echo_default
 | 
			
		||||
      break
 | 
			
		||||
      ;;
 | 
			
		||||
    2)
 | 
			
		||||
      header_info
 | 
			
		||||
      echo -e "${DEFAULT}${BOLD}${BL}Using Default Settings on node $PVEHOST_NAME (${VERBOSE_CROPPED}Verbose)${CL}"
 | 
			
		||||
      VERB="yes"
 | 
			
		||||
      VERBOSE="yes"
 | 
			
		||||
      METHOD="default"
 | 
			
		||||
      base_settings "$VERB"
 | 
			
		||||
      base_settings "$VERBOSE"
 | 
			
		||||
      echo_default
 | 
			
		||||
      break
 | 
			
		||||
      ;;
 | 
			
		||||
@@ -1027,16 +909,8 @@ check_container_storage() {
 | 
			
		||||
start() {
 | 
			
		||||
  source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
 | 
			
		||||
  if command -v pveversion >/dev/null 2>&1; then
 | 
			
		||||
    if ! (whiptail --backtitle "Proxmox VE Helper Scripts" --title "${APP} LXC" --yesno "This will create a New ${APP} LXC. Proceed?" 10 58); then
 | 
			
		||||
      clear
 | 
			
		||||
      exit_script
 | 
			
		||||
      exit
 | 
			
		||||
    fi
 | 
			
		||||
    SPINNER_PID=""
 | 
			
		||||
    install_script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if ! command -v pveversion >/dev/null 2>&1; then
 | 
			
		||||
  else
 | 
			
		||||
    CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "${APP} LXC Update/Setting" --menu \
 | 
			
		||||
      "Support/Update functions for ${APP} LXC. Choose an option:" \
 | 
			
		||||
      12 60 3 \
 | 
			
		||||
@@ -1046,11 +920,11 @@ start() {
 | 
			
		||||
 | 
			
		||||
    case "$CHOICE" in
 | 
			
		||||
    1)
 | 
			
		||||
      VERB="no"
 | 
			
		||||
      VERBOSE="no"
 | 
			
		||||
      set_std_mode
 | 
			
		||||
      ;;
 | 
			
		||||
    2)
 | 
			
		||||
      VERB="yes"
 | 
			
		||||
      VERBOSE="yes"
 | 
			
		||||
      set_std_mode
 | 
			
		||||
      ;;
 | 
			
		||||
    3)
 | 
			
		||||
@@ -1059,15 +933,13 @@ start() {
 | 
			
		||||
      exit
 | 
			
		||||
      ;;
 | 
			
		||||
    esac
 | 
			
		||||
 | 
			
		||||
    SPINNER_PID=""
 | 
			
		||||
    update_script
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function collects user settings and integrates all the collected information.
 | 
			
		||||
build_container() {
 | 
			
		||||
  #  if [ "$VERB" == "yes" ]; then set -x; fi
 | 
			
		||||
  #  if [ "$VERBOSE" == "yes" ]; then set -x; fi
 | 
			
		||||
 | 
			
		||||
  if [ "$CT_TYPE" == "1" ]; then
 | 
			
		||||
    FEATURES="keyctl=1,nesting=1"
 | 
			
		||||
@@ -1100,7 +972,7 @@ build_container() {
 | 
			
		||||
  export APPLICATION="$APP"
 | 
			
		||||
  export app="$NSAPP"
 | 
			
		||||
  export PASSWORD="$PW"
 | 
			
		||||
  export VERBOSE="$VERB"
 | 
			
		||||
  export VERBOSE="$VERBOSE"
 | 
			
		||||
  export SSH_ROOT="${SSH}"
 | 
			
		||||
  export SSH_AUTHORIZED_KEY
 | 
			
		||||
  export CTID="$CT_ID"
 | 
			
		||||
@@ -1124,7 +996,7 @@ build_container() {
 | 
			
		||||
    $PW
 | 
			
		||||
  "
 | 
			
		||||
  # This executes create_lxc.sh and creates the container and .conf file
 | 
			
		||||
  bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/create_lxc.sh)" $?
 | 
			
		||||
  bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/create_lxc.sh)" $?
 | 
			
		||||
 | 
			
		||||
  LXC_CONFIG=/etc/pve/lxc/${CTID}.conf
 | 
			
		||||
  if [ "$CT_TYPE" == "0" ]; then
 | 
			
		||||
@@ -1185,16 +1057,30 @@ EOF
 | 
			
		||||
  msg_info "Starting LXC Container"
 | 
			
		||||
  pct start "$CTID"
 | 
			
		||||
  msg_ok "Started LXC Container"
 | 
			
		||||
  msg_info "Customizing LXC Container"
 | 
			
		||||
  if [ "$var_os" == "alpine" ]; then
 | 
			
		||||
    sleep 3
 | 
			
		||||
    pct exec "$CTID" -- /bin/sh -c 'cat <<EOF >/etc/apk/repositories
 | 
			
		||||
http://dl-cdn.alpinelinux.org/alpine/latest-stable/main
 | 
			
		||||
http://dl-cdn.alpinelinux.org/alpine/latest-stable/community
 | 
			
		||||
EOF'
 | 
			
		||||
    pct exec "$CTID" -- ash -c "apk add bash >/dev/null"
 | 
			
		||||
  fi
 | 
			
		||||
  lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/"$var_install".sh)" $?
 | 
			
		||||
    pct exec "$CTID" -- ash -c "apk add bash newt curl openssh nano mc ncurses >/dev/null"
 | 
			
		||||
  else
 | 
			
		||||
    sleep 3
 | 
			
		||||
    # Set locale and timezone before update
 | 
			
		||||
    pct exec "$CTID" -- bash -c "sed -i '/$LANG/ s/^# //' /etc/locale.gen"
 | 
			
		||||
    pct exec "$CTID" -- bash -c "locale_line=\$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print \$1}' | head -n 1) && \
 | 
			
		||||
    echo LANG=\$locale_line >/etc/default/locale && \
 | 
			
		||||
    locale-gen >/dev/null && \
 | 
			
		||||
    export LANG=\$locale_line"
 | 
			
		||||
 | 
			
		||||
    pct exec "$CTID" -- bash -c "echo $tz >/etc/timezone && ln -sf /usr/share/zoneinfo/$tz /etc/localtime"
 | 
			
		||||
 | 
			
		||||
    # Install curl
 | 
			
		||||
    pct exec "$CTID" -- bash -c "apt-get update >/dev/null && apt-get install -y sudo curl mc gnupg2 >/dev/null"
 | 
			
		||||
  fi
 | 
			
		||||
  msg_ok "Customized LXC Container"
 | 
			
		||||
  lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/install/"$var_install".sh)" $?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function sets the description of the container.
 | 
			
		||||
@@ -1243,23 +1129,6 @@ EOF
 | 
			
		||||
  post_update_to_api "done" "none"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
set_std_mode() {
 | 
			
		||||
  if [ "$VERB" = "yes" ]; then
 | 
			
		||||
    STD=""
 | 
			
		||||
  else
 | 
			
		||||
    STD="silent"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Silent execution function
 | 
			
		||||
silent() {
 | 
			
		||||
  if [ "$VERB" = "no" ]; then
 | 
			
		||||
    "$@" >/dev/null 2>&1 || return 1
 | 
			
		||||
  else
 | 
			
		||||
    "$@" || return 1
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
api_exit_script() {
 | 
			
		||||
  exit_code=$? # Capture the exit status of the last executed command
 | 
			
		||||
  #200 exit codes indicate error in create_lxc.sh
 | 
			
		||||
 
 | 
			
		||||
@@ -53,15 +53,15 @@ config_file() {
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    if CT_ID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Container ID" 8 58 "$NEXTID" --title "CONTAINER ID" 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z "$CT_ID" ]; then
 | 
			
		||||
      CT_ID="$NEXTID"
 | 
			
		||||
      echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}"
 | 
			
		||||
      if [ -z "$CT_ID" ]; then
 | 
			
		||||
        CT_ID="$NEXTID"
 | 
			
		||||
        echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}"
 | 
			
		||||
      else
 | 
			
		||||
        echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}"
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${CONTAINERID}${BOLD}${DGN}Container ID: ${BGN}$CT_ID${CL}"
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  fi
 | 
			
		||||
  if [[ -n "${CT_TYPE-}" ]]; then
 | 
			
		||||
@@ -75,23 +75,22 @@ config_file() {
 | 
			
		||||
    fi
 | 
			
		||||
    echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}"
 | 
			
		||||
  else
 | 
			
		||||
   if CT_TYPE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CONTAINER TYPE" --radiolist "Choose Type" 10 58 2 \
 | 
			
		||||
        "1" "Unprivileged" ON \
 | 
			
		||||
        "0" "Privileged" OFF \
 | 
			
		||||
        3>&1 1>&2 2>&3); then
 | 
			
		||||
        if [ -n "$CT_TYPE" ]; then
 | 
			
		||||
          CT_TYPE_DESC="Unprivileged"
 | 
			
		||||
          if [ "$CT_TYPE" -eq 0 ]; then
 | 
			
		||||
            CT_TYPE_DESC="Privileged"
 | 
			
		||||
          fi
 | 
			
		||||
          echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}"
 | 
			
		||||
    if CT_TYPE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CONTAINER TYPE" --radiolist "Choose Type" 10 58 2 \
 | 
			
		||||
      "1" "Unprivileged" ON \
 | 
			
		||||
      "0" "Privileged" OFF \
 | 
			
		||||
      3>&1 1>&2 2>&3); then
 | 
			
		||||
      if [ -n "$CT_TYPE" ]; then
 | 
			
		||||
        CT_TYPE_DESC="Unprivileged"
 | 
			
		||||
        if [ "$CT_TYPE" -eq 0 ]; then
 | 
			
		||||
          CT_TYPE_DESC="Privileged"
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        exit_script
 | 
			
		||||
        echo -e "${CONTAINERTYPE}${BOLD}${DGN}Container Type: ${BGN}$CT_TYPE_DESC${CL}"
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  if [[ -n "${PW-}" ]]; then
 | 
			
		||||
    if [[ "$PW" == "none" ]]; then
 | 
			
		||||
      PW=""
 | 
			
		||||
@@ -109,50 +108,50 @@ config_file() {
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    while true; do
 | 
			
		||||
    if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nSet Root Password (needed for root ssh access)" 9 58 --title "PASSWORD (leave blank for automatic login)" 3>&1 1>&2 2>&3); then
 | 
			
		||||
      if [[ -n "$PW1" ]]; then
 | 
			
		||||
        if [[ "$PW1" == *" "* ]]; then
 | 
			
		||||
          whiptail --msgbox "Password cannot contain spaces. Please try again." 8 58
 | 
			
		||||
        elif [ ${#PW1} -lt 5 ]; then
 | 
			
		||||
          whiptail --msgbox "Password must be at least 5 characters long. Please try again." 8 58
 | 
			
		||||
        else
 | 
			
		||||
          if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then
 | 
			
		||||
            if [[ "$PW1" == "$PW2" ]]; then
 | 
			
		||||
              PW="-password $PW1"
 | 
			
		||||
              echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}"
 | 
			
		||||
              break
 | 
			
		||||
            else
 | 
			
		||||
              whiptail --msgbox "Passwords do not match. Please try again." 8 58
 | 
			
		||||
            fi
 | 
			
		||||
      if PW1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nSet Root Password (needed for root ssh access)" 9 58 --title "PASSWORD (leave blank for automatic login)" 3>&1 1>&2 2>&3); then
 | 
			
		||||
        if [[ -n "$PW1" ]]; then
 | 
			
		||||
          if [[ "$PW1" == *" "* ]]; then
 | 
			
		||||
            whiptail --msgbox "Password cannot contain spaces. Please try again." 8 58
 | 
			
		||||
          elif [ ${#PW1} -lt 5 ]; then
 | 
			
		||||
            whiptail --msgbox "Password must be at least 5 characters long. Please try again." 8 58
 | 
			
		||||
          else
 | 
			
		||||
            exit_script
 | 
			
		||||
            if PW2=$(whiptail --backtitle "Proxmox VE Helper Scripts" --passwordbox "\nVerify Root Password" 9 58 --title "PASSWORD VERIFICATION" 3>&1 1>&2 2>&3); then
 | 
			
		||||
              if [[ "$PW1" == "$PW2" ]]; then
 | 
			
		||||
                PW="-password $PW1"
 | 
			
		||||
                echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}********${CL}"
 | 
			
		||||
                break
 | 
			
		||||
              else
 | 
			
		||||
                whiptail --msgbox "Passwords do not match. Please try again." 8 58
 | 
			
		||||
              fi
 | 
			
		||||
            else
 | 
			
		||||
              exit_script
 | 
			
		||||
            fi
 | 
			
		||||
          fi
 | 
			
		||||
        else
 | 
			
		||||
          PW1="Automatic Login"
 | 
			
		||||
          PW=""
 | 
			
		||||
          echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}$PW1${CL}"
 | 
			
		||||
          break
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        PW1="Automatic Login"
 | 
			
		||||
        PW=""
 | 
			
		||||
        echo -e "${VERIFYPW}${BOLD}${DGN}Root Password: ${BGN}$PW1${CL}"
 | 
			
		||||
        break
 | 
			
		||||
        exit_script
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
    done
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ -n "${HN-}" ]]; then
 | 
			
		||||
    echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
 | 
			
		||||
  else
 | 
			
		||||
    if CT_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 "$NSAPP" --title "HOSTNAME" 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z "$CT_NAME" ]; then
 | 
			
		||||
      HN="$NSAPP"
 | 
			
		||||
      if [ -z "$CT_NAME" ]; then
 | 
			
		||||
        HN="$NSAPP"
 | 
			
		||||
      else
 | 
			
		||||
        HN=$(echo "${CT_NAME,,}" | tr -d ' ')
 | 
			
		||||
      fi
 | 
			
		||||
      echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      HN=$(echo "${CT_NAME,,}" | tr -d ' ')
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
    echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
 | 
			
		||||
  else
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ -n "${DISK_SIZE-}" ]]; then
 | 
			
		||||
@@ -164,19 +163,19 @@ config_file() {
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GB" 8 58 "$var_disk" --title "DISK SIZE" 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z "$DISK_SIZE" ]; then
 | 
			
		||||
      DISK_SIZE="$var_disk"
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      if ! [[ $DISK_SIZE =~ $INTEGER ]]; then
 | 
			
		||||
        echo -e "{INFO}${HOLD}${RD} DISK SIZE MUST BE AN INTEGER NUMBER!${CL}"
 | 
			
		||||
        advanced_settings
 | 
			
		||||
      if [ -z "$DISK_SIZE" ]; then
 | 
			
		||||
        DISK_SIZE="$var_disk"
 | 
			
		||||
        echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
 | 
			
		||||
      else
 | 
			
		||||
        if ! [[ $DISK_SIZE =~ $INTEGER ]]; then
 | 
			
		||||
          echo -e "{INFO}${HOLD}${RD} DISK SIZE MUST BE AN INTEGER NUMBER!${CL}"
 | 
			
		||||
          advanced_settings
 | 
			
		||||
        fi
 | 
			
		||||
        echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
 | 
			
		||||
      fi
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE} GB${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ -n "${CORE_COUNT-}" ]]; then
 | 
			
		||||
@@ -188,15 +187,15 @@ config_file() {
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 "$var_cpu" --title "CORE COUNT" 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z "$CORE_COUNT" ]; then
 | 
			
		||||
      CORE_COUNT="$var_cpu"
 | 
			
		||||
      echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
 | 
			
		||||
      if [ -z "$CORE_COUNT" ]; then
 | 
			
		||||
        CORE_COUNT="$var_cpu"
 | 
			
		||||
        echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
 | 
			
		||||
      else
 | 
			
		||||
        echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if [[ -n "${RAM_SIZE-}" ]]; then
 | 
			
		||||
@@ -208,15 +207,15 @@ config_file() {
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 "$var_ram" --title "RAM" 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z "$RAM_SIZE" ]; then
 | 
			
		||||
      RAM_SIZE="$var_ram"
 | 
			
		||||
      echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
 | 
			
		||||
      if [ -z "$RAM_SIZE" ]; then
 | 
			
		||||
        RAM_SIZE="$var_ram"
 | 
			
		||||
        echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
 | 
			
		||||
      else
 | 
			
		||||
        echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE} MiB${CL}"
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit_script
 | 
			
		||||
  fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  IFACE_FILEPATH_LIST="/etc/network/interfaces"$'\n'$(find "/etc/network/interfaces.d/" -type f)
 | 
			
		||||
@@ -227,20 +226,20 @@ config_file() {
 | 
			
		||||
  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}" || true
 | 
			
		||||
    (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}" || true
 | 
			
		||||
 | 
			
		||||
    if [ -f "${iface_indexes_tmpfile}" ]; then
 | 
			
		||||
 | 
			
		||||
        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)|ovs_type\s+OVSBridge)\b'; then
 | 
			
		||||
                iface_name=$(sed "${start}q;d" "${iface_filepath}" | awk '{print $2}')
 | 
			
		||||
                BRIDGES="${iface_name}"$'\n'"${BRIDGES}"
 | 
			
		||||
            fi
 | 
			
		||||
      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)|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
 | 
			
		||||
@@ -296,7 +295,7 @@ config_file() {
 | 
			
		||||
        done
 | 
			
		||||
      fi
 | 
			
		||||
    elif [[ "$NET" == *-* ]]; then
 | 
			
		||||
      IFS="-" read -r ip_start ip_end <<< "$NET"
 | 
			
		||||
      IFS="-" read -r ip_start ip_end <<<"$NET"
 | 
			
		||||
 | 
			
		||||
      if [[ ! "$ip_start" =~ $ip_cidr_regex ]] || [[ ! "$ip_end" =~ $ip_cidr_regex ]]; then
 | 
			
		||||
        msg_error "Invalid IP range format, was $NET should be 0.0.0.0/0-0.0.0.0/0"
 | 
			
		||||
@@ -309,21 +308,21 @@ config_file() {
 | 
			
		||||
 | 
			
		||||
      ip_to_int() {
 | 
			
		||||
        local IFS=.
 | 
			
		||||
        read -r i1 i2 i3 i4 <<< "$1"
 | 
			
		||||
        echo $(( (i1 << 24) + (i2 << 16) + (i3 << 8) + i4 ))
 | 
			
		||||
        read -r i1 i2 i3 i4 <<<"$1"
 | 
			
		||||
        echo $(((i1 << 24) + (i2 << 16) + (i3 << 8) + i4))
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      int_to_ip() {
 | 
			
		||||
        local ip=$1
 | 
			
		||||
        echo "$(( (ip >> 24) & 0xFF )).$(( (ip >> 16) & 0xFF )).$(( (ip >> 8) & 0xFF )).$(( ip & 0xFF ))"
 | 
			
		||||
        echo "$(((ip >> 24) & 0xFF)).$(((ip >> 16) & 0xFF)).$(((ip >> 8) & 0xFF)).$((ip & 0xFF))"
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      start_int=$(ip_to_int "$ip1")
 | 
			
		||||
      end_int=$(ip_to_int "$ip2")
 | 
			
		||||
 | 
			
		||||
      for ((ip_int=start_int; ip_int<=end_int; ip_int++)); do
 | 
			
		||||
      for ((ip_int = start_int; ip_int <= end_int; ip_int++)); do
 | 
			
		||||
        ip=$(int_to_ip $ip_int)
 | 
			
		||||
          msg_info "Checking IP: $ip"
 | 
			
		||||
        msg_info "Checking IP: $ip"
 | 
			
		||||
        if ! ping -c 2 -W 1 "$ip" >/dev/null 2>&1; then
 | 
			
		||||
          NET="$ip/$cidr"
 | 
			
		||||
          msg_ok "Using free IP Address: ${BGN}$NET${CL}"
 | 
			
		||||
@@ -363,37 +362,37 @@ config_file() {
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    while true; do
 | 
			
		||||
    NET=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Static IPv4 CIDR Address (/24)" 8 58 dhcp --title "IP ADDRESS" 3>&1 1>&2 2>&3)
 | 
			
		||||
    exit_status=$?
 | 
			
		||||
    if [ $exit_status -eq 0 ]; then
 | 
			
		||||
      if [ "$NET" = "dhcp" ]; then
 | 
			
		||||
        echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}"
 | 
			
		||||
        break
 | 
			
		||||
      else
 | 
			
		||||
        if [[ "$NET" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$ ]]; then
 | 
			
		||||
      NET=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Static IPv4 CIDR Address (/24)" 8 58 dhcp --title "IP ADDRESS" 3>&1 1>&2 2>&3)
 | 
			
		||||
      exit_status=$?
 | 
			
		||||
      if [ $exit_status -eq 0 ]; then
 | 
			
		||||
        if [ "$NET" = "dhcp" ]; then
 | 
			
		||||
          echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}"
 | 
			
		||||
          break
 | 
			
		||||
        else
 | 
			
		||||
          whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "$NET is an invalid IPv4 CIDR address. Please enter a valid IPv4 CIDR address or 'dhcp'" 8 58
 | 
			
		||||
          if [[ "$NET" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$ ]]; then
 | 
			
		||||
            echo -e "${NETWORK}${BOLD}${DGN}IP Address: ${BGN}$NET${CL}"
 | 
			
		||||
            break
 | 
			
		||||
          else
 | 
			
		||||
            whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "$NET is an invalid IPv4 CIDR address. Please enter a valid IPv4 CIDR address or 'dhcp'" 8 58
 | 
			
		||||
          fi
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        exit_script
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
    done
 | 
			
		||||
    if [ "$NET" != "dhcp" ]; then
 | 
			
		||||
    while true; do
 | 
			
		||||
      GATE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Enter gateway IP address" 8 58 --title "Gateway IP" 3>&1 1>&2 2>&3)
 | 
			
		||||
      if [ -z "$GATE1" ]; then
 | 
			
		||||
        whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Gateway IP address cannot be empty" 8 58
 | 
			
		||||
      elif [[ ! "$GATE1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
 | 
			
		||||
        whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Invalid IP address format" 8 58
 | 
			
		||||
      else
 | 
			
		||||
        GATE=",gw=$GATE1"
 | 
			
		||||
        echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE1${CL}"
 | 
			
		||||
        break
 | 
			
		||||
      fi
 | 
			
		||||
    done
 | 
			
		||||
      while true; do
 | 
			
		||||
        GATE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Enter gateway IP address" 8 58 --title "Gateway IP" 3>&1 1>&2 2>&3)
 | 
			
		||||
        if [ -z "$GATE1" ]; then
 | 
			
		||||
          whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Gateway IP address cannot be empty" 8 58
 | 
			
		||||
        elif [[ ! "$GATE1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
 | 
			
		||||
          whiptail --backtitle "Proxmox VE Helper Scripts" --msgbox "Invalid IP address format" 8 58
 | 
			
		||||
        else
 | 
			
		||||
          GATE=",gw=$GATE1"
 | 
			
		||||
          echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}$GATE1${CL}"
 | 
			
		||||
          break
 | 
			
		||||
        fi
 | 
			
		||||
      done
 | 
			
		||||
    else
 | 
			
		||||
      GATE=""
 | 
			
		||||
      echo -e "${GATEWAY}${BOLD}${DGN}Gateway IP Address: ${BGN}Default${CL}"
 | 
			
		||||
@@ -406,8 +405,8 @@ config_file() {
 | 
			
		||||
  else
 | 
			
		||||
    if [[ -n "${APT_CACHER_IP-}" ]]; then
 | 
			
		||||
      if [[ ! $APT_CACHER_IP == "none" ]]; then
 | 
			
		||||
          APT_CACHER="yes"
 | 
			
		||||
          echo -e "${NETWORK}${BOLD}${DGN}APT-CACHER IP Address: ${BGN}$APT_CACHER_IP${CL}"
 | 
			
		||||
        APT_CACHER="yes"
 | 
			
		||||
        echo -e "${NETWORK}${BOLD}${DGN}APT-CACHER IP Address: ${BGN}$APT_CACHER_IP${CL}"
 | 
			
		||||
      else
 | 
			
		||||
        APT_CACHER=""
 | 
			
		||||
        echo -e "${NETWORK}${BOLD}${DGN}APT-Cacher IP Address: ${BGN}No${CL}"
 | 
			
		||||
@@ -416,7 +415,7 @@ config_file() {
 | 
			
		||||
      if APT_CACHER_IP=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set APT-Cacher IP (leave blank for none)" 8 58 --title "APT-Cacher IP" 3>&1 1>&2 2>&3); then
 | 
			
		||||
        APT_CACHER="${APT_CACHER_IP:+yes}"
 | 
			
		||||
        echo -e "${NETWORK}${BOLD}${DGN}APT-Cacher IP Address: ${BGN}${APT_CACHER_IP:-Default}${CL}"
 | 
			
		||||
        if  [[ -n $APT_CACHER_IP ]]; then
 | 
			
		||||
        if [[ -n $APT_CACHER_IP ]]; then
 | 
			
		||||
          APT_CACHER_IP="none"
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
@@ -506,7 +505,7 @@ config_file() {
 | 
			
		||||
      fi
 | 
			
		||||
      echo -e "${NETWORK}${BOLD}${DGN}DNS Server IP Address: ${BGN}$NX${CL}"
 | 
			
		||||
    else
 | 
			
		||||
    exit_script
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
@@ -533,7 +532,7 @@ config_file() {
 | 
			
		||||
        echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC1${CL}"
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
    exit_script
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
@@ -582,7 +581,7 @@ config_file() {
 | 
			
		||||
      fi
 | 
			
		||||
      echo -e "${NETWORK}${BOLD}${DGN}Tags: ${BGN}$TAGS${CL}"
 | 
			
		||||
    else
 | 
			
		||||
    exit_script
 | 
			
		||||
      exit_script
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
@@ -646,7 +645,7 @@ config_file() {
 | 
			
		||||
      exit
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
   if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then
 | 
			
		||||
    if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "VERBOSE MODE" --yesno "Enable Verbose Mode?" 10 58); then
 | 
			
		||||
      VERBOSE="yes"
 | 
			
		||||
    else
 | 
			
		||||
      VERBOSE="no"
 | 
			
		||||
 
 | 
			
		||||
@@ -46,15 +46,26 @@ load_functions() {
 | 
			
		||||
on_error() {
 | 
			
		||||
  local exit_code="$1"
 | 
			
		||||
  local lineno="$2"
 | 
			
		||||
  msg_error "Script failed at line $lineno with exit code $exit_code"
 | 
			
		||||
  # Optionally log to your API or file here
 | 
			
		||||
 | 
			
		||||
  stop_spinner
 | 
			
		||||
 | 
			
		||||
  case "$exit_code" in
 | 
			
		||||
  1) msg_error "Generic error occurred (line $lineno)" ;;
 | 
			
		||||
  2) msg_error "Shell misuse (line $lineno)" ;;
 | 
			
		||||
  126) msg_error "Command cannot execute (line $lineno)" ;;
 | 
			
		||||
  127) msg_error "Command not found (line $lineno)" ;;
 | 
			
		||||
  128) msg_error "Invalid exit argument (line $lineno)" ;;
 | 
			
		||||
  130) msg_error "Script aborted by user (CTRL+C)" ;;
 | 
			
		||||
  143) msg_error "Script terminated by SIGTERM" ;;
 | 
			
		||||
  *) msg_error "Script failed at line $lineno with exit code $exit_code" ;;
 | 
			
		||||
  esac
 | 
			
		||||
 | 
			
		||||
  exit "$exit_code"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
on_exit() {
 | 
			
		||||
  # Always called on script exit, success or failure
 | 
			
		||||
  cleanup_temp_files || true
 | 
			
		||||
  msg_info "Script exited"
 | 
			
		||||
  cleanup_spinner || true
 | 
			
		||||
  [[ "${VERBOSE:-no}" == "yes" ]] && msg_info "Script exited"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
on_interrupt() {
 | 
			
		||||
@@ -184,6 +195,7 @@ icons() {
 | 
			
		||||
  CREATING="${TAB}🚀${TAB}${CL}"
 | 
			
		||||
  ADVANCED="${TAB}🧩${TAB}${CL}"
 | 
			
		||||
  FUSE="${TAB}🗂️${TAB}${CL}"
 | 
			
		||||
  HOURGLASS="${TAB}⏳${TAB}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# ------------------------------------------------------------------------------
 | 
			
		||||
@@ -429,8 +441,14 @@ msg_info() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  [[ -z "$msg" || -n "${MSG_INFO_SHOWN["$msg"]+x}" ]] && return
 | 
			
		||||
  MSG_INFO_SHOWN["$msg"]=1
 | 
			
		||||
 | 
			
		||||
  stop_spinner
 | 
			
		||||
  start_spinner "$msg"
 | 
			
		||||
 | 
			
		||||
  if [[ "${VERBOSE:-no}" == "no" && -t 2 ]]; then
 | 
			
		||||
    start_spinner "$msg"
 | 
			
		||||
  else
 | 
			
		||||
    printf "\r\e[2K%s %b" "$HOURGLASS" "${YW}${msg}${CL}" >&2
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
msg_ok() {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										261
									
								
								misc/create_lxc.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								misc/create_lxc.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,261 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2021-2025 tteck
 | 
			
		||||
# Author: tteck (tteckster)
 | 
			
		||||
# Co-Author: MickLesk
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
 | 
			
		||||
# This sets verbose mode if the global variable is set to "yes"
 | 
			
		||||
# if [ "$VERBOSE" == "yes" ]; then set -x; fi
 | 
			
		||||
 | 
			
		||||
if command -v curl >/dev/null 2>&1; then
 | 
			
		||||
  source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
 | 
			
		||||
  load_functions
 | 
			
		||||
  #echo "(create-lxc.sh) Loaded core.func via curl"
 | 
			
		||||
elif command -v wget >/dev/null 2>&1; then
 | 
			
		||||
  source <(wget -qO- https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
 | 
			
		||||
  load_functions
 | 
			
		||||
  #echo "(create-lxc.sh) Loaded core.func via wget"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# This sets error handling options and defines the error_handler function to handle errors
 | 
			
		||||
set -Eeuo pipefail
 | 
			
		||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
 | 
			
		||||
 | 
			
		||||
# This function handles errors
 | 
			
		||||
function error_handler() {
 | 
			
		||||
  printf "\e[?25h"
 | 
			
		||||
  local exit_code="$?"
 | 
			
		||||
  local line_number="$1"
 | 
			
		||||
  local command="$2"
 | 
			
		||||
  local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
 | 
			
		||||
  echo -e "\n$error_message\n"
 | 
			
		||||
  exit 200
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This checks for the presence of valid Container Storage and Template Storage locations
 | 
			
		||||
msg_info "Validating Storage"
 | 
			
		||||
VALIDCT=$(pvesm status -content rootdir | awk 'NR>1')
 | 
			
		||||
if [ -z "$VALIDCT" ]; then
 | 
			
		||||
  msg_error "Unable to detect a valid Container Storage location."
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
VALIDTMP=$(pvesm status -content vztmpl | awk 'NR>1')
 | 
			
		||||
if [ -z "$VALIDTMP" ]; then
 | 
			
		||||
  msg_error "Unable to detect a valid Template Storage location."
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# This function is used to select the storage class and determine the corresponding storage content type and label.
 | 
			
		||||
function select_storage() {
 | 
			
		||||
  local CLASS=$1
 | 
			
		||||
  local CONTENT
 | 
			
		||||
  local CONTENT_LABEL
 | 
			
		||||
  case $CLASS in
 | 
			
		||||
  container)
 | 
			
		||||
    CONTENT='rootdir'
 | 
			
		||||
    CONTENT_LABEL='Container'
 | 
			
		||||
    ;;
 | 
			
		||||
  template)
 | 
			
		||||
    CONTENT='vztmpl'
 | 
			
		||||
    CONTENT_LABEL='Container template'
 | 
			
		||||
    ;;
 | 
			
		||||
  *) false || {
 | 
			
		||||
    msg_error "Invalid storage class."
 | 
			
		||||
    exit 201
 | 
			
		||||
  } ;;
 | 
			
		||||
  esac
 | 
			
		||||
 | 
			
		||||
  # Collect storage options
 | 
			
		||||
  local -a MENU
 | 
			
		||||
  local MSG_MAX_LENGTH=0
 | 
			
		||||
 | 
			
		||||
  while read -r TAG TYPE _ _ _ FREE _; do
 | 
			
		||||
    local TYPE_PADDED
 | 
			
		||||
    local FREE_FMT
 | 
			
		||||
 | 
			
		||||
    TYPE_PADDED=$(printf "%-10s" "$TYPE")
 | 
			
		||||
    FREE_FMT=$(numfmt --to=iec --from-unit=K --format %.2f <<<"$FREE")B
 | 
			
		||||
    local ITEM="Type: $TYPE_PADDED Free: $FREE_FMT"
 | 
			
		||||
 | 
			
		||||
    ((${#ITEM} + 2 > MSG_MAX_LENGTH)) && MSG_MAX_LENGTH=$((${#ITEM} + 2))
 | 
			
		||||
 | 
			
		||||
    MENU+=("$TAG" "$ITEM" "OFF")
 | 
			
		||||
  done < <(pvesm status -content "$CONTENT" | awk 'NR>1')
 | 
			
		||||
 | 
			
		||||
  local OPTION_COUNT=$((${#MENU[@]} / 3))
 | 
			
		||||
 | 
			
		||||
  # Auto-select if only one option available
 | 
			
		||||
  if [[ "$OPTION_COUNT" -eq 1 ]]; then
 | 
			
		||||
    echo "${MENU[0]}"
 | 
			
		||||
    return 0
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Display selection menu
 | 
			
		||||
  local STORAGE
 | 
			
		||||
  while [[ -z "${STORAGE:+x}" ]]; do
 | 
			
		||||
    STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
 | 
			
		||||
      "Select the storage pool to use for the ${CONTENT_LABEL,,}.\nUse the spacebar to make a selection.\n" \
 | 
			
		||||
      16 $((MSG_MAX_LENGTH + 23)) 6 \
 | 
			
		||||
      "${MENU[@]}" 3>&1 1>&2 2>&3) || {
 | 
			
		||||
      msg_error "Storage selection cancelled."
 | 
			
		||||
      exit 202
 | 
			
		||||
    }
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  echo "$STORAGE"
 | 
			
		||||
}
 | 
			
		||||
# Test if required variables are set
 | 
			
		||||
[[ "${CTID:-}" ]] || {
 | 
			
		||||
  msg_error "You need to set 'CTID' variable."
 | 
			
		||||
  exit 203
 | 
			
		||||
}
 | 
			
		||||
[[ "${PCT_OSTYPE:-}" ]] || {
 | 
			
		||||
  msg_error "You need to set 'PCT_OSTYPE' variable."
 | 
			
		||||
  exit 204
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Test if ID is valid
 | 
			
		||||
[ "$CTID" -ge "100" ] || {
 | 
			
		||||
  msg_error "ID cannot be less than 100."
 | 
			
		||||
  exit 205
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Test if ID is in use
 | 
			
		||||
if qm status "$CTID" &>/dev/null || pct status "$CTID" &>/dev/null; then
 | 
			
		||||
  echo -e "ID '$CTID' is already in use."
 | 
			
		||||
  unset CTID
 | 
			
		||||
  msg_error "Cannot use ID that is already in use."
 | 
			
		||||
  exit 206
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Get template storage
 | 
			
		||||
TEMPLATE_STORAGE=$(select_storage template)
 | 
			
		||||
msg_ok "Using ${BL}$TEMPLATE_STORAGE${CL} ${GN}for Template Storage."
 | 
			
		||||
 | 
			
		||||
# Get container storage
 | 
			
		||||
CONTAINER_STORAGE=$(select_storage container)
 | 
			
		||||
msg_ok "Using ${BL}$CONTAINER_STORAGE${CL} ${GN}for Container Storage."
 | 
			
		||||
 | 
			
		||||
# Check free space on selected container storage
 | 
			
		||||
STORAGE_FREE=$(pvesm status | awk -v s="$CONTAINER_STORAGE" '$1 == s { print $6 }')
 | 
			
		||||
REQUIRED_KB=$((${PCT_DISK_SIZE:-8} * 1024 * 1024))
 | 
			
		||||
if [ "$STORAGE_FREE" -lt "$REQUIRED_KB" ]; then
 | 
			
		||||
  msg_error "Not enough space on '$CONTAINER_STORAGE'. Needed: ${PCT_DISK_SIZE:-8}G."
 | 
			
		||||
  exit 214
 | 
			
		||||
fi
 | 
			
		||||
# Check Cluster Quorum if in Cluster
 | 
			
		||||
if [ -f /etc/pve/corosync.conf ]; then
 | 
			
		||||
  msg_info "Checking Proxmox cluster quorum status"
 | 
			
		||||
  if ! pvecm status | awk -F':' '/^Quorate/ { exit ($2 ~ /Yes/) ? 0 : 1 }'; then
 | 
			
		||||
    printf "\e[?25h"
 | 
			
		||||
    msg_error "Cluster is not quorate. Start all nodes or configure quorum device (QDevice)."
 | 
			
		||||
    exit 210
 | 
			
		||||
  fi
 | 
			
		||||
  msg_ok "Cluster is quorate"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Update LXC template list
 | 
			
		||||
msg_info "Updating LXC Template List"
 | 
			
		||||
 | 
			
		||||
if ! timeout 10 pveam update >/dev/null 2>&1; then
 | 
			
		||||
  msg_error "Failed to update LXC template list. Please check your Proxmox host's internet connection and DNS resolution."
 | 
			
		||||
  exit 201
 | 
			
		||||
fi
 | 
			
		||||
$STD msg_ok "LXC Template List Updated"
 | 
			
		||||
 | 
			
		||||
# Get LXC template string
 | 
			
		||||
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
 | 
			
		||||
mapfile -t TEMPLATES < <(pveam available -section system | sed -n "s/.*\($TEMPLATE_SEARCH.*\)/\1/p" | sort -t - -k 2 -V)
 | 
			
		||||
 | 
			
		||||
if [ ${#TEMPLATES[@]} -eq 0 ]; then
 | 
			
		||||
  msg_error "No matching LXC template found for '${TEMPLATE_SEARCH}'. Make sure your host can reach the Proxmox template repository."
 | 
			
		||||
  exit 207
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
TEMPLATE="${TEMPLATES[-1]}"
 | 
			
		||||
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || echo "/var/lib/vz/template/cache/$TEMPLATE")"
 | 
			
		||||
 | 
			
		||||
# Check if template exists and is valid
 | 
			
		||||
if ! pveam list "$TEMPLATE_STORAGE" | grep -q "$TEMPLATE" || ! zstdcat "$TEMPLATE_PATH" | tar -tf - >/dev/null 2>&1; then
 | 
			
		||||
  msg_warn "Template $TEMPLATE not found or appears to be corrupted. Re-downloading."
 | 
			
		||||
 | 
			
		||||
  [[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
 | 
			
		||||
  for attempt in {1..3}; do
 | 
			
		||||
    msg_info "Attempt $attempt: Downloading LXC template..."
 | 
			
		||||
 | 
			
		||||
    if timeout 120 pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1; then
 | 
			
		||||
      msg_ok "Template download successful."
 | 
			
		||||
      break
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ $attempt -eq 3 ]; then
 | 
			
		||||
      msg_error "Failed after 3 attempts. Please check your Proxmox host’s internet access or manually run:\n  pveam download $TEMPLATE_STORAGE $TEMPLATE"
 | 
			
		||||
      exit 208
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    sleep $((attempt * 5))
 | 
			
		||||
  done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
msg_ok "LXC Template '$TEMPLATE' is ready to use."
 | 
			
		||||
# Check and fix subuid/subgid
 | 
			
		||||
grep -q "root:100000:65536" /etc/subuid || echo "root:100000:65536" >>/etc/subuid
 | 
			
		||||
grep -q "root:100000:65536" /etc/subgid || echo "root:100000:65536" >>/etc/subgid
 | 
			
		||||
 | 
			
		||||
# Combine all options
 | 
			
		||||
PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}})
 | 
			
		||||
[[ " ${PCT_OPTIONS[@]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "$CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}")
 | 
			
		||||
 | 
			
		||||
# Secure creation of the LXC container with lock and template check
 | 
			
		||||
lockfile="/tmp/template.${TEMPLATE}.lock"
 | 
			
		||||
exec 9>"$lockfile"
 | 
			
		||||
flock -w 60 9 || {
 | 
			
		||||
  msg_error "Timeout while waiting for template lock"
 | 
			
		||||
  exit 211
 | 
			
		||||
}
 | 
			
		||||
msg_info "Creating LXC Container"
 | 
			
		||||
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
 | 
			
		||||
  msg_error "Container creation failed. Checking if template is corrupted or incomplete."
 | 
			
		||||
 | 
			
		||||
  if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
 | 
			
		||||
    msg_error "Template file too small or missing – re-downloading."
 | 
			
		||||
    rm -f "$TEMPLATE_PATH"
 | 
			
		||||
  elif ! zstdcat "$TEMPLATE_PATH" | tar -tf - &>/dev/null; then
 | 
			
		||||
    msg_error "Template appears to be corrupted – re-downloading."
 | 
			
		||||
    rm -f "$TEMPLATE_PATH"
 | 
			
		||||
  else
 | 
			
		||||
    msg_error "Template is valid, but container creation still failed."
 | 
			
		||||
    exit 209
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  # Retry download
 | 
			
		||||
  for attempt in {1..3}; do
 | 
			
		||||
    msg_info "Attempt $attempt: Re-downloading template..."
 | 
			
		||||
    if timeout 120 pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null; then
 | 
			
		||||
      msg_ok "Template re-download successful."
 | 
			
		||||
      break
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$attempt" -eq 3 ]; then
 | 
			
		||||
      msg_error "Three failed attempts. Aborting."
 | 
			
		||||
      exit 208
 | 
			
		||||
    fi
 | 
			
		||||
    sleep $((attempt * 5))
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  sleep 1 # I/O-Sync-Delay
 | 
			
		||||
 | 
			
		||||
  msg_ok "Re-downloaded LXC Template"
 | 
			
		||||
 | 
			
		||||
  if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" &>/dev/null; then
 | 
			
		||||
    msg_error "Container creation failed after re-downloading template."
 | 
			
		||||
    exit 200
 | 
			
		||||
  fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if ! pct status "$CTID" &>/dev/null; then
 | 
			
		||||
  msg_error "Container not found after pct create – assuming failure."
 | 
			
		||||
  exit 210
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created."
 | 
			
		||||
@@ -4,53 +4,13 @@
 | 
			
		||||
# License: MIT
 | 
			
		||||
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
 | 
			
		||||
# This function sets color variables for formatting output in the terminal
 | 
			
		||||
color() {
 | 
			
		||||
  # Colors
 | 
			
		||||
  YW=$(echo "\033[33m")
 | 
			
		||||
  YWB=$(echo "\033[93m")
 | 
			
		||||
  BL=$(echo "\033[36m")
 | 
			
		||||
  RD=$(echo "\033[01;31m")
 | 
			
		||||
  GN=$(echo "\033[1;92m")
 | 
			
		||||
 | 
			
		||||
  # Formatting
 | 
			
		||||
  CL=$(echo "\033[m")
 | 
			
		||||
  BFR="\\r\\033[K"
 | 
			
		||||
  BOLD=$(echo "\033[1m")
 | 
			
		||||
  HOLD=" "
 | 
			
		||||
  TAB="  "
 | 
			
		||||
  TAB3="      "
 | 
			
		||||
 | 
			
		||||
  # System
 | 
			
		||||
  RETRY_NUM=10
 | 
			
		||||
  RETRY_EVERY=3
 | 
			
		||||
 | 
			
		||||
  # Icons
 | 
			
		||||
  CM="${TAB}✔️${TAB}${CL}"
 | 
			
		||||
  CROSS="${TAB}✖️${TAB}${CL}"
 | 
			
		||||
  INFO="${TAB}💡${TAB}${CL}"
 | 
			
		||||
  NETWORK="${TAB}📡${TAB}${CL}"
 | 
			
		||||
  OS="${TAB}🖥️${TAB}${CL}"
 | 
			
		||||
  OSVERSION="${TAB}🌟${TAB}${CL}"
 | 
			
		||||
  HOSTNAME="${TAB}🏠${TAB}${CL}"
 | 
			
		||||
  GATEWAY="${TAB}🌐${TAB}${CL}"
 | 
			
		||||
  DEFAULT="${TAB}⚙️${TAB}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Function to set STD mode based on verbosity
 | 
			
		||||
set_std_mode() {
 | 
			
		||||
  if [ "$VERBOSE" = "yes" ]; then
 | 
			
		||||
    STD=""
 | 
			
		||||
  else
 | 
			
		||||
    STD="silent"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Silent execution function
 | 
			
		||||
silent() {
 | 
			
		||||
  "$@" >/dev/null 2>&1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if ! command -v curl >/dev/null 2>&1; then
 | 
			
		||||
  printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
 | 
			
		||||
  apt-get update >/dev/null 2>&1
 | 
			
		||||
  apt-get install -y curl >/dev/null 2>&1
 | 
			
		||||
fi
 | 
			
		||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
 | 
			
		||||
load_functions
 | 
			
		||||
# This function enables IPv6 if it's not disabled and sets verbose mode
 | 
			
		||||
verb_ip6() {
 | 
			
		||||
  set_std_mode # Set STD mode based on VERBOSE
 | 
			
		||||
@@ -70,7 +30,6 @@ catch_errors() {
 | 
			
		||||
# This function handles errors
 | 
			
		||||
error_handler() {
 | 
			
		||||
  source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
 | 
			
		||||
  if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
 | 
			
		||||
  printf "\e[?25h"
 | 
			
		||||
  local exit_code="$?"
 | 
			
		||||
  local line_number="$1"
 | 
			
		||||
@@ -85,62 +44,15 @@ error_handler() {
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays a spinner.
 | 
			
		||||
spinner() {
 | 
			
		||||
  local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
 | 
			
		||||
  local spin_i=0
 | 
			
		||||
  local interval=0.1
 | 
			
		||||
  printf "\e[?25l"
 | 
			
		||||
 | 
			
		||||
  local color="${YWB}"
 | 
			
		||||
 | 
			
		||||
  while true; do
 | 
			
		||||
    printf "\r ${color}%s${CL}" "${frames[spin_i]}"
 | 
			
		||||
    spin_i=$(((spin_i + 1) % ${#frames[@]}))
 | 
			
		||||
    sleep "$interval"
 | 
			
		||||
  done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays an informational message with a yellow color.
 | 
			
		||||
msg_info() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
 | 
			
		||||
  spinner &
 | 
			
		||||
  SPINNER_PID=$!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays a success message with a green color.
 | 
			
		||||
msg_ok() {
 | 
			
		||||
  if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
 | 
			
		||||
  printf "\e[?25h"
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -e "${BFR}${CM}${GN}${msg}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function displays a error message with a red color.
 | 
			
		||||
msg_error() {
 | 
			
		||||
  if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
 | 
			
		||||
  printf "\e[?25h"
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
 | 
			
		||||
setting_up_container() {
 | 
			
		||||
  msg_info "Setting up Container OS"
 | 
			
		||||
  sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen
 | 
			
		||||
  locale_line=$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print $1}' | head -n 1)
 | 
			
		||||
  echo "LANG=${locale_line}" >/etc/default/locale
 | 
			
		||||
  locale-gen >/dev/null
 | 
			
		||||
  export LANG=${locale_line}
 | 
			
		||||
  echo "$tz" >/etc/timezone
 | 
			
		||||
  ln -sf /usr/share/zoneinfo/"$tz" /etc/localtime
 | 
			
		||||
  for ((i = RETRY_NUM; i > 0; i--)); do
 | 
			
		||||
    if [ "$(hostname -I)" != "" ]; then
 | 
			
		||||
      break
 | 
			
		||||
    fi
 | 
			
		||||
    echo 1>&2 -en "${CROSS}${RD} No Network! "
 | 
			
		||||
    sleep "$RETRY_EVERY"
 | 
			
		||||
    sleep $RETRY_EVERY
 | 
			
		||||
  done
 | 
			
		||||
  if [ "$(hostname -I)" = "" ]; then
 | 
			
		||||
    echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
 | 
			
		||||
@@ -150,7 +62,7 @@ setting_up_container() {
 | 
			
		||||
  rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
 | 
			
		||||
  systemctl disable -q --now systemd-networkd-wait-online.service
 | 
			
		||||
  msg_ok "Set up Container OS"
 | 
			
		||||
  msg_ok "Network Connected: ${BL}$(hostname -I)"
 | 
			
		||||
  msg_custom "${CM}" "${GN}" "Network Connected: ${BL}$(hostname -I)"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected
 | 
			
		||||
@@ -178,7 +90,7 @@ network_check() {
 | 
			
		||||
 | 
			
		||||
  # If both IPv4 and IPv6 checks fail, prompt the user
 | 
			
		||||
  if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
 | 
			
		||||
    read -r -p "No Internet detected,would you like to continue anyway? <y/N> " prompt
 | 
			
		||||
    read -r -p "No Internet detected, would you like to continue anyway? <y/N> " prompt
 | 
			
		||||
    if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
 | 
			
		||||
      echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
 | 
			
		||||
    else
 | 
			
		||||
@@ -187,8 +99,26 @@ network_check() {
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
 | 
			
		||||
  if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to ${BL}$RESOLVEDIP${CL}"; fi
 | 
			
		||||
  # DNS resolution checks for GitHub-related domains (IPv4 and/or IPv6)
 | 
			
		||||
  GITHUB_HOSTS=("github.com" "raw.githubusercontent.com" "api.github.com")
 | 
			
		||||
  GITHUB_STATUS="GitHub DNS:"
 | 
			
		||||
  DNS_FAILED=false
 | 
			
		||||
 | 
			
		||||
  for HOST in "${GITHUB_HOSTS[@]}"; do
 | 
			
		||||
    RESOLVEDIP=$(getent hosts "$HOST" | awk '{ print $1 }' | grep -E '(^([0-9]{1,3}\.){3}[0-9]{1,3}$)|(^[a-fA-F0-9:]+$)' | head -n1)
 | 
			
		||||
    if [[ -z "$RESOLVEDIP" ]]; then
 | 
			
		||||
      GITHUB_STATUS+="$HOST:($DNSFAIL)"
 | 
			
		||||
      DNS_FAILED=true
 | 
			
		||||
    else
 | 
			
		||||
      GITHUB_STATUS+=" $HOST:($DNSOK)"
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  if [[ "$DNS_FAILED" == true ]]; then
 | 
			
		||||
    fatal "$GITHUB_STATUS"
 | 
			
		||||
  else
 | 
			
		||||
    msg_ok "$GITHUB_STATUS"
 | 
			
		||||
  fi
 | 
			
		||||
  set -e
 | 
			
		||||
  trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
 | 
			
		||||
}
 | 
			
		||||
@@ -213,11 +143,7 @@ EOF
 | 
			
		||||
  rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
 | 
			
		||||
  msg_ok "Updated Container OS"
 | 
			
		||||
 | 
			
		||||
  msg_info "Installing core dependencies"
 | 
			
		||||
  $STD apt-get update
 | 
			
		||||
  $STD apt-get install -y sudo curl mc gnupg2
 | 
			
		||||
  source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
 | 
			
		||||
  msg_ok "Core dependencies installed"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# This function modifies the message of the day (motd) and SSH settings
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,6 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "ProxmoxVE",
 | 
			
		||||
  "lockfileVersion": 3,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "packages": {}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								tools/headers/filebrowser-quantum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tools/headers/filebrowser-quantum
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
    _______ __     ____                                       ____                    __                
 | 
			
		||||
   / ____(_) /__  / __ )_________ _      __________  _____   / __ \__  ______ _____  / /___  ______ ___ 
 | 
			
		||||
  / /_  / / / _ \/ __  / ___/ __ \ | /| / / ___/ _ \/ ___/  / / / / / / / __ `/ __ \/ __/ / / / __ `__ \
 | 
			
		||||
 / __/ / / /  __/ /_/ / /  / /_/ / |/ |/ (__  )  __/ /     / /_/ / /_/ / /_/ / / / / /_/ /_/ / / / / / /
 | 
			
		||||
/_/   /_/_/\___/_____/_/   \____/|__/|__/____/\___/_/      \___\_\__,_/\__,_/_/ /_/\__/\__,_/_/ /_/ /_/ 
 | 
			
		||||
                                                                                                        
 | 
			
		||||
@@ -79,6 +79,7 @@ mediaserver Media Server
 | 
			
		||||
nextcloud Nextcloud
 | 
			
		||||
observium Observium
 | 
			
		||||
odoo Odoo
 | 
			
		||||
openldap OpenLDAP
 | 
			
		||||
openvpn OpenVPN
 | 
			
		||||
owncloud ownCloud
 | 
			
		||||
phpbb phpBB
 | 
			
		||||
@@ -201,7 +202,7 @@ echo "TurnKey ${turnkey} password: ${PASS}" >>~/turnkey-${turnkey}.creds # file
 | 
			
		||||
# Start container
 | 
			
		||||
msg "Starting LXC Container..."
 | 
			
		||||
pct start "$CTID"
 | 
			
		||||
sleep 5
 | 
			
		||||
sleep 10
 | 
			
		||||
 | 
			
		||||
# Get container IP
 | 
			
		||||
set +euo pipefail # Turn off error checking
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								vm/headers/owncloud-vm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								vm/headers/owncloud-vm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
  ______                 __ __                                  ________                __   _    ____  ___
 | 
			
		||||
 /_  __/_  ___________  / //_/__  __  __   ____ _      ______  / ____/ /___  __  ______/ /  | |  / /  |/  /
 | 
			
		||||
  / / / / / / ___/ __ \/ ,< / _ \/ / / /  / __ \ | /| / / __ \/ /   / / __ \/ / / / __  /   | | / / /|_/ / 
 | 
			
		||||
 / / / /_/ / /  / / / / /| /  __/ /_/ /  / /_/ / |/ |/ / / / / /___/ / /_/ / /_/ / /_/ /    | |/ / /  / /  
 | 
			
		||||
/_/  \__,_/_/  /_/ /_/_/ |_\___/\__, /   \____/|__/|__/_/ /_/\____/_/\____/\__,_/\__,_/     |___/_/  /_/   
 | 
			
		||||
                               /____/                                                                      
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
 | 
			
		||||
 | 
			
		||||
function header_info {
 | 
			
		||||
  clear
 | 
			
		||||
  cat <<"EOF"
 | 
			
		||||
    __  ____ __              __  _ __      ____              __            ____  _____    ________  ______
 | 
			
		||||
   /  |/  (_) /___________  / /_(_) /__   / __ \____  __  __/ /____  _____/ __ \/ ___/   / ____/ / / / __ \
 | 
			
		||||
@@ -17,7 +18,6 @@ function header_info {
 | 
			
		||||
 | 
			
		||||
EOF
 | 
			
		||||
}
 | 
			
		||||
clear
 | 
			
		||||
header_info
 | 
			
		||||
echo -e "Loading..."
 | 
			
		||||
GEN_MAC=$(echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /:/g' | tr '[:lower:]' '[:upper:]')
 | 
			
		||||
@@ -108,7 +108,7 @@ function cleanup() {
 | 
			
		||||
 | 
			
		||||
TEMP_DIR=$(mktemp -d)
 | 
			
		||||
pushd $TEMP_DIR >/dev/null
 | 
			
		||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Debian 12 VM" --yesno "This will create a New Debian 12 VM. Proceed?" 10 58; then
 | 
			
		||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Mikrotik RouterOS CHR VM" --yesno "This will create a Mikrotik RouterOS CHR VM. Proceed?" 10 58; then
 | 
			
		||||
  :
 | 
			
		||||
else
 | 
			
		||||
  header_info && echo -e "${CROSS}${RD}User exited script${CL}\n" && exit
 | 
			
		||||
@@ -309,9 +309,9 @@ function advanced_settings() {
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 debian --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
  if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 mikrotik-routeros-chr --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z $VM_NAME ]; then
 | 
			
		||||
      HN="debian"
 | 
			
		||||
      HN="mikrotik-routeros-chr"
 | 
			
		||||
      echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      HN=$(echo ${VM_NAME,,} | tr -d ' ')
 | 
			
		||||
 
 | 
			
		||||
@@ -116,7 +116,7 @@ function cleanup() {
 | 
			
		||||
 | 
			
		||||
TEMP_DIR=$(mktemp -d)
 | 
			
		||||
pushd $TEMP_DIR >/dev/null
 | 
			
		||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Debian 12 VM" --yesno "This will create a New Debian 12 VM. Proceed?" 10 58; then
 | 
			
		||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Pimox Homeassistant OS VM" --yesno "This will create a New Pimox Homeassistant OS VM. Proceed?" 10 58; then
 | 
			
		||||
  :
 | 
			
		||||
else
 | 
			
		||||
  header_info && echo -e "${CROSS}${RD}User exited script${CL}\n" && exit
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										528
									
								
								vm/ubuntu2504-vm.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										528
									
								
								vm/ubuntu2504-vm.sh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,528 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# Copyright (c) 2021-2025 community-scripts ORG
 | 
			
		||||
# Author: MickLesk (CanbiZ)
 | 
			
		||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
 | 
			
		||||
 | 
			
		||||
source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
 | 
			
		||||
 | 
			
		||||
function header_info {
 | 
			
		||||
  clear
 | 
			
		||||
  cat <<"EOF"
 | 
			
		||||
   __  ____                __           ___   ______ ____  __ __     _    ____  ___
 | 
			
		||||
  / / / / /_  __  ______  / /___  __   |__ \ / ____// __ \/ // /    | |  / /  |/  /
 | 
			
		||||
 / / / / __ \/ / / / __ \/ __/ / / /   __/ //___ \ / / / / // /_    | | / / /|_/ / 
 | 
			
		||||
/ /_/ / /_/ / /_/ / / / / /_/ /_/ /   / __/____/ // /_/ /__  __/    | |/ / /  / /  
 | 
			
		||||
\____/_.___/\__,_/_/ /_/\__/\__,_/   /____/_____(_)____/  /_/       |___/_/  /_/ (Plucky Puffin)
 | 
			
		||||
                                                                                   
 | 
			
		||||
EOF
 | 
			
		||||
}
 | 
			
		||||
header_info
 | 
			
		||||
echo -e "\n Loading..."
 | 
			
		||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
 | 
			
		||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
 | 
			
		||||
METHOD=""
 | 
			
		||||
NSAPP="ubuntu-2504-vm"
 | 
			
		||||
var_os="ubuntu"
 | 
			
		||||
var_version="2504"
 | 
			
		||||
 | 
			
		||||
YW=$(echo "\033[33m")
 | 
			
		||||
BL=$(echo "\033[36m")
 | 
			
		||||
RD=$(echo "\033[01;31m")
 | 
			
		||||
BGN=$(echo "\033[4;92m")
 | 
			
		||||
GN=$(echo "\033[1;92m")
 | 
			
		||||
DGN=$(echo "\033[32m")
 | 
			
		||||
CL=$(echo "\033[m")
 | 
			
		||||
 | 
			
		||||
CL=$(echo "\033[m")
 | 
			
		||||
BOLD=$(echo "\033[1m")
 | 
			
		||||
BFR="\\r\\033[K"
 | 
			
		||||
HOLD=" "
 | 
			
		||||
TAB="  "
 | 
			
		||||
 | 
			
		||||
CM="${TAB}✔️${TAB}${CL}"
 | 
			
		||||
CROSS="${TAB}✖️${TAB}${CL}"
 | 
			
		||||
INFO="${TAB}💡${TAB}${CL}"
 | 
			
		||||
OS="${TAB}🖥️${TAB}${CL}"
 | 
			
		||||
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
 | 
			
		||||
DISKSIZE="${TAB}💾${TAB}${CL}"
 | 
			
		||||
CPUCORE="${TAB}🧠${TAB}${CL}"
 | 
			
		||||
RAMSIZE="${TAB}🛠️${TAB}${CL}"
 | 
			
		||||
CONTAINERID="${TAB}🆔${TAB}${CL}"
 | 
			
		||||
HOSTNAME="${TAB}🏠${TAB}${CL}"
 | 
			
		||||
BRIDGE="${TAB}🌉${TAB}${CL}"
 | 
			
		||||
GATEWAY="${TAB}🌐${TAB}${CL}"
 | 
			
		||||
DEFAULT="${TAB}⚙️${TAB}${CL}"
 | 
			
		||||
MACADDRESS="${TAB}🔗${TAB}${CL}"
 | 
			
		||||
VLANTAG="${TAB}🏷️${TAB}${CL}"
 | 
			
		||||
CREATING="${TAB}🚀${TAB}${CL}"
 | 
			
		||||
ADVANCED="${TAB}🧩${TAB}${CL}"
 | 
			
		||||
 | 
			
		||||
THIN="discard=on,ssd=1,"
 | 
			
		||||
set -e
 | 
			
		||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
 | 
			
		||||
trap cleanup EXIT
 | 
			
		||||
trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT
 | 
			
		||||
trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM
 | 
			
		||||
function error_handler() {
 | 
			
		||||
  local exit_code="$?"
 | 
			
		||||
  local line_number="$1"
 | 
			
		||||
  local command="$2"
 | 
			
		||||
  post_update_to_api "failed" "$command"
 | 
			
		||||
  local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
 | 
			
		||||
  echo -e "\n$error_message\n"
 | 
			
		||||
  cleanup_vmid
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function get_valid_nextid() {
 | 
			
		||||
  local try_id
 | 
			
		||||
  try_id=$(pvesh get /cluster/nextid)
 | 
			
		||||
  while true; do
 | 
			
		||||
    if [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; then
 | 
			
		||||
      try_id=$((try_id + 1))
 | 
			
		||||
      continue
 | 
			
		||||
    fi
 | 
			
		||||
    if lvs --noheadings -o lv_name | grep -qE "(^|[-_])${try_id}($|[-_])"; then
 | 
			
		||||
      try_id=$((try_id + 1))
 | 
			
		||||
      continue
 | 
			
		||||
    fi
 | 
			
		||||
    break
 | 
			
		||||
  done
 | 
			
		||||
  echo "$try_id"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function cleanup_vmid() {
 | 
			
		||||
  if qm status $VMID &>/dev/null; then
 | 
			
		||||
    qm stop $VMID &>/dev/null
 | 
			
		||||
    qm destroy $VMID &>/dev/null
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function cleanup() {
 | 
			
		||||
  popd >/dev/null
 | 
			
		||||
  rm -rf $TEMP_DIR
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEMP_DIR=$(mktemp -d)
 | 
			
		||||
pushd $TEMP_DIR >/dev/null
 | 
			
		||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Ubuntu 25.04 VM" --yesno "This will create a New Ubuntu 25.04 VM. Proceed?" 10 58; then
 | 
			
		||||
  :
 | 
			
		||||
else
 | 
			
		||||
  header_info && echo -e "${CROSS}${RD}User exited script${CL}\n" && exit
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
function msg_info() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function msg_ok() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -e "${BFR}${CM}${GN}${msg}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function msg_error() {
 | 
			
		||||
  local msg="$1"
 | 
			
		||||
  echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function check_root() {
 | 
			
		||||
  if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
 | 
			
		||||
    clear
 | 
			
		||||
    msg_error "Please run this script as root."
 | 
			
		||||
    echo -e "\nExiting..."
 | 
			
		||||
    sleep 2
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function pve_check() {
 | 
			
		||||
  if ! pveversion | grep -Eq "pve-manager/8\.[1-4](\.[0-9]+)*"; then
 | 
			
		||||
    msg_error "${CROSS}${RD}This version of Proxmox Virtual Environment is not supported"
 | 
			
		||||
    echo -e "Requires Proxmox Virtual Environment Version 8.1 or later."
 | 
			
		||||
    echo -e "Exiting..."
 | 
			
		||||
    sleep 2
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function arch_check() {
 | 
			
		||||
  if [ "$(dpkg --print-architecture)" != "amd64" ]; then
 | 
			
		||||
    echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
 | 
			
		||||
    echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
 | 
			
		||||
    echo -e "Exiting..."
 | 
			
		||||
    sleep 2
 | 
			
		||||
    exit
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ssh_check() {
 | 
			
		||||
  if command -v pveversion >/dev/null 2>&1; then
 | 
			
		||||
    if [ -n "${SSH_CLIENT:+x}" ]; then
 | 
			
		||||
      if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
 | 
			
		||||
        echo "you've been warned"
 | 
			
		||||
      else
 | 
			
		||||
        clear
 | 
			
		||||
        exit
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function exit-script() {
 | 
			
		||||
  clear
 | 
			
		||||
  echo -e "\n${CROSS}${RD}User exited script${CL}\n"
 | 
			
		||||
  exit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function default_settings() {
 | 
			
		||||
  VMID=$(get_valid_nextid)
 | 
			
		||||
  FORMAT=",efitype=4m"
 | 
			
		||||
  MACHINE=""
 | 
			
		||||
  DISK_SIZE="7G"
 | 
			
		||||
  DISK_CACHE=""
 | 
			
		||||
  HN="ubuntu"
 | 
			
		||||
  CPU_TYPE=""
 | 
			
		||||
  CORE_COUNT="2"
 | 
			
		||||
  RAM_SIZE="2048"
 | 
			
		||||
  BRG="vmbr0"
 | 
			
		||||
  MAC="$GEN_MAC"
 | 
			
		||||
  VLAN=""
 | 
			
		||||
  MTU=""
 | 
			
		||||
  START_VM="yes"
 | 
			
		||||
  METHOD="default"
 | 
			
		||||
  echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}${VMID}${CL}"
 | 
			
		||||
  echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}i440fx${CL}"
 | 
			
		||||
  echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE}${CL}"
 | 
			
		||||
  echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
 | 
			
		||||
  echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}${HN}${CL}"
 | 
			
		||||
  echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
 | 
			
		||||
  echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
 | 
			
		||||
  echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE}${CL}"
 | 
			
		||||
  echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}${BRG}${CL}"
 | 
			
		||||
  echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}${MAC}${CL}"
 | 
			
		||||
  echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}Default${CL}"
 | 
			
		||||
  echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}Default${CL}"
 | 
			
		||||
  echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
 | 
			
		||||
  echo -e "${CREATING}${BOLD}${DGN}Creating a Ubuntu 25.04 VM using the above default settings${CL}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function advanced_settings() {
 | 
			
		||||
  METHOD="advanced"
 | 
			
		||||
  [ -z "${VMID:-}" ] && VMID=$(get_valid_nextid)
 | 
			
		||||
  while true; do
 | 
			
		||||
    if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 $VMID --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
      if [ -z "$VMID" ]; then
 | 
			
		||||
        VMID=$(get_valid_nextid)
 | 
			
		||||
      fi
 | 
			
		||||
      if pct status "$VMID" &>/dev/null || qm status "$VMID" &>/dev/null; then
 | 
			
		||||
        echo -e "${CROSS}${RD} ID $VMID is already in use${CL}"
 | 
			
		||||
        sleep 2
 | 
			
		||||
        continue
 | 
			
		||||
      fi
 | 
			
		||||
      echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
 | 
			
		||||
      break
 | 
			
		||||
    else
 | 
			
		||||
      exit-script
 | 
			
		||||
    fi
 | 
			
		||||
  done
 | 
			
		||||
 | 
			
		||||
  if MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
 | 
			
		||||
    "i440fx" "Machine i440fx" ON \
 | 
			
		||||
    "q35" "Machine q35" OFF \
 | 
			
		||||
    3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ $MACH = q35 ]; then
 | 
			
		||||
      echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$MACH${CL}"
 | 
			
		||||
      FORMAT=""
 | 
			
		||||
      MACHINE=" -machine q35"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$MACH${CL}"
 | 
			
		||||
      FORMAT=",efitype=4m"
 | 
			
		||||
      MACHINE=""
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GiB (e.g., 10, 20)" 8 58 "$DISK_SIZE" --title "DISK SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
    DISK_SIZE=$(echo "$DISK_SIZE" | tr -d ' ')
 | 
			
		||||
    if [[ "$DISK_SIZE" =~ ^[0-9]+$ ]]; then
 | 
			
		||||
      DISK_SIZE="${DISK_SIZE}G"
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
 | 
			
		||||
    elif [[ "$DISK_SIZE" =~ ^[0-9]+G$ ]]; then
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${RD}Invalid Disk Size. Please use a number (e.g., 10 or 10G).${CL}"
 | 
			
		||||
      exit-script
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if DISK_CACHE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
 | 
			
		||||
    "0" "None (Default)" ON \
 | 
			
		||||
    "1" "Write Through" OFF \
 | 
			
		||||
    3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ $DISK_CACHE = "1" ]; then
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}Write Through${CL}"
 | 
			
		||||
      DISK_CACHE="cache=writethrough,"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
 | 
			
		||||
      DISK_CACHE=""
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 ubuntu --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z $VM_NAME ]; then
 | 
			
		||||
      HN="ubuntu"
 | 
			
		||||
      echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      HN=$(echo ${VM_NAME,,} | tr -d ' ')
 | 
			
		||||
      echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
 | 
			
		||||
    "0" "KVM64 (Default)" ON \
 | 
			
		||||
    "1" "Host" OFF \
 | 
			
		||||
    3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ $CPU_TYPE1 = "1" ]; then
 | 
			
		||||
      echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
 | 
			
		||||
      CPU_TYPE=" -cpu host"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
 | 
			
		||||
      CPU_TYPE=""
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 2 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z $CORE_COUNT ]; then
 | 
			
		||||
      CORE_COUNT="2"
 | 
			
		||||
      echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 2048 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z $RAM_SIZE ]; then
 | 
			
		||||
      RAM_SIZE="2048"
 | 
			
		||||
      echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 vmbr0 --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z $BRG ]; then
 | 
			
		||||
      BRG="vmbr0"
 | 
			
		||||
      echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 $GEN_MAC --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z $MAC1 ]; then
 | 
			
		||||
      MAC="$GEN_MAC"
 | 
			
		||||
      echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      MAC="$MAC1"
 | 
			
		||||
      echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC1${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z $VLAN1 ]; then
 | 
			
		||||
      VLAN1="Default"
 | 
			
		||||
      VLAN=""
 | 
			
		||||
      echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      VLAN=",tag=$VLAN1"
 | 
			
		||||
      echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
 | 
			
		||||
    if [ -z $MTU1 ]; then
 | 
			
		||||
      MTU1="Default"
 | 
			
		||||
      MTU=""
 | 
			
		||||
      echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
 | 
			
		||||
    else
 | 
			
		||||
      MTU=",mtu=$MTU1"
 | 
			
		||||
      echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    exit-script
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58); then
 | 
			
		||||
    echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
 | 
			
		||||
    START_VM="yes"
 | 
			
		||||
  else
 | 
			
		||||
    echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}no${CL}"
 | 
			
		||||
    START_VM="no"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create a Ubuntu 25.04 VM?" --no-button Do-Over 10 58); then
 | 
			
		||||
    echo -e "${CREATING}${BOLD}${DGN}Creating a Ubuntu 25.04 VM using the above advanced settings${CL}"
 | 
			
		||||
  else
 | 
			
		||||
    header_info
 | 
			
		||||
    echo -e "${ADVANCED}${BOLD}${RD}Using Advanced Settings${CL}"
 | 
			
		||||
    advanced_settings
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function start_script() {
 | 
			
		||||
  if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58); then
 | 
			
		||||
    header_info
 | 
			
		||||
    echo -e "${DEFAULT}${BOLD}${BL}Using Default Settings${CL}"
 | 
			
		||||
    default_settings
 | 
			
		||||
  else
 | 
			
		||||
    header_info
 | 
			
		||||
    echo -e "${ADVANCED}${BOLD}${RD}Using Advanced Settings${CL}"
 | 
			
		||||
    advanced_settings
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
check_root
 | 
			
		||||
arch_check
 | 
			
		||||
pve_check
 | 
			
		||||
ssh_check
 | 
			
		||||
start_script
 | 
			
		||||
post_to_api_vm
 | 
			
		||||
 | 
			
		||||
msg_info "Validating Storage"
 | 
			
		||||
while read -r line; do
 | 
			
		||||
  TAG=$(echo $line | awk '{print $1}')
 | 
			
		||||
  TYPE=$(echo $line | awk '{printf "%-10s", $2}')
 | 
			
		||||
  FREE=$(echo $line | numfmt --field 4-6 --from-unit=K --to=iec --format %.2f | awk '{printf( "%9sB", $6)}')
 | 
			
		||||
  ITEM="  Type: $TYPE Free: $FREE "
 | 
			
		||||
  OFFSET=2
 | 
			
		||||
  if [[ $((${#ITEM} + $OFFSET)) -gt ${MSG_MAX_LENGTH:-} ]]; then
 | 
			
		||||
    MSG_MAX_LENGTH=$((${#ITEM} + $OFFSET))
 | 
			
		||||
  fi
 | 
			
		||||
  STORAGE_MENU+=("$TAG" "$ITEM" "OFF")
 | 
			
		||||
done < <(pvesm status -content images | awk 'NR>1')
 | 
			
		||||
VALID=$(pvesm status -content images | awk 'NR>1')
 | 
			
		||||
if [ -z "$VALID" ]; then
 | 
			
		||||
  msg_error "Unable to detect a valid storage location."
 | 
			
		||||
  exit
 | 
			
		||||
elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
 | 
			
		||||
  STORAGE=${STORAGE_MENU[0]}
 | 
			
		||||
else
 | 
			
		||||
  while [ -z "${STORAGE:+x}" ]; do
 | 
			
		||||
    STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
 | 
			
		||||
      "Which storage pool would you like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
 | 
			
		||||
      16 $(($MSG_MAX_LENGTH + 23)) 6 \
 | 
			
		||||
      "${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3)
 | 
			
		||||
  done
 | 
			
		||||
fi
 | 
			
		||||
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
 | 
			
		||||
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
 | 
			
		||||
msg_info "Retrieving the URL for the Ubuntu 25.04 Disk Image"
 | 
			
		||||
URL=https://cloud-images.ubuntu.com/plucky/current/plucky-server-cloudimg-amd64.img
 | 
			
		||||
sleep 2
 | 
			
		||||
msg_ok "${CL}${BL}${URL}${CL}"
 | 
			
		||||
curl -f#SL -o "$(basename "$URL")" "$URL"
 | 
			
		||||
echo -en "\e[1A\e[0K"
 | 
			
		||||
FILE=$(basename $URL)
 | 
			
		||||
msg_ok "Downloaded ${CL}${BL}${FILE}${CL}"
 | 
			
		||||
 | 
			
		||||
STORAGE_TYPE=$(pvesm status -storage $STORAGE | awk 'NR>1 {print $2}')
 | 
			
		||||
case $STORAGE_TYPE in
 | 
			
		||||
nfs | dir | cifs)
 | 
			
		||||
  DISK_EXT=".qcow2"
 | 
			
		||||
  DISK_REF="$VMID/"
 | 
			
		||||
  DISK_IMPORT="-format qcow2"
 | 
			
		||||
  THIN=""
 | 
			
		||||
  ;;
 | 
			
		||||
btrfs)
 | 
			
		||||
  DISK_EXT=".raw"
 | 
			
		||||
  DISK_REF="$VMID/"
 | 
			
		||||
  DISK_IMPORT="-format raw"
 | 
			
		||||
  FORMAT=",efitype=4m"
 | 
			
		||||
  THIN=""
 | 
			
		||||
  ;;
 | 
			
		||||
esac
 | 
			
		||||
for i in {0,1}; do
 | 
			
		||||
  disk="DISK$i"
 | 
			
		||||
  eval DISK${i}=vm-${VMID}-disk-${i}${DISK_EXT:-}
 | 
			
		||||
  eval DISK${i}_REF=${STORAGE}:${DISK_REF:-}${!disk}
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
msg_info "Creating a Ubuntu 25.04 VM"
 | 
			
		||||
qm create $VMID -agent 1${MACHINE} -tablet 0 -localtime 1 -bios ovmf${CPU_TYPE} -cores $CORE_COUNT -memory $RAM_SIZE \
 | 
			
		||||
  -name $HN -tags community-script -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
 | 
			
		||||
pvesm alloc $STORAGE $VMID $DISK0 4M 1>&/dev/null
 | 
			
		||||
qm importdisk $VMID ${FILE} $STORAGE ${DISK_IMPORT:-} 1>&/dev/null
 | 
			
		||||
qm set $VMID \
 | 
			
		||||
  -efidisk0 ${DISK0_REF}${FORMAT} \
 | 
			
		||||
  -scsi0 ${DISK1_REF},${DISK_CACHE}${THIN}size=${DISK_SIZE} \
 | 
			
		||||
  -ide2 ${STORAGE}:cloudinit \
 | 
			
		||||
  -boot order=scsi0 \
 | 
			
		||||
  -serial0 socket >/dev/null
 | 
			
		||||
DESCRIPTION=$(
 | 
			
		||||
  cat <<EOF
 | 
			
		||||
<div align='center'>
 | 
			
		||||
  <a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
 | 
			
		||||
    <img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
 | 
			
		||||
  </a>
 | 
			
		||||
 | 
			
		||||
  <h2 style='font-size: 24px; margin: 20px 0;'>ubuntu VM</h2>
 | 
			
		||||
 | 
			
		||||
  <p style='margin: 16px 0;'>
 | 
			
		||||
    <a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
 | 
			
		||||
      <img src='https://img.shields.io/badge/☕-Buy us a coffee-blue' alt='spend Coffee' />
 | 
			
		||||
    </a>
 | 
			
		||||
  </p>
 | 
			
		||||
  
 | 
			
		||||
  <span style='margin: 0 10px;'>
 | 
			
		||||
    <i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
 | 
			
		||||
    <a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
 | 
			
		||||
  </span>
 | 
			
		||||
  <span style='margin: 0 10px;'>
 | 
			
		||||
    <i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
 | 
			
		||||
    <a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
 | 
			
		||||
  </span>
 | 
			
		||||
  <span style='margin: 0 10px;'>
 | 
			
		||||
    <i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
 | 
			
		||||
    <a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
 | 
			
		||||
  </span>
 | 
			
		||||
</div>
 | 
			
		||||
EOF
 | 
			
		||||
)
 | 
			
		||||
qm set "$VMID" -description "$DESCRIPTION" >/dev/null
 | 
			
		||||
if [ -n "$DISK_SIZE" ]; then
 | 
			
		||||
  msg_info "Resizing disk to $DISK_SIZE GB"
 | 
			
		||||
  qm resize $VMID scsi0 ${DISK_SIZE} >/dev/null
 | 
			
		||||
else
 | 
			
		||||
  msg_info "Using default disk size of $DEFAULT_DISK_SIZE GB"
 | 
			
		||||
  qm resize $VMID scsi0 ${DEFAULT_DISK_SIZE} >/dev/null
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
msg_ok "Created a Ubuntu 25.04 VM ${CL}${BL}(${HN})"
 | 
			
		||||
if [ "$START_VM" == "yes" ]; then
 | 
			
		||||
  msg_info "Starting Ubuntu 25.04 VM"
 | 
			
		||||
  qm start $VMID
 | 
			
		||||
  msg_ok "Started Ubuntu 25.04 VM"
 | 
			
		||||
fi
 | 
			
		||||
post_update_to_api "done" "none"
 | 
			
		||||
msg_ok "Completed Successfully!\n"
 | 
			
		||||
echo -e "Setup Cloud-Init before starting \n
 | 
			
		||||
More info at https://github.com/community-scripts/ProxmoxVE/discussions/272 \n"
 | 
			
		||||
		Reference in New Issue
	
	Block a user