Compare commits

...

26 Commits

Author SHA1 Message Date
community-scripts-pr-app[bot]
46ca78abc8 Update CHANGELOG.md (#3984)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-22 19:57:02 +02:00
community-scripts-pr-app[bot]
933539ca7c Update .app files (#3985)
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
2025-04-22 19:56:13 +02:00
push-app-to-main[bot]
2c46695b72 reactive-resume (#3980)
* 'Add new script'

* Update reactive-resume.sh

* Update reactive-resume-install.sh

* fssl

* fssl

* date

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com>
Co-authored-by: CanbiZ <47820557+MickLesk@users.noreply.github.com>
2025-04-22 19:48:13 +02:00
community-scripts-pr-app[bot]
f46c3005b3 Update versions.json (#3963)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-22 18:29:21 +02:00
community-scripts-pr-app[bot]
bad84322ee Update CHANGELOG.md (#3982)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-22 16:21:12 +02:00
Michel Roegl-Brunner
3b12c0ca62 Create close-ttek-issues.yaml (#3981) 2025-04-22 15:48:01 +02:00
community-scripts-pr-app[bot]
2583c110d2 Update CHANGELOG.md (#3979)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-22 15:35:40 +02:00
Michel Roegl-Brunner
22c960c99c Fix Turnkey Source Link (#3978) 2025-04-22 14:41:17 +02:00
community-scripts-pr-app[bot]
fcb674b755 Update CHANGELOG.md (#3976)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-22 11:56:30 +02:00
Slaviša Arežina
0373324653 FIx a bug in update procedure and general code maintenance (#3974) 2025-04-22 11:51:50 +02:00
community-scripts-pr-app[bot]
3297df1d50 Update CHANGELOG.md (#3970)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-22 09:53:33 +02:00
Slaviša Arežina
80f1330a75 qBittorrent: Update web page (#3969)
* Set updateable to true

* Update documentation link
2025-04-22 09:30:29 +02:00
community-scripts-pr-app[bot]
05fda7e56a Update versions.json (#3956)
Co-authored-by: GitHub Actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-20 20:59:26 +02:00
community-scripts-pr-app[bot]
73a42eaaae Update CHANGELOG.md (#3954) 2025-04-19 20:02:15 +02:00
Desert Gamer
1ae420eef5 LXC Iptag (#3531) 2025-04-19 20:00:43 +02:00
Slaviša Arežina
96fc1ea91d Clarify tailscale script instruction (#3952) 2025-04-19 19:59:54 +02:00
Slaviša Arežina
432c6837e7 seelf: Add missing gpg dependency (#3953) 2025-04-19 19:59:29 +02:00
community-scripts-pr-app[bot]
2450baffc0 Update CHANGELOG.md (#3939) 2025-04-18 20:08:10 +02:00
Slaviša Arežina
4be3bca2e3 Increase connection timeout for older systems (#3935) 2025-04-18 17:18:20 +02:00
community-scripts-pr-app[bot]
1f93341311 Update CHANGELOG.md (#3931)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-18 09:21:40 +02:00
uSlackr
5723abb81f VaultWarden: Update json with additonal information (#3929)
* Update vaultwarden.json

Add description of issue if web sited accessed without proxy & cert in an attempt to limit support issues

* Update frontend/public/json/vaultwarden.json

---------

Co-authored-by: Slaviša Arežina <58952836+tremor021@users.noreply.github.com>
2025-04-18 09:14:08 +02:00
community-scripts-pr-app[bot]
5cfeb8a0bc Update versions.json (#3908) 2025-04-17 20:21:53 +02:00
community-scripts-pr-app[bot]
8cf9658efb Update CHANGELOG.md (#3923)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-04-17 15:12:46 +02:00
Slaviša Arežina
5dcb75a121 Fix tar command (#3925) 2025-04-17 15:09:18 +02:00
Slaviša Arežina
3c909cabb6 Fix install and update process (final time) (#3922) 2025-04-17 15:09:07 +02:00
Jordan Patton
85a5bf2a55 updated word order in several scripts (#3921) 2025-04-17 08:49:55 +02:00
36 changed files with 1773 additions and 452 deletions

View File

@@ -0,0 +1,51 @@
name: Auto-Close tteck Issues
on:
issues:
types: [opened]
jobs:
close_tteck_issues:
runs-on: ubuntu-latest
steps:
- name: Auto-close if tteck script detected
uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue;
const content = `${issue.title}\n${issue.body}`;
const issueNumber = issue.number;
// Check for tteck script mention
if (content.includes("tteck") || content.includes("tteck/Proxmox")) {
const message = `Hello, it looks like you are referencing the **old tteck repo**.
This repository is no longer used for active scripts.
**Please update your bookmarks** and use: [https://helper-scripts.com](https://helper-scripts.com)
Also make sure your Bash command starts with:
\`\`\`bash
bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/...)
\`\`\`
This issue is being closed automatically.`;
await github.rest.issues.createComment({
...context.repo,
issue_number: issueNumber,
body: message
});
// Optionally apply a label like "not planned"
await github.rest.issues.addLabels({
...context.repo,
issue_number: issueNumber,
labels: ["not planned"]
});
// Close the issue
await github.rest.issues.update({
...context.repo,
issue_number: issueNumber,
state: "closed"
});
}

View File

@@ -14,6 +14,77 @@ 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-04-22
### 🆕 New Scripts
- reactive-resume ([#3980](https://github.com/community-scripts/ProxmoxVE/pull/3980))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- wger: Fix a bug in update procedure and general code maintenance [@tremor021](https://github.com/tremor021) ([#3974](https://github.com/community-scripts/ProxmoxVE/pull/3974))
### 🧰 Maintenance
- #### 📂 Github
- Add workflow to close ttek Repo relatate issues [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#3981](https://github.com/community-scripts/ProxmoxVE/pull/3981))
### 🌐 Website
- #### 🐞 Bug Fixes
- Fix Turnkey Source Link in Button Component [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#3978](https://github.com/community-scripts/ProxmoxVE/pull/3978))
- #### 📝 Script Information
- qBittorrent: Update web page [@tremor021](https://github.com/tremor021) ([#3969](https://github.com/community-scripts/ProxmoxVE/pull/3969))
## 2025-04-19
### 🆕 New Scripts
- LXC Iptag [@DesertGamer](https://github.com/DesertGamer) ([#3531](https://github.com/community-scripts/ProxmoxVE/pull/3531))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- seelf: Add missing gpg dependency [@tremor021](https://github.com/tremor021) ([#3953](https://github.com/community-scripts/ProxmoxVE/pull/3953))
### 🌐 Website
- #### 📝 Script Information
- Tailscale: Clarify tailscale script instruction on website [@tremor021](https://github.com/tremor021) ([#3952](https://github.com/community-scripts/ProxmoxVE/pull/3952))
## 2025-04-18
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Changedetection: Increase connection timeout for older systems [@tremor021](https://github.com/tremor021) ([#3935](https://github.com/community-scripts/ProxmoxVE/pull/3935))
### 🌐 Website
- #### 📝 Script Information
- VaultWarden: Update json with additonal information [@uSlackr](https://github.com/uSlackr) ([#3929](https://github.com/community-scripts/ProxmoxVE/pull/3929))
## 2025-04-17
### 🚀 Updated Scripts
- fix minor grammatical error in several scripts [@jordanpatton](https://github.com/jordanpatton) ([#3921](https://github.com/community-scripts/ProxmoxVE/pull/3921))
- #### 🐞 Bug Fixes
- PeaNUT: Fix tar command [@tremor021](https://github.com/tremor021) ([#3925](https://github.com/community-scripts/ProxmoxVE/pull/3925))
- GoMFT: Fix install and update process (final time) [@tremor021](https://github.com/tremor021) ([#3922](https://github.com/community-scripts/ProxmoxVE/pull/3922))
## 2025-04-15
### 🚀 Updated Scripts

View File

@@ -147,7 +147,7 @@ function select_storage() {
local STORAGE
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for the ${CONTENT_LABEL,,}?\nTo make a selection, use the Spacebar.\n" \
"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."

View File

@@ -51,11 +51,8 @@ function update_script() {
tar -xzf "$temp_file"
cp -rf "GoMFT-${RELEASE}"/* /opt/gomft/
cd /opt/gomft
rm -rf /opt/gomft/node_modules
$STD npm ci
$STD node build.js
$STD go mod download
$STD go get -u github.com/a-h/templ
$STD npm install
$STD npm run build
$STD "$HOME"/go/bin/templ generate
export CGO_ENABLED=1
export GOOS=linux

View File

@@ -0,0 +1,6 @@
____ __ _ ____
/ __ \___ ____ ______/ /_(_) _____ / __ \___ _______ ______ ___ ___
/ /_/ / _ \/ __ `/ ___/ __/ / | / / _ \______/ /_/ / _ \/ ___/ / / / __ `__ \/ _ \
/ _, _/ __/ /_/ / /__/ /_/ /| |/ / __/_____/ _, _/ __(__ ) /_/ / / / / / / __/
/_/ |_|\___/\__,_/\___/\__/_/ |___/\___/ /_/ |_|\___/____/\__,_/_/ /_/ /_/\___/

View File

@@ -32,7 +32,7 @@ function update_script() {
msg_info "Updating $APP to ${RELEASE}"
systemctl stop peanut
curl -fsSL "https://api.github.com/repos/Brandawg93/PeaNUT/tarball/${RELEASE}" -o "peanut.tar.gz"
tar -xzf peanut.tar.gz -C /opt/peanut --strip-components
tar -xzf peanut.tar.gz -C /opt/peanut --strip-components=1
rm peanut.tar.gz
cd /opt/peanut
$STD pnpm i

106
ct/reactive-resume.sh Normal file
View File

@@ -0,0 +1,106 @@
#!/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://rxresu.me
APP="Reactive-Resume"
var_tags="${var_tags:-documents}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-3072}"
var_disk="${var_disk:-8}"
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/Reactive-Resume.service ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/AmruthPillai/Reactive-Resume/releases/latest | 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 services"
systemctl stop Reactive-Resume
msg_ok "Stopped services"
msg_info "Updating $APP to v${RELEASE}"
cp /opt/${APP}/.env /opt/rxresume.env
res_tmp=$(mktemp)
rm -rf /opt/${APP}
curl -fsSL "https://github.com/AmruthPillai/Reactive-Resume/archive/refs/tags/v${RELEASE}.zip" -O $res_tmp
unzip -q $res_tmp
mv ${APP}-${RELEASE}/ /opt/${APP}
cd /opt/${APP}
export PUPPETEER_SKIP_DOWNLOAD="true"
export NEXT_TELEMETRY_DISABLED=1
export CI="true"
export NODE_ENV="production"
$STD pnpm install --frozen-lockfile
$STD pnpm run build
$STD pnpm run prisma:generate
mv /opt/rxresume.env /opt/${APP}/.env
msg_ok "Updated $APP to v${RELEASE}"
msg_info "Updating Minio"
systemctl stop minio
cd /tmp
curl -fsSL https://dl.min.io/server/minio/release/linux-amd64/minio.deb -o minio.deb
$STD dpkg -i minio.deb
msg_ok "Updated Minio"
msg_info "Updating Browserless (Patience)"
systemctl stop browserless
cp /opt/browserless/.env /opt/browserless.env
rm -rf browserless
brwsr_tmp=$(mktemp)
TAG=$(curl -fsSL https://api.github.com/repos/browserless/browserless/tags?per_page=1 | grep "name" | awk '{print substr($2, 3, length($2)-4) }')
curl -fsSL https://github.com/browserless/browserless/archive/refs/tags/v${TAG}.zip -O $brwsr_tmp
unzip -q $brwsr_tmp
mv browserless-${TAG}/ /opt/browserless
cd /opt/browserless
$STD npm install
rm -rf src/routes/{chrome,edge,firefox,webkit}
$STD node_modules/playwright-core/cli.js install --with-deps chromium
$STD npm run build
$STD npm run build:function
$STD npm prune production
mv /opt/browserless.env /opt/browserless/.env
msg_ok "Updated Browserless"
msg_info "Restarting services"
systemctl start minio Reactive-Resume browserless
msg_ok "Restarted services"
msg_info "Cleaning Up"
rm -f /tmp/minio.deb
rm -f $brwsr_tmp
rm -f $res_tmp
msg_ok "Cleanup Completed"
echo "${RELEASE}" >/opt/${APP}_version.txt
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}:3000${CL}"

View File

@@ -20,46 +20,45 @@ color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /home/wger ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/wger-project/wger/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
if [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]] || [[ ! -f /opt/${APP}_version.txt ]]; then
msg_info "Stopping $APP"
systemctl stop wger
msg_ok "Stopped $APP"
msg_info "Updating $APP to v${RELEASE}"
temp_file=$(mktemp)
cd $temp_file
curl -fsSL "https://github.com/wger-project/wger/archive/refs/tags/$RELEASE.tar.gz" -o "$temp_file"
tar xzf $temp_file
cp -rf wger-$RELEASE/* /home/wger/src
cd /home/wger/src
python3 manage.py migrate &>/dev/null
yarn install &>/dev/null
yarn build:css:sass &>/dev/null
python3 manage.py collectstatic --noinput &>/dev/null
echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated $APP to v${RELEASE}"
msg_info "Starting $APP"
systemctl start wger
msg_ok "Started $APP"
msg_info "Cleaning Up"
rm -rf $temp_file
msg_ok "Cleanup Completed"
msg_ok "Update Successful"
else
msg_ok "No update required. ${APP} is already at v${RELEASE}"
fi
header_info
check_container_storage
check_container_resources
if [[ ! -d /home/wger ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
RELEASE=$(curl -fsSL https://api.github.com/repos/wger-project/wger/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
if [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]] || [[ ! -f /opt/${APP}_version.txt ]]; then
msg_info "Stopping $APP"
systemctl stop wger
msg_ok "Stopped $APP"
msg_info "Updating $APP to v${RELEASE}"
temp_file=$(mktemp)
curl -fsSL "https://github.com/wger-project/wger/archive/refs/tags/$RELEASE.tar.gz" -o "$temp_file"
tar xzf "$temp_file"
cp -rf wger-"$RELEASE"/* /home/wger/src
cd /home/wger/src
python3 manage.py migrate &>/dev/null
yarn install &>/dev/null
yarn build:css:sass &>/dev/null
python3 manage.py collectstatic --noinput &>/dev/null
echo "${RELEASE}" >/opt/${APP}_version.txt
msg_ok "Updated $APP to v${RELEASE}"
msg_info "Starting $APP"
systemctl start wger
msg_ok "Started $APP"
msg_info "Cleaning Up"
rm -rf "$temp_file"
msg_ok "Cleanup Completed"
msg_ok "Update Successful"
else
msg_ok "No update required. ${APP} is already at v${RELEASE}"
fi
exit
}
start
@@ -69,4 +68,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}:3000${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"

View File

@@ -1,7 +1,9 @@
{
"name": "Tailscale",
"slug": "add-tailscale-lxc",
"categories": [1],
"categories": [
1
],
"date_created": "2024-05-02",
"type": "addon",
"updateable": false,
@@ -38,7 +40,7 @@
"type": "info"
},
{
"text": "Execute within the Proxmox shell",
"text": "Execute within the Proxmox host shell",
"type": "info"
}
]

View File

@@ -1,34 +1,34 @@
{
"name": "qBittorrent",
"slug": "qbittorrent",
"categories": [
11
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": false,
"privileged": false,
"interface_port": 8090,
"documentation": null,
"website": "https://www.qbittorrent.org/",
"logo": "https://raw.githubusercontent.com/selfhst/icons/refs/heads/main/svg/qbittorrent.svg",
"description": "qBittorrent offers a user-friendly interface that allows users to search for and download torrent files easily. It also supports magnet links, which allow users to start downloading files without the need for a torrent file.",
"install_methods": [
{
"type": "default",
"script": "ct/qbittorrent.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": "admin",
"password": "changeme"
},
"notes": []
}
"name": "qBittorrent",
"slug": "qbittorrent",
"categories": [
11
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8090,
"documentation": "https://github.com/qbittorrent/qBittorrent/wiki/",
"website": "https://www.qbittorrent.org/",
"logo": "https://raw.githubusercontent.com/selfhst/icons/refs/heads/main/svg/qbittorrent.svg",
"description": "qBittorrent offers a user-friendly interface that allows users to search for and download torrent files easily. It also supports magnet links, which allow users to start downloading files without the need for a torrent file.",
"install_methods": [
{
"type": "default",
"script": "ct/qbittorrent.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": "admin",
"password": "changeme"
},
"notes": []
}

View File

@@ -0,0 +1,34 @@
{
"name": "Reactive Resume",
"slug": "reactive-resume",
"categories": [
12
],
"date_created": "2025-04-22",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3000,
"documentation": "https://docs.rxresu.me/",
"website": "https://rxresu.me",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/png/reactive-resume-light.png",
"description": "A one-of-a-kind resume builder that keeps your privacy in mind. Completely secure, customizable, portable, open-source and free forever.",
"install_methods": [
{
"type": "default",
"script": "ct/reactive-resume.sh",
"resources": {
"cpu": 2,
"ram": 3072,
"hdd": 8,
"os": "Debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -43,7 +43,7 @@
},
"notes": [
{
"text": "Vaultwarden needs to be behind a proxy (Nginx Proxy Manager) to obtain HTTPS and to allow clients to connect.",
"text": "Vaultwarden needs to be behind a proxy (Nginx Proxy Manager, Caddy, etc) to obtain HTTPS and to allow clients to connect. If you try to open the web page directly on the new container, the web site will not load",
"type": "warning"
},
{

View File

@@ -2,7 +2,12 @@
{
"name": "fhem/fhem-mirror",
"version": "6.2",
"date": "2025-04-15T10:34:54Z"
"date": "2025-04-22T10:34:10Z"
},
{
"name": "OctoPrint/OctoPrint",
"version": "1.11.0",
"date": "2025-04-22T09:33:46Z"
},
{
"name": "n8n-io/n8n",
@@ -10,19 +15,334 @@
"date": "2025-04-09T09:20:55Z"
},
{
"name": "wazuh/wazuh",
"version": "coverity-w16-4.12.0",
"date": "2025-04-15T08:25:08Z"
"name": "zabbix/zabbix",
"version": "6.0.40",
"date": "2025-04-22T08:43:35Z"
},
{
"name": "Checkmk/checkmk",
"version": "v2.4.0b6-rc1",
"date": "2025-04-22T08:12:24Z"
},
{
"name": "nzbgetcom/nzbget",
"version": "v24.8",
"date": "2025-03-18T07:33:51Z"
},
{
"name": "openobserve/openobserve",
"version": "v0.14.6-rc5",
"date": "2025-04-22T06:50:13Z"
},
{
"name": "mattermost/mattermost",
"version": "v10.6.2",
"date": "2025-04-15T08:14:23Z"
},
{
"name": "morpheus65535/bazarr",
"version": "v1.5.1",
"date": "2025-01-01T16:15:52Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.2.12",
"date": "2025-04-20T19:22:17Z"
},
{
"name": "Jackett/Jackett",
"version": "v0.22.1778",
"date": "2025-04-15T06:26:21Z"
"version": "v0.22.1809",
"date": "2025-04-22T05:55:35Z"
},
{
"name": "monicahq/monica",
"version": "v4.1.2",
"date": "2024-05-04T08:06:50Z"
},
{
"name": "OliveTin/OliveTin",
"version": "2025.4.21",
"date": "2025-04-21T19:16:09Z"
},
{
"name": "Suwayomi/Suwayomi-Server",
"version": "v2.0.1727",
"date": "2025-04-21T17:53:05Z"
},
{
"name": "TasmoAdmin/TasmoAdmin",
"version": "v4.3.0",
"date": "2025-04-21T17:44:40Z"
},
{
"name": "emqx/emqx",
"version": "e5.9.0-beta.4",
"date": "2025-04-21T17:08:59Z"
},
{
"name": "runtipi/runtipi",
"version": "v3.10.0-beta.9",
"date": "2025-04-17T11:46:08Z"
},
{
"name": "AdguardTeam/AdGuardHome",
"version": "v0.107.60",
"date": "2025-04-14T11:46:19Z"
},
{
"name": "keycloak/keycloak",
"version": "26.2.0",
"date": "2025-04-11T12:48:27Z"
},
{
"name": "cross-seed/cross-seed",
"version": "v6.11.2",
"date": "2025-02-26T14:54:49Z"
},
{
"name": "Prowlarr/Prowlarr",
"version": "v1.34.1.5021",
"date": "2025-04-20T19:29:50Z"
},
{
"name": "semaphoreui/semaphore",
"version": "v2.13.14",
"date": "2025-04-19T20:39:23Z"
},
{
"name": "pocket-id/pocket-id",
"version": "v0.49.0",
"date": "2025-04-20T18:03:03Z"
},
{
"name": "YunoHost/yunohost",
"version": "debian/12.0.14",
"date": "2025-04-09T10:09:00Z"
},
{
"name": "Kareadita/Kavita",
"version": "v0.8.6.2",
"date": "2025-04-20T16:55:38Z"
},
{
"name": "openhab/openhab-core",
"version": "5.0.0.M2",
"date": "2025-04-20T13:16:29Z"
},
{
"name": "pocketbase/pocketbase",
"version": "v0.27.1",
"date": "2025-04-20T11:26:50Z"
},
{
"name": "karakeep-app/karakeep",
"version": "extension/v1.2.5",
"date": "2025-04-20T10:19:06Z"
},
{
"name": "MediaBrowser/Emby.Releases",
"version": "4.8.11.0",
"date": "2025-03-10T06:39:11Z"
},
{
"name": "Readarr/Readarr",
"version": "v2.0.0.4645",
"date": "2017-03-07T18:56:06Z"
},
{
"name": "Radarr/Radarr",
"version": "v5.21.1.9799",
"date": "2025-03-24T15:52:12Z"
},
{
"name": "paperless-ngx/paperless-ngx",
"version": "v2.15.3",
"date": "2025-04-19T23:02:17Z"
},
{
"name": "ellite/Wallos",
"version": "v2.52.0",
"date": "2025-04-19T20:36:50Z"
},
{
"name": "msgbyte/tianji",
"version": "v1.20.7",
"date": "2025-04-19T20:35:09Z"
},
{
"name": "theonedev/onedev",
"version": "v11.8.7",
"date": "2025-04-19T11:19:29Z"
},
{
"name": "home-assistant/core",
"version": "2025.4.3",
"date": "2025-04-19T10:23:38Z"
},
{
"name": "moghtech/komodo",
"version": "v1.17.2",
"date": "2025-04-19T06:56:25Z"
},
{
"name": "ollama/ollama",
"version": "v0.6.6-rc1",
"date": "2025-04-17T01:56:29Z"
},
{
"name": "caddyserver/caddy",
"version": "v2.10.0",
"date": "2025-04-18T20:46:28Z"
},
{
"name": "homarr-labs/homarr",
"version": "v1.17.0",
"date": "2025-04-18T19:14:57Z"
},
{
"name": "Paymenter/Paymenter",
"version": "v1.0.4",
"date": "2025-04-18T16:08:02Z"
},
{
"name": "prometheus/prometheus",
"version": "v3.3.0",
"date": "2025-04-18T13:46:38Z"
},
{
"name": "dgtlmoon/changedetection.io",
"version": "0.49.15",
"date": "2025-04-18T12:58:26Z"
},
{
"name": "traefik/traefik",
"version": "v3.3.6",
"date": "2025-04-18T09:28:22Z"
},
{
"name": "TandoorRecipes/recipes",
"version": "1.5.34",
"date": "2025-03-27T16:17:38Z"
},
{
"name": "Luligu/matterbridge",
"version": "2.2.9",
"date": "2025-04-18T10:05:52Z"
},
{
"name": "HabitRPG/habitica",
"version": "v5.35.4",
"date": "2025-04-17T21:18:55Z"
},
{
"name": "tailscale/tailscale",
"version": "v1.82.5",
"date": "2025-04-17T20:59:15Z"
},
{
"name": "TriliumNext/Notes",
"version": "v0.93.0",
"date": "2025-04-17T20:05:25Z"
},
{
"name": "coder/code-server",
"version": "v4.99.3",
"date": "2025-04-17T18:33:11Z"
},
{
"name": "VictoriaMetrics/VictoriaMetrics",
"version": "v1.19.0-victorialogs",
"date": "2025-04-17T18:26:31Z"
},
{
"name": "duplicati/duplicati",
"version": "v2.1.0.116-2.1.0.116_canary_2025-04-17",
"date": "2025-04-17T17:52:31Z"
},
{
"name": "benzino77/tasmocompiler",
"version": "v12.6.1",
"date": "2025-04-17T17:35:02Z"
},
{
"name": "docker/compose",
"version": "v2.35.1",
"date": "2025-04-17T14:29:11Z"
},
{
"name": "influxdata/influxdb",
"version": "v3.0.1",
"date": "2025-04-17T14:06:09Z"
},
{
"name": "documenso/documenso",
"version": "v1.10.0-rc.5",
"date": "2025-04-17T13:01:43Z"
},
{
"name": "prometheus-pve/prometheus-pve-exporter",
"version": "v3.5.3",
"date": "2025-04-17T10:40:47Z"
},
{
"name": "IceWhaleTech/CasaOS",
"version": "v0.4.15",
"date": "2024-12-19T03:19:49Z"
},
{
"name": "esphome/esphome",
"version": "2025.4.0",
"date": "2025-04-17T00:55:34Z"
},
{
"name": "docmost/docmost",
"version": "v0.10.2",
"date": "2025-04-16T20:43:40Z"
},
{
"name": "forgejo/forgejo",
"version": "v11.0.0",
"date": "2025-04-16T19:25:53Z"
},
{
"name": "element-hq/synapse",
"version": "v1.129.0rc1",
"date": "2025-04-16T15:18:13Z"
},
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.506",
"date": "2025-04-15T15:40:50Z"
},
{
"name": "wazuh/wazuh",
"version": "coverity-w17-4.12.0",
"date": "2025-04-16T11:20:57Z"
},
{
"name": "icereed/paperless-gpt",
"version": "v0.15.0",
"date": "2025-04-16T03:58:02Z"
},
{
"name": "rabbitmq/rabbitmq-server",
"version": "v4.1.0",
"date": "2025-04-15T16:18:29Z"
},
{
"name": "Brandawg93/PeaNUT",
"version": "v5.7.2",
"date": "2025-04-15T15:44:49Z"
},
{
"name": "WordPress/WordPress",
"version": "6.8",
"date": "2025-04-15T15:41:16Z"
},
{
"name": "Stirling-Tools/Stirling-PDF",
"version": "v0.45.6",
"date": "2025-04-15T14:16:52Z"
},
{
"name": "slskd/slskd",
@@ -34,91 +354,21 @@
"version": "v0.14.1",
"date": "2024-08-29T22:32:51Z"
},
{
"name": "esphome/esphome",
"version": "2025.3.3",
"date": "2025-03-31T22:07:05Z"
},
{
"name": "moghtech/komodo",
"version": "v1.17.1",
"date": "2025-04-14T22:35:13Z"
},
{
"name": "influxdata/influxdb",
"version": "v3.0.0",
"date": "2025-04-14T22:16:28Z"
},
{
"name": "Kareadita/Kavita",
"version": "v0.8.6",
"date": "2025-04-14T22:09:30Z"
},
{
"name": "keycloak/keycloak",
"version": "26.2.0",
"date": "2025-04-11T12:48:27Z"
},
{
"name": "paperless-ngx/paperless-ngx",
"version": "v2.15.2",
"date": "2025-04-14T20:48:52Z"
},
{
"name": "semaphoreui/semaphore",
"version": "v2.13.13",
"date": "2025-04-11T10:15:13Z"
},
{
"name": "netbox-community/netbox",
"version": "v4.2.7",
"date": "2025-04-10T20:08:13Z"
},
{
"name": "duplicati/duplicati",
"version": "v2.1.0.115-2.1.0.115_canary_2025-04-14",
"date": "2025-04-14T18:03:36Z"
},
{
"name": "OliveTin/OliveTin",
"version": "2025.4.14",
"date": "2025-04-14T16:53:53Z"
},
{
"name": "msgbyte/tianji",
"version": "v1.20.0",
"date": "2025-04-14T16:19:23Z"
},
{
"name": "home-assistant/operating-system",
"version": "15.2",
"date": "2025-04-14T15:37:12Z"
},
{
"name": "Checkmk/checkmk",
"version": "v2.4.0b5-rc1",
"date": "2025-04-14T15:29:21Z"
},
{
"name": "stackblitz-labs/bolt.diy",
"version": "v0.0.7-hf1",
"date": "2025-03-10T20:49:39Z"
},
{
"name": "zabbix/zabbix",
"version": "7.2.6rc1",
"date": "2025-04-14T15:00:15Z"
},
{
"name": "rabbitmq/rabbitmq-server",
"version": "v4.0.9",
"date": "2025-04-14T14:40:34Z"
},
{
"name": "AdguardTeam/AdGuardHome",
"version": "v0.107.60",
"date": "2025-04-14T11:46:19Z"
},
{
"name": "Graylog2/graylog2-server",
"version": "6.2.0-rc.1",
@@ -129,11 +379,6 @@
"version": "v1.12.0",
"date": "2025-04-14T10:36:04Z"
},
{
"name": "Stirling-Tools/Stirling-PDF",
"version": "v0.45.5",
"date": "2025-04-14T09:57:39Z"
},
{
"name": "open-webui/open-webui",
"version": "v0.6.5",
@@ -149,26 +394,11 @@
"version": "0.203.1",
"date": "2025-04-14T07:23:02Z"
},
{
"name": "morpheus65535/bazarr",
"version": "v1.5.1",
"date": "2025-01-01T16:15:52Z"
},
{
"name": "firefly-iii/firefly-iii",
"version": "v6.2.10",
"date": "2025-03-22T13:02:26Z"
},
{
"name": "glanceapp/glance",
"version": "v0.7.12",
"date": "2025-04-14T00:16:15Z"
},
{
"name": "ellite/Wallos",
"version": "v2.49.1",
"date": "2025-04-13T22:36:24Z"
},
{
"name": "rogerfar/rdt-client",
"version": "v2.0.108",
@@ -184,21 +414,6 @@
"version": "v4.47.1",
"date": "2025-01-05T21:14:23Z"
},
{
"name": "pocket-id/pocket-id",
"version": "v0.46.0",
"date": "2025-04-13T18:31:13Z"
},
{
"name": "runtipi/runtipi",
"version": "v3.10.0",
"date": "2025-03-15T14:38:16Z"
},
{
"name": "karakeep-app/karakeep",
"version": "mcp/v0.23.4",
"date": "2025-04-13T14:09:19Z"
},
{
"name": "syncthing/syncthing",
"version": "v2.0.0-beta.9",
@@ -214,21 +429,6 @@
"version": "v2.10.3.4602",
"date": "2025-03-23T11:00:37Z"
},
{
"name": "Readarr/Readarr",
"version": "v2.0.0.4645",
"date": "2017-03-07T18:56:06Z"
},
{
"name": "Prowlarr/Prowlarr",
"version": "v1.33.3.5008",
"date": "2025-04-09T17:58:37Z"
},
{
"name": "Radarr/Radarr",
"version": "v5.21.1.9799",
"date": "2025-03-24T15:52:12Z"
},
{
"name": "Tautulli/Tautulli",
"version": "v2.15.2",
@@ -239,16 +439,6 @@
"version": "v0.2.11",
"date": "2025-04-12T21:13:08Z"
},
{
"name": "MediaBrowser/Emby.Releases",
"version": "4.8.11.0",
"date": "2025-03-10T06:39:11Z"
},
{
"name": "home-assistant/core",
"version": "2025.4.2",
"date": "2025-04-12T09:46:22Z"
},
{
"name": "readeck/readeck",
"version": "0.18.0",
@@ -259,46 +449,11 @@
"version": "v5.5.2",
"date": "2025-04-11T22:00:06Z"
},
{
"name": "homarr-labs/homarr",
"version": "v1.16.0",
"date": "2025-04-11T19:15:24Z"
},
{
"name": "tailscale/tailscale",
"version": "v1.82.4",
"date": "2025-04-11T17:58:09Z"
},
{
"name": "coder/code-server",
"version": "v4.99.2",
"date": "2025-04-11T17:57:47Z"
},
{
"name": "TriliumNext/Notes",
"version": "v0.0.0",
"date": "2025-04-11T14:18:00Z"
},
{
"name": "emqx/emqx",
"version": "e5.9.0-beta.3",
"date": "2025-04-11T14:17:53Z"
},
{
"name": "NLnetLabs/unbound",
"version": "release-1.23.0rc2",
"date": "2025-04-11T13:24:25Z"
},
{
"name": "docmost/docmost",
"version": "v0.10.1",
"date": "2025-04-11T12:42:08Z"
},
{
"name": "dgtlmoon/changedetection.io",
"version": "0.49.13",
"date": "2025-04-11T11:48:06Z"
},
{
"name": "sabnzbd/sabnzbd",
"version": "4.5.1",
@@ -309,16 +464,6 @@
"version": "v0.83.0",
"date": "2025-04-11T03:53:10Z"
},
{
"name": "openobserve/openobserve",
"version": "v0.14.6-rc3",
"date": "2025-04-11T03:08:28Z"
},
{
"name": "Luligu/matterbridge",
"version": "2.2.8",
"date": "2025-04-10T20:30:49Z"
},
{
"name": "gristlabs/grist-core",
"version": "v1.5.1",
@@ -329,26 +474,11 @@
"version": "cassandra-5.0.4",
"date": "2025-04-10T16:32:00Z"
},
{
"name": "VictoriaMetrics/VictoriaMetrics",
"version": "v1.18.0-victorialogs",
"date": "2025-04-10T15:05:20Z"
},
{
"name": "NodeBB/NodeBB",
"version": "v4.2.1",
"date": "2025-04-10T14:03:47Z"
},
{
"name": "Paymenter/Paymenter",
"version": "v1.0.3",
"date": "2025-04-10T13:57:39Z"
},
{
"name": "docker/compose",
"version": "v2.35.0",
"date": "2025-04-10T13:45:22Z"
},
{
"name": "mongodb/mongo",
"version": "r8.0.5-rc2",
@@ -359,31 +489,16 @@
"version": "v7.4.0",
"date": "2025-04-09T17:36:14Z"
},
{
"name": "Brandawg93/PeaNUT",
"version": "v5.7.1",
"date": "2025-04-09T15:06:49Z"
},
{
"name": "glpi-project/glpi",
"version": "10.0.18",
"date": "2025-02-12T11:07:02Z"
},
{
"name": "HabitRPG/habitica",
"version": "v5.35.2",
"date": "2025-04-09T13:46:58Z"
},
{
"name": "zitadel/zitadel",
"version": "v2.69.10",
"date": "2025-04-09T12:16:51Z"
},
{
"name": "YunoHost/yunohost",
"version": "debian/12.0.14",
"date": "2025-04-09T10:09:00Z"
},
{
"name": "minio/minio",
"version": "RELEASE.2025-04-08T15-41-24Z",
@@ -394,26 +509,11 @@
"version": "version/2025.2.4",
"date": "2025-04-08T18:39:57Z"
},
{
"name": "jenkinsci/jenkins",
"version": "jenkins-2.505",
"date": "2025-04-08T15:46:42Z"
},
{
"name": "element-hq/synapse",
"version": "v1.128.0",
"date": "2025-04-08T14:27:55Z"
},
{
"name": "linkwarden/linkwarden",
"version": "v2.10.0",
"date": "2025-04-08T12:33:57Z"
},
{
"name": "prometheus/prometheus",
"version": "v0.303.0-rc.1",
"date": "2025-04-07T04:39:38Z"
},
{
"name": "pelican-dev/panel",
"version": "v1.0.0-beta19",
@@ -449,11 +549,6 @@
"version": "8.0-rc1-int2",
"date": "2025-04-02T19:05:08Z"
},
{
"name": "nzbgetcom/nzbget",
"version": "v24.8",
"date": "2025-03-18T07:33:51Z"
},
{
"name": "Dolibarr/dolibarr",
"version": "21.0.1",
@@ -469,11 +564,6 @@
"version": "2.0.3",
"date": "2025-04-06T17:35:41Z"
},
{
"name": "TandoorRecipes/recipes",
"version": "1.5.34",
"date": "2025-03-27T16:17:38Z"
},
{
"name": "TechnitiumSoftware/DnsServer",
"version": "v13.5.0",
@@ -489,11 +579,6 @@
"version": "0.17.10",
"date": "2025-04-06T05:31:49Z"
},
{
"name": "ollama/ollama",
"version": "v0.6.5",
"date": "2025-04-06T00:15:39Z"
},
{
"name": "jellyfin/jellyfin",
"version": "v10.10.7",
@@ -539,21 +624,11 @@
"version": "5.7.0",
"date": "2025-04-04T18:10:16Z"
},
{
"name": "icereed/paperless-gpt",
"version": "v0.14.4",
"date": "2025-04-04T14:18:53Z"
},
{
"name": "apache/tomcat",
"version": "9.0.104",
"date": "2025-04-04T12:58:11Z"
},
{
"name": "OctoPrint/OctoPrint",
"version": "1.10.3",
"date": "2024-11-05T09:20:50Z"
},
{
"name": "BookStackApp/BookStack",
"version": "v25.02.2",
@@ -579,11 +654,6 @@
"version": "v2.31.0",
"date": "2025-04-01T18:12:45Z"
},
{
"name": "theonedev/onedev",
"version": "v11.8.6",
"date": "2025-04-01T13:52:03Z"
},
{
"name": "neo4j/neo4j",
"version": "5.26.5",
@@ -600,14 +670,9 @@
"date": "2025-03-31T21:31:48Z"
},
{
"name": "traefik/traefik",
"version": "v3.3.5",
"date": "2025-03-31T08:55:12Z"
},
{
"name": "documenso/documenso",
"version": "v1.10.0-rc.4",
"date": "2025-03-31T09:02:22Z"
"name": "mysql/mysql-server",
"version": "mysql-cluster-9.3.0",
"date": "2025-03-31T07:42:45Z"
},
{
"name": "louislam/dockge",
@@ -624,16 +689,6 @@
"version": "v1.17.0",
"date": "2025-03-30T14:21:53Z"
},
{
"name": "openhab/openhab-core",
"version": "4.3.4",
"date": "2025-03-30T13:32:38Z"
},
{
"name": "pocketbase/pocketbase",
"version": "v0.26.6",
"date": "2025-03-30T08:02:19Z"
},
{
"name": "aceberg/WatchYourLAN",
"version": "2.1.2-alpine",
@@ -654,11 +709,6 @@
"version": "v1.6.1",
"date": "2025-03-15T17:29:17Z"
},
{
"name": "TasmoAdmin/TasmoAdmin",
"version": "v4.2.3",
"date": "2025-02-09T23:07:48Z"
},
{
"name": "grocy/grocy",
"version": "v4.5.0",
@@ -689,11 +739,6 @@
"version": "2025.2",
"date": "2025-03-27T19:21:13Z"
},
{
"name": "forgejo/forgejo",
"version": "v12.0.0-dev",
"date": "2025-03-26T09:58:55Z"
},
{
"name": "sct/overseerr",
"version": "v1.34.0",
@@ -724,11 +769,6 @@
"version": "v1.6.8",
"date": "2025-03-25T13:33:10Z"
},
{
"name": "caddyserver/caddy",
"version": "v2.9.1",
"date": "2025-01-08T15:22:53Z"
},
{
"name": "ZoeyVid/NPMplus",
"version": "2025-03-24-r2",
@@ -885,7 +925,7 @@
"date": "2025-03-05T21:41:29Z"
},
{
"name": "snipe/snipe-it",
"name": "grokability/snipe-it",
"version": "v8.0.4",
"date": "2025-03-05T17:12:03Z"
},
@@ -909,11 +949,6 @@
"version": "v1.5.7",
"date": "2025-02-27T20:04:08Z"
},
{
"name": "cross-seed/cross-seed",
"version": "v6.11.2",
"date": "2025-02-26T14:54:49Z"
},
{
"name": "silverbulletmd/silverbullet",
"version": "0.10.4",
@@ -924,11 +959,6 @@
"version": "v0.25.1",
"date": "2025-02-25T17:30:48Z"
},
{
"name": "benzino77/tasmocompiler",
"version": "v12.5.0",
"date": "2025-02-25T14:55:50Z"
},
{
"name": "schlagmichdoch/PairDrop",
"version": "v1.11.2",
@@ -949,11 +979,6 @@
"version": "v1.1.05",
"date": "2025-02-24T11:53:12Z"
},
{
"name": "prometheus-pve/prometheus-pve-exporter",
"version": "v3.5.2",
"date": "2025-02-18T16:43:41Z"
},
{
"name": "typesense/typesense",
"version": "v28.0",
@@ -994,11 +1019,6 @@
"version": "mariadb-11.7.2",
"date": "2025-02-13T04:13:46Z"
},
{
"name": "WordPress/WordPress",
"version": "6.7.2",
"date": "2025-02-11T16:13:18Z"
},
{
"name": "homebridge/homebridge",
"version": "v1.9.0",
@@ -1079,16 +1099,6 @@
"version": "v0.24.6",
"date": "2024-12-22T20:24:35Z"
},
{
"name": "IceWhaleTech/CasaOS",
"version": "v0.4.15",
"date": "2024-12-19T03:19:49Z"
},
{
"name": "mysql/mysql-server",
"version": "mysql-cluster-7.6.33",
"date": "2024-12-16T11:55:50Z"
},
{
"name": "ArchiveBox/ArchiveBox",
"version": "v0.7.3",
@@ -1184,11 +1194,6 @@
"version": "v3.3.21",
"date": "2024-06-26T01:14:46Z"
},
{
"name": "Suwayomi/Suwayomi-Server",
"version": "v1.1.1",
"date": "2024-06-15T17:23:48Z"
},
{
"name": "Forceu/barcodebuddy",
"version": "v1.8.1.8",
@@ -1224,11 +1229,6 @@
"version": "1.0.0",
"date": "2024-05-05T02:01:51Z"
},
{
"name": "monicahq/monica",
"version": "v4.1.2",
"date": "2024-05-04T08:06:50Z"
},
{
"name": "thelounge/thelounge-deb",
"version": "v4.4.3",

View File

@@ -24,6 +24,8 @@ const generateSourceUrl = (slug: string, type: string) => {
return `${baseUrl}/tools/pve/${slug}.sh`;
case "addon":
return `${baseUrl}/tools/addon/${slug}.sh`;
case "turnkey":
return `${baseUrl}/turnkey/${slug}.sh`;
default:
return `${baseUrl}/ct/${slug}.sh`; // fallback for "ct"
}

View File

@@ -137,6 +137,7 @@ cat <<EOF >/etc/systemd/system/browserless.service
Description=browserless service
After=network.target
[Service]
Environment=CONNECTION_TIMEOUT=60000
WorkingDirectory=/opt/browserless
ExecStart=/opt/browserless/scripts/start.sh
SyslogIdentifier=browserless

View File

@@ -47,19 +47,13 @@ msg_ok "Installed Node.js"
msg_info "Setup ${APPLICATION} (Patience)"
temp_file=$(mktemp)
RELEASE=$(curl -fsSL https://api.github.com/repos/StarFleetCPTN/GoMFT/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
curl -fsSL "https://github.com/StarFleetCPTN/GoMFT/archive/refs/tags/v${RELEASE}.tar.gz" -o $temp_file
tar -xzf $temp_file
mv GoMFT-${RELEASE}/ /opt/gomft
curl -fsSL "https://github.com/StarFleetCPTN/GoMFT/archive/refs/tags/v${RELEASE}.tar.gz" -o "$temp_file"
tar -xzf "$temp_file"
mv GoMFT-"${RELEASE}"/ /opt/gomft
cd /opt/gomft
$STD npm ci
$STD node build.js
$STD go mod download
$STD go install github.com/a-h/templ/cmd/templ@latest
$STD go get -u github.com/a-h/templ
$STD $HOME/go/bin/templ generate
export CGO_ENABLED=1
export GOOS=linux
$STD go build -o gomft
$STD "$HOME"/go/bin/templ generate
$STD go build -o gomft main.go
chmod +x /opt/gomft/gomft
JWT_SECRET_KEY=$(openssl rand -base64 24 | tr -d '/+=')
@@ -83,7 +77,7 @@ EMAIL_USERNAME=smtp_username
EMAIL_PASSWORD=smtp_password
EOF
echo "${RELEASE}" >/opt/${APPLICATION}_version.txt
echo "${RELEASE}" >/opt/"${APPLICATION}"_version.txt
msg_ok "Setup ${APPLICATION}"
msg_info "Creating Service"
@@ -109,7 +103,7 @@ motd_ssh
customize
msg_info "Cleaning up"
rm -f $temp_file
rm -f "$temp_file"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -34,7 +34,7 @@ msg_info "Installing Peanut"
RELEASE=$(curl -fsSL https://api.github.com/repos/Brandawg93/PeaNUT/releases/latest | grep '"tag_name":' | cut -d'"' -f4)
curl -fsSL "https://api.github.com/repos/Brandawg93/PeaNUT/tarball/${RELEASE}" -o "peanut.tar.gz"
mkdir -p /opt/peanut
tar -xzf peanut.tar.gz -C /opt/peanut --strip-components 1
tar -xzf peanut.tar.gz -C /opt/peanut --strip-components=1
rm peanut.tar.gz
cd /opt/peanut
$STD npm install -g pnpm

View File

@@ -0,0 +1,190 @@
#!/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://rxresu.me
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 \
gnupg \
unzip \
postgresql-common
msg_ok "Installed Dependencies"
msg_info "Installing Additional Dependencies"
mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" >/etc/apt/sources.list.d/nodesource.list
echo "YES" | /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh &>/dev/null
$STD apt-get install -y postgresql-16 nodejs
cd /tmp
curl -fsSL https://dl.min.io/server/minio/release/linux-amd64/minio.deb -o minio.deb
$STD dpkg -i minio.deb
msg_info "Setting up Database"
DB_USER="rxresume"
DB_NAME="rxresume"
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
$STD sudo -u postgres psql -c "CREATE USER $DB_USER WITH ENCRYPTED 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 "GRANT ALL PRIVILEGES ON DATABASE $DB_NAME to $DB_USER;"
$STD sudo -u postgres psql -c "ALTER USER $DB_USER WITH SUPERUSER;"
msg_ok "Set up Database"
msg_info "Installing ${APPLICATION}"
MINIO_PASS=$(openssl rand -base64 48)
ACCESS_TOKEN=$(openssl rand -base64 48)
REFRESH_TOKEN=$(openssl rand -base64 48)
CHROME_TOKEN=$(openssl rand -hex 32)
LOCAL_IP=$(hostname -I | awk '{print $1}')
TAG=$(curl -fsSL https://api.github.com/repos/browserless/browserless/tags?per_page=1 | grep "name" | awk '{print substr($2, 3, length($2)-4) }')
RELEASE=$(curl -fsSL https://api.github.com/repos/AmruthPillai/Reactive-Resume/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
curl -fsSL "https://github.com/AmruthPillai/Reactive-Resume/archive/refs/tags/v${RELEASE}.zip" -o v${RELEASE}.zip
unzip -q v${RELEASE}.zip
mv ${APPLICATION}-${RELEASE}/ /opt/${APPLICATION}
cd /opt/${APPLICATION}
corepack enable
export CI="true"
export PUPPETEER_SKIP_DOWNLOAD="true"
export NODE_ENV="production"
export NEXT_TELEMETRY_DISABLED=1
$STD pnpm install --frozen-lockfile
$STD pnpm run build
$STD pnpm install --prod --frozen-lockfile
$STD pnpm run prisma:generate
msg_ok "Installed ${APPLICATION}"
msg_info "Installing Browserless (Patience)"
cd /tmp
curl -fsSL https://github.com/browserless/browserless/archive/refs/tags/v${TAG}.zip -o v${TAG}.zip
unzip -q v${TAG}.zip
mv browserless-${TAG} /opt/browserless
cd /opt/browserless
$STD npm install
rm -rf src/routes/{chrome,edge,firefox,webkit}
$STD node_modules/playwright-core/cli.js install --with-deps chromium
$STD npm run build
$STD npm run build:function
$STD npm prune production
msg_ok "Installed Browserless"
msg_info "Configuring applications"
mkdir -p /opt/minio
cat <<EOF >/opt/minio/.env
MINIO_ROOT_USER="storageadmin"
MINIO_ROOT_PASSWORD="${MINIO_PASS}"
MINIO_VOLUMES=/opt/minio
MINIO_OPTS="--address :9000 --console-address 127.0.0.1:9001"
EOF
cat <<EOF >/opt/${APPLICATION}/.env
NODE_ENV=production
PORT=3000
PUBLIC_URL=http://${LOCAL_IP}:3000
STORAGE_URL=http://${LOCAL_IP}:9000/rxresume
DATABASE_URL=postgresql://${DB_USER}:${DB_PASS}@localhost:5432/${DB_NAME}?schema=public
ACCESS_TOKEN_SECRET=${ACCESS_TOKEN}
REFRESH_TOKEN_SECRET=${REFRESH_TOKEN}
CHROME_PORT=8080
CHROME_TOKEN=${CHROME_TOKEN}
CHROME_URL=ws://localhost:8080
CHROME_IGNORE_HTTPS_ERRORS=true
MAIL_FROM=noreply@locahost
# SMTP_URL=smtp://username:password@smtp.server.mail:587 #
STORAGE_ENDPOINT=localhost
STORAGE_PORT=9000
STORAGE_REGION=us-east-1
STORAGE_BUCKET=rxresume
STORAGE_ACCESS_KEY=storageadmin
STORAGE_SECRET_KEY=${MINIO_PASS}
STORAGE_USE_SSL=false
STORAGE_SKIP_BUCKET_CHECK=false
# GitHub (OAuth, Optional)
# GITHUB_CLIENT_ID=
# GITHUB_CLIENT_SECRET=
# GITHUB_CALLBACK_URL=http://localhost:5173/api/auth/github/callback
# Google (OAuth, Optional)
# GOOGLE_CLIENT_ID=
# GOOGLE_CLIENT_SECRET=
# GOOGLE_CALLBACK_URL=http://localhost:5173/api/auth/google/callback
EOF
cat <<EOF >/opt/browserless/.env
DEBUG=browserless*,-**:verbose
HOST=localhost
PORT=8080
TOKEN=${CHROME_TOKEN}
EOF
echo "${RELEASE}" >/opt/${APPLICATION}_version.txt
{
echo "${APPLICATION} Credentials"
echo "Database User: $DB_USER"
echo "Database Password: $DB_PASS"
echo "Database Name: $DB_NAME"
echo "Minio Root Password: ${MINIO_PASS}"
} >>~/${APPLICATION}.creds
msg_ok "Configured applications"
msg_info "Creating Services"
mkdir -p /etc/systemd/system/minio.service.d/
cat <<EOF >/etc/systemd/system/minio.service.d/override.conf
[Service]
User=root
Group=root
WorkingDirectory=/usr/local/bin
EnvironmentFile=/opt/minio/.env
EOF
cat <<EOF >/etc/systemd/system/${APPLICATION}.service
[Unit]
Description=${APPLICATION} Service
After=network.target postgresql.service minio.service
Wants=postgresql.service minio.service
[Service]
WorkingDirectory=/opt/${APPLICATION}
EnvironmentFile=/opt/${APPLICATION}/.env
ExecStart=/usr/bin/pnpm run start
Restart=always
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/browserless.service
[Unit]
Description=Browserless service
After=network.target ${APPLICATION}.service
[Service]
WorkingDirectory=/opt/browserless
EnvironmentFile=/opt/browserless/.env
ExecStart=/usr/bin/npm run start
Restart=unless-stopped
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable -q --now minio.service ${APPLICATION}.service browserless.service
msg_ok "Created Services"
motd_ssh
customize
msg_info "Cleaning up"
rm -f /tmp/v${RELEASE}.zip
rm -f /tmp/v${TAG}.zip
rm -f /tmp/minio.deb
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"

View File

@@ -16,7 +16,8 @@ update_os
msg_info "Installing Dependencies"
$STD apt-get install -y \
make \
gcc
gcc \
gpg
msg_ok "Installed Dependencies"
msg_info "Installing Golang"
@@ -43,8 +44,8 @@ msg_ok "Installed Node.js"
msg_info "Setting up seelf. Patience"
RELEASE=$(curl -fsSL https://api.github.com/repos/YuukanOO/seelf/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
curl -fsSL "https://github.com/YuukanOO/seelf/archive/refs/tags/v${RELEASE}.tar.gz" -o $(basename "https://github.com/YuukanOO/seelf/archive/refs/tags/v${RELEASE}.tar.gz")
tar -xzf v${RELEASE}.tar.gz
mv seelf-${RELEASE}/ /opt/seelf
tar -xzf v"${RELEASE}".tar.gz
mv seelf-"${RELEASE}"/ /opt/seelf
cd /opt/seelf
$STD make build
PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
@@ -84,11 +85,11 @@ customize
# Cleanup
msg_info "Cleaning up"
rm -f ~/v${RELEASE}.tar.gz
rm -f $temp_file
rm -f ~/v"${RELEASE}".tar.gz
rm -f "$temp_file"
$STD apt-get -y autoremove
$STD apt-get -y autoclean
msg_ok "Cleaned"
motd_ssh
customize
customize

View File

@@ -15,10 +15,10 @@ update_os
msg_info "Installing Dependencies"
$STD apt-get install -y \
git \
gnupg \
apache2 \
libapache2-mod-wsgi-py3
git \
gnupg \
apache2 \
libapache2-mod-wsgi-py3
msg_ok "Installed Dependencies"
msg_info "Installing Python"

867
misc/add-iptag.sh Normal file
View File

@@ -0,0 +1,867 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: MickLesk (Canbiz) && Desert_Gamer
# License: MIT
# Source: https://github.com/gitsang/iptag
function header_info {
clear
cat <<"EOF"
___ ____ _____
|_ _| _ \ _ |_ _|_ _ __ _
| || |_) (_) | |/ _` |/ _` |
| || __/ _ | | (_| | (_| |
|___|_| (_) |_|\__,_|\__, |
|___/
EOF
}
clear
header_info
APP="IP-Tag"
hostname=$(hostname)
# Farbvariablen
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
RD=$(echo "\033[01;31m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD=" "
CM=" ✔️ ${CL}"
CROSS=" ✖️ ${CL}"
# This function enables error handling in the script by setting options and defining a trap for the ERR signal.
catch_errors() {
set -Eeuo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# 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() {
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"
}
# 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}"
}
# Check if service exists
check_service_exists() {
if systemctl is-active --quiet iptag.service; then
return 0
else
return 1
fi
}
# Migrate configuration from old path to new
migrate_config() {
local old_config="/opt/lxc-iptag"
local new_config="/opt/iptag/iptag.conf"
if [[ -f "$old_config" ]]; then
msg_info "Migrating configuration from old path"
if cp "$old_config" "$new_config" &>/dev/null; then
rm -rf "$old_config" &>/dev/null
msg_ok "Configuration migrated and old config removed"
else
msg_error "Failed to migrate configuration"
fi
fi
}
# Update existing installation
update_installation() {
msg_info "Updating IP-Tag Scripts"
systemctl stop iptag.service &>/dev/null
# Create directory if it doesn't exist
if [[ ! -d "/opt/iptag" ]]; then
mkdir -p /opt/iptag
fi
# Migrate config if needed
migrate_config
# Update main script
cat <<'EOF' >/opt/iptag/iptag
#!/bin/bash
# =============== CONFIGURATION =============== #
readonly CONFIG_FILE="/opt/iptag/iptag.conf"
readonly DEFAULT_TAG_FORMAT="full"
readonly DEFAULT_CHECK_INTERVAL=60
# Load the configuration file if it exists
if [ -f "$CONFIG_FILE" ]; then
# shellcheck source=./iptag.conf
source "$CONFIG_FILE"
fi
# Convert IP to integer for comparison
ip_to_int() {
local ip="$1"
local a b c d
IFS=. read -r a b c d <<< "${ip}"
echo "$((a << 24 | b << 16 | c << 8 | d))"
}
# Check if IP is in CIDR
ip_in_cidr() {
local ip="$1" cidr="$2"
ipcalc -c "$ip" "$cidr" >/dev/null 2>&1 || return 1
local network prefix ip_parts net_parts
network=$(echo "$cidr" | cut -d/ -f1)
prefix=$(echo "$cidr" | cut -d/ -f2)
IFS=. read -r -a ip_parts <<< "$ip"
IFS=. read -r -a net_parts <<< "$network"
case $prefix in
8) [[ "${ip_parts[0]}" == "${net_parts[0]}" ]] ;;
16) [[ "${ip_parts[0]}.${ip_parts[1]}" == "${net_parts[0]}.${net_parts[1]}" ]] ;;
24) [[ "${ip_parts[0]}.${ip_parts[1]}.${ip_parts[2]}" == "${net_parts[0]}.${net_parts[1]}.${net_parts[2]}" ]] ;;
32) [[ "$ip" == "$network" ]] ;;
*) return 1 ;;
esac
}
# Format IP address according to the configuration
format_ip_tag() {
local ip="$1"
local format="${TAG_FORMAT:-$DEFAULT_TAG_FORMAT}"
case "$format" in
"last_octet") echo "${ip##*.}" ;;
"last_two_octets") echo "${ip#*.*.}" ;;
*) echo "$ip" ;;
esac
}
# Check if IP is in any CIDRs
ip_in_cidrs() {
local ip="$1" cidrs="$2"
[[ -z "$cidrs" ]] && return 1
local IFS=' '
for cidr in $cidrs; do ip_in_cidr "$ip" "$cidr" && return 0; done
return 1
}
# Check if IP is valid
is_valid_ipv4() {
local ip="$1"
[[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || return 1
local IFS='.' parts
read -ra parts <<< "$ip"
for part in "${parts[@]}"; do
(( part >= 0 && part <= 255 )) || return 1
done
return 0
}
lxc_status_changed() {
current_lxc_status=$(pct list 2>/dev/null)
if [ "${last_lxc_status}" == "${current_lxc_status}" ]; then
return 1
else
last_lxc_status="${current_lxc_status}"
return 0
fi
}
vm_status_changed() {
current_vm_status=$(qm list 2>/dev/null)
if [ "${last_vm_status}" == "${current_vm_status}" ]; then
return 1
else
last_vm_status="${current_vm_status}"
return 0
fi
}
fw_net_interface_changed() {
current_net_interface=$(ifconfig | grep "^fw")
if [ "${last_net_interface}" == "${current_net_interface}" ]; then
return 1
else
last_net_interface="${current_net_interface}"
return 0
fi
}
# Get VM IPs using MAC addresses and ARP table
get_vm_ips() {
local vmid=$1 ips="" macs found_ip=false
qm status "$vmid" 2>/dev/null | grep -q "status: running" || return
macs=$(qm config "$vmid" 2>/dev/null | grep -E 'net[0-9]+' | grep -oE '[a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}')
[[ -z "$macs" ]] && return
for mac in $macs; do
local ip
ip=$(arp -an 2>/dev/null | grep -i "$mac" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}')
[[ -n "$ip" ]] && { ips+="$ip "; found_ip=true; }
done
if ! $found_ip; then
local agent_ip
agent_ip=$(qm agent "$vmid" network-get-interfaces 2>/dev/null | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' || true)
[[ -n "$agent_ip" ]] && ips+="$agent_ip "
fi
echo "${ips% }"
}
# Update tags
update_tags() {
local type="$1" vmid="$2" config_cmd="pct"
[[ "$type" == "vm" ]] && config_cmd="qm"
local current_ips_full
if [[ "$type" == "lxc" ]]; then
current_ips_full=$(lxc-info -n "${vmid}" -i 2>/dev/null | grep -E "^IP:" | awk '{print $2}')
else
current_ips_full=$(get_vm_ips "${vmid}")
fi
[[ -z "$current_ips_full" ]] && return
local current_tags=() next_tags=() current_ip_tags=()
mapfile -t current_tags < <($config_cmd config "${vmid}" 2>/dev/null | grep tags | awk '{print $2}' | sed 's/;/\n/g')
# Separate IP and non-IP tags
for tag in "${current_tags[@]}"; do
if is_valid_ipv4 "${tag}" || [[ "$tag" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
current_ip_tags+=("${tag}")
else
next_tags+=("${tag}")
fi
done
local formatted_ips=() needs_update=false added_ips=()
for ip in ${current_ips_full}; do
if is_valid_ipv4 "$ip" && ip_in_cidrs "$ip" "${CIDR_LIST[*]}"; then
local formatted_ip=$(format_ip_tag "$ip")
formatted_ips+=("$formatted_ip")
if [[ ! " ${current_ip_tags[*]} " =~ " ${formatted_ip} " ]]; then
needs_update=true
added_ips+=("$formatted_ip")
next_tags+=("$formatted_ip")
fi
fi
done
[[ ${#formatted_ips[@]} -eq 0 ]] && return
# Add existing IP tags that are still valid
for tag in "${current_ip_tags[@]}"; do
if [[ " ${formatted_ips[*]} " =~ " ${tag} " ]]; then
if [[ ! " ${next_tags[*]} " =~ " ${tag} " ]]; then
next_tags+=("$tag")
fi
fi
done
if [[ "$needs_update" == true ]]; then
echo "${type^} ${vmid}: adding IP tags: ${added_ips[*]}"
$config_cmd set "${vmid}" -tags "$(IFS=';'; echo "${next_tags[*]}")" &>/dev/null
elif [[ ${#current_ip_tags[@]} -gt 0 ]]; then
echo "${type^} ${vmid}: IP tags already set: ${current_ip_tags[*]}"
else
echo "${type^} ${vmid}: setting initial IP tags: ${formatted_ips[*]}"
$config_cmd set "${vmid}" -tags "$(IFS=';'; echo "${formatted_ips[*]}")" &>/dev/null
fi
}
# Check if status changed
check_status() {
local type="$1" current
case "$type" in
"lxc") current=$(pct list 2>/dev/null | grep -v VMID) ;;
"vm") current=$(qm list 2>/dev/null | grep -v VMID) ;;
"fw") current=$(ifconfig 2>/dev/null | grep "^fw") ;;
esac
local last_var="last_${type}_status"
[[ "${!last_var}" == "$current" ]] && return 1
eval "$last_var='$current'"
return 0
}
# Update all instances
update_all() {
local type="$1" list_cmd="pct" vmids count=0
[[ "$type" == "vm" ]] && list_cmd="qm"
vmids=$($list_cmd list 2>/dev/null | grep -v VMID | awk '{print $1}')
for vmid in $vmids; do ((count++)); done
echo "Found ${count} running ${type}s"
[[ $count -eq 0 ]] && return
for vmid in $vmids; do
update_tags "$type" "$vmid"
done
}
# Main check function
check() {
local current_time changes_detected=false
current_time=$(date +%s)
for type in "lxc" "vm"; do
local interval_var="${type^^}_STATUS_CHECK_INTERVAL"
local last_check_var="last_${type}_check_time"
local last_update_var="last_update_${type}_time"
if [[ "${!interval_var}" -gt 0 ]] && (( current_time - ${!last_check_var} >= ${!interval_var} )); then
echo "Checking ${type^^} status..."
eval "${last_check_var}=\$current_time"
if check_status "$type"; then
changes_detected=true
update_all "$type"
eval "${last_update_var}=\$current_time"
fi
fi
if (( current_time - ${!last_update_var} >= FORCE_UPDATE_INTERVAL )); then
echo "Force updating ${type} tags..."
changes_detected=true
update_all "$type"
eval "${last_update_var}=\$current_time"
fi
done
if [[ "${FW_NET_INTERFACE_CHECK_INTERVAL}" -gt 0 ]] && \
(( current_time - last_fw_check_time >= FW_NET_INTERFACE_CHECK_INTERVAL )); then
echo "Checking network interfaces..."
last_fw_check_time=$current_time
if check_status "fw"; then
changes_detected=true
update_all "lxc"
update_all "vm"
last_update_lxc_time=$current_time
last_update_vm_time=$current_time
fi
fi
$changes_detected || echo "No changes detected in system status"
}
# Initialize time variables
declare -g last_lxc_status="" last_vm_status="" last_fw_status=""
declare -g last_lxc_check_time=0 last_vm_check_time=0 last_fw_check_time=0
declare -g last_update_lxc_time=0 last_update_vm_time=0
# Main loop
main() {
while true; do
check
sleep "${LOOP_INTERVAL:-$DEFAULT_CHECK_INTERVAL}"
done
}
main
EOF
chmod +x /opt/iptag/iptag
# Update service file
cat <<EOF >/lib/systemd/system/iptag.service
[Unit]
Description=IP-Tag service
After=network.target
[Service]
Type=simple
ExecStart=/opt/iptag/iptag
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload &>/dev/null
systemctl enable -q --now iptag.service &>/dev/null
msg_ok "Updated IP-Tag Scripts"
}
# Main installation process
if check_service_exists; then
while true; do
read -p "IP-Tag service is already installed. Do you want to update it? (y/n): " yn
case $yn in
[Yy]*)
update_installation
exit 0
;;
[Nn]*)
msg_error "Installation cancelled."
exit 0
;;
*)
msg_error "Please answer yes or no."
;;
esac
done
fi
while true; do
read -p "This will install ${APP} on ${hostname}. Proceed? (y/n): " yn
case $yn in
[Yy]*)
break
;;
[Nn]*)
msg_error "Installation cancelled."
exit
;;
*)
msg_error "Please answer yes or no."
;;
esac
done
if ! pveversion | grep -Eq "pve-manager/8\.[0-4](\.[0-9]+)*"; then
msg_error "This version of Proxmox Virtual Environment is not supported"
msg_error "⚠️ Requires Proxmox Virtual Environment Version 8.0 or later."
msg_error "Exiting..."
sleep 2
exit
fi
FILE_PATH="/usr/local/bin/iptag"
if [[ -f "$FILE_PATH" ]]; then
msg_info "The file already exists: '$FILE_PATH'. Skipping installation."
exit 0
fi
msg_info "Installing Dependencies"
apt-get update &>/dev/null
apt-get install -y ipcalc net-tools &>/dev/null
msg_ok "Installed Dependencies"
msg_info "Setting up IP-Tag Scripts"
mkdir -p /opt/iptag
msg_ok "Setup IP-Tag Scripts"
# Migrate config if needed
migrate_config
msg_info "Setup Default Config"
if [[ ! -f /opt/iptag/iptag.conf ]]; then
cat <<EOF >/opt/iptag/iptag.conf
# Configuration file for LXC IP tagging
# List of allowed CIDRs
CIDR_LIST=(
192.168.0.0/16
172.16.0.0/12
10.0.0.0/8
100.64.0.0/10
)
# Tag format options:
# - "full": full IP address (e.g., 192.168.0.100)
# - "last_octet": only the last octet (e.g., 100)
# - "last_two_octets": last two octets (e.g., 0.100)
TAG_FORMAT="full"
# Interval settings (in seconds)
LOOP_INTERVAL=60
VM_STATUS_CHECK_INTERVAL=60
FW_NET_INTERFACE_CHECK_INTERVAL=60
LXC_STATUS_CHECK_INTERVAL=60
FORCE_UPDATE_INTERVAL=1800
EOF
msg_ok "Setup default config"
else
msg_ok "Default config already exists"
fi
msg_info "Setup Main Function"
if [[ ! -f /opt/iptag/iptag ]]; then
cat <<'EOF' >/opt/iptag/iptag
#!/bin/bash
# =============== CONFIGURATION =============== #
CONFIG_FILE="/opt/iptag/iptag.conf"
# Load the configuration file if it exists
if [ -f "$CONFIG_FILE" ]; then
# shellcheck source=./iptag.conf
source "$CONFIG_FILE"
fi
# Convert IP to integer for comparison
ip_to_int() {
local ip="$1"
local a b c d
IFS=. read -r a b c d <<< "${ip}"
echo "$((a << 24 | b << 16 | c << 8 | d))"
}
# Check if IP is in CIDR
ip_in_cidr() {
local ip="$1"
local cidr="$2"
# Use ipcalc with the -c option (check), which returns 0 if the IP is in the network
if ipcalc -c "$ip" "$cidr" >/dev/null 2>&1; then
# Get network address and mask from CIDR
local network prefix
network=$(echo "$cidr" | cut -d/ -f1)
prefix=$(echo "$cidr" | cut -d/ -f2)
# Check if IP is in the network
local ip_a ip_b ip_c ip_d net_a net_b net_c net_d
IFS=. read -r ip_a ip_b ip_c ip_d <<< "$ip"
IFS=. read -r net_a net_b net_c net_d <<< "$network"
# Check octets match based on prefix length
local result=0
if (( prefix >= 8 )); then
[[ "$ip_a" != "$net_a" ]] && result=1
fi
if (( prefix >= 16 )); then
[[ "$ip_b" != "$net_b" ]] && result=1
fi
if (( prefix >= 24 )); then
[[ "$ip_c" != "$net_c" ]] && result=1
fi
return $result
fi
return 1
}
# Format IP address according to the configuration
format_ip_tag() {
local ip="$1"
local format="${TAG_FORMAT:-full}"
case "$format" in
"last_octet")
echo "${ip##*.}"
;;
"last_two_octets")
echo "${ip#*.*.}"
;;
*)
echo "$ip"
;;
esac
}
# Check if IP is in any CIDRs
ip_in_cidrs() {
local ip="$1"
local cidrs="$2"
# Check that cidrs is not empty
[[ -z "$cidrs" ]] && return 1
local IFS=' '
for cidr in $cidrs; do
ip_in_cidr "$ip" "$cidr" && return 0
done
return 1
}
# Check if IP is valid
is_valid_ipv4() {
local ip="$1"
[[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || return 1
local IFS='.'
read -ra parts <<< "$ip"
for part in "${parts[@]}"; do
[[ "$part" =~ ^[0-9]+$ ]] && ((part >= 0 && part <= 255)) || return 1
done
return 0
}
lxc_status_changed() {
current_lxc_status=$(pct list 2>/dev/null)
if [ "${last_lxc_status}" == "${current_lxc_status}" ]; then
return 1
else
last_lxc_status="${current_lxc_status}"
return 0
fi
}
vm_status_changed() {
current_vm_status=$(qm list 2>/dev/null)
if [ "${last_vm_status}" == "${current_vm_status}" ]; then
return 1
else
last_vm_status="${current_vm_status}"
return 0
fi
}
fw_net_interface_changed() {
current_net_interface=$(ifconfig | grep "^fw")
if [ "${last_net_interface}" == "${current_net_interface}" ]; then
return 1
else
last_net_interface="${current_net_interface}"
return 0
fi
}
# Get VM IPs using MAC addresses and ARP table
get_vm_ips() {
local vmid=$1
local ips=""
# Check if VM is running
qm status "$vmid" 2>/dev/null | grep -q "status: running" || return
# Get MAC addresses from VM configuration
local macs
macs=$(qm config "$vmid" 2>/dev/null | grep -E 'net[0-9]+' | grep -o -E '[a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}')
# Look up IPs from ARP table using MAC addresses
for mac in $macs; do
local ip
ip=$(arp -an 2>/dev/null | grep -i "$mac" | grep -o -E '([0-9]{1,3}\.){3}[0-9]{1,3}')
if [ -n "$ip" ]; then
ips+="$ip "
fi
done
echo "$ips"
}
# Update tags for container or VM
update_tags() {
local type="$1"
local vmid="$2"
local config_cmd="pct"
[[ "$type" == "vm" ]] && config_cmd="qm"
# Get current IPs
local current_ips_full
if [[ "$type" == "lxc" ]]; then
# Redirect error output to suppress AppArmor warnings
current_ips_full=$(lxc-info -n "${vmid}" -i 2>/dev/null | grep -E "^IP:" | awk '{print $2}')
else
current_ips_full=$(get_vm_ips "${vmid}")
fi
# Parse current tags and get valid IPs
local current_tags=()
local next_tags=()
mapfile -t current_tags < <($config_cmd config "${vmid}" 2>/dev/null | grep tags | awk '{print $2}' | sed 's/;/\n/g')
for tag in "${current_tags[@]}"; do
# Skip tag if it looks like an IP (full or partial)
if ! is_valid_ipv4 "${tag}" && ! [[ "$tag" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
next_tags+=("${tag}")
fi
done
# Add valid IPs to tags
local added_ips=()
local skipped_ips=()
for ip in ${current_ips_full}; do
if is_valid_ipv4 "${ip}"; then
if ip_in_cidrs "${ip}" "${CIDR_LIST[*]}"; then
local formatted_ip=$(format_ip_tag "$ip")
next_tags+=("${formatted_ip}")
added_ips+=("${formatted_ip}")
else
skipped_ips+=("${ip}")
fi
fi
done
# Log only if there are changes
if [ ${#added_ips[@]} -gt 0 ]; then
echo "${type^} ${vmid}: added IP tags: ${added_ips[*]}"
fi
# Update if changed
if [[ "$(IFS=';'; echo "${current_tags[*]}")" != "$(IFS=';'; echo "${next_tags[*]}")" ]]; then
$config_cmd set "${vmid}" -tags "$(IFS=';'; echo "${next_tags[*]}")" &>/dev/null
fi
}
# Check if status changed
check_status_changed() {
local type="$1"
local current_status
case "$type" in
"lxc")
current_status=$(pct list 2>/dev/null | grep -v VMID)
[[ "${last_lxc_status}" == "${current_status}" ]] && return 1
last_lxc_status="${current_status}"
;;
"vm")
current_status=$(qm list 2>/dev/null | grep -v VMID)
[[ "${last_vm_status}" == "${current_status}" ]] && return 1
last_vm_status="${current_status}"
;;
"fw")
current_status=$(ifconfig 2>/dev/null | grep "^fw")
[[ "${last_net_interface}" == "${current_status}" ]] && return 1
last_net_interface="${current_status}"
;;
esac
return 0
}
check() {
current_time=$(date +%s)
# Check LXC status
time_since_last_lxc_status_check=$((current_time - last_lxc_status_check_time))
if [[ "${LXC_STATUS_CHECK_INTERVAL}" -gt 0 ]] \
&& [[ "${time_since_last_lxc_status_check}" -ge "${LXC_STATUS_CHECK_INTERVAL}" ]]; then
echo "Checking LXC status..."
last_lxc_status_check_time=${current_time}
if check_status_changed "lxc"; then
update_all_tags "lxc"
last_update_lxc_time=${current_time}
fi
fi
# Check VM status
time_since_last_vm_status_check=$((current_time - last_vm_status_check_time))
if [[ "${VM_STATUS_CHECK_INTERVAL}" -gt 0 ]] \
&& [[ "${time_since_last_vm_status_check}" -ge "${VM_STATUS_CHECK_INTERVAL}" ]]; then
echo "Checking VM status..."
last_vm_status_check_time=${current_time}
if check_status_changed "vm"; then
update_all_tags "vm"
last_update_vm_time=${current_time}
fi
fi
# Check network interface changes
time_since_last_fw_net_interface_check=$((current_time - last_fw_net_interface_check_time))
if [[ "${FW_NET_INTERFACE_CHECK_INTERVAL}" -gt 0 ]] \
&& [[ "${time_since_last_fw_net_interface_check}" -ge "${FW_NET_INTERFACE_CHECK_INTERVAL}" ]]; then
echo "Checking network interfaces..."
last_fw_net_interface_check_time=${current_time}
if check_status_changed "fw"; then
update_all_tags "lxc"
update_all_tags "vm"
last_update_lxc_time=${current_time}
last_update_vm_time=${current_time}
fi
fi
# Force update if needed
for type in "lxc" "vm"; do
local last_update_var="last_update_${type}_time"
local time_since_last_update=$((current_time - ${!last_update_var}))
if [ ${time_since_last_update} -ge ${FORCE_UPDATE_INTERVAL} ]; then
echo "Force updating ${type} tags..."
update_all_tags "$type"
eval "${last_update_var}=${current_time}"
fi
done
}
# Initialize time variables
last_lxc_status_check_time=0
last_vm_status_check_time=0
last_fw_net_interface_check_time=0
last_update_lxc_time=0
last_update_vm_time=0
# main: Set the IP tags for all LXC containers and VMs
main() {
while true; do
check
sleep "${LOOP_INTERVAL}"
done
}
main
EOF
msg_ok "Setup Main Function"
else
msg_ok "Main Function already exists"
fi
chmod +x /opt/iptag/iptag
msg_info "Creating Service"
if [[ ! -f /lib/systemd/system/iptag.service ]]; then
cat <<EOF >/lib/systemd/system/iptag.service
[Unit]
Description=IP-Tag service
After=network.target
[Service]
Type=simple
ExecStart=/opt/iptag/iptag
Restart=always
[Install]
WantedBy=multi-user.target
EOF
msg_ok "Created Service"
else
msg_ok "Service already exists."
fi
msg_ok "Setup IP-Tag Scripts"
msg_info "Starting Service"
systemctl daemon-reload &>/dev/null
systemctl enable -q --now iptag.service &>/dev/null
msg_ok "Started Service"
SPINNER_PID=""
echo -e "\n${APP} installation completed successfully! ${CL}\n"

View File

@@ -133,7 +133,7 @@ function select_storage() {
local STORAGE
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for the ${CONTENT_LABEL,,}?\n\n" \
"Which storage pool would you like to use for the ${CONTENT_LABEL,,}?\n\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${MENU[@]}" 3>&1 1>&2 2>&3) || die "Menu aborted."
done

View File

@@ -154,7 +154,7 @@ function select_storage() {
local STORAGE
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for the ${CONTENT_LABEL,,}?\n\n" \
"Which storage pool would you like to use for the ${CONTENT_LABEL,,}?\n\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${MENU[@]}" 3>&1 1>&2 2>&3) || die "Menu aborted."
done

View File

@@ -413,7 +413,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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

View File

@@ -414,7 +414,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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

View File

@@ -377,7 +377,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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

View File

@@ -417,7 +417,7 @@ else
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
printf "\e[?25h"
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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

View File

@@ -241,7 +241,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for the Mikrotik RouterOS CHR VM?\n\n" \
"Which storage pool would you like to use for the Mikrotik RouterOS CHR VM?\n\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3)
done

View File

@@ -378,7 +378,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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

View File

@@ -438,7 +438,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for the OpenWrt VM?\n\n" \
"Which storage pool would you like to use for the OpenWrt VM?\n\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3)
done

View File

@@ -516,7 +516,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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

View File

@@ -378,7 +378,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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

View File

@@ -285,7 +285,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for the HAOS VM?\n\n" \
"Which storage pool would you like to use for the HAOS VM?\n\n" \
16 $(($MSG_MAX_LENGTH + 23)) 6 \
"${STORAGE_MENU[@]}" 3>&1 1>&2 2>&3)
done

View File

@@ -412,7 +412,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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

View File

@@ -412,7 +412,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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

View File

@@ -412,7 +412,7 @@ elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
else
while [ -z "${STORAGE:+x}" ]; do
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
"Which storage pool you would like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
"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