Compare commits

...

21 Commits

Author SHA1 Message Date
MickLesk
9ba61e4cd9 Post the command that tests a ct/ or install/ change
Reviewing a script change meant working out the URL yourself, and the
obvious guess is wrong: curling the branch URL alone gives you the ct/
script from the PR and the install/ script from main, because each script
pins _CS_DEFAULT_URL to main and that pin is what fills
COMMUNITY_SCRIPTS_URL when it is unset. Frequently the install script is
the only thing that changed.

So the comment spells out both lines, per changed app.

Only for scripts already on the core bootstrap. The older one-liner
resolves everything from ProxmoxVE/main and ignores the variable, so a
command built for it would install main and look like it passed --  worse
than no comment. Those are named instead, with what to do about them.

pull_request_target for fork PRs, and nothing from the PR is checked out
or executed: the file list and the bootstrap line come from the API, and
a branch name that is not [A-Za-z0-9._/-]+ stops the run rather than
reaching a fenced code block.
2026-08-28 09:27:20 +02:00
community-scripts-pr-app[bot]
d14ca63429 Update CHANGELOG.md (#16825)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-28 01:20:05 +00:00
Tobias
1b714dceda pve-ups: fix: add pip binary (#16820)
* pve-ups: fix: pip binary

* pve-ups: fix: pip binary
2026-08-28 11:19:40 +10:00
community-scripts-pr-app[bot]
519f5630ce Update CHANGELOG.md (#16823)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-27 19:44:27 +00:00
Michel Roegl-Brunner
8734eba9a7 excalidash: Add a sed to switch to the correct DB Provider (#16814) 2026-08-27 21:43:54 +02:00
community-scripts-pr-app[bot]
d80fbc9629 Update CHANGELOG.md (#16817)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-27 14:12:00 +00:00
Michel Roegl-Brunner
f114aa553c fix(stirling-pdf): remove broken ExecStop using %n (#16813)
ExecStop=/bin/kill -15 %n expands %n to the unit name, not a PID, so
/bin/kill fails to parse it and logs a spurious status=1/FAILURE on
every stop/restart. Type=simple already sends SIGTERM to the main PID
and SuccessExitStatus=143 makes that a graceful stop, so the line is
redundant and broken. Fixes #16807
2026-08-27 16:11:30 +02:00
community-scripts-pr-app[bot]
db80438531 Update CHANGELOG.md (#16812)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-27 08:05:36 +00:00
Michel Roegl-Brunner
07d1f0837d Fix: Incorporate the new update functions to prevent a empty grep on … (#16809)
* Fix: Incorporate the new update functions to prevent a empty grep on the legacy link in /usr/bin/update

* Remove outdated comments from update-apps.sh

Removed comments regarding the new-style entrypoint and fallback logic for service extraction.

---------

Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com>
2026-08-27 10:05:08 +02:00
community-scripts-pr-app[bot]
45a6102d48 Update CHANGELOG.md (#16811)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-27 07:56:44 +00:00
community-scripts-pr-app[bot]
6cc27497a0 Update CHANGELOG.md (#16810)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-27 07:56:22 +00:00
push-app-to-main[bot]
beb5c3a573 Seanime (#16777)
* Add seanime (ct)

* Update ct/seanime.sh

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: Sam Heinz <sam@samheinz.com>
2026-08-27 09:56:12 +02:00
push-app-to-main[bot]
e60b90f385 Yopass (#16778)
* Add yopass (ct)

* Update ct/yopass.sh

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: Sam Heinz <sam@samheinz.com>
2026-08-27 09:55:56 +02:00
community-scripts-pr-app[bot]
fadcb0c375 Update CHANGELOG.md (#16802)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-26 19:28:08 +00:00
Jonathan Starck
89f5d3000e [Fix]: LimeSurvey - enable Apache mod_rewrite (#16767) 2026-08-26 21:27:12 +02:00
community-scripts-pr-app[bot]
0a6e59dab2 Update CHANGELOG.md (#16801)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-26 19:26:53 +00:00
CanbiZ (MickLesk)
4168f6c5d4 endurain: migrate legacy FRONTEND_DIR path on update (#16794) 2026-08-26 21:26:31 +02:00
community-scripts-pr-app[bot]
a51488a406 Update CHANGELOG.md (#16800)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-26 19:26:18 +00:00
CanbiZ (MickLesk)
ab1869fbb0 tools.func: recognize bare XZ-compressed tarballs in fetch_and_deploy* (#16796) 2026-08-26 21:25:51 +02:00
community-scripts-pr-app[bot]
e470b6ddf1 Update CHANGELOG.md (#16799)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-26 19:25:06 +00:00
CanbiZ (MickLesk)
416deb8fd0 tools.func: fix mongodb version comparison, guard apt purge against removing dependents (#16795) 2026-08-26 21:24:33 +02:00
17 changed files with 590 additions and 19 deletions

179
.github/workflows/pr-test-command.yml generated vendored Normal file
View File

@@ -0,0 +1,179 @@
name: PR test command
# A reviewer should not have to work out which URL exercises a pull request.
# The engine and the scripts resolve independently, so pointing
# COMMUNITY_SCRIPTS_URL at this PR's branch runs the changed ct/ and install/
# scripts against the production engine. This posts that command, filled in.
#
# Only for scripts that already bootstrap from community-scripts/core: the older
# one-liner ignores COMMUNITY_SCRIPTS_URL entirely, so a command built for it
# would quietly install main and look like it passed.
#
# pull_request_target, so the comment can be posted on PRs from forks -- which is
# most of them. Nothing from the pull request is checked out or executed here.
# The file list, the branch name and the bootstrap line all come from the API,
# the branch name is pattern-checked before it reaches the comment, and the body
# is assembled in JavaScript, so no attacker-controlled string reaches a shell.
on:
pull_request_target:
branches: ["main"]
types: [opened, synchronize, reopened]
paths:
- "ct/**"
- "install/**"
jobs:
comment:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: self-hosted
permissions:
pull-requests: write
contents: read
steps:
- uses: actions/github-script@v9
with:
script: |
const MARKER = '<!-- pr-test-command -->';
const MAX_APPS = 10;
const pr = context.payload.pull_request;
const head = pr.head.repo; // null when the fork is gone
if (!head) return;
const owner = context.repo.owner;
const repo = context.repo.repo;
// Git allows backticks in a ref name, and this one ends up inside a
// fenced block. Anything outside the ordinary set is not worth
// rendering, so bail rather than escape.
const ref = pr.head.ref;
if (!/^[A-Za-z0-9._\/-]+$/.test(ref)) return;
const base = `https://raw.githubusercontent.com/${head.full_name}/${ref}`;
const files = await github.paginate(github.rest.pulls.listFiles, {
owner, repo, pull_number: pr.number, per_page: 100,
});
// ct/foo.sh and install/foo-install.sh are the same app. A removed
// file has nothing left to run.
const apps = new Map(); // slug -> {ct, install}
for (const f of files) {
if (f.status === 'removed') continue;
let m = f.filename.match(/^ct\/([a-z0-9][a-z0-9._-]*)\.sh$/);
if (m) { apps.set(m[1], { ...apps.get(m[1]), ct: true }); continue; }
m = f.filename.match(/^install\/([a-z0-9][a-z0-9._-]*)-install\.sh$/);
if (m) apps.set(m[1], { ...apps.get(m[1]), install: true });
}
if (apps.size === 0) return;
// Read the ct script at the PR head to see which engine it loads.
// Read only -- it is never sourced or run.
async function bootstrapOf(slug) {
try {
const res = await github.rest.repos.getContent({
owner: head.owner.login, repo: head.name,
path: `ct/${slug}.sh`, ref: pr.head.sha,
});
if (!res.data.content) return 'unknown';
const text = Buffer.from(res.data.content, 'base64').toString('utf8');
const firstLines = text.split('\n').slice(0, 12).join('\n');
return /_cs_boot=/.test(firstLines) ? 'core' : 'legacy';
} catch (e) {
return e.status === 404 ? 'missing' : 'unknown';
}
}
const ready = [], legacy = [], missing = [];
for (const slug of [...apps.keys()].sort()) {
const kind = await bootstrapOf(slug);
if (kind === 'core') ready.push(slug);
else if (kind === 'legacy') legacy.push(slug);
else if (kind === 'missing') missing.push(slug);
}
const lines = [MARKER];
if (ready.length > 0) {
const shown = ready.slice(0, MAX_APPS);
lines.push(
'### Try this branch',
'',
'The engine and the scripts resolve independently, so this runs the changed',
'`ct/` and `install/` scripts against the **production** engine:',
'',
);
for (const slug of shown) {
lines.push(
'```bash',
`export COMMUNITY_SCRIPTS_URL=${base}`,
`bash -c "$(curl -fsSL "$COMMUNITY_SCRIPTS_URL/ct/${slug}.sh")"`,
'```',
'',
);
}
if (ready.length > shown.length) {
lines.push(
`${ready.length - shown.length} more script(s) changed; same command, different slug.`,
'',
);
}
lines.push(
'Both lines are needed. Each script pins `_CS_DEFAULT_URL` to `main`, and that',
'pin is what fills `COMMUNITY_SCRIPTS_URL` when the variable is unset — so',
'curling the branch URL on its own gives you the `ct/` script from this PR and',
'the `install/` script from `main`. Frequently the one you meant to test.',
'',
'The same command works on an Incus host: the engine detects the platform and',
'loads the matching backend, while the scripts still come from this branch.',
'',
'<details><summary>Useful while testing</summary>',
'',
'`dev_mode=net` logs every fetch with status and URL, which is the quickest way',
'to confirm the branch is really being used. `dev_mode=keep` stops a failed',
'build from deleting the container along with the evidence.',
'',
'```bash',
`export COMMUNITY_SCRIPTS_URL=${base}`,
`dev_mode=net,keep bash -c "$(curl -fsSL "$COMMUNITY_SCRIPTS_URL/ct/${shown[0]}.sh")"`,
'```',
'</details>',
);
}
if (legacy.length > 0) {
lines.push(
'',
ready.length > 0 ? '---' : '### Not testable this way yet',
'',
`\`${legacy.join('`, `')}\` still uses the older one-liner bootstrap, which`,
'resolves everything from `ProxmoxVE/main` and ignores `COMMUNITY_SCRIPTS_URL`.',
'There is no way to point it at this branch — test it from a checkout on the',
'host instead, or migrate the script to the `_cs_boot` bootstrap first.',
);
}
if (missing.length > 0) {
lines.push(
'',
`No \`ct/\` script found for \`${missing.join('`, `')}\`, so there is nothing to`,
'run. If the install script was renamed, its `ct/` counterpart needs the same',
'name.',
);
}
if (lines.length === 1) return; // marker only, nothing worth saying
const body = lines.join('\n');
// Update in place rather than posting again on every push.
const comments = await github.paginate(github.rest.issues.listComments, {
owner, repo, issue_number: pr.number, per_page: 100,
});
const mine = comments.find(c => c.body.includes(MARKER));
if (mine) {
if (mine.body !== body) {
await github.rest.issues.updateComment({ owner, repo, comment_id: mine.id, body });
}
} else {
await github.rest.issues.createComment({ owner, repo, issue_number: pr.number, body });
}

View File

@@ -527,6 +527,34 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-08-28
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- pve-ups: fix: add pip binary [@CrazyWolf13](https://github.com/CrazyWolf13) ([#16820](https://github.com/community-scripts/ProxmoxVE/pull/16820))
## 2026-08-27
### 🆕 New Scripts
- Seanime ([#16777](https://github.com/community-scripts/ProxmoxVE/pull/16777))
- Yopass ([#16778](https://github.com/community-scripts/ProxmoxVE/pull/16778))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- excalidash: Add a sed to switch to the correct DB Provider [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#16814](https://github.com/community-scripts/ProxmoxVE/pull/16814))
- fix(stirling-pdf): remove broken ExecStop using %n [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#16813](https://github.com/community-scripts/ProxmoxVE/pull/16813))
### 🧰 Tools
- #### 🐞 Bug Fixes
- Fix: Incorporate the new update functions to prevent a empty grep on … [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#16809](https://github.com/community-scripts/ProxmoxVE/pull/16809))
## 2026-08-26
### 🆕 New Scripts
@@ -541,6 +569,20 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- Directus ([#16779](https://github.com/community-scripts/ProxmoxVE/pull/16779))
- HAProxy ([#16760](https://github.com/community-scripts/ProxmoxVE/pull/16760))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- [Fix]: LimeSurvey - enable Apache mod_rewrite [@jonathan8devs](https://github.com/jonathan8devs) ([#16767](https://github.com/community-scripts/ProxmoxVE/pull/16767))
- endurain: migrate legacy FRONTEND_DIR path on update [@MickLesk](https://github.com/MickLesk) ([#16794](https://github.com/community-scripts/ProxmoxVE/pull/16794))
### 💾 Core
- #### 🐞 Bug Fixes
- tools.func: recognize bare XZ-compressed tarballs in fetch_and_deploy* [@MickLesk](https://github.com/MickLesk) ([#16796](https://github.com/community-scripts/ProxmoxVE/pull/16796))
- tools.func: fix mongodb version comparison, guard apt purge against removing dependents [@MickLesk](https://github.com/MickLesk) ([#16795](https://github.com/community-scripts/ProxmoxVE/pull/16795))
### 📂 Github
- github: teach the PocketBase bot every field [@MickLesk](https://github.com/MickLesk) ([#16781](https://github.com/community-scripts/ProxmoxVE/pull/16781))

View File

@@ -35,29 +35,29 @@ function update_script() {
msg_ok "Stopped Service"
NODE_VERSION="24" setup_nodejs
create_backup /opt/endurain/.env /opt/endurain/frontend/dist/env.js
CLEAN_INSTALL=1 fetch_and_deploy_codeberg_release "endurain" "endurain-project/endurain" "tarball" "latest" "/opt/endurain"
msg_info "Preparing Update"
msg_info "Updating Endurain Frontend"
cd /opt/endurain
rm -rf /opt/endurain/{docs,example.env,screenshot_01.png} /opt/endurain/docker* /opt/endurain/*.yml
msg_ok "Prepared Update"
msg_info "Updating Frontend"
cd /opt/endurain/frontend
$STD npm ci
$STD npm run build
msg_ok "Updated Frontend"
msg_ok "Updated Endurain Frontend"
restore_backup
msg_info "Updating Backend"
if grep -qxF 'FRONTEND_DIR="/opt/endurain/frontend/app/dist"' /opt/endurain/.env; then
sed -i 's|^FRONTEND_DIR="/opt/endurain/frontend/app/dist"$|FRONTEND_DIR="/opt/endurain/frontend/dist"|' /opt/endurain/.env
fi
msg_info "Updating Endurain Backend"
cd /opt/endurain/backend
UV_VERSION=$(grep -Po 'required-version\s*=\s*"\K[^"]+' pyproject.toml 2>/dev/null || echo "0.11.18")
UV_VERSION="$UV_VERSION" setup_uv
$STD uv sync --frozen --no-dev
msg_ok "Backend Updated"
msg_ok "Endurain Backend Updated"
msg_info "Starting Service"
systemctl start endurain

View File

@@ -42,6 +42,7 @@ function update_script() {
msg_info "Configuring Database Provider (${DATABASE_PROVIDER:-sqlite})"
cd /opt/excalidash/backend
sed -i '/datasource db {/,/}/ s/provider = env("[^"]*")/provider = "'"${DATABASE_PROVIDER:-sqlite}"'"/' prisma/schema.prisma
sed -i '/datasource db {/,/}/ s/provider = "[^"]*"/provider = "'"${DATABASE_PROVIDER:-sqlite}"'"/' prisma/schema.prisma
mv prisma/migrations/"${DATABASE_PROVIDER:-sqlite}"/* prisma/migrations/
rm -rf prisma/migrations/postgresql prisma/migrations/sqlite
msg_ok "Configured Database Provider"

6
ct/headers/seanime Normal file
View File

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

6
ct/headers/yopass Normal file
View File

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

View File

@@ -28,6 +28,13 @@ function update_script() {
msg_error "No ${APP} Installation Found!"
exit
fi
if [[ ! -L /etc/apache2/mods-enabled/rewrite.load ]]; then
msg_info "Enabling Apache mod_rewrite"
$STD a2enmod rewrite
systemctl restart apache2
msg_ok "Enabled Apache mod_rewrite"
fi
setup_mariadb
msg_warn "Application is updated via Web Interface"

View File

@@ -41,7 +41,7 @@ function update_script() {
msg_info "Updating Application"
cd /opt/pve-usv
$STD uv venv --clear venv
$STD uv venv --clear --seed venv
$STD uv pip install --python venv/bin/python .
chown -R pveusv:pveusv /opt/pve-usv
chmod 0755 deploy/pve-usv-agent.sh

63
ct/seanime.sh Normal file
View File

@@ -0,0 +1,63 @@
#!/usr/bin/env bash
_CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main"
_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func"
source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/build.func")
# Copyright (c) 2021-2026 community-scripts ORG
# Author: hasan-ismail
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://seanime.app/
APP="Seanime"
var_tags="${var_tags:-media;anime;manga}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-yes}"
var_unprivileged="${var_unprivileged:-1}"
var_gpu="${var_gpu:-yes}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/seanime ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "seanime" "5rahim/seanime"; then
msg_info "Stopping Service"
systemctl stop seanime
msg_ok "Stopped Service"
create_backup /opt/seanime-data/config.toml
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "seanime" "5rahim/seanime" "prebuild" "latest" "/opt/seanime" "seanime-[0-9]*_Linux_$(arch_resolve x86_64 arm64).tar.gz"
chmod +x /opt/seanime/seanime
restore_backup
msg_info "Starting Service"
systemctl start seanime
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}:43211${CL}"

65
ct/yopass.sh Normal file
View File

@@ -0,0 +1,65 @@
#!/usr/bin/env bash
_CS_DEFAULT_URL="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main"
_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func"
source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/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/jhaals/yopass
APP="Yopass"
var_tags="${var_tags:-security;secrets}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-8}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
#var_arm64="${var_arm64:-no}" # unset = ask the user; set yes/no only when verified
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/yopass ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "yopass" "jhaals/yopass"; then
msg_info "Stopping Service"
systemctl stop yopass
msg_ok "Stopped Service"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "yopass" "jhaals/yopass" "tarball"
msg_info "Building Yopass"
cd /opt/yopass
$STD go build -ldflags "-X main.version=$(cat ~/.yopass)" ./cmd/yopass-server
cd /opt/yopass/website
$STD yarn install --network-timeout 600000
$STD yarn build
msg_ok "Built Yopass"
msg_info "Starting Service"
systemctl start yopass
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}https://${IP}:1337${CL}"

View File

@@ -60,6 +60,7 @@ cat <<EOF >/etc/apache2/sites-enabled/000-default.conf
EOF
chown -R www-data:www-data "/opt/limesurvey"
chmod -R 750 "/opt/limesurvey"
$STD a2enmod rewrite
systemctl reload apache2
rm -rf "$temp_file"
msg_ok "Set up LimeSurvey"

View File

@@ -27,7 +27,7 @@ install -d -o pveusv -g pveusv -m 0750 \
/var/lib/pve-usv/updates
chown -R pveusv:pveusv /opt/pve-usv
cd /opt/pve-usv
$STD uv venv --clear venv
$STD uv venv --clear --seed venv
$STD uv pip install --python venv/bin/python .
chmod 0755 deploy/pve-usv-agent.sh
msg_ok "Set up Application"

View File

@@ -0,0 +1,67 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: hasan-ismail
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://seanime.app/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
setup_hwaccel
msg_info "Installing FFmpeg"
setup_deb822_repo \
"jellyfin" \
"https://repo.jellyfin.org/jellyfin_team.gpg.key" \
"https://repo.jellyfin.org/debian" \
"$(get_os_info codename)"
$STD apt install -y jellyfin-ffmpeg7
ln -sf /usr/lib/jellyfin-ffmpeg/ffmpeg /usr/bin/ffmpeg
ln -sf /usr/lib/jellyfin-ffmpeg/ffprobe /usr/bin/ffprobe
msg_ok "Installed FFmpeg"
fetch_and_deploy_gh_release "seanime" "5rahim/seanime" "prebuild" "latest" "/opt/seanime" "seanime-[0-9]*_Linux_$(arch_resolve x86_64 arm64).tar.gz"
chmod +x /opt/seanime/seanime
msg_info "Configuring Seanime"
SEANIME_PASSWORD=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)
mkdir -p /opt/seanime-data
cat <<EOF >/opt/seanime-data/config.toml
[server]
password = "${SEANIME_PASSWORD}"
EOF
cat <<EOF >/root/seanime.creds
Seanime URL: http://${LOCAL_IP}:43211
Password: ${SEANIME_PASSWORD}
EOF
msg_ok "Configured Seanime"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/seanime.service
[Unit]
Description=Seanime
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/seanime
ExecStart=/opt/seanime/seanime --datadir /opt/seanime-data --host 0.0.0.0
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now seanime
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -147,7 +147,6 @@ Group=root
EnvironmentFile=/opt/Stirling-PDF/.env
WorkingDirectory=/opt/Stirling-PDF
ExecStart=/usr/bin/java -jar Stirling-PDF.jar
ExecStop=/bin/kill -15 %n
Restart=always
RestartSec=10

69
install/yopass-install.sh Normal file
View File

@@ -0,0 +1,69 @@
#!/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/jhaals/yopass
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 redis-server
systemctl enable -q --now redis-server
msg_ok "Installed Dependencies"
setup_go
NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
fetch_and_deploy_gh_release "yopass" "jhaals/yopass" "tarball"
msg_info "Building Yopass"
cd /opt/yopass
$STD go build -ldflags "-X main.version=$(cat ~/.yopass)" ./cmd/yopass-server
cd /opt/yopass/website
$STD yarn install --network-timeout 600000
$STD yarn build
msg_ok "Built Yopass"
msg_info "Generating SSL Certificate"
mkdir -p /opt/yopass/certificates
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /opt/yopass/certificates/key.pem \
-out /opt/yopass/certificates/cert.pem \
-subj "/C=US/ST=State/L=City/O=Yopass/CN=${LOCAL_IP}" \
-addext "subjectAltName=IP:${LOCAL_IP},DNS:localhost,IP:127.0.0.1" \
2>/dev/null
chmod 600 /opt/yopass/certificates/key.pem
chmod 644 /opt/yopass/certificates/cert.pem
msg_ok "Generated SSL Certificate"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/yopass.service
[Unit]
Description=Yopass
Wants=network-online.target
After=network-online.target redis-server.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/yopass
ExecStart=/opt/yopass/yopass-server --address 0.0.0.0 --port 1337 --tls-cert /opt/yopass/certificates/cert.pem --tls-key /opt/yopass/certificates/key.pem --database redis --redis redis://127.0.0.1:6379/0 --asset-path /opt/yopass/website/dist
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now yopass
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -632,7 +632,7 @@ is_tool_installed() {
;;
mongodb | mongod)
if command -v mongod >/dev/null 2>&1; then
installed_version=$(mongod --version 2>/dev/null | awk '/db version/{print $3}' | cut -d. -f1,2)
installed_version=$(mongod --version 2>/dev/null | awk '/db version/{print $3}' | sed 's/^v//' | cut -d. -f1,2)
fi
;;
node | nodejs)
@@ -685,6 +685,39 @@ is_tool_installed() {
return 0 # Installed and version matches (if specified)
}
# ------------------------------------------------------------------------------
# Checks whether purging the given package glob(s) would also remove packages
# outside those globs (i.e. reverse dependents, such as an app depending on
# mongodb-org-server). Uses `apt-get -s` (simulate) with the stable apt-get
# output format, not `apt`, whose output is explicitly unstable for scripting.
# Returns 0 (safe to purge) or 1 (unsafe - prints the unexpected packages).
# Usage: _purge_is_safe 'mongodb*' ['other-glob*' ...]
# ------------------------------------------------------------------------------
_purge_is_safe() {
local -a globs=("$@")
local -a collateral=()
local pkg glob matched
local sim_out
sim_out=$(apt-get -s purge -y "${globs[@]}" 2>/dev/null) || return 0
while IFS= read -r pkg; do
[[ -z "$pkg" ]] && continue
matched=0
for glob in "${globs[@]}"; do
# shellcheck disable=SC2053
[[ "$pkg" == $glob ]] && {
matched=1
break
}
done
((matched)) || collateral+=("$pkg")
done < <(awk '/^(Remv|Purg) /{print $2}' <<<"$sim_out")
if ((${#collateral[@]} > 0)); then
msg_warn "Refusing purge of '${globs[*]}': would also remove ${collateral[*]}"
return 1
fi
return 0
}
# ------------------------------------------------------------------------------
# Remove old tool version completely (purge + cleanup repos)
# Usage: remove_old_tool_version "mariadb" "repository-name"
@@ -696,11 +729,13 @@ remove_old_tool_version() {
case "$tool_name" in
mariadb)
stop_all_services "mariadb"
_purge_is_safe 'mariadb*' || return 1
$STD apt purge -y 'mariadb*' >/dev/null 2>&1 || true
cleanup_tool_keyrings "mariadb"
;;
mysql)
stop_all_services "mysql"
_purge_is_safe 'mysql*' || return 1
$STD apt purge -y 'mysql*' >/dev/null 2>&1 || true
# Keep data directory for safety (remove manually if needed)
# rm -rf /var/lib/mysql 2>/dev/null || true
@@ -708,12 +743,14 @@ remove_old_tool_version() {
;;
mongodb)
stop_all_services "mongod"
_purge_is_safe 'mongodb*' || return 1
$STD apt purge -y 'mongodb*' >/dev/null 2>&1 || true
# Keep data directory for safety (remove manually if needed)
# rm -rf /var/lib/mongodb 2>/dev/null || true
cleanup_tool_keyrings "mongodb"
;;
node | nodejs)
_purge_is_safe nodejs npm || return 1
$STD apt purge -y nodejs npm >/dev/null 2>&1 || true
# Clean up npm global modules
if command -v npm >/dev/null 2>&1; then
@@ -726,23 +763,27 @@ remove_old_tool_version() {
;;
php)
stop_all_services "php.*-fpm"
_purge_is_safe 'php*' || return 1
$STD apt purge -y 'php*' >/dev/null 2>&1 || true
rm -rf /etc/php 2>/dev/null || true
cleanup_tool_keyrings "deb.sury.org-php" "php"
;;
postgresql)
stop_all_services "postgresql"
_purge_is_safe 'postgresql*' || return 1
$STD apt purge -y 'postgresql*' >/dev/null 2>&1 || true
# Keep data directory for safety (can be removed manually if needed)
# rm -rf /var/lib/postgresql 2>/dev/null || true
cleanup_tool_keyrings "postgresql" "pgdg"
;;
java)
_purge_is_safe 'temurin*' 'adoptium*' 'openjdk*' || return 1
$STD apt purge -y 'temurin*' 'adoptium*' 'openjdk*' >/dev/null 2>&1 || true
cleanup_tool_keyrings "adoptium"
;;
ruby)
cleanup_legacy_install "ruby"
_purge_is_safe 'ruby*' || return 1
$STD apt purge -y 'ruby*' >/dev/null 2>&1 || true
;;
rust)
@@ -754,6 +795,7 @@ remove_old_tool_version() {
;;
clickhouse)
stop_all_services "clickhouse-server"
_purge_is_safe 'clickhouse*' || return 1
$STD apt purge -y 'clickhouse*' >/dev/null 2>&1 || true
# Keep data directory for safety (remove manually if needed)
# rm -rf /var/lib/clickhouse 2>/dev/null || true
@@ -4473,7 +4515,10 @@ setup_clickhouse() {
if [[ -n "$CURRENT_VERSION" && "$CURRENT_VERSION" != "$CLICKHOUSE_VERSION" ]]; then
msg_info "Upgrade ClickHouse from $CURRENT_VERSION to $CLICKHOUSE_VERSION"
stop_all_services "clickhouse-server"
remove_old_tool_version "clickhouse"
remove_old_tool_version "clickhouse" || {
msg_error "Aborting ClickHouse upgrade: another package depends on it"
return 1
}
else
msg_info "Setup ClickHouse $CLICKHOUSE_VERSION"
fi
@@ -5150,7 +5195,10 @@ setup_go() {
# Scenario 2: Different version or not installed
if [[ -n "$CURRENT_VERSION" && "$CURRENT_VERSION" != "$GO_VERSION" ]]; then
msg_info "Upgrade Go from $CURRENT_VERSION to $GO_VERSION"
remove_old_tool_version "go"
remove_old_tool_version "go" || {
msg_error "Aborting Go upgrade: another package depends on it"
return 1
}
else
msg_info "Setup Go $GO_VERSION"
fi
@@ -6753,7 +6801,10 @@ EOF
# Scenario 2b: Different version installed - clean upgrade
if [[ -n "$CURRENT_VERSION" ]] && ! version_matches_spec "$CURRENT_VERSION" "$MARIADB_VERSION"; then
msg_info "Upgrade MariaDB from $CURRENT_VERSION to $MARIADB_VERSION"
remove_old_tool_version "mariadb"
remove_old_tool_version "mariadb" || {
msg_error "Aborting MariaDB upgrade: another package depends on it"
return 1
}
fi
# Scenario 3: Fresh install or version change with specific version
@@ -7283,7 +7334,10 @@ setup_mongodb() {
# Scenario 2: Different version installed - clean upgrade
if [[ -n "$INSTALLED_VERSION" && "$INSTALLED_VERSION" != "$MONGO_VERSION" ]]; then
msg_info "Upgrade MongoDB from $INSTALLED_VERSION to $MONGO_VERSION"
remove_old_tool_version "mongodb"
remove_old_tool_version "mongodb" || {
msg_error "Aborting MongoDB upgrade: another package depends on it (e.g. an app using it)"
return 1
}
else
msg_info "Setup MongoDB $MONGO_VERSION"
fi
@@ -7473,7 +7527,10 @@ setup_mysql() {
# Scenario 2: Different version installed - clean upgrade
if [[ -n "$CURRENT_VERSION" ]] && ! version_matches_spec "$CURRENT_VERSION" "$MYSQL_VERSION"; then
msg_info "Upgrade MySQL from $CURRENT_VERSION to $MYSQL_VERSION"
remove_old_tool_version "mysql"
remove_old_tool_version "mysql" || {
msg_error "Aborting MySQL upgrade: another package depends on it"
return 1
}
else
msg_info "Setup MySQL $MYSQL_VERSION"
fi
@@ -7637,7 +7694,10 @@ setup_nodejs() {
if [[ -n "$CURRENT_NODE_VERSION" && "$CURRENT_NODE_VERSION" != "$NODE_VERSION" ]]; then
msg_info "Upgrade Node.js from $CURRENT_NODE_VERSION to $NODE_VERSION"
node_setup_ok_msg="Upgrade Node.js to $NODE_VERSION"
remove_old_tool_version "nodejs"
remove_old_tool_version "nodejs" || {
msg_error "Aborting Node.js upgrade: another package depends on it"
return 1
}
else
msg_info "Setup Node.js $NODE_VERSION"
node_setup_ok_msg="Setup Node.js $NODE_VERSION"
@@ -9334,6 +9394,8 @@ fetch_and_deploy_from_url() {
if [[ "$file_desc" =~ gzip.*compressed|gzip\ compressed\ data ]]; then
archive_type="tar"
elif [[ "$file_desc" =~ XZ\ compressed\ data ]]; then
archive_type="tar"
elif [[ "$file_desc" =~ Zip.*archive|ZIP\ archive ]]; then
archive_type="zip"
elif [[ "$file_desc" =~ Debian.*package|Debian\ binary\ package ]]; then

View File

@@ -173,7 +173,11 @@ function detect_service() {
rm -rf "$tmpdir"
return 1
fi
service=$(grep -oE '/ct/[a-zA-Z0-9._-]+\.sh' "$update_file" 2>/dev/null | head -n1 | sed 's|.*/ct/||; s|\.sh$||')
service=$(sed -n -E 's/^[[:space:]]*export[[:space:]]+UPDATE_SCRIPT_NAME=["'"'"']?([a-zA-Z0-9._-]+).*/\1/p' "$update_file" | head -n1)
[[ -z "$service" ]] && service=$(sed -n -E 's/^[[:space:]]*export[[:space:]]+SCRIPT_SLUG=["'"'"']?([a-zA-Z0-9._-]+).*/\1/p' "$update_file" | head -n1)
[[ -z "$service" ]] && service=$(grep -oE '/ct/[a-zA-Z0-9._-]+\.sh' "$update_file" 2>/dev/null | head -n1 | sed 's|.*/ct/||; s|\.sh$||')
rm -rf "$tmpdir"
}