Compare commits

..

36 Commits

Author SHA1 Message Date
CanbiZ (MickLesk)
ddb827dc8c Add workflow to close unauthorized new-script PRs
Add a GitHub Actions workflow that runs on pull_request_target (opened, labeled) for main and automatically closes PRs labeled "new script" when the author is not an allowed bot or a member of the "contributor" team. The workflow comments explaining that new scripts must be submitted to the ProxmoxVED testing repo, closes the PR, and adds a "not a script issue" label. It scopes execution to the community-scripts/ProxmoxVE repo, uses a coolify-runner, and requires pull-requests: write and contents: read permissions.
2026-02-26 14:05:54 +01:00
community-scripts-pr-app[bot]
3911b09d1d chore: update github-versions.json (#12354)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-26 12:15:04 +00:00
community-scripts-pr-app[bot]
c24e9ead1c Update .app files (#12350)
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
2026-02-26 11:17:15 +01:00
community-scripts-pr-app[bot]
603d5b8f5e Update CHANGELOG.md (#12351)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-26 10:15:03 +00:00
community-scripts-pr-app[bot]
4fd70137b4 Update CHANGELOG.md (#12349)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-26 10:14:45 +00:00
community-scripts-pr-app[bot]
7398ffd9f4 Update date in json (#12348)
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
2026-02-26 10:14:37 +00:00
push-app-to-main[bot]
f1c765c534 Kima-Hub (#12319)
* Add kima-hub (ct)

* Change default disk size to 20

Updated the disk size default from 24 to 20.

* Modify date_created and hdd size in kima-hub.json

Updated the creation date and HDD size for kima-hub.

* remove: ai

* Update kima-hub.sh

* Update kima-hub-install.sh

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com>
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
2026-02-26 11:14:18 +01:00
community-scripts-pr-app[bot]
40aa06940c Update CHANGELOG.md (#12347)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-26 07:46:30 +00:00
Chris
117786376a [QOL] Immich: add warning regarding library compilation time (#12345) 2026-02-26 08:45:59 +01:00
community-scripts-pr-app[bot]
c5a635cdd7 chore: update github-versions.json (#12346)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-26 06:22:51 +00:00
community-scripts-pr-app[bot]
165e3f22cd Update CHANGELOG.md (#12344)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-26 00:19:57 +00:00
community-scripts-pr-app[bot]
2561a50d05 chore: update github-versions.json (#12343)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-26 00:19:34 +00:00
community-scripts-pr-app[bot]
6db5479b26 Update CHANGELOG.md (#12341)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 21:47:40 +00:00
Tobias
e74ddff49a fix: overseer migration (#12340) 2026-02-25 22:47:14 +01:00
community-scripts-pr-app[bot]
80132b0332 Update CHANGELOG.md (#12338)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 20:02:12 +00:00
CanbiZ (MickLesk)
83a19adbb4 tools.func: Improve GitHub/Codeberg API error handling and error output (#12330) 2026-02-25 21:01:45 +01:00
community-scripts-pr-app[bot]
6b196a7c81 chore: update github-versions.json (#12334)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 18:24:21 +00:00
community-scripts-pr-app[bot]
30082a1ba7 Update CHANGELOG.md (#12332)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 17:27:38 +00:00
Tobias
7741caa6ba add: vikunja: daemon reload (#12323) 2026-02-25 18:27:11 +01:00
community-scripts-pr-app[bot]
a3841d3cef Update CHANGELOG.md (#12331)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 16:32:03 +00:00
CanbiZ (MickLesk)
89cdabd040 opnsense-VM: Use ip link to verify bridge existence (#12329) 2026-02-25 17:31:41 +01:00
CanbiZ (MickLesk)
cbb82812b2 wger: Use $http_host for proxy Host header (#12327) 2026-02-25 17:31:14 +01:00
community-scripts-pr-app[bot]
1c463369c7 Update .app files (#12325)
Co-authored-by: GitHub Actions <github-actions[bot]@users.noreply.github.com>
2026-02-25 16:18:48 +01:00
community-scripts-pr-app[bot]
1a1e707db3 Update CHANGELOG.md (#12326)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 15:16:59 +00:00
push-app-to-main[bot]
95a63e66a8 Zerobyte (#12321)
* Add zerobyte (ct)

* Refactor zerobyte.sh to streamline Node.js setup

Removed redundant NODE_VERSION setup for Node.js during the build process.

* Update note to include FUSE pre-configuration detail

* Update date_created from 2026-02-18 to 2026-02-25

* Update zerobyte-install.sh

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com>
2026-02-25 16:16:23 +01:00
CanbiZ (MickLesk)
b09f2db2a9 Handle job-control signals and clear tostop
Prevent terminal job-control signals from suspending the script during recovery by trapping TSTP, TTIN and TTOU (instead of only TSTP) and restoring them on exit. Also clear the terminal 'tostop' flag in stop_spinner() with `stty -tostop` to avoid background spinner I/O from stopping the process group.
2026-02-25 14:45:11 +01:00
CanbiZ (MickLesk)
340d999b2b force gitea sync 2026-02-25 14:25:37 +01:00
community-scripts-pr-app[bot]
8c9874c4aa Update CHANGELOG.md (#12318)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 13:08:50 +00:00
community-scripts-pr-app[bot]
e9b98c2ab0 Update CHANGELOG.md (#12317)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 13:08:28 +00:00
CanbiZ (MickLesk)
dd46dd2d87 core: remove duplicate traps, consolidate error handling and harden signal traps (#12316)
* fix(zammad): configure Elasticsearch for LXC container startup

- Set discovery.type: single-node (required for single-node ES)
- Set xpack.security.enabled: false (not needed in local LXC)
- Set bootstrap.memory_lock: false (fails in unprivileged LXC)
- Add startup wait loop (up to 60s) to ensure ES is ready before
  Zammad installation continues

Fixes #12301-related recurring Elasticsearch startup failures

* refactor(api): eliminate duplicate traps, harden error handling & telemetry

Phase 1 - Structural:
- Remove api_exit_script() and 5 inline traps from build.func
- error_handler.func is now the sole trap owner via catch_errors()
- Update api.func comment reference (api_exit_script -> on_exit)

Phase 2 - Quality:
- Add stop_spinner() + cursor restore to error_handler(), on_interrupt(),
  on_terminate(), on_hangup() to prevent spinner/cursor artifacts
- Enhance _send_abort_telemetry() with error text (last 20 log lines),
  duration calculation, and 2 retry attempts (was fire-and-forget)
- Harden json_escape() to also strip DEL (0x7F) character

* fix(build): show spinner during post_update_to_api to prevent Ctrl+Z abort

post_update_to_api can take up to 33 seconds worst-case (3 curl attempts
x 10s timeout + sleep delays). Without any terminal output during this
time, users think the script is stuck and press Ctrl+Z, which prevents
the recovery menu from ever appearing.

Add msg_info spinner before both post_update_to_api calls in the failure
path (initial report + final force retry after recovery menu).

* fix(build): prevent SIGTSTP from killing recovery dialog

- Replace msg_info/stop_spinner with plain echo for telemetry reporting
  The background spinner process in non-interactive shells (bash -c)
  can trigger SIGTSTP, stopping the entire process group before the
  recovery dialog appears. Plain echo avoids this.

- Add trap '' TSTP at failure path entry to ignore suspension signals
  Prevents Ctrl+Z or terminal-related SIGTSTP from interrupting the
  recovery menu. Restored with trap - TSTP before exit.

- Root cause: msg_info starts a background process (spinner &) that
  is not properly detached in non-interactive shells where job control
  (set -m) is OFF. The disown builtin has no effect without job
  control, leaving the spinner in the same process group. This can
  cause terminal I/O conflicts during the 33-second post_update_to_api
  retry window, resulting in [2]+ Stopped.

* fix(test): initialize colors and remove illegal local in test harness

- Call load_functions() after sourcing core.func to initialize
  color/formatting/icon variables (RD, GN, YW, CL, TAB, etc.)
- Remove 'local' keyword from top-level scope (not inside function)
- Default REPO_SOURCE to ref_api instead of main

* chore: remove test-recovery-dialog.sh from branch

* Revert "fix(zammad): configure Elasticsearch for LXC container startup"

This reverts commit 10e450b72f.

* fix(build): show telemetry status only in verbose mode

Telemetry reporting is an implementation detail that doesn't help
the user during failure recovery. Wrap echo statements with
VERBOSE check so they only appear when verbose mode is enabled.
2026-02-25 14:08:24 +01:00
Slaviša Arežina
719761de6c Update Nginx client_max_body_size for Passbolt (#12313) 2026-02-25 14:08:02 +01:00
community-scripts-pr-app[bot]
765cd6d123 Update CHANGELOG.md (#12315)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 12:55:32 +00:00
CanbiZ (MickLesk)
26915e3979 Zammad: configure Elasticsearch before zammad start (#12308)
* fix(zammad): configure Elasticsearch for LXC container startup

- Set discovery.type: single-node (required for single-node ES)
- Set xpack.security.enabled: false (not needed in local LXC)
- Set bootstrap.memory_lock: false (fails in unprivileged LXC)
- Add startup wait loop (up to 60s) to ensure ES is ready before
  Zammad installation continues

Fixes #12301-related recurring Elasticsearch startup failures

* Update install/zammad-install.sh

Co-authored-by: Slaviša Arežina <58952836+tremor021@users.noreply.github.com>

---------

Co-authored-by: Slaviša Arežina <58952836+tremor021@users.noreply.github.com>
2026-02-25 13:55:07 +01:00
community-scripts-pr-app[bot]
34343bc61c chore: update github-versions.json (#12314)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 12:15:02 +00:00
community-scripts-pr-app[bot]
7484c58175 Update CHANGELOG.md (#12311)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-02-25 10:28:24 +00:00
CanbiZ (MickLesk)
dd4a15fff1 github: improvements for node drift wf (#12309)
* fix(workflow): improve Node.js version drift detection accuracy

1. Fix source URL regex: now captures 'Github: https://github.com/...'
   pattern (pipe-separated), not just '# Source: https://github.com/...'
   This was causing ~50 scripts to show 'No GitHub source'

2. Fix semver comparison: engines.node constraints like '>=18.0.0'
   no longer flag version 22 as drift. >= and ^ constraints are now
   properly evaluated (our_version >= min_major = satisfied)

3. Add fallback detection: when no Dockerfile or engines.node is found,
   check .nvmrc and .node-version files for Node version hints

4. Add subdirectory search: Dockerfile and package.json are now found
   via GitHub API tree search, not just in repo root

5. Use GitHub API to detect default branch instead of guessing
   main/master/dev with multiple HEAD requests

* fix typos in node_version

* runs on vps
2026-02-25 11:27:47 +01:00
26 changed files with 1009 additions and 121 deletions

119
.github/workflows/close-new-script-prs.yml generated vendored Normal file
View File

@@ -0,0 +1,119 @@
name: Close Unauthorized New Script PRs
on:
pull_request_target:
branches: ["main"]
types: [opened, labeled]
jobs:
check-new-script:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: coolify-runner
permissions:
pull-requests: write
contents: read
steps:
- name: Close PR if unauthorized new script submission
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
const prNumber = pr.number;
const author = pr.user.login;
const authorType = pr.user.type; // "User" or "Bot"
const owner = context.repo.owner;
const repo = context.repo.repo;
// --- Only act on PRs with the "new script" label ---
const labels = pr.labels.map(l => l.name);
if (!labels.includes("new script")) {
core.info(`PR #${prNumber} does not have "new script" label — skipping.`);
return;
}
// --- Allow our bots ---
const allowedBots = [
"push-app-to-main[bot]",
"push-app-to-main",
];
if (allowedBots.includes(author)) {
core.info(`PR #${prNumber} by allowed bot "${author}" — skipping.`);
return;
}
// --- Check if author is a member of the contributor team ---
const teamSlug = "contributor";
let isMember = false;
try {
const { status } = await github.rest.teams.getMembershipForUserInOrg({
org: owner,
team_slug: teamSlug,
username: author,
});
// status 200 means the user is a member (active or pending)
isMember = true;
} catch (error) {
if (error.status === 404) {
isMember = false;
} else {
core.warning(`Could not check team membership for ${author}: ${error.message}`);
// Fallback: check org membership
try {
await github.rest.orgs.checkMembershipForUser({
org: owner,
username: author,
});
isMember = true;
} catch {
isMember = false;
}
}
}
if (isMember) {
core.info(`PR #${prNumber} by contributor "${author}" — skipping.`);
return;
}
// --- Unauthorized: close the PR with a comment ---
core.info(`Closing PR #${prNumber} by "${author}" — not a contributor or allowed bot.`);
const comment = [
`👋 Hi @${author},`,
``,
`Thank you for your interest in contributing a new script!`,
``,
`However, **new scripts must first be submitted to our development repository** for testing and review before they can be merged here.`,
``,
`> 🛑 New scripts must be submitted to [**ProxmoxVED**](https://github.com/community-scripts/ProxmoxVED) for testing.`,
`> PRs without prior testing will be closed.`,
``,
`Please open your PR at **https://github.com/community-scripts/ProxmoxVED** instead.`,
`Once your script has been tested and approved there, it will be pushed to this repository automatically.`,
``,
`This PR will now be closed. Thank you for understanding! 🙏`,
].join("\n");
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: comment,
});
await github.rest.pulls.update({
owner,
repo,
pull_number: prNumber,
state: "closed",
});
// Add a label to indicate why it was closed
await github.rest.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels: ["not a script issue"],
});

View File

@@ -407,10 +407,35 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-02-25
## 2026-02-26
### 🆕 New Scripts
- Kima-Hub ([#12319](https://github.com/community-scripts/ProxmoxVE/pull/12319))
### 🚀 Updated Scripts
- #### ✨ New Features
- [QOL] Immich: add warning regarding library compilation time [@vhsdream](https://github.com/vhsdream) ([#12345](https://github.com/community-scripts/ProxmoxVE/pull/12345))
## 2026-02-25
### 🆕 New Scripts
- Zerobyte ([#12321](https://github.com/community-scripts/ProxmoxVE/pull/12321))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix: overseer migration [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12340](https://github.com/community-scripts/ProxmoxVE/pull/12340))
- add: vikunja: daemon reload [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12323](https://github.com/community-scripts/ProxmoxVE/pull/12323))
- opnsense-VM: Use ip link to verify bridge existence [@MickLesk](https://github.com/MickLesk) ([#12329](https://github.com/community-scripts/ProxmoxVE/pull/12329))
- wger: Use $http_host for proxy Host header [@MickLesk](https://github.com/MickLesk) ([#12327](https://github.com/community-scripts/ProxmoxVE/pull/12327))
- Passbolt: Update Nginx config `client_max_body_size` [@tremor021](https://github.com/tremor021) ([#12313](https://github.com/community-scripts/ProxmoxVE/pull/12313))
- Zammad: configure Elasticsearch before zammad start [@MickLesk](https://github.com/MickLesk) ([#12308](https://github.com/community-scripts/ProxmoxVE/pull/12308))
- #### 🔧 Refactor
- OpenProject: Various fixes [@tremor021](https://github.com/tremor021) ([#12246](https://github.com/community-scripts/ProxmoxVE/pull/12246))
@@ -421,6 +446,18 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- Fix detection of ssh keys [@1-tempest](https://github.com/1-tempest) ([#12230](https://github.com/community-scripts/ProxmoxVE/pull/12230))
- #### ✨ New Features
- tools.func: Improve GitHub/Codeberg API error handling and error output [@MickLesk](https://github.com/MickLesk) ([#12330](https://github.com/community-scripts/ProxmoxVE/pull/12330))
- #### 🔧 Refactor
- core: remove duplicate traps, consolidate error handling and harden signal traps [@MickLesk](https://github.com/MickLesk) ([#12316](https://github.com/community-scripts/ProxmoxVE/pull/12316))
### 📂 Github
- github: improvements for node drift wf [@MickLesk](https://github.com/MickLesk) ([#12309](https://github.com/community-scripts/ProxmoxVE/pull/12309))
## 2026-02-24
### 🚀 Updated Scripts

6
ct/headers/kima-hub Normal file
View File

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

6
ct/headers/zerobyte Normal file
View File

@@ -0,0 +1,6 @@
_____ __ __
/__ / ___ _________ / /_ __ __/ /____
/ / / _ \/ ___/ __ \/ __ \/ / / / __/ _ \
/ /__/ __/ / / /_/ / /_/ / /_/ / /_/ __/
/____/\___/_/ \____/_.___/\__, /\__/\___/
/____/

View File

@@ -97,7 +97,7 @@ EOF
if [[ -f ~/.immich_library_revisions ]]; then
libraries=("libjxl" "libheif" "libraw" "imagemagick" "libvips")
cd "$BASE_DIR"
msg_info "Checking for updates to custom image-processing libraries"
msg_warn "Checking for updates to custom image-processing libraries (recompile time: 2-15min per library)"
$STD git pull
for library in "${libraries[@]}"; do
compile_"$library"

79
ct/kima-hub.sh Normal file
View File

@@ -0,0 +1,79 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/Chevron7Locked/kima-hub
APP="Kima-Hub"
var_tags="${var_tags:-music;streaming;media}"
var_cpu="${var_cpu:-4}"
var_ram="${var_ram:-8192}"
var_disk="${var_disk:-20}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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/kima-hub ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "kima-hub" "Chevron7Locked/kima-hub"; then
msg_info "Stopping Services"
systemctl stop kima-frontend kima-backend kima-analyzer kima-analyzer-clap
msg_ok "Stopped Services"
msg_info "Backing up Data"
cp /opt/kima-hub/backend/.env /opt/kima-hub-backend-env.bak
cp /opt/kima-hub/frontend/.env /opt/kima-hub-frontend-env.bak
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "kima-hub" "Chevron7Locked/kima-hub" "tarball"
msg_info "Restoring Data"
cp /opt/kima-hub-backend-env.bak /opt/kima-hub/backend/.env
cp /opt/kima-hub-frontend-env.bak /opt/kima-hub/frontend/.env
rm -f /opt/kima-hub-backend-env.bak /opt/kima-hub-frontend-env.bak
msg_ok "Restored Data"
msg_info "Rebuilding Backend"
cd /opt/kima-hub/backend
$STD npm install
$STD npm run build
$STD npx prisma generate
$STD npx prisma migrate deploy
msg_ok "Rebuilt Backend"
msg_info "Rebuilding Frontend"
cd /opt/kima-hub/frontend
$STD npm install
$STD npm run build
msg_ok "Rebuilt Frontend"
msg_info "Starting Services"
systemctl start kima-backend kima-frontend kima-analyzer kima-analyzer-clap
msg_ok "Started Services"
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 "${TAB}${GATEWAY}${BGN}http://${IP}:3030${CL}"

View File

@@ -28,7 +28,7 @@ function update_script() {
exit
fi
if [[ -f "$HOME/.overseerr" ]] && [[ "$(cat "$HOME/.overseerr")" == "1.34.0" ]]; then
if [[ -f "$HOME/.overseerr" ]] && [[ "$(printf '%s\n' "1.34.0" "$(cat "$HOME/.overseerr")" | sort -V | head -n1)" == "1.35.0" ]]; then
echo
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Overseerr v1.34.0 detected."

View File

@@ -65,6 +65,7 @@ function update_script() {
msg_ok "Stopped Service"
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary"
$STD systemctl daemon-reload
msg_info "Starting Service"
systemctl start vikunja

71
ct/zerobyte.sh Normal file
View File

@@ -0,0 +1,71 @@
#!/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: community-scripts
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/nicotsx/zerobyte
APP="Zerobyte"
var_tags="${var_tags:-backup;encryption;restic}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-6144}"
var_disk="${var_disk:-10}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
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/zerobyte ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "zerobyte" "nicotsx/zerobyte"; then
msg_info "Stopping Service"
systemctl stop zerobyte
msg_ok "Stopped Service"
msg_info "Backing up Configuration"
cp /opt/zerobyte/.env /opt/zerobyte.env.bak
msg_ok "Backed up Configuration"
NODE_VERSION="24" setup_nodejs
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "zerobyte" "nicotsx/zerobyte" "tarball"
msg_info "Building Zerobyte"
export NODE_OPTIONS="--max-old-space-size=3072"
cd /opt/zerobyte
$STD bun install
$STD node ./node_modules/vite/bin/vite.js build
msg_ok "Built Zerobyte"
msg_info "Restoring Configuration"
cp /opt/zerobyte.env.bak /opt/zerobyte/.env
rm -f /opt/zerobyte.env.bak
msg_ok "Restored Configuration"
msg_info "Starting Service"
systemctl start zerobyte
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 "${TAB}${GATEWAY}${BGN}http://${IP}:4096${CL}"

View File

@@ -1,5 +1,5 @@
{
"generated": "2026-02-25T06:25:10Z",
"generated": "2026-02-26T12:14:56Z",
"versions": [
{
"slug": "2fauth",
@@ -39,9 +39,9 @@
{
"slug": "ampache",
"repo": "ampache/ampache",
"version": "7.9.0",
"version": "7.9.1",
"pinned": false,
"date": "2026-02-19T07:01:25Z"
"date": "2026-02-25T08:52:58Z"
},
{
"slug": "argus",
@@ -109,9 +109,9 @@
{
"slug": "bazarr",
"repo": "morpheus65535/bazarr",
"version": "v1.5.5",
"version": "v1.5.6",
"pinned": false,
"date": "2026-02-01T18:00:34Z"
"date": "2026-02-26T11:33:11Z"
},
{
"slug": "bentopdf",
@@ -151,9 +151,9 @@
{
"slug": "booklore",
"repo": "booklore-app/BookLore",
"version": "v2.0.1",
"version": "v2.0.2",
"pinned": false,
"date": "2026-02-24T04:15:33Z"
"date": "2026-02-25T19:59:20Z"
},
{
"slug": "bookstack",
@@ -242,9 +242,9 @@
{
"slug": "cosmos",
"repo": "azukaar/Cosmos-Server",
"version": "v0.20.2",
"version": "v0.21.2",
"pinned": false,
"date": "2026-01-24T00:12:39Z"
"date": "2026-02-26T11:32:33Z"
},
{
"slug": "cronicle",
@@ -270,16 +270,16 @@
{
"slug": "databasus",
"repo": "databasus/databasus",
"version": "v3.16.2",
"version": "v3.16.3",
"pinned": false,
"date": "2026-02-22T21:10:12Z"
"date": "2026-02-25T19:57:26Z"
},
{
"slug": "dawarich",
"repo": "Freika/dawarich",
"version": "1.2.0",
"version": "1.3.0",
"pinned": false,
"date": "2026-02-15T22:33:56Z"
"date": "2026-02-25T19:30:25Z"
},
{
"slug": "discopanel",
@@ -452,9 +452,9 @@
{
"slug": "gitea-mirror",
"repo": "RayLabsHQ/gitea-mirror",
"version": "v3.9.4",
"version": "v3.9.5",
"pinned": false,
"date": "2026-02-24T06:17:56Z"
"date": "2026-02-26T05:32:12Z"
},
{
"slug": "glance",
@@ -606,16 +606,16 @@
{
"slug": "invoiceninja",
"repo": "invoiceninja/invoiceninja",
"version": "v5.12.66",
"version": "v5.12.68",
"pinned": false,
"date": "2026-02-24T09:12:50Z"
"date": "2026-02-25T19:38:19Z"
},
{
"slug": "jackett",
"repo": "Jackett/Jackett",
"version": "v0.24.1205",
"version": "v0.24.1218",
"pinned": false,
"date": "2026-02-25T05:49:14Z"
"date": "2026-02-26T05:55:11Z"
},
{
"slug": "jellystat",
@@ -627,9 +627,9 @@
{
"slug": "joplin-server",
"repo": "laurent22/joplin",
"version": "v3.5.12",
"version": "v3.5.13",
"pinned": false,
"date": "2026-01-17T14:20:33Z"
"date": "2026-02-25T21:19:11Z"
},
{
"slug": "jotty",
@@ -666,12 +666,19 @@
"pinned": false,
"date": "2026-02-20T09:19:45Z"
},
{
"slug": "kima-hub",
"repo": "Chevron7Locked/kima-hub",
"version": "v1.5.7",
"pinned": false,
"date": "2026-02-23T23:58:59Z"
},
{
"slug": "kimai",
"repo": "kimai/kimai",
"version": "2.49.0",
"version": "2.50.0",
"pinned": false,
"date": "2026-02-15T20:40:19Z"
"date": "2026-02-25T20:13:51Z"
},
{
"slug": "kitchenowl",
@@ -711,9 +718,9 @@
{
"slug": "kubo",
"repo": "ipfs/kubo",
"version": "v0.39.0",
"version": "v0.40.0",
"pinned": false,
"date": "2025-11-27T03:47:38Z"
"date": "2026-02-25T23:16:17Z"
},
{
"slug": "kutt",
@@ -809,9 +816,9 @@
{
"slug": "mail-archiver",
"repo": "s1t5/mail-archiver",
"version": "2602.3",
"version": "2602.4",
"pinned": false,
"date": "2026-02-22T20:24:18Z"
"date": "2026-02-26T08:43:01Z"
},
{
"slug": "managemydamnlife",
@@ -823,9 +830,9 @@
{
"slug": "manyfold",
"repo": "manyfold3d/manyfold",
"version": "v0.132.1",
"version": "v0.133.0",
"pinned": false,
"date": "2026-02-09T22:02:28Z"
"date": "2026-02-25T10:40:26Z"
},
{
"slug": "mealie",
@@ -995,6 +1002,13 @@
"pinned": false,
"date": "2026-02-03T09:00:43Z"
},
{
"slug": "openproject",
"repo": "jemalloc/jemalloc",
"version": "5.3.0",
"pinned": false,
"date": "2022-05-06T19:14:21Z"
},
{
"slug": "ots",
"repo": "Luzifer/ots",
@@ -1159,9 +1173,9 @@
{
"slug": "prometheus",
"repo": "prometheus/prometheus",
"version": "v3.9.1",
"version": "v3.10.0",
"pinned": false,
"date": "2026-01-07T17:05:53Z"
"date": "2026-02-26T01:19:51Z"
},
{
"slug": "prometheus-alertmanager",
@@ -1257,9 +1271,9 @@
{
"slug": "radicale",
"repo": "Kozea/Radicale",
"version": "v3.6.0",
"version": "v3.6.1",
"pinned": false,
"date": "2026-01-10T06:56:46Z"
"date": "2026-02-24T06:36:23Z"
},
{
"slug": "rclone",
@@ -1285,9 +1299,9 @@
{
"slug": "recyclarr",
"repo": "recyclarr/recyclarr",
"version": "v8.3.1",
"version": "v8.3.2",
"pinned": false,
"date": "2026-02-25T01:01:31Z"
"date": "2026-02-25T22:39:51Z"
},
{
"slug": "reitti",
@@ -1383,9 +1397,9 @@
{
"slug": "signoz",
"repo": "SigNoz/signoz-otel-collector",
"version": "v0.144.1",
"version": "v0.144.2",
"pinned": false,
"date": "2026-02-25T05:57:17Z"
"date": "2026-02-26T05:57:26Z"
},
{
"slug": "silverbullet",
@@ -1593,9 +1607,9 @@
{
"slug": "tunarr",
"repo": "chrisbenincasa/tunarr",
"version": "v1.1.16",
"version": "v1.1.17",
"pinned": false,
"date": "2026-02-23T21:24:47Z"
"date": "2026-02-25T19:56:36Z"
},
{
"slug": "uhf",
@@ -1656,9 +1670,9 @@
{
"slug": "vikunja",
"repo": "go-vikunja/vikunja",
"version": "v1.1.0",
"version": "v2.0.0",
"pinned": false,
"date": "2026-02-09T10:34:29Z"
"date": "2026-02-25T13:58:47Z"
},
{
"slug": "wallabag",
@@ -1772,6 +1786,13 @@
"pinned": false,
"date": "2026-02-24T15:15:46Z"
},
{
"slug": "zerobyte",
"repo": "restic/restic",
"version": "v0.18.1",
"pinned": false,
"date": "2025-09-21T18:24:38Z"
},
{
"slug": "zigbee2mqtt",
"repo": "Koenkk/zigbee2mqtt",

View File

@@ -51,6 +51,10 @@
{
"text": "Logs: `/var/log/immich`",
"type": "info"
},
{
"text": "During first install, 5 custom libraries need to be compiled from source. Depending on your CPU, this can take anywhere between 15 minutes and 2 hours. Please be patient. Touch grass or something.",
"type": "warning"
}
]
}

View File

@@ -0,0 +1,48 @@
{
"name": "Kima-Hub",
"slug": "kima-hub",
"categories": [
13
],
"date_created": "2026-02-26",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 3030,
"documentation": "https://github.com/Chevron7Locked/kima-hub#readme",
"website": "https://github.com/Chevron7Locked/kima-hub",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/kima-hub.webp",
"config_path": "/opt/kima-hub/backend/.env",
"description": "Self-hosted, on-demand audio streaming platform with AI-powered vibe matching, mood detection, smart playlists, and Lidarr/Audiobookshelf integration.",
"install_methods": [
{
"type": "default",
"script": "ct/kima-hub.sh",
"resources": {
"cpu": 4,
"ram": 8192,
"hdd": 20,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "First user to register becomes the administrator.",
"type": "info"
},
{
"text": "Mount your music library to /music in the container.",
"type": "warning"
},
{
"text": "Audio analysis (mood/vibe detection) requires significant RAM (2-4GB per worker).",
"type": "info"
}
]
}

View File

@@ -0,0 +1,40 @@
{
"name": "Zerobyte",
"slug": "zerobyte",
"categories": [
7
],
"date_created": "2026-02-25",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 4096,
"documentation": "https://github.com/nicotsx/zerobyte#readme",
"website": "https://github.com/nicotsx/zerobyte",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/zerobyte.webp",
"config_path": "/opt/zerobyte/.env",
"description": "Zerobyte is a backup automation tool built on top of Restic that provides a modern web interface to schedule, manage, and monitor encrypted backups across multiple storage backends including NFS, SMB, WebDAV, SFTP, S3, and local directories.",
"install_methods": [
{
"type": "default",
"script": "ct/zerobyte.sh",
"resources": {
"cpu": 2,
"ram": 6144,
"hdd": 10,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "For remote mount support (NFS, SMB, WebDAV, SFTP), enable FUSE device passthrough on the LXC container. (FUSE is pre-configured)",
"type": "info"
}
]
}

View File

@@ -154,7 +154,7 @@ sed -i -e "/^#shared_preload/s/^#//;/^shared_preload/s/''/'vchord.so'/" /etc/pos
systemctl restart postgresql.service
PG_DB_NAME="immich" PG_DB_USER="immich" PG_DB_GRANT_SUPERUSER="true" PG_DB_SKIP_ALTER_ROLE="true" setup_postgresql_db
msg_info "Compiling Custom Photo-processing Library (extreme patience)"
msg_warn "Compiling Custom Photo-processing Libraries (can take anywhere from 15min to 2h)"
LD_LIBRARY_PATH=/usr/local/lib
export LD_RUN_PATH=/usr/local/lib
STAGING_DIR=/opt/staging

212
install/kima-hub-install.sh Normal file
View File

@@ -0,0 +1,212 @@
#!/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/Chevron7Locked/kima-hub
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 \
build-essential \
git \
openssl \
ffmpeg \
python3 \
python3-pip \
python3-dev \
python3-numpy \
redis-server
msg_ok "Installed Dependencies"
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
PG_DB_NAME="kima" PG_DB_USER="kima" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
NODE_VERSION="20" setup_nodejs
msg_info "Configuring Redis"
systemctl enable -q --now redis-server
msg_ok "Configured Redis"
fetch_and_deploy_gh_release "kima-hub" "Chevron7Locked/kima-hub" "tarball"
msg_info "Installing Python Dependencies"
export PIP_BREAK_SYSTEM_PACKAGES=1
$STD pip3 install --no-cache-dir \
tensorflow \
essentia-tensorflow \
redis \
psycopg2-binary \
laion-clap \
torch \
torchaudio \
librosa \
transformers \
pgvector \
python-dotenv \
requests
msg_ok "Installed Python Dependencies"
msg_info "Downloading Essentia ML Models"
mkdir -p /opt/kima-hub/models
cd /opt/kima-hub/models
curl -fsSL -o msd-musicnn-1.pb "https://essentia.upf.edu/models/autotagging/msd/msd-musicnn-1.pb"
curl -fsSL -o mood_happy-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_happy/mood_happy-msd-musicnn-1.pb"
curl -fsSL -o mood_sad-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_sad/mood_sad-msd-musicnn-1.pb"
curl -fsSL -o mood_relaxed-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_relaxed/mood_relaxed-msd-musicnn-1.pb"
curl -fsSL -o mood_aggressive-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_aggressive/mood_aggressive-msd-musicnn-1.pb"
curl -fsSL -o mood_party-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_party/mood_party-msd-musicnn-1.pb"
curl -fsSL -o mood_acoustic-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_acoustic/mood_acoustic-msd-musicnn-1.pb"
curl -fsSL -o mood_electronic-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/mood_electronic/mood_electronic-msd-musicnn-1.pb"
curl -fsSL -o danceability-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/danceability/danceability-msd-musicnn-1.pb"
curl -fsSL -o voice_instrumental-msd-musicnn-1.pb "https://essentia.upf.edu/models/classification-heads/voice_instrumental/voice_instrumental-msd-musicnn-1.pb"
msg_ok "Downloaded Essentia ML Models"
msg_info "Downloading CLAP Model"
curl -fsSL -o /opt/kima-hub/models/music_audioset_epoch_15_esc_90.14.pt "https://huggingface.co/lukewys/laion_clap/resolve/main/music_audioset_epoch_15_esc_90.14.pt"
msg_ok "Downloaded CLAP Model"
msg_info "Building Backend"
cd /opt/kima-hub/backend
$STD npm ci
$STD npm run build
msg_ok "Built Backend"
msg_info "Configuring Backend"
SESSION_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
cat <<EOF >/opt/kima-hub/backend/.env
NODE_ENV=production
DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}
REDIS_URL=redis://localhost:6379
PORT=3006
MUSIC_PATH=/music
TRANSCODE_CACHE_PATH=/opt/kima-hub/cache/transcodes
SESSION_SECRET=${SESSION_SECRET}
SETTINGS_ENCRYPTION_KEY=${ENCRYPTION_KEY}
INTERNAL_API_SECRET=$(openssl rand -hex 16)
EOF
msg_ok "Configured Backend"
msg_info "Running Database Migrations"
cd /opt/kima-hub/backend
$STD npx prisma generate
$STD npx prisma migrate deploy
msg_ok "Ran Database Migrations"
msg_info "Building Frontend"
cd /opt/kima-hub/frontend
$STD npm ci
export NEXT_PUBLIC_BACKEND_URL=http://127.0.0.1:3006
$STD npm run build
msg_ok "Built Frontend"
msg_info "Configuring Frontend"
cat <<EOF >/opt/kima-hub/frontend/.env
NODE_ENV=production
BACKEND_URL=http://localhost:3006
PORT=3030
EOF
msg_ok "Configured Frontend"
msg_info "Creating Directories"
mkdir -p /opt/kima-hub/cache/transcodes
mkdir -p /music
msg_ok "Created Directories"
msg_info "Creating Services"
cat <<EOF >/etc/systemd/system/kima-backend.service
[Unit]
Description=Kima Hub Backend
After=network.target postgresql.service redis-server.service
Wants=postgresql.service redis-server.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/kima-hub/backend
EnvironmentFile=/opt/kima-hub/backend/.env
ExecStart=/usr/bin/node /opt/kima-hub/backend/dist/index.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/kima-frontend.service
[Unit]
Description=Kima Hub Frontend
After=network.target kima-backend.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/kima-hub/frontend
EnvironmentFile=/opt/kima-hub/frontend/.env
ExecStart=/usr/bin/npm start
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/kima-analyzer.service
[Unit]
Description=Kima Hub Audio Analyzer (Essentia)
After=network.target postgresql.service redis-server.service kima-backend.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/kima-hub/services/audio-analyzer
Environment=DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}
Environment=REDIS_URL=redis://localhost:6379
Environment=MUSIC_PATH=/music
Environment=BATCH_SIZE=10
Environment=SLEEP_INTERVAL=5
Environment=NUM_WORKERS=2
Environment=THREADS_PER_WORKER=1
ExecStart=/usr/bin/python3 /opt/kima-hub/services/audio-analyzer/analyzer.py
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
cat <<EOF >/etc/systemd/system/kima-analyzer-clap.service
[Unit]
Description=Kima Hub CLAP Audio Analyzer
After=network.target postgresql.service redis-server.service kima-backend.service kima-analyzer.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/kima-hub/services/audio-analyzer-clap
Environment=DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}
Environment=REDIS_URL=redis://localhost:6379
Environment=BACKEND_URL=http://localhost:3006
Environment=MUSIC_PATH=/music
Environment=SLEEP_INTERVAL=5
Environment=NUM_WORKERS=1
ExecStart=/usr/bin/python3 /opt/kima-hub/services/audio-analyzer-clap/analyzer.py
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now kima-backend kima-frontend kima-analyzer kima-analyzer-clap
msg_ok "Created Services"
motd_ssh
customize
cleanup_lxc

View File

@@ -44,6 +44,8 @@ echo passbolt-ce-server passbolt/nginx-domain string $LOCAL_IP | debconf-set-sel
echo passbolt-ce-server passbolt/nginx-certificate-file string /etc/ssl/passbolt/passbolt.crt | debconf-set-selections
echo passbolt-ce-server passbolt/nginx-certificate-key-file string /etc/ssl/passbolt/passbolt.key | debconf-set-selections
$STD apt install -y --no-install-recommends passbolt-ce-server
sed -i 's/client_max_body_size[[:space:]]\+[0-9]\+M;/client_max_body_size 15M;/' /etc/nginx/sites-enabled/nginx-passbolt.conf
systemctl reload nginx
msg_ok "Setup Passbolt"
motd_ssh

View File

@@ -164,7 +164,7 @@ server {
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;

View File

@@ -28,12 +28,23 @@ setup_deb822_repo \
"stable" \
"main"
$STD apt install -y elasticsearch
sed -i 's/^-Xms.*/-Xms2g/' /etc/elasticsearch/jvm.options
sed -i 's/^-Xmx.*/-Xmx2g/' /etc/elasticsearch/jvm.options
sed -i 's/^#\{0,2\} *-Xms[0-9]*g.*/-Xms2g/' /etc/elasticsearch/jvm.options
sed -i 's/^#\{0,2\} *-Xmx[0-9]*g.*/-Xmx2g/' /etc/elasticsearch/jvm.options
cat <<EOF >>/etc/elasticsearch/elasticsearch.yml
discovery.type: single-node
xpack.security.enabled: false
bootstrap.memory_lock: false
EOF
$STD /usr/share/elasticsearch/bin/elasticsearch-plugin install ingest-attachment -b
systemctl daemon-reload
systemctl enable -q elasticsearch
systemctl restart -q elasticsearch
for i in $(seq 1 30); do
if curl -s http://localhost:9200 >/dev/null 2>&1; then
break
fi
sleep 2
done
msg_ok "Setup Elasticsearch"
msg_info "Installing Zammad"

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: community-scripts
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/nicotsx/zerobyte
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
echo "davfs2 davfs2/suid_file boolean false" | debconf-set-selections
$STD apt-get install -y \
bzip2 \
fuse3 \
sshfs \
davfs2 \
openssh-client
msg_ok "Installed Dependencies"
fetch_and_deploy_gh_release "restic" "restic/restic" "singlefile" "latest" "/usr/local/bin" "restic_*_linux_amd64.bz2"
mv /usr/local/bin/restic /usr/local/bin/restic.bz2
bzip2 -d /usr/local/bin/restic.bz2
chmod +x /usr/local/bin/restic
fetch_and_deploy_gh_release "rclone" "rclone/rclone" "prebuild" "latest" "/opt/rclone" "rclone-*-linux-amd64.zip"
ln -sf /opt/rclone/rclone /usr/local/bin/rclone
fetch_and_deploy_gh_release "shoutrrr" "nicholas-fedor/shoutrrr" "prebuild" "latest" "/opt/shoutrrr" "shoutrrr_linux_amd64_*.tar.gz"
ln -sf /opt/shoutrrr/shoutrrr /usr/local/bin/shoutrrr
msg_info "Installing Bun"
export BUN_INSTALL="/root/.bun"
curl -fsSL https://bun.sh/install | $STD bash
ln -sf /root/.bun/bin/bun /usr/local/bin/bun
ln -sf /root/.bun/bin/bunx /usr/local/bin/bunx
msg_ok "Installed Bun"
NODE_VERSION="24" setup_nodejs
fetch_and_deploy_gh_release "zerobyte" "nicotsx/zerobyte" "tarball"
msg_info "Building Zerobyte (Patience)"
cd /opt/zerobyte
export VITE_RESTIC_VERSION=$(cat ~/.restic)
export VITE_RCLONE_VERSION=$(cat ~/.rclone)
export VITE_SHOUTRRR_VERSION=$(cat ~/.shoutrrr)
export NODE_OPTIONS="--max-old-space-size=3072"
$STD bun install
$STD node ./node_modules/vite/bin/vite.js build
msg_ok "Built Zerobyte"
msg_info "Configuring Zerobyte"
mkdir -p /var/lib/zerobyte/{data,restic/cache,repositories,volumes}
APP_SECRET=$(openssl rand -hex 32)
cat <<EOF >/opt/zerobyte/.env
BASE_URL=http://${LOCAL_IP}:4096
APP_SECRET=${APP_SECRET}
PORT=4096
ZEROBYTE_DATABASE_URL=/var/lib/zerobyte/data/zerobyte.db
RESTIC_CACHE_DIR=/var/lib/zerobyte/restic/cache
ZEROBYTE_REPOSITORIES_DIR=/var/lib/zerobyte/repositories
ZEROBYTE_VOLUMES_DIR=/var/lib/zerobyte/volumes
MIGRATIONS_PATH=/opt/zerobyte/app/drizzle
NODE_ENV=production
EOF
msg_ok "Configured Zerobyte"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/zerobyte.service
[Unit]
Description=Zerobyte Backup Automation
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/zerobyte
EnvironmentFile=/opt/zerobyte/.env
ExecStart=/usr/local/bin/bun .output/server/index.mjs
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now zerobyte
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -312,7 +312,8 @@ json_escape() {
s=${s//$'\r'/}
s=${s//$'\t'/\\t}
# Remove any remaining control characters (0x00-0x1F except those already handled)
s=$(printf '%s' "$s" | tr -d '\000-\010\013\014\016-\037')
# Also remove DEL (0x7F) and invalid high bytes that break JSON parsers
s=$(printf '%s' "$s" | tr -d '\000-\010\013\014\016-\037\177')
printf '%s' "$s"
}
@@ -982,7 +983,7 @@ EOF
fi
# All 3 attempts failed — do NOT set POST_UPDATE_DONE=true.
# This allows the EXIT trap (api_exit_script) to retry with 3 fresh attempts.
# This allows the EXIT trap (on_exit in error_handler.func) to retry.
# No infinite loop risk: EXIT trap fires exactly once.
}

View File

@@ -4098,6 +4098,12 @@ EOF'
# Installation failed?
if [[ $install_exit_code -ne 0 ]]; then
# Prevent job-control signals from suspending the script during recovery.
# In non-interactive shells (bash -c), background processes (spinner) can
# trigger terminal-related signals that stop the entire process group.
# TSTP = Ctrl+Z, TTIN = bg read from tty, TTOU = bg write to tty (tostop)
trap '' TSTP TTIN TTOU
msg_error "Installation failed in container ${CTID} (exit code: ${install_exit_code})"
# Copy install log from container BEFORE API call so get_error_text() can read it
@@ -4173,7 +4179,12 @@ EOF'
fi
# Report failure to telemetry API (now with log available on host)
# NOTE: Do NOT use msg_info/spinner here — the background spinner process
# causes SIGTSTP in non-interactive shells (bash -c "$(curl ...)"), which
# stops the entire process group and prevents the recovery dialog from appearing.
$STD echo -e "${TAB}⏳ Reporting failure to telemetry..."
post_update_to_api "failed" "$install_exit_code"
$STD echo -e "${TAB}${CM:-} Failure reported"
# Defense-in-depth: Ensure error handling stays disabled during recovery.
# Some functions (e.g. silent/$STD) unconditionally re-enable set -Eeuo pipefail
@@ -4537,8 +4548,12 @@ EOF'
# Force one final status update attempt after cleanup
# This ensures status is updated even if the first attempt failed (e.g., HTTP 400)
$STD echo -e "${TAB}⏳ Finalizing telemetry report..."
post_update_to_api "failed" "$install_exit_code" "force"
$STD echo -e "${TAB}${CM:-} Telemetry finalized"
# Restore default job-control signal handling before exit
trap - TSTP TTIN TTOU
exit $install_exit_code
fi
@@ -5608,44 +5623,21 @@ ensure_log_on_host() {
fi
}
# ------------------------------------------------------------------------------
# api_exit_script()
# ==============================================================================
# TRAP MANAGEMENT
# ==============================================================================
# All traps (ERR, EXIT, INT, TERM, HUP) are set by catch_errors() in
# error_handler.func — called at the top of this file after sourcing.
#
# - Exit trap handler for reporting to API telemetry
# - Captures exit code and reports to PocketBase using centralized error descriptions
# - Uses explain_exit_code() from api.func for consistent error messages
# - ALWAYS sends telemetry FIRST before log collection to prevent pct pull
# hangs from blocking status updates (container may be dead/unresponsive)
# - For non-zero exit codes: posts "failed" status
# - For zero exit codes where post_update_to_api was never called:
# catches orphaned "installing" records (e.g., script exited cleanly
# but description() was never reached)
# ------------------------------------------------------------------------------
api_exit_script() {
local exit_code=$?
if [ $exit_code -ne 0 ]; then
# ALWAYS send telemetry FIRST - ensure status is reported even if
# ensure_log_on_host hangs (e.g. pct pull on dead container)
post_update_to_api "failed" "$exit_code" 2>/dev/null || true
# Best-effort log collection (non-critical after telemetry is sent)
if declare -f ensure_log_on_host >/dev/null 2>&1; then
ensure_log_on_host 2>/dev/null || true
fi
# Stop orphaned container if we're in the install phase
if [[ "${CONTAINER_INSTALLING:-}" == "true" && -n "${CTID:-}" ]] && command -v pct &>/dev/null; then
pct stop "$CTID" 2>/dev/null || true
fi
elif [[ "${POST_TO_API_DONE:-}" == "true" && "${POST_UPDATE_DONE:-}" != "true" ]]; then
# Script exited with 0 but never sent a completion status
# exit_code=0 is never an error — report as success
post_update_to_api "done" "0"
fi
}
if command -v pveversion >/dev/null 2>&1; then
trap 'api_exit_script' EXIT
fi
trap 'local _ec=$?; if [[ $_ec -ne 0 ]]; then post_update_to_api "failed" "$_ec" 2>/dev/null || true; if declare -f ensure_log_on_host &>/dev/null; then ensure_log_on_host 2>/dev/null || true; fi; fi' ERR
trap 'post_update_to_api "failed" "129" 2>/dev/null || true; if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null; then pct stop "$CTID" 2>/dev/null || true; fi; exit 129' SIGHUP
trap 'post_update_to_api "failed" "130" 2>/dev/null || true; if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null; then pct stop "$CTID" 2>/dev/null || true; fi; exit 130' SIGINT
trap 'post_update_to_api "failed" "143" 2>/dev/null || true; if [[ -n "${CTID:-}" ]] && command -v pct &>/dev/null; then pct stop "$CTID" 2>/dev/null || true; fi; exit 143' SIGTERM
# Do NOT set duplicate traps here. The handlers in error_handler.func
# (on_exit, on_interrupt, on_terminate, on_hangup, error_handler) already:
# - Send telemetry via post_update_to_api / _send_abort_telemetry
# - Stop orphaned containers via _stop_container_if_installing
# - Collect logs via ensure_log_on_host
# - Clean up lock files and spinner processes
#
# Previously, inline traps here overwrote catch_errors() traps, causing:
# - error_handler() never fired (no error output, no cleanup dialog)
# - on_hangup() never fired (SSH disconnect → stuck records)
# - Duplicated logic in two places (hard to debug)
# ==============================================================================

View File

@@ -607,6 +607,7 @@ stop_spinner() {
unset SPINNER_PID SPINNER_MSG
stty sane 2>/dev/null || true
stty -tostop 2>/dev/null || true
}
# ==============================================================================

View File

@@ -199,11 +199,16 @@ error_handler() {
return 0
fi
# Stop spinner and restore cursor FIRST — before any output
# This prevents spinner text overlapping with error messages
if declare -f stop_spinner >/dev/null 2>&1; then
stop_spinner 2>/dev/null || true
fi
printf "\e[?25h"
local explanation
explanation="$(explain_exit_code "$exit_code")"
printf "\e[?25h"
# ALWAYS report failure to API immediately - don't wait for container checks
# This ensures we capture failures that occur before/after container exists
if declare -f post_update_to_api &>/dev/null; then
@@ -359,9 +364,39 @@ _send_abort_telemetry() {
command -v curl &>/dev/null || return 0
[[ "${DIAGNOSTICS:-no}" == "no" ]] && return 0
[[ -z "${RANDOM_UUID:-}" ]] && return 0
curl -fsS -m 5 -X POST "${TELEMETRY_URL:-https://telemetry.community-scripts.org/telemetry}" \
-H "Content-Type: application/json" \
-d "{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"${TELEMETRY_TYPE:-lxc}\",\"nsapp\":\"${NSAPP:-${app:-unknown}}\",\"status\":\"failed\",\"exit_code\":${exit_code}}" &>/dev/null || true
# Collect last 20 log lines for error diagnosis (best-effort)
local error_text=""
if [[ -n "${INSTALL_LOG:-}" && -s "${INSTALL_LOG}" ]]; then
error_text=$(tail -n 20 "$INSTALL_LOG" 2>/dev/null | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\\/\\\\/g; s/"/\\"/g; s/\r//g' | tr '\n' '|' | sed 's/|$//' | tr -d '\000-\010\013\014\016-\037\177') || true
fi
# Calculate duration if start time is available
local duration=""
if [[ -n "${DIAGNOSTICS_START_TIME:-}" ]]; then
duration=$(($(date +%s) - DIAGNOSTICS_START_TIME))
fi
# Build JSON payload with error context
local payload
payload="{\"random_id\":\"${RANDOM_UUID}\",\"execution_id\":\"${EXECUTION_ID:-${RANDOM_UUID}}\",\"type\":\"${TELEMETRY_TYPE:-lxc}\",\"nsapp\":\"${NSAPP:-${app:-unknown}}\",\"status\":\"failed\",\"exit_code\":${exit_code}"
[[ -n "$error_text" ]] && payload="${payload},\"error\":\"${error_text}\""
[[ -n "$duration" ]] && payload="${payload},\"duration\":${duration}"
payload="${payload}}"
local api_url="${TELEMETRY_URL:-https://telemetry.community-scripts.org/telemetry}"
# 2 attempts (retry once on failure) — original had no retry
local attempt
for attempt in 1 2; do
if curl -fsS -m 5 -X POST "$api_url" \
-H "Content-Type: application/json" \
-d "$payload" &>/dev/null; then
return 0
fi
[[ $attempt -eq 1 ]] && sleep 1
done
return 0
}
# ------------------------------------------------------------------------------
@@ -437,6 +472,12 @@ on_exit() {
# - Exits with code 130 (128 + SIGINT=2)
# ------------------------------------------------------------------------------
on_interrupt() {
# Stop spinner and restore cursor before any output
if declare -f stop_spinner >/dev/null 2>&1; then
stop_spinner 2>/dev/null || true
fi
printf "\e[?25h" 2>/dev/null || true
_send_abort_telemetry "130"
_stop_container_if_installing
if declare -f msg_error >/dev/null 2>&1; then
@@ -456,6 +497,12 @@ on_interrupt() {
# - Exits with code 143 (128 + SIGTERM=15)
# ------------------------------------------------------------------------------
on_terminate() {
# Stop spinner and restore cursor before any output
if declare -f stop_spinner >/dev/null 2>&1; then
stop_spinner 2>/dev/null || true
fi
printf "\e[?25h" 2>/dev/null || true
_send_abort_telemetry "143"
_stop_container_if_installing
if declare -f msg_error >/dev/null 2>&1; then
@@ -478,6 +525,11 @@ on_terminate() {
# - Exits with code 129 (128 + SIGHUP=1)
# ------------------------------------------------------------------------------
on_hangup() {
# Stop spinner (no cursor restore needed — terminal is already gone)
if declare -f stop_spinner >/dev/null 2>&1; then
stop_spinner 2>/dev/null || true
fi
_send_abort_telemetry "129"
_stop_container_if_installing
exit 129

View File

@@ -783,16 +783,25 @@ github_api_call() {
for attempt in $(seq 1 $max_retries); do
local http_code
http_code=$(curl -fsSL -w "%{http_code}" -o "$output_file" \
http_code=$(curl -sSL -w "%{http_code}" -o "$output_file" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"${header_args[@]}" \
"$url" 2>/dev/null || echo "000")
"$url" 2>/dev/null) || true
case "$http_code" in
200)
return 0
;;
401)
msg_error "GitHub API authentication failed (HTTP 401)."
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
msg_error "Your GITHUB_TOKEN appears to be invalid or expired."
else
msg_error "The repository may require authentication. Try: export GITHUB_TOKEN=\"ghp_your_token\""
fi
return 1
;;
403)
# Rate limit - check if we can retry
if [[ $attempt -lt $max_retries ]]; then
@@ -801,11 +810,22 @@ github_api_call() {
retry_delay=$((retry_delay * 2))
continue
fi
msg_error "GitHub API rate limit exceeded. Set GITHUB_TOKEN to increase limits."
msg_error "GitHub API rate limit exceeded (HTTP 403)."
msg_error "To increase the limit, export a GitHub token before running the script:"
msg_error " export GITHUB_TOKEN=\"ghp_your_token_here\""
return 1
;;
404)
msg_error "GitHub API endpoint not found: $url"
msg_error "GitHub repository or release not found (HTTP 404): $url"
return 1
;;
000 | "")
if [[ $attempt -lt $max_retries ]]; then
sleep "$retry_delay"
continue
fi
msg_error "GitHub API connection failed (no response)."
msg_error "Check your network/DNS: curl -sSL https://api.github.com/rate_limit"
return 1
;;
*)
@@ -813,7 +833,7 @@ github_api_call() {
sleep "$retry_delay"
continue
fi
msg_error "GitHub API call failed with HTTP $http_code"
msg_error "GitHub API call failed (HTTP $http_code)."
return 1
;;
esac
@@ -833,14 +853,18 @@ codeberg_api_call() {
for attempt in $(seq 1 $max_retries); do
local http_code
http_code=$(curl -fsSL -w "%{http_code}" -o "$output_file" \
http_code=$(curl -sSL -w "%{http_code}" -o "$output_file" \
-H "Accept: application/json" \
"$url" 2>/dev/null || echo "000")
"$url" 2>/dev/null) || true
case "$http_code" in
200)
return 0
;;
401)
msg_error "Codeberg API authentication failed (HTTP 401)."
return 1
;;
403)
# Rate limit - retry
if [[ $attempt -lt $max_retries ]]; then
@@ -849,11 +873,20 @@ codeberg_api_call() {
retry_delay=$((retry_delay * 2))
continue
fi
msg_error "Codeberg API rate limit exceeded."
msg_error "Codeberg API rate limit exceeded (HTTP 403)."
return 1
;;
404)
msg_error "Codeberg API endpoint not found: $url"
msg_error "Codeberg repository or release not found (HTTP 404): $url"
return 1
;;
000 | "")
if [[ $attempt -lt $max_retries ]]; then
sleep "$retry_delay"
continue
fi
msg_error "Codeberg API connection failed (no response)."
msg_error "Check your network/DNS: curl -sSL https://codeberg.org"
return 1
;;
*)
@@ -861,7 +894,7 @@ codeberg_api_call() {
sleep "$retry_delay"
continue
fi
msg_error "Codeberg API call failed with HTTP $http_code"
msg_error "Codeberg API call failed (HTTP $http_code)."
return 1
;;
esac
@@ -1441,7 +1474,7 @@ get_latest_github_release() {
if ! github_api_call "https://api.github.com/repos/${repo}/releases/latest" "$temp_file"; then
rm -f "$temp_file"
return 1
return 0
fi
local version
@@ -1449,7 +1482,8 @@ get_latest_github_release() {
rm -f "$temp_file"
if [[ -z "$version" ]]; then
return 1
msg_error "Could not determine latest version for ${repo}"
return 0
fi
echo "$version"
@@ -1466,7 +1500,7 @@ get_latest_codeberg_release() {
# Codeberg API: get all releases and pick the first non-draft/non-prerelease
if ! codeberg_api_call "https://codeberg.org/api/v1/repos/${repo}/releases" "$temp_file"; then
rm -f "$temp_file"
return 1
return 0
fi
local version
@@ -1480,7 +1514,8 @@ get_latest_codeberg_release() {
rm -f "$temp_file"
if [[ -z "$version" ]]; then
return 1
msg_error "Could not determine latest version for ${repo}"
return 0
fi
echo "$version"
@@ -1567,13 +1602,34 @@ get_latest_gh_tag() {
"${header_args[@]}" \
"https://api.github.com/repos/${repo}/tags?per_page=100" 2>/dev/null) || true
if [[ "$http_code" == "401" ]]; then
msg_error "GitHub API authentication failed (HTTP 401)."
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
msg_error "Your GITHUB_TOKEN appears to be invalid or expired."
else
msg_error "The repository may require authentication. Try: export GITHUB_TOKEN=\"ghp_your_token\""
fi
rm -f /tmp/gh_tags.json
return 1
fi
if [[ "$http_code" == "403" ]]; then
msg_warn "GitHub API rate limit exceeded while fetching tags for ${repo}"
msg_error "GitHub API rate limit exceeded (HTTP 403)."
msg_error "To increase the limit, export a GitHub token before running the script:"
msg_error " export GITHUB_TOKEN=\"ghp_your_token_here\""
rm -f /tmp/gh_tags.json
return 1
fi
if [[ "$http_code" == "000" || -z "$http_code" ]]; then
msg_error "GitHub API connection failed (no response)."
msg_error "Check your network/DNS: curl -sSL https://api.github.com/rate_limit"
rm -f /tmp/gh_tags.json
return 1
fi
if [[ "$http_code" != "200" ]] || [[ ! -s /tmp/gh_tags.json ]]; then
msg_error "Unable to fetch tags for ${repo} (HTTP ${http_code})"
rm -f /tmp/gh_tags.json
return 1
fi
@@ -1659,6 +1715,15 @@ check_for_gh_release() {
if [[ "$http_code" == "200" ]] && [[ -s /tmp/gh_check.json ]]; then
releases_json="[$(</tmp/gh_check.json)]"
elif [[ "$http_code" == "401" ]]; then
msg_error "GitHub API authentication failed (HTTP 401)."
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
msg_error "Your GITHUB_TOKEN appears to be invalid or expired."
else
msg_error "The repository may require authentication. Try: export GITHUB_TOKEN=\"ghp_your_token\""
fi
rm -f /tmp/gh_check.json
return 1
elif [[ "$http_code" == "403" ]]; then
msg_error "GitHub API rate limit exceeded (HTTP 403)."
msg_error "To increase the limit, export a GitHub token before running the script:"
@@ -1679,12 +1744,26 @@ check_for_gh_release() {
if [[ "$http_code" == "200" ]] && [[ -s /tmp/gh_check.json ]]; then
releases_json=$(</tmp/gh_check.json)
elif [[ "$http_code" == "401" ]]; then
msg_error "GitHub API authentication failed (HTTP 401)."
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
msg_error "Your GITHUB_TOKEN appears to be invalid or expired."
else
msg_error "The repository may require authentication. Try: export GITHUB_TOKEN=\"ghp_your_token\""
fi
rm -f /tmp/gh_check.json
return 1
elif [[ "$http_code" == "403" ]]; then
msg_error "GitHub API rate limit exceeded (HTTP 403)."
msg_error "To increase the limit, export a GitHub token before running the script:"
msg_error " export GITHUB_TOKEN=\"ghp_your_token_here\""
rm -f /tmp/gh_check.json
return 1
elif [[ "$http_code" == "000" || -z "$http_code" ]]; then
msg_error "GitHub API connection failed (no response)."
msg_error "Check your network/DNS: curl -sSL https://api.github.com/rate_limit"
rm -f /tmp/gh_check.json
return 1
else
msg_error "Unable to fetch releases for ${app} (HTTP ${http_code})"
rm -f /tmp/gh_check.json
@@ -2608,12 +2687,22 @@ function fetch_and_deploy_gh_release() {
done
if ! $success; then
if [[ "$http_code" == "403" ]]; then
if [[ "$http_code" == "401" ]]; then
msg_error "GitHub API authentication failed (HTTP 401)."
if [[ -n "${GITHUB_TOKEN:-}" ]]; then
msg_error "Your GITHUB_TOKEN appears to be invalid or expired."
else
msg_error "The repository may require authentication. Try: export GITHUB_TOKEN=\"ghp_your_token\""
fi
elif [[ "$http_code" == "403" ]]; then
msg_error "GitHub API rate limit exceeded (HTTP 403)."
msg_error "To increase the limit, export a GitHub token before running the script:"
msg_error " export GITHUB_TOKEN=\"ghp_your_token_here\""
elif [[ "$http_code" == "000" || -z "$http_code" ]]; then
msg_error "GitHub API connection failed (no response)."
msg_error "Check your network/DNS: curl -sSL https://api.github.com/rate_limit"
else
msg_error "Failed to fetch release metadata from $api_url after $max_retries attempts (HTTP $http_code)"
msg_error "Failed to fetch release metadata (HTTP $http_code)"
fi
return 1
fi

View File

@@ -28,7 +28,7 @@ INSTALL_PATH="/opt/immich-proxy"
CONFIG_PATH="/opt/immich-proxy/app"
DEFAULT_PORT=3000
# Initialize all core functions (colors, formatting, icons, STD mode)
# Initialize all core functions (colors, formatting, icons, $STD mode)
load_functions
init_tool_telemetry "" "addon"

View File

@@ -288,8 +288,8 @@ function default_settings() {
echo -e "${DGN}Using Hostname: ${BGN}${HN}${CL}"
echo -e "${DGN}Allocated Cores: ${BGN}${CORE_COUNT}${CL}"
echo -e "${DGN}Allocated RAM: ${BGN}${RAM_SIZE}${CL}"
if ! grep -q "^iface ${BRG}" /etc/network/interfaces; then
msg_error "Bridge '${BRG}' does not exist in /etc/network/interfaces"
if ! ip link show "${BRG}" &>/dev/null; then
msg_error "Bridge '${BRG}' does not exist"
exit
else
echo -e "${DGN}Using LAN Bridge: ${BGN}${BRG}${CL}"
@@ -305,8 +305,8 @@ function default_settings() {
if [ "$NETWORK_MODE" = "dual" ]; then
echo -e "${DGN}Network Mode: ${BGN}Dual Interface (Firewall)${CL}"
echo -e "${DGN}Using WAN MAC Address: ${BGN}${WAN_MAC}${CL}"
if ! grep -q "^iface ${WAN_BRG}" /etc/network/interfaces; then
msg_error "Bridge '${WAN_BRG}' does not exist in /etc/network/interfaces"
if ! ip link show "${WAN_BRG}" &>/dev/null; then
msg_error "Bridge '${WAN_BRG}' does not exist"
exit
else
echo -e "${DGN}Using WAN Bridge: ${BGN}${WAN_BRG}${CL}"
@@ -424,8 +424,8 @@ function advanced_settings() {
if [ -z $BRG ]; then
BRG="vmbr0"
fi
if ! grep -q "^iface ${BRG}" /etc/network/interfaces; then
msg_error "Bridge '${BRG}' does not exist in /etc/network/interfaces"
if ! ip link show "${BRG}" &>/dev/null; then
msg_error "Bridge '${BRG}' does not exist"
exit
fi
echo -e "${DGN}Using LAN Bridge: ${BGN}$BRG${CL}"
@@ -474,8 +474,8 @@ function advanced_settings() {
if [ -z $WAN_BRG ]; then
WAN_BRG="vmbr1"
fi
if ! grep -q "^iface ${WAN_BRG}" /etc/network/interfaces; then
msg_error "WAN Bridge '${WAN_BRG}' does not exist in /etc/network/interfaces"
if ! ip link show "${WAN_BRG}" &>/dev/null; then
msg_error "WAN Bridge '${WAN_BRG}' does not exist"
exit
fi
echo -e "${DGN}Using WAN Bridge: ${BGN}$WAN_BRG${CL}"