Compare commits

..

2 Commits

25 changed files with 74 additions and 505 deletions
+2 -18
View File
@@ -314,17 +314,12 @@ jobs:
// ── Allow-lists (mirror the slash bot) ───────────────────────────── // ── Allow-lists (mirror the slash bot) ─────────────────────────────
const ALLOWED_FIELDS = { const ALLOWED_FIELDS = {
name: 'string', description: 'string', logo: 'string', documentation: 'string', name: 'string', description: 'string', logo: 'string', documentation: 'string',
website: 'string', project_url: 'string', repository: 'string', config_path: 'string', website: 'string', project_url: 'string', github: 'string', config_path: 'string',
tags: 'string', port: 'number', default_user: 'nullable_string', default_passwd: 'nullable_string', tags: 'string', port: 'number', default_user: 'nullable_string', default_passwd: 'nullable_string',
unprivileged: 'number', updateable: 'boolean', privileged: 'boolean', unprivileged: 'number', updateable: 'boolean', privileged: 'boolean', has_arm: 'boolean',
architectures: 'select_list', platforms: 'select_list',
is_dev: 'boolean', is_disabled: 'boolean', disable_message: 'string', is_dev: 'boolean', is_disabled: 'boolean', disable_message: 'string',
is_deleted: 'boolean', deleted_message: 'string' is_deleted: 'boolean', deleted_message: 'string'
}; };
const SELECT_VALUES = {
architectures: ['amd64', 'arm64'],
platforms: ['pve', 'incus'],
};
const FIELD_TO_CT_VAR = { tags: 'var_tags', unprivileged: 'var_unprivileged' }; const FIELD_TO_CT_VAR = { tags: 'var_tags', unprivileged: 'var_unprivileged' };
const RESOURCE_KEYS = { cpu: 'number', ram: 'number', hdd: 'number', os: 'string', version: 'string' }; const RESOURCE_KEYS = { cpu: 'number', ram: 'number', hdd: 'number', os: 'string', version: 'string' };
const METHOD_KEYS = { config_path: 'string', script: 'string' }; const METHOD_KEYS = { config_path: 'string', script: 'string' };
@@ -344,17 +339,6 @@ jobs:
if (isNaN(n)) return { error: '`' + key + '` must be a number' }; if (isNaN(n)) return { error: '`' + key + '` must be a number' };
return { value: n }; return { value: n };
} }
if (type === 'select_list') {
// architectures/platforms are multi-selects over a closed set,
// so an unknown value is rejected rather than stored. The model
// may hand back an array or a comma-separated string.
const allowed = SELECT_VALUES[key] || [];
const raw = Array.isArray(rawVal) ? rawVal : String(rawVal == null ? '' : rawVal).split(',');
const values = raw.map(function (v) { return String(v).trim(); }).filter(Boolean);
const bad = values.filter(function (v) { return allowed.indexOf(v) === -1; });
if (bad.length > 0) return { error: '`' + key + '` accepts ' + allowed.join(', ') + ' — got: ' + bad.join(', ') };
return { value: values };
}
if (type === 'nullable_string') return { value: rawVal === '' || rawVal == null ? null : String(rawVal) }; if (type === 'nullable_string') return { value: rawVal === '' || rawVal == null ? null : String(rawVal) };
return { value: String(rawVal) }; return { value: String(rawVal) };
} }
+6 -25
View File
@@ -323,10 +323,9 @@ jobs:
'/pocketbase <slug> method remove <type>\n' + '/pocketbase <slug> method remove <type>\n' +
'```\n' + '```\n' +
'Method fields: `cpu` `ram` `hdd` `os` `version` `config_path` `script`\n\n' + 'Method fields: `cpu` `ram` `hdd` `os` `version` `config_path` `script`\n\n' +
'**Editable fields:** `name` `description` `logo` `documentation` `website` `project_url` `repository` ' + '**Editable fields:** `name` `description` `logo` `documentation` `website` `project_url` `github` ' +
'`config_path` `port` `default_user` `default_passwd` ' + '`config_path` `port` `default_user` `default_passwd` ' +
'`updateable` `privileged` `is_dev` ' + '`updateable` `privileged` `has_arm` `is_dev` ' +
'`architectures` (amd64,arm64) `platforms` (pve,incus) ' +
'`is_disabled` `disable_message` `is_deleted` `deleted_message`'; '`is_disabled` `disable_message` `is_deleted` `deleted_message`';
if (!withoutCmd) { if (!withoutCmd) {
@@ -505,8 +504,7 @@ jobs:
out.push('- **Port:** ' + (record.port != null ? '`' + record.port + '`' : '—')); out.push('- **Port:** ' + (record.port != null ? '`' + record.port + '`' : '—'));
out.push('- **Updateable:** ' + (record.updateable ? 'Yes' : 'No')); out.push('- **Updateable:** ' + (record.updateable ? 'Yes' : 'No'));
out.push('- **Privileged:** ' + (record.privileged ? 'Yes' : 'No')); out.push('- **Privileged:** ' + (record.privileged ? 'Yes' : 'No'));
out.push('- **Architectures:** ' + ((record.architectures || []).join(', ') || 'amd64')); out.push('- **ARM:** ' + (record.has_arm ? 'Yes' : 'No'));
out.push('- **Platforms:** ' + ((record.platforms || []).join(', ') || 'pve'));
if (record.is_dev) out.push('- **Dev:** Yes'); if (record.is_dev) out.push('- **Dev:** Yes');
if (record.is_disabled) out.push('- **Disabled:** Yes' + (record.disable_message ? ' — ' + record.disable_message : '')); if (record.is_disabled) out.push('- **Disabled:** Yes' + (record.disable_message ? ' — ' + record.disable_message : ''));
if (record.is_deleted) out.push('- **Deleted:** Yes' + (record.deleted_message ? ' — ' + record.deleted_message : '')); if (record.is_deleted) out.push('- **Deleted:** Yes' + (record.deleted_message ? ' — ' + record.deleted_message : ''));
@@ -840,7 +838,7 @@ jobs:
const fieldName = setMatch[1].toLowerCase(); const fieldName = setMatch[1].toLowerCase();
const SET_ALLOWED = { const SET_ALLOWED = {
name: 'string', description: 'string', logo: 'string', name: 'string', description: 'string', logo: 'string',
documentation: 'string', website: 'string', project_url: 'string', repository: 'string', documentation: 'string', website: 'string', project_url: 'string', github: 'string',
config_path: 'string', disable_message: 'string', deleted_message: 'string' config_path: 'string', disable_message: 'string', deleted_message: 'string'
}; };
if (!SET_ALLOWED[fieldName]) { if (!SET_ALLOWED[fieldName]) {
@@ -890,7 +888,7 @@ jobs:
documentation: 'string', documentation: 'string',
website: 'string', website: 'string',
project_url: 'string', project_url: 'string',
repository: 'string', github: 'string',
config_path: 'string', config_path: 'string',
tags: 'string', tags: 'string',
port: 'number', port: 'number',
@@ -899,8 +897,7 @@ jobs:
unprivileged: 'number', unprivileged: 'number',
updateable: 'boolean', updateable: 'boolean',
privileged: 'boolean', privileged: 'boolean',
architectures: 'select_list', has_arm: 'boolean',
platforms: 'select_list',
is_dev: 'boolean', is_dev: 'boolean',
is_disabled: 'boolean', is_disabled: 'boolean',
disable_message: 'string', disable_message: 'string',
@@ -927,10 +924,6 @@ jobs:
} }
// Cast values to correct types // Cast values to correct types
const SELECT_VALUES = {
architectures: ['amd64', 'arm64'],
platforms: ['pve', 'incus'],
};
const payload = {}; const payload = {};
for (const [key, rawVal] of Object.entries(parsedFields)) { for (const [key, rawVal] of Object.entries(parsedFields)) {
const type = ALLOWED_FIELDS[key]; const type = ALLOWED_FIELDS[key];
@@ -950,18 +943,6 @@ jobs:
process.exit(0); process.exit(0);
} }
payload[key] = n; payload[key] = n;
} else if (type === 'select_list') {
// architectures/platforms are multi-selects over a closed set,
// so an unknown value is rejected rather than stored.
const allowed = SELECT_VALUES[key] || [];
const values = rawVal.split(',').map(function (v) { return v.trim(); }).filter(Boolean);
const bad = values.filter(function (v) { return allowed.indexOf(v) === -1; });
if (bad.length > 0) {
await addReaction('-1');
await postComment('❌ **PocketBase Bot**: `' + key + '` accepts ' + allowed.join(', ') + ' — got: `' + bad.join(', ') + '`');
process.exit(0);
}
payload[key] = values;
} else if (type === 'nullable_string') { } else if (type === 'nullable_string') {
payload[key] = rawVal === '' ? null : rawVal; payload[key] = rawVal === '' ? null : rawVal;
} else { } else {
+1 -13
View File
@@ -179,19 +179,7 @@ jobs:
if (resolvedType) payload.type = resolvedType; if (resolvedType) payload.type = resolvedType;
var resolvedCats = (data.categories || []).map(function(n) { return categoryNameToPbId[categoryIdToName[n]]; }).filter(Boolean); var resolvedCats = (data.categories || []).map(function(n) { return categoryNameToPbId[categoryIdToName[n]]; }).filter(Boolean);
if (resolvedCats.length) payload.categories = resolvedCats; if (resolvedCats.length) payload.categories = resolvedCats;
// architectures replaces has_arm: a boolean could say "also ARM" but if (data.has_arm !== undefined) payload.has_arm = data.has_arm === true || data.has_arm === 'true';
// not "ARM only" or "amd64 only". A record written before the field
// existed is read through the old key so nothing silently drops.
if (Array.isArray(data.architectures)) {
payload.architectures = data.architectures.filter(function (a) { return a === 'amd64' || a === 'arm64'; });
} else if (data.has_arm !== undefined) {
payload.architectures = (data.has_arm === true || data.has_arm === 'true') ? ['amd64', 'arm64'] : ['amd64'];
}
if (Array.isArray(data.platforms)) {
payload.platforms = data.platforms.filter(function (p) { return p === 'pve' || p === 'incus'; });
}
if (Array.isArray(data.app_vars)) payload.app_vars = data.app_vars;
if (data.repository !== undefined) payload.repository = data.repository;
if (data.version !== undefined) payload.version = data.version; if (data.version !== undefined) payload.version = data.version;
if (data.changelog !== undefined) payload.changelog = data.changelog; if (data.changelog !== undefined) payload.changelog = data.changelog;
if (data.screenshots !== undefined) payload.screenshots = data.screenshots; if (data.screenshots !== undefined) payload.screenshots = data.screenshots;
-38
View File
@@ -518,44 +518,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-08-07
### 🆕 New Scripts
- NetworkOptimizer ([#16328](https://github.com/community-scripts/ProxmoxVE/pull/16328))
- Orb ([#16329](https://github.com/community-scripts/ProxmoxVE/pull/16329))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- HortusFox: start applying db migrations [@tomfrenzel](https://github.com/tomfrenzel) ([#16324](https://github.com/community-scripts/ProxmoxVE/pull/16324))
- Docker: report container updates instead of prompting, stop auto-updating Portainer Agent, fix addon detection of legacy Portainer [@MickLesk](https://github.com/MickLesk) ([#16298](https://github.com/community-scripts/ProxmoxVE/pull/16298))
- Immich: retry mise install on transient npm download failures [@MickLesk](https://github.com/MickLesk) ([#16301](https://github.com/community-scripts/ProxmoxVE/pull/16301))
- changedetection: remove msttcorefonts to fix install hang [@austinpilz](https://github.com/austinpilz) ([#16319](https://github.com/community-scripts/ProxmoxVE/pull/16319))
- #### 🔧 Refactor
- core: extend new vars and pocketbase values [@MickLesk](https://github.com/MickLesk) ([#16313](https://github.com/community-scripts/ProxmoxVE/pull/16313))
## 2026-08-06
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- paperless: change update abort message (endless spinner) [@MickLesk](https://github.com/MickLesk) ([#16299](https://github.com/community-scripts/ProxmoxVE/pull/16299))
- #### ✨ New Features
- Vikunja: remove version pin, v2.5.0 fixes the systemd syscall filter crash [@MickLesk](https://github.com/MickLesk) ([#16300](https://github.com/community-scripts/ProxmoxVE/pull/16300))
### 💾 Core
- #### 🔧 Refactor
- build.func: filter templates by host architecture during search [@MickLesk](https://github.com/MickLesk) ([#16302](https://github.com/community-scripts/ProxmoxVE/pull/16302))
## 2026-08-05 ## 2026-08-05
### 🚀 Updated Scripts ### 🚀 Updated Scripts
-49
View File
@@ -103,55 +103,6 @@ Key rules at a glance:
- Quote all variables: `"$VAR"` not `$VAR` - Quote all variables: `"$VAR"` not `$VAR`
- Use lowercase variable names - Use lowercase variable names
- Do not hardcode credentials or sensitive values - Do not hardcode credentials or sensitive values
- Never prompt without an escape hatch — see below
### Answering a prompt up front
An install script that only asks cannot be deployed unattended. Read the
variable first and prompt only when it is unset:
```bash
if [[ -z "${var_admin_user:-}" ]]; then
read -r -p "${TAB3}Admin username: " var_admin_user
fi
var_admin_user="${var_admin_user:-admin}"
```
Name them `var_<something>`, the same namespace the container variables use.
`install/forgejo-runner-install.sh`, `install/pangolin-install.sh`, and `install/docker-install.sh` all
follow this.
The variable also has to be exported from `ct/<app>.sh`, or it never reaches
the container — `lxc-attach` carries the caller's environment, but only for
what was actually exported:
```bash
export var_admin_user="${var_admin_user:-}"
```
Declare them on the script's PocketBase record in `app_vars` so the website's
generator can offer them as fields:
```json
"app_vars": [
{
"name": "var_admin_user",
"label": "Admin Username",
"type": "text",
"default": "admin"
},
{
"name": "var_admin_pass",
"label": "Admin Password",
"type": "password",
"secret": true
}
]
```
`type` is one of `text`, `password`, `number`, `boolean` (`yes`/`no`) or
`select` (with `options`). Mark anything credential-like `secret` — the
generator keeps those out of shareable links and out of the on-screen summary.
Full standards and examples: **[community-scripts.org/docs/contribution](https://community-scripts.org/docs/contribution)** Full standards and examples: **[community-scripts.org/docs/contribution](https://community-scripts.org/docs/contribution)**
-5
View File
@@ -18,7 +18,6 @@ var_nesting="${var_nesting:-1}"
var_keyctl="${var_keyctl:-1}" var_keyctl="${var_keyctl:-1}"
export var_forgejo_instance="${var_forgejo_instance:-}" export var_forgejo_instance="${var_forgejo_instance:-}"
export var_forgejo_runner_uuid="${var_forgejo_runner_uuid:-}"
export var_forgejo_runner_token="${var_forgejo_runner_token:-}" export var_forgejo_runner_token="${var_forgejo_runner_token:-}"
export var_runner_labels="${var_runner_labels:-}" export var_runner_labels="${var_runner_labels:-}"
@@ -65,10 +64,6 @@ if [[ -n "${mode:-}" ]]; then
msg_error "var_forgejo_instance is required for unattended installs." msg_error "var_forgejo_instance is required for unattended installs."
exit 1 exit 1
fi fi
if [[ -z "${var_forgejo_runner_uuid:-}" ]]; then
msg_error "var_forgejo_runner_uuid is required for unattended installs."
exit 1
fi
if [[ -z "${var_forgejo_runner_token:-}" ]]; then if [[ -z "${var_forgejo_runner_token:-}" ]]; then
msg_error "var_forgejo_runner_token is required for unattended installs." msg_error "var_forgejo_runner_token is required for unattended installs."
exit 1 exit 1
-6
View File
@@ -1,6 +0,0 @@
_ __ __ __ ____ __ _ _
/ | / /__ / /__ ______ _____/ /__/ __ \____ / /_(_)___ ___ (_)___ ___ _____
/ |/ / _ \/ __/ | /| / / __ \/ ___/ //_/ / / / __ \/ __/ / __ `__ \/ /_ / / _ \/ ___/
/ /| / __/ /_ | |/ |/ / /_/ / / / ,< / /_/ / /_/ / /_/ / / / / / / / / /_/ __/ /
/_/ |_/\___/\__/ |__/|__/\____/_/ /_/|_|\____/ .___/\__/_/_/ /_/ /_/_/ /___/\___/_/
/_/
-6
View File
@@ -1,6 +0,0 @@
____ __
/ __ \_____/ /_
/ / / / ___/ __ \
/ /_/ / / / /_/ /
\____/_/ /_.___/
+9 -36
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG # Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ) | Co-Author: Tom Frenzel (tomfrenzel) # Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/danielbrendel/hortusfox-web # Source: https://github.com/danielbrendel/hortusfox-web
@@ -34,56 +34,29 @@ function update_script() {
systemctl stop apache2 systemctl stop apache2
msg_ok "Stopped Service" msg_ok "Stopped Service"
cd /opt/hortusfox msg_info "Backing up current HortusFox installation"
if [[ ! -s app/migrations/migrations.list ]]; then cd /opt
msg_info "Rebuilding HortusFox migration history" mv /opt/hortusfox/ /opt/hortusfox-backup
local database_tables msg_ok "Backed up current HortusFox installation"
database_tables="$(mariadb -u root -D hortusfox -NBe "SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE();")"
: >app/migrations/migrations.list
local migration migration_file table_name
for migration in app/migrations/*.php; do
migration_file="${migration##*/}"
table_name="${migration_file%.php}"
if [[ "$migration_file" == "VersionModel.php" ]] || grep -Fxq "$table_name" <<<"$database_tables"; then
php -r 'echo hash("sha512", $argv[1]), PHP_EOL;' -- "$migration_file" >>app/migrations/migrations.list
fi
done
msg_ok "Rebuilt HortusFox migration history"
fi
if [[ ! -f app/migrations/verhist.json && -f ~/.hortusfox ]]; then
printf '["%s"]\n' "$(<~/.hortusfox)" >app/migrations/verhist.json
fi
create_backup \
/opt/hortusfox/.env \
/opt/hortusfox/app/migrations/migrations.list \
/opt/hortusfox/app/migrations/verhist.json \
/opt/hortusfox/public/img \
/opt/hortusfox/public/attachments \
/opt/hortusfox/public/backup \
/opt/hortusfox/public/exports \
/opt/hortusfox/public/snd \
/opt/hortusfox/public/themes
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "hortusfox" "danielbrendel/hortusfox-web" "tarball" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "hortusfox" "danielbrendel/hortusfox-web" "tarball"
restore_backup
msg_info "Updating HortusFox" msg_info "Updating HortusFox"
cd /opt/hortusfox cd /opt/hortusfox
cp /opt/hortusfox-backup/.env /opt/hortusfox/.env
cp -a /opt/hortusfox-backup/public/img/. /opt/hortusfox/public/img/
export COMPOSER_ALLOW_SUPERUSER=1 export COMPOSER_ALLOW_SUPERUSER=1
$STD composer install --no-dev --optimize-autoloader $STD composer install --no-dev --optimize-autoloader
$STD php asatru migrate:list
$STD php asatru migrate:upgrade $STD php asatru migrate:upgrade
$STD php asatru calendar:classes
$STD php asatru plants:attributes $STD php asatru plants:attributes
$STD php asatru aquashell:config $STD php asatru calendar:classes
chown -R www-data:www-data /opt/hortusfox chown -R www-data:www-data /opt/hortusfox
rm -r /opt/hortusfox-backup
msg_ok "Updated HortusFox" msg_ok "Updated HortusFox"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start apache2 systemctl start apache2
msg_ok "Started Service" msg_ok "Started Service"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
exit exit
+1 -10
View File
@@ -214,16 +214,7 @@ EOF
cd "$SRC_DIR" cd "$SRC_DIR"
export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml
export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg
mise_ok=0 $STD mise install
for i in 1 2 3; do
$STD mise install && {
mise_ok=1
break
}
msg_warn "mise install failed (attempt $i/3) - retrying"
sleep 5
done
[[ "$mise_ok" -eq 1 ]] || exit 1
export PATH="$(mise bin-paths 2>/dev/null | tr '\n' ':')$PATH" export PATH="$(mise bin-paths 2>/dev/null | tr '\n' ':')$PATH"
if ! command -v extism-js >/dev/null 2>&1; then if ! command -v extism-js >/dev/null 2>&1; then
# extism-js ships as a bare gzip-compressed single binary (.gz) that # extism-js ships as a bare gzip-compressed single binary (.gz) that
-70
View File
@@ -1,70 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/Ozark-Connect/NetworkOptimizer
APP="NetworkOptimizer"
var_tags="${var_tags:-network;monitoring;unifi}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-12}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-yes}"
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/networkoptimizer ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "networkoptimizer" "Ozark-Connect/NetworkOptimizer"; then
msg_info "Stopping Service"
systemctl stop networkoptimizer
msg_ok "Stopped Service"
create_backup /opt/networkoptimizer/networkoptimizer.env
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "networkoptimizer" "Ozark-Connect/NetworkOptimizer" "tarball"
msg_info "Rebuilding NetworkOptimizer"
RID="linux-x64"
[[ "$(dpkg --print-architecture)" == "arm64" ]] && RID="linux-arm64"
cd /opt/networkoptimizer
$STD dotnet publish src/NetworkOptimizer.Web -c Release -r "$RID" --self-contained -o /opt/networkoptimizer/publish
chmod +x /opt/networkoptimizer/publish/NetworkOptimizer.Web
mkdir -p /opt/networkoptimizer/publish/tools
cd /opt/networkoptimizer/src/uwnspeedtest
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $STD go build -trimpath -ldflags "-s -w" -o /opt/networkoptimizer/publish/tools/uwnspeedtest-linux-arm64 .
msg_ok "Rebuilt NetworkOptimizer"
restore_backup
msg_info "Starting Service"
systemctl start networkoptimizer
msg_ok "Started Service"
msg_ok "Updated successfully!"
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 "${GATEWAY}${BGN}http://${IP}:8042${CL}"
-47
View File
@@ -1,47 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: angusmaul
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://orb.net/
APP="Orb"
var_tags="${var_tags:-network;monitoring}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if ! dpkg -s orb >/dev/null 2>&1; then
msg_error "No ${APP} Installation Found!"
exit 233
fi
msg_info "Updating Orb"
$STD apt update
$STD apt install -y --only-upgrade orb
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed Successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${TAB}${GATEWAY}${BGN}To link the sensor to your orb account run:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}pct exec ${CTID} -- runuser -u orb -- orb link${CL}"
-3
View File
@@ -17,9 +17,6 @@ var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
var_tun="${var_tun:-1}" var_tun="${var_tun:-1}"
export var_pangolin_url="${var_pangolin_url:-}"
export var_pangolin_email="${var_pangolin_email:-}"
header_info "$APP" header_info "$APP"
variables variables
color color
+1 -1
View File
@@ -65,7 +65,7 @@ function update_script() {
read -rp "Do you want to continue with the update? (y/N): " MIGRATE read -rp "Do you want to continue with the update? (y/N): " MIGRATE
echo echo
if [[ ! "$MIGRATE" =~ ^[Yy]$ ]]; then if [[ ! "$MIGRATE" =~ ^[Yy]$ ]]; then
msg_custom "⚠️" "Update aborted. Decrypt all documents before upgrading to v3." msg_info "Update aborted. Decrypt all documents before upgrading to v3."
exit 0 exit 0
fi fi
fi fi
+3 -2
View File
@@ -46,7 +46,8 @@ function update_script() {
[[ "$CONFIRM2" =~ ^[yY]$ ]] || exit 0 [[ "$CONFIRM2" =~ ^[yY]$ ]] || exit 0
fi fi
if check_for_gh_release "vikunja" "go-vikunja/vikunja"; then RELEASE="v2.3.0"
if check_for_gh_release "vikunja" "go-vikunja/vikunja" "${RELEASE}" "v2.4.0 is killed at startup by the systemd SystemCallFilter shipped in the .deb (upstream go-vikunja/vikunja#3252); pinned until a fixed release is out"; then
echo echo
msg_warn "The package update may include config file changes." msg_warn "The package update may include config file changes."
echo -e "${TAB}${YW}How do you want to handle /etc/vikunja/config.yml?${CL}" echo -e "${TAB}${YW}How do you want to handle /etc/vikunja/config.yml?${CL}"
@@ -65,7 +66,7 @@ function update_script() {
systemctl stop vikunja systemctl stop vikunja
msg_ok "Stopped Service" msg_ok "Stopped Service"
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb" fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "${RELEASE}" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
$STD systemctl daemon-reload $STD systemctl daemon-reload
msg_info "Starting Service" msg_info "Starting Service"
+1
View File
@@ -83,6 +83,7 @@ $STD apt-get install -y \
fonts-kacst fonts-liberation \ fonts-kacst fonts-liberation \
fonts-noto-cjk \ fonts-noto-cjk \
fonts-noto-color-emoji \ fonts-noto-color-emoji \
msttcorefonts \
fonts-roboto \ fonts-roboto \
fonts-thai-tlwg \ fonts-thai-tlwg \
fonts-wqy-zenhei fonts-wqy-zenhei
+2 -5
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG # Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ) | Co-Author: Tom Frenzel (tomfrenzel) # Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/danielbrendel/hortusfox-web # Source: https://github.com/danielbrendel/hortusfox-web
@@ -36,15 +36,12 @@ msg_ok "Composer dependencies installed"
msg_info "Running DB migration" msg_info "Running DB migration"
$STD php asatru migrate:fresh $STD php asatru migrate:fresh
HORTUSFOX_VERSION="$(<~/.hortusfox)"
printf '["%s"]\n' "$HORTUSFOX_VERSION" >/opt/hortusfox/app/migrations/verhist.json
msg_ok "Migration finished" msg_ok "Migration finished"
msg_info "Setting up HortusFox" msg_info "Setting up HortusFox"
$STD mariadb -u root -D $MARIADB_DB_NAME -e "INSERT IGNORE INTO AppModel (workspace, language, created_at) VALUES ('Default Workspace', 'en', NOW());" $STD mariadb -u root -D $MARIADB_DB_NAME -e "INSERT IGNORE INTO AppModel (workspace, language, created_at) VALUES ('Default Workspace', 'en', NOW());"
$STD php asatru calendar:classes
$STD php asatru plants:attributes $STD php asatru plants:attributes
$STD php asatru aquashell:config $STD php asatru calendar:classes
ADMIN_EMAIL="admin@example.com" ADMIN_EMAIL="admin@example.com"
ADMIN_PASS="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)" ADMIN_PASS="$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)"
ADMIN_HASH=$(php -r "echo password_hash('$ADMIN_PASS', PASSWORD_BCRYPT);") ADMIN_HASH=$(php -r "echo password_hash('$ADMIN_PASS', PASSWORD_BCRYPT);")
+1 -10
View File
@@ -355,16 +355,7 @@ cp LICENSE "$APP_DIR"
cd "$SRC_DIR" cd "$SRC_DIR"
export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml
export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg
mise_ok=0 $STD mise install
for i in 1 2 3; do
$STD mise install && {
mise_ok=1
break
}
msg_warn "mise install failed (attempt $i/3) - retrying"
sleep 5
done
[[ "$mise_ok" -eq 1 ]] || exit 1
export PATH="$(mise bin-paths 2>/dev/null | tr '\n' ':')$PATH" export PATH="$(mise bin-paths 2>/dev/null | tr '\n' ':')$PATH"
if ! command -v extism-js >/dev/null 2>&1; then if ! command -v extism-js >/dev/null 2>&1; then
# extism-js is published as a bare gzip-compressed single binary (.gz), which # extism-js is published as a bare gzip-compressed single binary (.gz), which
-79
View File
@@ -1,79 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/Ozark-Connect/NetworkOptimizer
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y \
git \
sshpass \
iperf3
setup_deb822_repo \
"microsoft" \
"https://packages.microsoft.com/keys/microsoft-2025.asc" \
"https://packages.microsoft.com/debian/13/prod/" \
"trixie"
$STD apt install -y dotnet-sdk-10.0
msg_ok "Installed Dependencies"
setup_go
fetch_and_deploy_gh_release "networkoptimizer" "Ozark-Connect/NetworkOptimizer" "tarball"
msg_info "Building NetworkOptimizer"
RID="linux-x64"
[[ "$(dpkg --print-architecture)" == "arm64" ]] && RID="linux-arm64"
cd /opt/networkoptimizer
export MinVerVersionOverride="$(cat ~/.networkoptimizer)"
$STD dotnet publish src/NetworkOptimizer.Web -c Release -r "$RID" --self-contained -o /opt/networkoptimizer/publish
chmod +x /opt/networkoptimizer/publish/NetworkOptimizer.Web
msg_ok "Built NetworkOptimizer"
msg_info "Building Gateway Speed Test Binary"
mkdir -p /opt/networkoptimizer/publish/tools
cd /opt/networkoptimizer/src/uwnspeedtest
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $STD go build -trimpath -ldflags "-s -w" -o /opt/networkoptimizer/publish/tools/uwnspeedtest-linux-arm64 .
msg_ok "Built Gateway Speed Test Binary"
msg_info "Configuring NetworkOptimizer"
cat <<EOF >/opt/networkoptimizer/networkoptimizer.env
ASPNETCORE_URLS=http://*:8042
HOST_IP=${LOCAL_IP}
Iperf3Server__Enabled=true
EOF
msg_ok "Configured NetworkOptimizer"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/networkoptimizer.service
[Unit]
Description=NetworkOptimizer
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/networkoptimizer/publish
EnvironmentFile=/opt/networkoptimizer/networkoptimizer.env
ExecStart=/opt/networkoptimizer/publish/NetworkOptimizer.Web
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now networkoptimizer
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: angusmaul
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://orb.net/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
setup_deb822_repo \
"orb" \
"https://pkgs.orb.net/stable/debian/orbforge.noarmor.gpg" \
"https://pkgs.orb.net/stable/debian" \
"orb" \
"main"
msg_info "Installing Orb"
$STD apt install -y orb
msg_ok "Installed Orb"
msg_info "Enabling Service"
systemctl enable -q --now orb
msg_ok "Enabled Service"
motd_ssh
customize
cleanup_lxc
+2 -11
View File
@@ -27,18 +27,9 @@ fetch_and_deploy_gh_release "pangolin" "fosrl/pangolin" "tarball" "$PANGOLIN_VER
fetch_and_deploy_gh_release "gerbil" "fosrl/gerbil" "singlefile" "latest" "/usr/bin" "gerbil_linux_$(arch_resolve)" fetch_and_deploy_gh_release "gerbil" "fosrl/gerbil" "singlefile" "latest" "/usr/bin" "gerbil_linux_$(arch_resolve)"
fetch_and_deploy_gh_release "traefik" "traefik/traefik" "prebuild" "latest" "/usr/bin" "traefik_v*_linux_$(arch_resolve).tar.gz" fetch_and_deploy_gh_release "traefik" "traefik/traefik" "prebuild" "latest" "/usr/bin" "traefik_v*_linux_$(arch_resolve).tar.gz"
# Read the variable first and prompt only when it is unset, so the install can read -rp "${TAB3}Enter your Pangolin URL (ex: https://pangolin.example.com): " pango_url
# be supplied up front. Same convention as install/forgejo-runner-install.sh.
pango_url="${var_pangolin_url:-}"
if [[ -z "$pango_url" ]]; then
read -rp "${TAB3}Enter your Pangolin URL (ex: https://pangolin.example.com): " pango_url
fi
[[ "$pango_url" != https://* && "$pango_url" != http://* ]] && pango_url="https://${pango_url}" [[ "$pango_url" != https://* && "$pango_url" != http://* ]] && pango_url="https://${pango_url}"
read -rp "${TAB3}Enter your email address: " pango_email
pango_email="${var_pangolin_email:-}"
if [[ -z "$pango_email" ]]; then
read -rp "${TAB3}Enter your email address: " pango_email
fi
msg_info "Setup Pangolin" msg_info "Setup Pangolin"
SECRET_KEY=$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 32) SECRET_KEY=$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 32)
+2 -1
View File
@@ -13,7 +13,8 @@ setting_up_container
network_check network_check
update_os update_os
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb" RELEASE="v2.3.0"
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "${RELEASE}" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
msg_info "Setting up Vikunja" msg_info "Setting up Vikunja"
sed -i 's|^# \(service:\)|\1|' /etc/vikunja/config.yml sed -i 's|^# \(service:\)|\1|' /etc/vikunja/config.yml
+3 -8
View File
@@ -922,10 +922,8 @@ choose_and_set_storage_for_file() {
_list_os_versions() { _list_os_versions() {
local ostype="${1:-}" local ostype="${1:-}"
[[ -n "$ostype" ]] || return 0 [[ -n "$ostype" ]] || return 0
local arch
arch="$(dpkg --print-architecture 2>/dev/null || echo amd64)"
pveam available -section system 2>/dev/null | pveam available -section system 2>/dev/null |
grep -E "_${arch}\.(tar\.zst|tar\.xz|tar\.gz)([[:space:]]|$)" | grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
awk '{print $2}' | awk '{print $2}' |
sed -nE "s/^${ostype}-([0-9]+(\.[0-9]+)?).*/\1/p" | sed -nE "s/^${ostype}-([0-9]+(\.[0-9]+)?).*/\1/p" |
sort -u -V || true sort -u -V || true
@@ -938,10 +936,8 @@ _list_os_versions() {
_list_templates() { _list_templates() {
local search="${1:-}" pattern="${2:-}" local search="${1:-}" pattern="${2:-}"
[[ -n "$search" ]] || return 0 [[ -n "$search" ]] || return 0
local arch
arch="$(dpkg --print-architecture 2>/dev/null || echo amd64)"
pveam available -section system 2>/dev/null | pveam available -section system 2>/dev/null |
grep -E "_${arch}\.(tar\.zst|tar\.xz|tar\.gz)([[:space:]]|$)" | grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
awk '{print $2}' | awk '{print $2}' |
grep -E "^${search}.*${pattern}" | grep -E "^${search}.*${pattern}" |
sort -t - -k 2 -V || true sort -t - -k 2 -V || true
@@ -6725,8 +6721,7 @@ create_lxc_container() {
# Step 1: Check local templates first (instant) # Step 1: Check local templates first (instant)
mapfile -t LOCAL_TEMPLATES < <( mapfile -t LOCAL_TEMPLATES < <(
pveam list "$TEMPLATE_STORAGE" 2>/dev/null | pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" -v arch="${ARCH}" \ awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
'$1 ~ search && $1 ~ pattern && $1 ~ ("_" arch "\\.(tar\\.zst|tar\\.xz|tar\\.gz)$") {print $1}' |
sed 's|.*/||' | sort -t - -k 2 -V sed 's|.*/||' | sort -t - -k 2 -V
) )
+28 -29
View File
@@ -2576,6 +2576,11 @@ _deploy_unpacked_archive() {
local archive="$1" target="$2" workdir="$3" local archive="$1" target="$2" workdir="$3"
local filename="${archive##*/}" local filename="${archive##*/}"
mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete
fi
if [[ "$filename" == *.zip ]]; then if [[ "$filename" == *.zip ]]; then
ensure_dependencies unzip ensure_dependencies unzip
unzip -q "$archive" -d "$workdir" || { unzip -q "$archive" -d "$workdir" || {
@@ -2602,44 +2607,38 @@ _deploy_unpacked_archive() {
return 65 return 65
fi fi
local top_entries inner_dir source_dir local top_entries inner_dir
top_entries=$(find "$workdir" -mindepth 1 -maxdepth 1) top_entries=$(find "$workdir" -mindepth 1 -maxdepth 1)
if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then
inner_dir="$top_entries" inner_dir="$top_entries"
source_dir="$inner_dir" shopt -s dotglob nullglob
else if compgen -G "$inner_dir/*" >/dev/null; then
source_dir="$workdir" cp -r "$inner_dir"/* "$target/" || {
fi msg_error "Failed to copy contents from $inner_dir to $target"
shopt -u dotglob nullglob
shopt -s dotglob nullglob return 252
if ! compgen -G "$source_dir/*" >/dev/null; then }
if [[ -n "$inner_dir" ]]; then else
msg_error "Inner directory is empty: $inner_dir" msg_error "Inner directory is empty: $inner_dir"
shopt -u dotglob nullglob
return 252
fi
shopt -u dotglob nullglob
else
shopt -s dotglob nullglob
if compgen -G "$workdir/*" >/dev/null; then
cp -r "$workdir"/* "$target/" || {
msg_error "Failed to copy contents to $target"
shopt -u dotglob nullglob
return 252
}
else else
msg_error "Unpacked archive is empty" msg_error "Unpacked archive is empty"
shopt -u dotglob nullglob
return 252
fi fi
shopt -u dotglob nullglob shopt -u dotglob nullglob
return 252
fi fi
# <target> is only touched once the payload is known good. Wiping earlier left
# CLEAN_INSTALL callers with an empty target directory whenever the download
# was truncated, the archive was unreadable, or it unpacked to nothing.
mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
find "${target:?}" -mindepth 1 -delete
fi
if ! cp -r "$source_dir"/* "$target/"; then
if [[ -n "$inner_dir" ]]; then
msg_error "Failed to copy contents from $inner_dir to $target"
else
msg_error "Failed to copy contents to $target"
fi
shopt -u dotglob nullglob
return 252
fi
shopt -u dotglob nullglob
return 0 return 0
} }
+12
View File
@@ -125,6 +125,12 @@ EOF
no) msg_error "Selected no to Correcting Proxmox VE Sources" ;; no) msg_error "Selected no to Correcting Proxmox VE Sources" ;;
esac esac
if [[ "$(dpkg --print-architecture 2>/dev/null)" == "arm64" ]]; then
msg_ok "ARM64 detected - skipping Proxmox repository setup"
post_routines_common
return
fi
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PVE-ENTERPRISE" --menu "The 'pve-enterprise' repository is only available to users who have purchased a Proxmox VE subscription.\n \nDisable 'pve-enterprise' repository?" 14 58 2 \ CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PVE-ENTERPRISE" --menu "The 'pve-enterprise' repository is only available to users who have purchased a Proxmox VE subscription.\n \nDisable 'pve-enterprise' repository?" 14 58 2 \
"yes" " " \ "yes" " " \
"no" " " 3>&2 2>&1 1>&3) "no" " " 3>&2 2>&1 1>&3)
@@ -282,6 +288,12 @@ EOF
esac esac
fi fi
if [[ "$(dpkg --print-architecture 2>/dev/null)" == "arm64" ]]; then
msg_ok "ARM64 detected - skipping Proxmox repository setup"
post_routines_common
return
fi
# ---- PVE-ENTERPRISE ---- # ---- PVE-ENTERPRISE ----
if component_exists_in_sources "pve-enterprise"; then if component_exists_in_sources "pve-enterprise"; then
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" \ CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" \