Compare commits

...

88 Commits

Author SHA1 Message Date
github-actions[bot]
bd7d806bae Update CHANGELOG.md 2026-06-02 18:15:39 +00:00
Tom Frenzel
131d521052 fix(openthread-br): preserve config during update (#14893) 2026-06-02 20:15:16 +02:00
CanbiZ (MickLesk)
f679553c0f Update systemd service to use network-online.target 2026-06-02 15:02:50 +02:00
community-scripts-pr-app[bot]
6131060b19 Update CHANGELOG.md (#14891)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 12:36:55 +00:00
community-scripts-pr-app[bot]
b978bd3499 Update CHANGELOG.md (#14890)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 12:36:40 +00:00
push-app-to-main[bot]
23f6b8a158 Add ddns-updater (ct) (#14883)
Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
2026-06-02 14:36:21 +02:00
community-scripts-pr-app[bot]
e77461942d Update CHANGELOG.md (#14889)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 12:36:13 +00:00
community-scripts-pr-app[bot]
ef65fb396a Update CHANGELOG.md (#14888)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 12:35:48 +00:00
push-app-to-main[bot]
6410586e2e Add invoiceshelf (ct) (#14882)
Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
2026-06-02 14:35:38 +02:00
push-app-to-main[bot]
0c4e5b5a63 Add certimate (ct) (#14881)
Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
2026-06-02 14:35:16 +02:00
Michel Roegl-Brunner
354ceef128 fix(pocketbase-ai-bot): open CT-defaults sync PR with built-in GITHUB_TOKEN
The App installation token lacks contents:write, so creating the
pocketbase-sync/<slug> branch failed with 403 "Resource not accessible by
integration". Mirror the slash bot: run the CT-defaults branch/commit/PR
operations with the built-in GITHUB_TOKEN (workflow now requests
contents:write + pull-requests:write), while the App token still posts the
user-facing comments/reactions. ensureBranch/upsertCtDefaultsPr shadow
ghRequest with a GITHUB_TOKEN-authenticated ghDefault.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 14:11:43 +02:00
Michel Roegl-Brunner
1a6dbb0bf8 fix(pocketbase-ai-bot): use @pocketbase-bot handle and harden confirm flow
- Trigger and all user-facing text now use @pocketbase-bot (the bare
  @pocketbase handle collides with an existing account)
- Confirm flow only trusts a pocketbase-pending marker found in a comment
  authored by this bot app (performed_via_github_app.id == PB_BOT_APP_ID),
  preventing a forged-marker spoof; decoded operations are re-validated
  against the field/op allow-lists before applying (shared sanitizeOperations)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 14:03:17 +02:00
Michel Roegl-Brunner
f14eca3bc9 feat(pocketbase-ai-bot): natural-language @pocketbase bot via GitHub Models
Adds an isolated workflow that lets maintainers manage PocketBase script
records in plain English by mentioning @pocketbase in an issue/PR comment
(e.g. "@pocketbase change RAM to 4096 on zigbee2mqtt").

- Interprets the request with GitHub Models (built-in GITHUB_TOKEN + models:read)
- Posts under a dedicated GitHub App identity (PB_BOT_APP_ID/PB_BOT_APP_PRIVATE_KEY)
- Propose-then-confirm: replies with the parsed change set and a hidden marker;
  applies only after "@pocketbase confirm"
- Reuses the slash bot's field/note/method allow-lists, validation, revalidate,
  and CT-defaults sync PR logic; self-author guard prevents trigger loops
- Existing /pocketbase slash bot is untouched (triggers do not overlap)

Inert until the GitHub App is created and its two secrets are added.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 13:54:12 +02:00
Michel Roegl-Brunner
d4b4880e0d fix(pocketbase-bot): recognize /pocketbase command on any line of a comment
- Job gate uses contains() instead of startsWith() so comments with leading
  text still trigger the bot
- Script scans all lines for the first one starting with /pocketbase, instead
  of only reading line 0
- Command-line detection moved above the permission check so mid-sentence
  mentions exit silently without a "not authorized" reply

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 11:52:47 +02:00
Michel Roegl-Brunner
9dc08aa8c1 ci(workflows): harden new-script close, slug-match VED issue close, 7-day lock
- close-new-script-prs: trigger on added script file OR label, exempt by
  author_association (OWNER/MEMBER/COLLABORATOR) instead of team API
- close_issue_in_dev: match VED issues by derived slug, close all matches
- lock-issue: lock closed issues after 7 days instead of 3

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 11:43:08 +02:00
community-scripts-pr-app[bot]
06af8cca46 Update CHANGELOG.md (#14879)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 08:25:37 +00:00
Michel Roegl-Brunner
5668ad9a8d fix(workflow): only flag node drift when local is behind upstream (#14874)
Update the node version drift check to count drift only when our script version is lower than upstream, so newer local versions no longer create false-positive drift issues.

Co-authored-by: Michel Roegl-Brunner <michel.roegl-brunner@example.com>
2026-06-02 10:25:05 +02:00
community-scripts-pr-app[bot]
bd9bae075d Update CHANGELOG.md (#14878)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 08:19:16 +00:00
Michel Roegl-Brunner
7cdb6c8133 feat(degoog): enable default valkey cache integration (#14871) 2026-06-02 10:18:45 +02:00
community-scripts-pr-app[bot]
6315547e65 Update CHANGELOG.md (#14877)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 07:05:47 +00:00
Michel Roegl-Brunner
e9a9bf17ee chore: bump Node version in selected scripts (#14873) 2026-06-02 09:05:25 +02:00
community-scripts-pr-app[bot]
40b86bef63 Update CHANGELOG.md (#14876)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 07:05:15 +00:00
Michel Roegl-Brunner
a43ca27d2f infisical: fix update abort due to creds field mismatch (#14868) (#14870)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 09:04:47 +02:00
community-scripts-pr-app[bot]
ee06ac1819 Update CHANGELOG.md (#14875)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-02 07:04:21 +00:00
CanbiZ (MickLesk)
1a63343a17 tools.func: add support for Rust installation profile in setup_rust (#14872) 2026-06-02 09:03:53 +02:00
community-scripts-pr-app[bot]
cd8a6f1de0 Update CHANGELOG.md (#14867)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 19:39:38 +00:00
Michel Roegl-Brunner
da64475612 fix(dispatcharr): forward nginx port for M3U URLs on new installs (#14862)
Dispatcharr builds absolute proxy URLs from reverse-proxy headers. Without X-Forwarded-Port, downloaded M3U playlists omit :9191.

Fixes #14839

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 21:39:10 +02:00
community-scripts-pr-app[bot]
a2aea34aa7 Update CHANGELOG.md (#14866)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 19:38:33 +00:00
SystemIdleProcess
839fba1e0c Set environment paths in service for apprise-api-install.sh (#14805) 2026-06-01 21:38:02 +02:00
community-scripts-pr-app[bot]
83398645ca Update CHANGELOG.md (#14861)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 14:00:34 +00:00
Michel Roegl-Brunner
06cf2ec50d Fix Kan build failure (TS7016 nodemailer) (#14856)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 16:00:00 +02:00
community-scripts-pr-app[bot]
bdc968e86d Update CHANGELOG.md (#14860)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 13:59:36 +00:00
community-scripts-pr-app[bot]
0b7d64b240 Update CHANGELOG.md (#14859)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 13:59:08 +00:00
Michel Roegl-Brunner
e013403db1 fix(fireshare): rebuild client on update to fix nginx 500 (#14848)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 15:59:05 +02:00
Michel Roegl-Brunner
465996653a fix(firefly): set Data Importer APP_URL for subdirectory install (#14847)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 15:58:32 +02:00
community-scripts-pr-app[bot]
6a7391f430 Update CHANGELOG.md (#14857)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 13:42:08 +00:00
CanbiZ (MickLesk)
aed34659c9 Kometa: also update Quickstart in update_script (#14529)
* Kometa: also update Quickstart in update_script

* Kometa: also update Quickstart in update_script
2026-06-01 15:41:36 +02:00
MickLesk
cd4a3e854e Update tsconfig path in installation scripts to support multiple locations 2026-06-01 13:39:23 +02:00
MickLesk
be46da731a Refactor kan installation script to ignore scripts during pnpm install and update tsconfig path 2026-06-01 13:13:03 +02:00
CanbiZ (MickLesk)
58179050a8 Fix indentation in kan.sh for clarity 2026-06-01 12:11:55 +02:00
CanbiZ (MickLesk)
955cb97a3b Update kan-install.sh 2026-06-01 12:11:34 +02:00
CanbiZ (MickLesk)
04e618798e Update fetch_and_deploy_gh_tag to use 'latest' tag 2026-06-01 12:02:12 +02:00
community-scripts-pr-app[bot]
4c358450d8 Update CHANGELOG.md (#14854)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 09:45:00 +00:00
CanbiZ (MickLesk)
fa238ddbdd kan: extend fetch_and_deploy_gh_tag to use 'latest' tag (#14853) 2026-06-01 11:44:28 +02:00
community-scripts-pr-app[bot]
0fe653f8de Update CHANGELOG.md (#14850)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 08:22:51 +00:00
community-scripts-pr-app[bot]
278e8315f3 Update CHANGELOG.md (#14849)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 08:22:40 +00:00
Michel Roegl-Brunner
ded4bba04d fix(glance): preserve glance.yml across updates (#14845)
CLEAN_INSTALL wipes /opt/glance without restoring user config; back up and restore glance.yml around the prebuild deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 10:22:20 +02:00
CanbiZ (MickLesk)
5b6f8e2674 NginxProxymanager: set Certbot version in npm.service environment variable (2.15.0) (#14843) 2026-06-01 10:22:10 +02:00
community-scripts-pr-app[bot]
162cb9b887 Update CHANGELOG.md (#14844)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 08:01:45 +00:00
Adrián Musante
5776f3fef5 Fix FileFlows service handling by using systemctl --all with quoted glob (#14838) 2026-06-01 10:01:17 +02:00
community-scripts-pr-app[bot]
26377b7a7f Update CHANGELOG.md (#14841)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-01 05:53:17 +00:00
CanbiZ (MickLesk)
151cd6581f Fix Caddy configuration message placement 2026-06-01 07:52:49 +02:00
community-scripts-pr-app[bot]
69641d322d Update CHANGELOG.md (#14835)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-31 20:05:20 +00:00
community-scripts-pr-app[bot]
6608deeb92 Update CHANGELOG.md (#14834)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-31 20:05:07 +00:00
CanbiZ (MickLesk)
de7c00e285 Manyfold: regenerate Rails credentials on update to fix encryption mimatch (#14817) 2026-05-31 22:04:55 +02:00
community-scripts-pr-app[bot]
eb74ba2edb Update CHANGELOG.md (#14833)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-31 20:04:40 +00:00
CanbiZ (MickLesk)
203131d042 PBS4-Upgrade: update current PBS3 packages before switching to Trixie repos (#14815) 2026-05-31 22:04:14 +02:00
community-scripts-pr-app[bot]
44db73c58d Update CHANGELOG.md (#14831)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-31 12:11:21 +00:00
Tom Frenzel
d074d3f292 fix(openthread-br): use correct ipv6 configuration (#14829) 2026-05-31 14:10:55 +02:00
community-scripts-pr-app[bot]
65f3a23cff Update CHANGELOG.md (#14828)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-31 10:54:56 +00:00
CanbiZ (MickLesk)
4da4a47eb7 Webtrees: use PHP CLI for initial setup instead of curl to setup wizard (#14818) 2026-05-31 12:54:34 +02:00
community-scripts-pr-app[bot]
cf3d8f902c Update CHANGELOG.md (#14827)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-31 10:54:18 +00:00
CanbiZ (MickLesk)
8c0333151b Kima-Hub: use curl_with_retry for ML model downloads to fix timeout issues (#14816) 2026-05-31 12:53:56 +02:00
community-scripts-pr-app[bot]
dc355d07bf Update CHANGELOG.md (#14823)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-31 00:22:53 +00:00
community-scripts-pr-app[bot]
4e51373669 Archive old changelog entries (#14822)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-31 00:22:31 +00:00
community-scripts-pr-app[bot]
256020b847 Update CHANGELOG.md (#14821)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-30 21:48:55 +00:00
CanbiZ (MickLesk)
19cd2b3dad Flatnotes: fix empty package name in pyproject.toml (#14814)
* Flatnotes: fix empty package name in pyproject.toml

* Flatnotes: fix empty package name in update script too
2026-05-30 23:48:30 +02:00
community-scripts-pr-app[bot]
9c06910526 Update CHANGELOG.md (#14803)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-29 21:49:58 +00:00
Slaviša Arežina
d3feeb4900 small fixes (#14801) 2026-05-29 23:49:34 +02:00
community-scripts-pr-app[bot]
4926d426a8 Update CHANGELOG.md (#14799)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-29 16:07:55 +00:00
CanbiZ (MickLesk)
7fea6cc9eb karakeep: add more hdd space (#14797) 2026-05-29 18:07:14 +02:00
community-scripts-pr-app[bot]
b59ab46000 Update CHANGELOG.md (#14794)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-29 11:55:35 +00:00
Danny Meier
d41fd37f1a Fix lobehub docker path (#14793)
* Fix docker.cjs path in lobehub.sh

* Update lobehub.sh

* Update lobehub.sh

* Update lobehub.sh

* Update lobehub.sh
2026-05-29 13:55:05 +02:00
community-scripts-pr-app[bot]
b065c5e081 Update CHANGELOG.md (#14790)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-29 09:05:23 +00:00
push-app-to-main[bot]
1f9c670648 Kan (#14776)
* Add kan (ct)

* add: tarball mode

* Update kan-install.sh

* Update install/kan-install.sh

Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>

---------

Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
Co-authored-by: Tobias <96661824+CrazyWolf13@users.noreply.github.com>
Co-authored-by: CanbiZ (MickLesk) <47820557+MickLesk@users.noreply.github.com>
2026-05-29 11:04:49 +02:00
community-scripts-pr-app[bot]
fdfb603930 Update CHANGELOG.md (#14788)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-29 08:41:48 +00:00
push-app-to-main[bot]
9a05da0b60 Add dynacat (ct) (#14777)
Co-authored-by: push-app-to-main[bot] <203845782+push-app-to-main[bot]@users.noreply.github.com>
2026-05-29 10:41:19 +02:00
community-scripts-pr-app[bot]
38a14454c4 Update CHANGELOG.md (#14785)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-29 06:30:02 +00:00
Slaviša Arežina
c3294436b5 Revert installation of EE (#14784) 2026-05-29 08:29:33 +02:00
community-scripts-pr-app[bot]
44a4c97a4c Update CHANGELOG.md (#14773)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-28 09:13:22 +00:00
github-actions[bot]
8c9477506c chore(ct): sync adventurelog defaults with PocketBase (#14772) 2026-05-28 11:12:52 +02:00
MickLesk
f7224f3db8 minor fix 2026-05-28 10:07:01 +02:00
community-scripts-pr-app[bot]
03dd5e7e88 Update CHANGELOG.md (#14770)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-28 06:33:41 +00:00
community-scripts-pr-app[bot]
7b5e2f9656 Update CHANGELOG.md (#14769)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-28 06:33:29 +00:00
CanbiZ (MickLesk)
7703edf4b6 RomM: remove nginx default.conf during installation (#14766) 2026-05-28 08:33:16 +02:00
CanbiZ (MickLesk)
32f1956023 Yamtrack: migrate to uv (#14767) 2026-05-28 08:33:02 +02:00
community-scripts-pr-app[bot]
49817d14f8 Update CHANGELOG.md (#14768)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-05-28 06:31:38 +00:00
CanbiZ (MickLesk)
d64b9f6878 Open-Archiver: replace pnpm approve-builds --yes with --all (#14765) 2026-05-28 08:31:12 +02:00
63 changed files with 1872 additions and 287 deletions

129
.github/changelogs/2026/05.md generated vendored
View File

@@ -1,3 +1,132 @@
## 2026-05-30
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Flatnotes: fix empty package name in pyproject.toml [@MickLesk](https://github.com/MickLesk) ([#14814](https://github.com/community-scripts/ProxmoxVE/pull/14814))
## 2026-05-29
### 🆕 New Scripts
- Kan ([#14776](https://github.com/community-scripts/ProxmoxVE/pull/14776))
- Dynacat ([#14777](https://github.com/community-scripts/ProxmoxVE/pull/14777))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Fix lobehub docker path [@dannyyy](https://github.com/dannyyy) ([#14793](https://github.com/community-scripts/ProxmoxVE/pull/14793))
- karakeep: add more hdd space [@MickLesk](https://github.com/MickLesk) ([#14797](https://github.com/community-scripts/ProxmoxVE/pull/14797))
- Grist: Revert installation of EE [@tremor021](https://github.com/tremor021) ([#14784](https://github.com/community-scripts/ProxmoxVE/pull/14784))
- #### 🔧 Refactor
- Sure: Remove `$STD` for `systemctl enable -q` [@tremor021](https://github.com/tremor021) ([#14801](https://github.com/community-scripts/ProxmoxVE/pull/14801))
## 2026-05-28
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- RomM: remove nginx default.conf during installation [@MickLesk](https://github.com/MickLesk) ([#14766](https://github.com/community-scripts/ProxmoxVE/pull/14766))
- Open-Archiver: replace pnpm approve-builds --yes with --all [@MickLesk](https://github.com/MickLesk) ([#14765](https://github.com/community-scripts/ProxmoxVE/pull/14765))
- fix(hermesagent): set npm_config_yes=true to suppress interactive pro… [@steveonjava](https://github.com/steveonjava) ([#14763](https://github.com/community-scripts/ProxmoxVE/pull/14763))
- #### 🔧 Refactor
- Yamtrack: migrate to uv [@MickLesk](https://github.com/MickLesk) ([#14767](https://github.com/community-scripts/ProxmoxVE/pull/14767))
### ❔ Uncategorized
- chore(ct): sync adventurelog defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#14772](https://github.com/community-scripts/ProxmoxVE/pull/14772))
## 2026-05-27
### 🆕 New Scripts
- MusicSeerr ([#14746](https://github.com/community-scripts/ProxmoxVE/pull/14746))
- Hermes Agent ([#14751](https://github.com/community-scripts/ProxmoxVE/pull/14751))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- grist: restore install:ee step [@paulfitz](https://github.com/paulfitz) ([#14759](https://github.com/community-scripts/ProxmoxVE/pull/14759))
### 💾 Core
- #### 🐞 Bug Fixes
- [tools.func]: `setup_gs()` fix getting dotted release format [@tremor021](https://github.com/tremor021) ([#14745](https://github.com/community-scripts/ProxmoxVE/pull/14745))
## 2026-05-26
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Add directory creation to Profilarr update script [@ryansully](https://github.com/ryansully) ([#14740](https://github.com/community-scripts/ProxmoxVE/pull/14740))
- profilarr: Fix ARCH assignment in profilarr.sh to support Profilarr build usage [@mpeleshenko](https://github.com/mpeleshenko) ([#14709](https://github.com/community-scripts/ProxmoxVE/pull/14709))
- Jackett: Remove quotes in Service File [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14729](https://github.com/community-scripts/ProxmoxVE/pull/14729))
- Open-archiver: approve pnpm build scripts and run build:oss without subshell [@MickLesk](https://github.com/MickLesk) ([#14711](https://github.com/community-scripts/ProxmoxVE/pull/14711))
- Docuseal: read Ruby version from Gemfile, upgrade on update if needed [@MickLesk](https://github.com/MickLesk) ([#14715](https://github.com/community-scripts/ProxmoxVE/pull/14715))
- #### ✨ New Features
- Birdnet-GO: install libonnxruntime.so from release tarball [@MickLesk](https://github.com/MickLesk) ([#14716](https://github.com/community-scripts/ProxmoxVE/pull/14716))
### 💾 Core
- #### ✨ New Features
- tools.func: better error diagnostics, consistent OS detection, setup function ordering [@MickLesk](https://github.com/MickLesk) ([#14692](https://github.com/community-scripts/ProxmoxVE/pull/14692))
### 🧰 Tools
- #### 🐞 Bug Fixes
- IPTag-Tool: use qm set for VM tags to handle snapshot sections crrectly [@MickLesk](https://github.com/MickLesk) ([#14713](https://github.com/community-scripts/ProxmoxVE/pull/14713))
- #### ✨ New Features
- Netdata: extend PVE version support to 9.x [@MickLesk](https://github.com/MickLesk) ([#14714](https://github.com/community-scripts/ProxmoxVE/pull/14714))
## 2026-05-25
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- karakeep: fix: pip config [@CrazyWolf13](https://github.com/CrazyWolf13) ([#14703](https://github.com/community-scripts/ProxmoxVE/pull/14703))
### 💾 Core
- #### ✨ New Features
- tools.func: replace raw GitHub API curl calls with get_latest_github_release [@MickLesk](https://github.com/MickLesk) ([#14690](https://github.com/community-scripts/ProxmoxVE/pull/14690))
### 🧰 Tools
- #### 🔧 Refactor
- Kernel-Clean: detect meta-packages and fix silent removal failures [@MickLesk](https://github.com/MickLesk) ([#14674](https://github.com/community-scripts/ProxmoxVE/pull/14674))
## 2026-05-24
### 🚀 Updated Scripts
- #### ✨ New Features
- RomM: add installation steps for Nginx mod_zip module [@MickLesk](https://github.com/MickLesk) ([#14678](https://github.com/community-scripts/ProxmoxVE/pull/14678))
- ISponsorblockTV: detect CPU capabilities to select compatible binary [@MickLesk](https://github.com/MickLesk) ([#14677](https://github.com/community-scripts/ProxmoxVE/pull/14677))
- #### 🔧 Refactor
- Refactor: MQTT [@tremor021](https://github.com/tremor021) ([#14673](https://github.com/community-scripts/ProxmoxVE/pull/14673))
## 2026-05-23 ## 2026-05-23
### 🚀 Updated Scripts ### 🚀 Updated Scripts

View File

@@ -336,6 +336,7 @@ jobs:
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo") issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
drift_count=$((drift_count + 1)) drift_count=$((drift_count + 1))
elif [[ -n "$upstream_major" && "$our_version" != "$upstream_major" ]]; then elif [[ -n "$upstream_major" && "$our_version" != "$upstream_major" ]]; then
if (( our_version < upstream_major )); then
# Check if engines.node is a minimum constraint that our version satisfies # Check if engines.node is a minimum constraint that our version satisfies
if [[ -z "$DF_NODE_MAJOR" && "$ENGINES_IS_MINIMUM" == "true" ]] && \ if [[ -z "$DF_NODE_MAJOR" && "$ENGINES_IS_MINIMUM" == "true" ]] && \
version_satisfies_engines "$our_version" "$ENGINES_MIN_MAJOR" "$ENGINES_IS_MINIMUM"; then version_satisfies_engines "$our_version" "$ENGINES_MIN_MAJOR" "$ENGINES_IS_MINIMUM"; then
@@ -345,6 +346,9 @@ jobs:
issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo") issue_scripts+=("$slug|$our_version|$upstream_major|$upstream_hint|$repo")
drift_count=$((drift_count + 1)) drift_count=$((drift_count + 1))
fi fi
else
status="✅ Ahead of upstream ($upstream_major via $upstream_hint)"
fi
fi fi
report_lines+=("| \`$slug\` | $our_version | $engines_display | $dockerfile_display | [$repo](https://github.com/$repo) | $status |") report_lines+=("| \`$slug\` | $our_version | $engines_display | $dockerfile_display | [$repo](https://github.com/$repo) | $status |")

View File

@@ -3,7 +3,7 @@ name: Close Unauthorized New Script PRs
on: on:
pull_request_target: pull_request_target:
branches: ["main"] branches: ["main"]
types: [opened, labeled] types: [opened, labeled, reopened, synchronize]
jobs: jobs:
check-new-script: check-new-script:
@@ -24,13 +24,6 @@ jobs:
const owner = context.repo.owner; const owner = context.repo.owner;
const repo = context.repo.repo; 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 --- // --- Allow our bots ---
const allowedBots = [ const allowedBots = [
"push-app-to-main[bot]", "push-app-to-main[bot]",
@@ -42,38 +35,40 @@ jobs:
return; return;
} }
// --- Check if author is a member of the contributor team --- // --- Exempt contributors via author_association ---
const teamSlug = "contributor"; // OWNER/MEMBER/COLLABORATOR are trusted; CONTRIBUTOR ("has merged before")
let isMember = false; // and NONE are not — their new-script PRs are still closed.
const association = pr.author_association;
const exempt = ["OWNER", "MEMBER", "COLLABORATOR"];
if (exempt.includes(association)) {
core.info(`PR #${prNumber} by ${association} "${author}" — skipping.`);
return;
}
// --- Detect a new-script PR: "new script" label OR a newly-added
// script file under ct/ install/ turnkey/ vm/ (mirrors
// autolabeler-config.json). Removes the label-timing dependency. ---
const labels = pr.labels.map(l => l.name);
const hasNewScriptLabel = labels.includes("new script");
const scriptPrefixes = ["ct/", "install/", "turnkey/", "vm/"];
let hasAddedScriptFile = false;
try { try {
const { status } = await github.rest.teams.getMembershipForUserInOrg({ const files = await github.paginate(github.rest.pulls.listFiles, {
org: owner, owner,
team_slug: teamSlug, repo,
username: author, pull_number: prNumber,
per_page: 100,
}); });
// status 200 means the user is a member (active or pending) hasAddedScriptFile = files.some(
isMember = true; f => f.status === "added" && scriptPrefixes.some(p => f.filename.startsWith(p))
);
} catch (error) { } catch (error) {
if (error.status === 404) { core.warning(`Could not list files for PR #${prNumber}: ${error.message}`);
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) { if (!hasNewScriptLabel && !hasAddedScriptFile) {
core.info(`PR #${prNumber} by contributor "${author}" — skipping.`); core.info(`PR #${prNumber} is not a new-script submission (no label, no added script file) — skipping.`);
return; return;
} }

View File

@@ -56,46 +56,57 @@ jobs:
echo "$slugs" > pocketbase_slugs.txt echo "$slugs" > pocketbase_slugs.txt
echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT" echo "count=$(echo $slugs | wc -w)" >> "$GITHUB_OUTPUT"
- name: Search for Issues with Similar Titles - name: Find matching issues in ProxmoxVED by slug
id: find_issue id: find_issue
env: env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
issues=$(gh issue list --repo community-scripts/ProxmoxVED --json number,title --jq '.[] | {number, title}') if [[ ! -s pocketbase_slugs.txt ]]; then
echo "No slugs derived from PR — nothing to match."
best_match_score=0 echo "issue_numbers=" >> "$GITHUB_OUTPUT"
best_match_number=0
for issue in $(echo "$issues" | jq -r '. | @base64'); do
_jq() {
echo ${issue} | base64 --decode | jq -r ${1}
}
issue_title=$(_jq '.title' | tr '[:upper:]' '[:lower:]' | sed 's/ //g' | sed 's/-//g')
issue_number=$(_jq '.number')
match_score=$(echo "$title" | grep -o "$issue_title" | wc -l)
if [ "$match_score" -gt "$best_match_score" ]; then
best_match_score=$match_score
best_match_number=$issue_number
fi
done
if [ "$best_match_number" != "0" ]; then
echo "issue_number=$best_match_number" >> $GITHUB_ENV
else
echo "No matching issue found."
exit 0 exit 0
fi fi
slugs=$(cat pocketbase_slugs.txt)
- name: Comment on the Best-Matching Issue and Close It # Normalize: lowercase, strip spaces and hyphens (same shape as the slug derivation)
if: env.issue_number != '' norm() { echo "$1" | tr '[:upper:]' '[:lower:]' | sed 's/[[:space:]]//g; s/-//g'; }
issues=$(gh issue list --repo community-scripts/ProxmoxVED --state open --limit 1000 --json number,title,body)
matched=""
for slug in $slugs; do
nslug=$(norm "$slug")
[[ -z "$nslug" ]] && continue
while IFS= read -r row; do
num=$(echo "$row" | jq -r '.number')
ntitle=$(norm "$(echo "$row" | jq -r '.title')")
body=$(echo "$row" | jq -r '.body // ""' | tr '[:upper:]' '[:lower:]')
# Match when the issue title contains the slug, or the body mentions it verbatim
if [[ "$ntitle" == *"$nslug"* ]] || [[ "$body" == *"$slug"* ]]; then
matched="$matched $num"
fi
done < <(echo "$issues" | jq -c '.[]')
done
matched=$(echo $matched | xargs -n1 2>/dev/null | sort -un | tr '\n' ' ')
if [[ -z "$matched" ]]; then
echo "No matching ProxmoxVED issues found for slugs: $slugs"
echo "issue_numbers=" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Matched ProxmoxVED issues: $matched"
echo "issue_numbers=$matched" >> "$GITHUB_OUTPUT"
- name: Comment on and close matching ProxmoxVED issues
if: steps.find_issue.outputs.issue_numbers != ''
env: env:
GH_TOKEN: ${{ secrets.PAT_MICHEL }} GH_TOKEN: ${{ secrets.PAT_MICHEL }}
run: | run: |
gh issue comment $issue_number --repo community-scripts/ProxmoxVED --body "Merged with #${{ github.event.pull_request.number }} in ProxmoxVE" for issue_number in ${{ steps.find_issue.outputs.issue_numbers }}; do
gh issue close $issue_number --repo community-scripts/ProxmoxVED echo "Closing ProxmoxVED issue #$issue_number"
gh issue comment "$issue_number" --repo community-scripts/ProxmoxVED --body "Merged with #${{ github.event.pull_request.number }} in ProxmoxVE"
gh issue close "$issue_number" --repo community-scripts/ProxmoxVED
done
- name: Set is_dev to false in PocketBase - name: Set is_dev to false in PocketBase
if: steps.get_slugs.outputs.count != '0' if: steps.get_slugs.outputs.count != '0'

4
.github/workflows/lock-issue.yaml generated vendored
View File

@@ -17,7 +17,7 @@ jobs:
uses: actions/github-script@v7 uses: actions/github-script@v7
with: with:
script: | script: |
const daysBeforeLock = 3; const daysBeforeLock = 7;
const lockDate = new Date(); const lockDate = new Date();
lockDate.setDate(lockDate.getDate() - daysBeforeLock); lockDate.setDate(lockDate.getDate() - daysBeforeLock);
@@ -28,7 +28,7 @@ jobs:
/dependabot/i /dependabot/i
]; ];
// Search for closed, unlocked issues older than 3 days (paginated, oldest first) // Search for closed, unlocked issues older than 7 days (paginated, oldest first)
let page = 1; let page = 1;
let totalLocked = 0; let totalLocked = 0;

610
.github/workflows/pocketbase-ai-bot.yml generated vendored Normal file
View File

@@ -0,0 +1,610 @@
name: PocketBase AI Bot
# Natural-language companion to pocketbase-bot.yml.
# Mention the bot in plain English, e.g.:
# @pocketbase-bot change RAM to 4096 on zigbee2mqtt
# @pocketbase-bot disable script Nextcloud because upstream is broken
# The bot parses the request with GitHub Models, replies with the exact change(s)
# it understood, and only applies them after you reply "@pocketbase-bot confirm".
# The slash-command bot (/pocketbase ...) is unaffected; triggers do not overlap.
on:
issue_comment:
types: [created]
permissions:
models: read # lets the built-in GITHUB_TOKEN call GitHub Models inference
contents: write # built-in token opens the CT-defaults sync PR (like the slash bot)
pull-requests: write
jobs:
ai-bot:
runs-on: self-hosted
# Broad gate; the script does precise keyword + self-author checks.
if: contains(github.event.comment.body, '@pocketbase-bot')
steps:
- name: Mint GitHub App token (bot identity)
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.PB_BOT_APP_ID }}
private-key: ${{ secrets.PB_BOT_APP_PRIVATE_KEY }}
- name: Run PocketBase AI bot
env:
# GitHub REST as the bot identity
GH_APP_TOKEN: ${{ steps.app-token.outputs.token }}
PB_BOT_APP_ID: ${{ secrets.PB_BOT_APP_ID }}
# GitHub Models inference uses the built-in token (needs models: read)
MODELS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Built-in token for git/PR ops (CT-defaults sync), mirroring the slash bot
GH_DEFAULT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AI_MODEL: openai/gpt-4o
# PocketBase
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
FRONTEND_URL: ${{ secrets.FRONTEND_URL }}
REVALIDATE_SECRET: ${{ secrets.REVALIDATE_SECRET }}
# Event context
COMMENT_BODY: ${{ github.event.comment.body }}
COMMENT_ID: ${{ github.event.comment.id }}
COMMENT_AUTHOR_TYPE: ${{ github.event.comment.user.type }}
ISSUE_NUMBER: ${{ github.event.issue.number }}
REPO_OWNER: ${{ github.repository_owner }}
REPO_NAME: ${{ github.event.repository.name }}
ACTOR: ${{ github.event.comment.user.login }}
ACTOR_ASSOCIATION: ${{ github.event.comment.author_association }}
run: |
node << 'ENDSCRIPT'
(async function () {
const https = require('https');
const http = require('http');
const url = require('url');
// ── HTTP helper with redirect following ────────────────────────────
function request(fullUrl, opts, redirectCount) {
redirectCount = redirectCount || 0;
return new Promise(function (resolve, reject) {
const u = url.parse(fullUrl);
const isHttps = u.protocol === 'https:';
const body = opts.body;
const options = {
hostname: u.hostname,
port: u.port || (isHttps ? 443 : 80),
path: u.path,
method: opts.method || 'GET',
headers: opts.headers || {}
};
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
const lib = isHttps ? https : http;
const req = lib.request(options, function (res) {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
if (redirectCount >= 5) return reject(new Error('Too many redirects from ' + fullUrl));
const redirectUrl = url.resolve(fullUrl, res.headers.location);
res.resume();
resolve(request(redirectUrl, opts, redirectCount + 1));
return;
}
let data = '';
res.on('data', function (chunk) { data += chunk; });
res.on('end', function () {
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
});
});
req.on('error', reject);
if (body) req.write(body);
req.end();
});
}
// ── GitHub REST (as the bot app) ───────────────────────────────────
const owner = process.env.REPO_OWNER;
const repo = process.env.REPO_NAME;
const issueNumber = parseInt(process.env.ISSUE_NUMBER, 10);
const commentId = parseInt(process.env.COMMENT_ID, 10);
const actor = process.env.ACTOR;
function ghRequest(path, method, body) {
const headers = {
'Authorization': 'Bearer ' + process.env.GH_APP_TOKEN,
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
'User-Agent': 'PocketBase-AI-Bot'
};
const bodyStr = body ? JSON.stringify(body) : undefined;
if (bodyStr) headers['Content-Type'] = 'application/json';
return request('https://api.github.com' + path, { method: method || 'GET', headers, body: bodyStr });
}
// Same as ghRequest but authenticated with the built-in GITHUB_TOKEN.
// Used for the CT-defaults sync branch/PR (the App token lacks contents:write).
function ghDefault(path, method, body) {
const headers = {
'Authorization': 'Bearer ' + process.env.GH_DEFAULT_TOKEN,
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
'User-Agent': 'PocketBase-AI-Bot'
};
const bodyStr = body ? JSON.stringify(body) : undefined;
if (bodyStr) headers['Content-Type'] = 'application/json';
return request('https://api.github.com' + path, { method: method || 'GET', headers, body: bodyStr });
}
async function addReaction(content) {
try {
await ghRequest('/repos/' + owner + '/' + repo + '/issues/comments/' + commentId + '/reactions', 'POST', { content });
} catch (e) { console.warn('Could not add reaction:', e.message); }
}
async function postComment(text) {
const res = await ghRequest('/repos/' + owner + '/' + repo + '/issues/' + issueNumber + '/comments', 'POST', { body: text });
if (!res.ok) console.warn('Could not post comment:', res.body);
return res.ok ? JSON.parse(res.body) : null;
}
async function updateComment(id, text) {
const res = await ghRequest('/repos/' + owner + '/' + repo + '/issues/comments/' + id, 'PATCH', { body: text });
if (!res.ok) console.warn('Could not update comment:', res.body);
}
async function listIssueComments() {
const all = [];
let page = 1;
while (page <= 10) {
const res = await ghRequest('/repos/' + owner + '/' + repo + '/issues/' + issueNumber + '/comments?per_page=100&page=' + page);
if (!res.ok) break;
const batch = JSON.parse(res.body);
all.push.apply(all, batch);
if (batch.length < 100) break;
page++;
}
return all;
}
// ── 1. Self-trigger guard (App-token comments DO re-fire this event) ─
if (process.env.COMMENT_AUTHOR_TYPE === 'Bot') {
console.log('Comment authored by a bot — skipping to avoid loops.');
return;
}
// ── 2. Permission gate (mirrors the slash bot) ─────────────────────
const association = process.env.ACTOR_ASSOCIATION;
if (association !== 'OWNER' && association !== 'MEMBER') {
await addReaction('-1');
await postComment(
'❌ **PocketBase AI Bot**: @' + actor + ' is not authorized to use this command.\n' +
'Only org members (Contributors team) can use `@pocketbase-bot`.'
);
return;
}
// ── 3. Extract the instruction after the @pocketbase-bot handle ────
const commentBody = process.env.COMMENT_BODY || '';
const handleMatch = commentBody.match(/@pocketbase-bot(\[bot\])?/i);
if (!handleMatch) {
console.log('No @pocketbase-bot handle found — ignoring.');
return;
}
const instruction = commentBody.slice(handleMatch.index + handleMatch[0].length).trim();
if (!instruction) {
await addReaction('-1');
await postComment(
' **PocketBase AI Bot**: Tell me what to do, e.g.\n' +
'`@pocketbase-bot change RAM to 4096 on zigbee2mqtt` or `@pocketbase-bot disable script Nextcloud`.'
);
return;
}
// ── PocketBase auth + low-level helpers ────────────────────────────
const pbRaw = process.env.POCKETBASE_URL.replace(/\/$/, '');
const apiBase = /\/api$/i.test(pbRaw) ? pbRaw : pbRaw + '/api';
const coll = process.env.POCKETBASE_COLLECTION;
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
async function pbAuth() {
const res = await request(apiBase + '/collections/users/auth-with-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ identity: process.env.POCKETBASE_ADMIN_EMAIL, password: process.env.POCKETBASE_ADMIN_PASSWORD })
});
if (!res.ok) throw new Error('PocketBase auth failed: ' + res.body);
return JSON.parse(res.body).token;
}
async function pbFindRecord(token, slug) {
const filter = "(slug='" + String(slug).replace(/'/g, "''") + "')";
const res = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', { headers: { 'Authorization': token } });
const list = JSON.parse(res.body);
return list.items && list.items[0];
}
async function pbPatch(token, id, payload) {
return request(recordsUrl + '/' + id, {
method: 'PATCH',
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
}
function readJsonBlob(val) {
if (Array.isArray(val)) return val;
try { return JSON.parse(val || '[]'); } catch (e) { return []; }
}
async function revalidate(s) {
const frontendUrl = process.env.FRONTEND_URL;
const secret = process.env.REVALIDATE_SECRET;
if (!frontendUrl || !secret) return;
try {
await request(frontendUrl.replace(/\/$/, '') + '/api/revalidate', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + secret, 'Content-Type': 'application/json' },
body: JSON.stringify({ tags: ['scripts', 'script-' + s] })
});
} catch (e) { console.warn('Revalidation skipped:', e.message); }
}
// ── CT-defaults sync PR (copied from slash bot) ────────────────────
function encodeContentPath(filePath) { return filePath.split('/').map(encodeURIComponent).join('/'); }
function decodeGitHubContent(content) { return Buffer.from((content || '').replace(/\n/g, ''), 'base64').toString('utf8'); }
function sanitizeBranchPart(value) {
return (value || '').toLowerCase().replace(/[^a-z0-9._/-]+/g, '-').replace(/\/+/g, '/').replace(/^-+|-+$/g, '');
}
function applyCtDefaultChanges(scriptText, varChanges) {
let nextText = scriptText;
const updatedVars = [], unchangedVars = [];
for (const [varName, rawValue] of Object.entries(varChanges)) {
const newValue = String(rawValue);
const pattern = new RegExp('(^\\s*' + varName + '="\\$\\{' + varName + ':-)([^"}]*)(\\}"\\s*$)', 'm');
const match = nextText.match(pattern);
if (!match) continue;
if (match[2] === newValue) { unchangedVars.push(varName); continue; }
nextText = nextText.replace(pattern, '$1' + newValue + '$3');
updatedVars.push(varName);
}
return { nextText, updatedVars, unchangedVars };
}
async function ensureBranch(defaultBranch, branchName) {
const ghRequest = ghDefault; // git ops run as the built-in token
const branchRefRes = await ghRequest('/repos/' + owner + '/' + repo + '/git/ref/heads/' + encodeURIComponent(branchName));
if (branchRefRes.ok) return;
const defaultRefRes = await ghRequest('/repos/' + owner + '/' + repo + '/git/ref/heads/' + encodeURIComponent(defaultBranch));
if (!defaultRefRes.ok) throw new Error('Could not read default branch ref: ' + defaultRefRes.body);
const defaultRef = JSON.parse(defaultRefRes.body);
const createBranchRes = await ghRequest('/repos/' + owner + '/' + repo + '/git/refs', 'POST', { ref: 'refs/heads/' + branchName, sha: defaultRef.object.sha });
if (!createBranchRes.ok) throw new Error('Could not create branch: ' + createBranchRes.body);
}
async function upsertCtDefaultsPr(slugValue, varChanges) {
const ghRequest = ghDefault; // contents/PR ops run as the built-in token
const wantedEntries = Object.entries(varChanges || {}).filter(function ([, v]) { return v !== undefined && v !== null && String(v) !== ''; });
if (wantedEntries.length === 0) return { status: 'skipped', reason: 'No mapped CT defaults changed.' };
const repoRes = await ghRequest('/repos/' + owner + '/' + repo);
if (!repoRes.ok) throw new Error('Could not read repository metadata: ' + repoRes.body);
const defaultBranch = JSON.parse(repoRes.body).default_branch;
const ctPath = 'ct/' + slugValue + '.sh';
const encodedCtPath = encodeContentPath(ctPath);
const defaultFileRes = await ghRequest('/repos/' + owner + '/' + repo + '/contents/' + encodedCtPath + '?ref=' + encodeURIComponent(defaultBranch));
if (defaultFileRes.statusCode === 404) return { status: 'skipped', reason: 'No matching CT file found at `' + ctPath + '`.' };
if (!defaultFileRes.ok) throw new Error('Could not read CT file from default branch: ' + defaultFileRes.body);
const branchName = 'pocketbase-sync/' + sanitizeBranchPart(slugValue || 'unknown');
await ensureBranch(defaultBranch, branchName);
const branchFileRes = await ghRequest('/repos/' + owner + '/' + repo + '/contents/' + encodedCtPath + '?ref=' + encodeURIComponent(branchName));
if (!branchFileRes.ok) throw new Error('Could not read CT file from sync branch: ' + branchFileRes.body);
const branchFile = JSON.parse(branchFileRes.body);
const currentBranchText = decodeGitHubContent(branchFile.content);
const updateResult = applyCtDefaultChanges(currentBranchText, Object.fromEntries(wantedEntries));
if (updateResult.updatedVars.length === 0) return { status: 'skipped', reason: 'CT defaults already up to date.' };
const putRes = await ghRequest('/repos/' + owner + '/' + repo + '/contents/' + encodedCtPath, 'PUT', {
message: 'chore(ct): sync ' + slugValue + ' defaults from PocketBase',
content: Buffer.from(updateResult.nextText, 'utf8').toString('base64'),
sha: branchFile.sha,
branch: branchName
});
if (!putRes.ok) throw new Error('Could not update CT file: ' + putRes.body);
const openPrRes = await ghRequest('/repos/' + owner + '/' + repo + '/pulls?state=open&head=' + encodeURIComponent(owner + ':' + branchName) + '&base=' + encodeURIComponent(defaultBranch));
if (!openPrRes.ok) throw new Error('Could not query existing PRs: ' + openPrRes.body);
const openPrs = JSON.parse(openPrRes.body);
if (openPrs.length > 0) return { status: 'updated', prUrl: openPrs[0].html_url, updatedVars: updateResult.updatedVars };
const createPrRes = await ghRequest('/repos/' + owner + '/' + repo + '/pulls', 'POST', {
title: 'chore(ct): sync ' + slugValue + ' defaults with PocketBase',
body: '## Summary\n- Sync default CT variables for `' + slugValue + '` after an `@pocketbase-bot` update.\n- Updated vars: `' + updateResult.updatedVars.join('`, `') + '`.\n\n## Source\n- Triggered by @' + actor + ' via PocketBase AI bot.\n',
head: branchName,
base: defaultBranch
});
if (!createPrRes.ok) throw new Error('Could not create PR: ' + createPrRes.body);
return { status: 'created', prUrl: JSON.parse(createPrRes.body).html_url, updatedVars: updateResult.updatedVars };
}
// ── Allow-lists (mirror the slash bot) ─────────────────────────────
const ALLOWED_FIELDS = {
name: 'string', description: 'string', logo: 'string', documentation: 'string',
website: 'string', project_url: 'string', github: 'string', config_path: 'string',
tags: 'string', port: 'number', default_user: 'nullable_string', default_passwd: 'nullable_string',
unprivileged: 'number', updateable: 'boolean', privileged: 'boolean', has_arm: 'boolean',
is_dev: 'boolean', is_disabled: 'boolean', disable_message: 'string',
is_deleted: 'boolean', deleted_message: 'string'
};
const FIELD_TO_CT_VAR = { tags: 'var_tags', unprivileged: 'var_unprivileged' };
const RESOURCE_KEYS = { cpu: 'number', ram: 'number', hdd: 'number', os: 'string', version: 'string' };
const METHOD_KEYS = { config_path: 'string', script: 'string' };
const ALL_METHOD_KEYS = Object.assign({}, RESOURCE_KEYS, METHOD_KEYS);
const RESOURCE_TO_CT_VAR = { cpu: 'var_cpu', ram: 'var_ram', hdd: 'var_disk', os: 'var_os', version: 'var_version' };
function castFieldValue(key, rawVal) {
const type = ALLOWED_FIELDS[key];
if (!type) return { error: 'Unknown field `' + key + '`' };
if (type === 'boolean') {
if (rawVal === true || rawVal === 'true') return { value: true };
if (rawVal === false || rawVal === 'false') return { value: false };
return { error: '`' + key + '` must be true/false' };
}
if (type === 'number') {
const n = parseInt(rawVal, 10);
if (isNaN(n)) return { error: '`' + key + '` must be a number' };
return { value: n };
}
if (type === 'nullable_string') return { value: rawVal === '' || rawVal == null ? null : String(rawVal) };
return { value: String(rawVal) };
}
// ── Operation validation (used at propose AND confirm time) ────────
// Never trust raw operations: enforce the field/op allow-lists and
// re-cast values. Returns only well-formed, allowed operations.
function sanitizeOperations(ops) {
const validOps = [], problems = [];
for (const op of (Array.isArray(ops) ? ops : [])) {
if (op && op.kind === 'field') {
const cast = castFieldValue(op.field, op.value);
if (cast.error) { problems.push(cast.error); continue; }
validOps.push({ kind: 'field', field: op.field, value: cast.value });
} else if (op && op.kind === 'note' && ['add', 'edit', 'remove'].includes(op.action)) {
validOps.push({ kind: 'note', action: op.action, type: String(op.type || ''), text: op.text, newText: op.newText });
} else if (op && op.kind === 'method' && ['add', 'edit', 'remove'].includes(op.action)) {
const changes = {};
for (const [k, v] of Object.entries(op.changes || {})) { if (ALL_METHOD_KEYS[k]) changes[k] = v; }
validOps.push({ kind: 'method', action: op.action, type: String(op.type || 'default'), changes });
} else {
problems.push('Unsupported operation: `' + JSON.stringify(op) + '`');
}
}
return { validOps, problems };
}
// ── Executor: apply a validated {slug, operations} set ─────────────
async function applyOperations(action) {
const token = await pbAuth();
const record = await pbFindRecord(token, action.slug);
if (!record) return { ok: false, summary: '❌ No PocketBase record for slug `' + action.slug + '`.' };
const fieldPayload = {};
let notesArr = readJsonBlob(record.notes);
let methodsArr = readJsonBlob(record.install_methods);
let notesChanged = false, methodsChanged = false;
const ctChanges = {};
const lines = [];
for (const op of action.operations) {
if (op.kind === 'field') {
const cast = castFieldValue(op.field, op.value);
if (cast.error) { lines.push('- ⚠️ skipped field: ' + cast.error); continue; }
fieldPayload[op.field] = cast.value;
if (FIELD_TO_CT_VAR[op.field]) ctChanges[FIELD_TO_CT_VAR[op.field]] = cast.value;
lines.push('- `' + op.field + '` → `' + JSON.stringify(cast.value) + '`');
} else if (op.kind === 'note') {
const type = String(op.type || '').toLowerCase();
if (op.action === 'add') {
notesArr.push({ type, text: String(op.text || '') });
notesChanged = true; lines.push('- note add `' + type + '`: ' + op.text);
} else if (op.action === 'remove') {
const before = notesArr.length;
notesArr = notesArr.filter(function (n) { return !(String(n.type).toLowerCase() === type && n.text === op.text); });
if (notesArr.length !== before) { notesChanged = true; lines.push('- note remove `' + type + '`: ' + op.text); }
else lines.push('- ⚠️ note remove: no `' + type + '` note matched');
} else if (op.action === 'edit') {
const idx = notesArr.findIndex(function (n) { return String(n.type).toLowerCase() === type && n.text === op.text; });
if (idx !== -1) { notesArr[idx].text = String(op.newText || ''); notesChanged = true; lines.push('- note edit `' + type + '`'); }
else lines.push('- ⚠️ note edit: no `' + type + '` note matched');
}
} else if (op.kind === 'method') {
const type = String(op.type || '').toLowerCase();
const changes = op.changes || {};
if (op.action === 'remove') {
const before = methodsArr.length;
methodsArr = methodsArr.filter(function (im) { return String(im.type || '').toLowerCase() !== type; });
if (methodsArr.length !== before) { methodsChanged = true; lines.push('- method remove `' + type + '`'); }
else lines.push('- ⚠️ method remove: `' + type + '` not found');
} else {
let method = methodsArr.find(function (im) { return String(im.type || '').toLowerCase() === type; });
if (!method && op.action === 'add') { method = { type, resources: { cpu: 1, ram: 512, hdd: 4, os: 'debian', version: '13' } }; methodsArr.push(method); }
if (!method) { lines.push('- ⚠️ method edit: `' + type + '` not found'); continue; }
if (!method.resources) method.resources = {};
for (const [k, v] of Object.entries(changes)) {
if (RESOURCE_KEYS[k]) {
method.resources[k] = RESOURCE_KEYS[k] === 'number' ? parseInt(v, 10) : String(v);
if (RESOURCE_TO_CT_VAR[k]) ctChanges[RESOURCE_TO_CT_VAR[k]] = method.resources[k];
} else if (METHOD_KEYS[k]) {
method[k] = v === '' ? null : String(v);
}
}
methodsChanged = true;
lines.push('- method `' + (op.action === 'add' ? 'add' : 'edit') + '` `' + type + '`: ' + JSON.stringify(changes));
}
}
}
if (Object.keys(fieldPayload).length) {
const r = await pbPatch(token, record.id, fieldPayload);
if (!r.ok) return { ok: false, summary: '❌ Field update failed:\n```\n' + r.body + '\n```' };
}
if (notesChanged) {
const r = await pbPatch(token, record.id, { notes: notesArr });
if (!r.ok) return { ok: false, summary: '❌ Notes update failed:\n```\n' + r.body + '\n```' };
}
if (methodsChanged) {
const r = await pbPatch(token, record.id, { install_methods: methodsArr });
if (!r.ok) return { ok: false, summary: '❌ Install-method update failed:\n```\n' + r.body + '\n```' };
}
await revalidate(action.slug);
let ctNote = '';
if (Object.keys(ctChanges).length) {
try {
const sync = await upsertCtDefaultsPr(action.slug, ctChanges);
if (sync.status === 'created') ctNote = '\n\n**CT sync PR:** ' + sync.prUrl;
else if (sync.status === 'updated') ctNote = '\n\n**CT sync PR updated:** ' + sync.prUrl;
else if (sync.status === 'skipped') ctNote = '\n\n**CT sync skipped:** ' + sync.reason;
} catch (e) { ctNote = '\n\n**CT sync failed:** ' + e.message; }
}
return { ok: true, summary: lines.join('\n') + ctNote };
}
// ── 4. Confirm branch ──────────────────────────────────────────────
const PENDING_RE = /<!--\s*pocketbase-pending:\s*([A-Za-z0-9+/=]+)\s*-->/;
const isConfirm = /^(confirm|yes|apply|do it|y)\b/i.test(instruction);
if (isConfirm) {
const comments = await listIssueComments();
const appId = String(process.env.PB_BOT_APP_ID || '');
let pending = null, pendingComment = null;
for (let i = comments.length - 1; i >= 0; i--) {
const c = comments[i];
// Only trust a marker in a comment THIS bot app authored — otherwise a
// user could hand-craft a forged pocketbase-pending marker and confirm it.
const byBotApp = c.user && c.user.type === 'Bot' &&
c.performed_via_github_app && String(c.performed_via_github_app.id) === appId;
if (!byBotApp) continue;
const m = c.body && c.body.match(PENDING_RE);
if (m) { pending = m[1]; pendingComment = c; break; }
}
if (!pending) {
await addReaction('confused');
await postComment('🤔 **PocketBase AI Bot**: I have no pending change to confirm in this thread.');
return;
}
let action;
try { action = JSON.parse(Buffer.from(pending, 'base64').toString('utf8')); }
catch (e) { await postComment('❌ **PocketBase AI Bot**: Could not decode the pending change.'); return; }
// Re-validate the decoded operations before applying (defense-in-depth).
const recheck = sanitizeOperations(action.operations);
if (!action.slug || recheck.validOps.length === 0) {
await addReaction('-1');
await postComment('❌ **PocketBase AI Bot**: The pending change is no longer valid. Please restate the request.');
return;
}
action.operations = recheck.validOps;
let result;
try { result = await applyOperations(action); }
catch (e) { await addReaction('-1'); await postComment('❌ **PocketBase AI Bot**: ' + e.message); return; }
if (!result.ok) { await addReaction('-1'); await postComment(result.summary); return; }
await updateComment(pendingComment.id, pendingComment.body.replace(PENDING_RE, '<!-- pocketbase-applied -->'));
await addReaction('+1');
await postComment(
'✅ **PocketBase AI Bot**: Applied to **`' + action.slug + '`**\n\n' + result.summary +
'\n\n*Confirmed by @' + actor + '*'
);
return;
}
// ── 5. New request: acknowledge, fetch script list, call the model ─
await addReaction('eyes');
const token0 = await pbAuth();
const scripts = [];
let page = 1;
while (page <= 5) {
const res = await request(recordsUrl + '?fields=slug,name&perPage=500&page=' + page, { headers: { 'Authorization': token0 } });
if (!res.ok) break;
const data = JSON.parse(res.body);
(data.items || []).forEach(function (it) { if (it.slug) scripts.push({ slug: it.slug, name: it.name || it.slug }); });
if (!data.items || data.items.length < 500) break;
page++;
}
const SYSTEM_PROMPT =
'You translate a maintainer\'s natural-language request into a STRICT JSON change-set for a ' +
'script catalog (PocketBase). Respond with a SINGLE JSON object and nothing else.\n\n' +
'Schema:\n' +
'{\n' +
' "slug": string|null, // MUST be one of the known slugs below, chosen from the request\n' +
' "operations": [ ... ], // [] if you cannot determine concrete changes\n' +
' "human_summary": string, // short plain-English description\n' +
' "clarification": string|null // a question to ask if ambiguous/unsupported; else null\n' +
'}\n\n' +
'Operation kinds:\n' +
'- {"kind":"field","field":<one of: ' + Object.keys(ALLOWED_FIELDS).join(', ') + '>,"value":<bool|number|string>}\n' +
' (booleans true/false; "is_disabled"/"is_deleted"/"is_dev" are booleans; "port"/"unprivileged" are numbers; rest strings.)\n' +
'- {"kind":"note","action":"add"|"edit"|"remove","type":string,"text":string,"newText":string?}\n' +
'- {"kind":"method","action":"add"|"edit"|"remove","type":string,"changes":{cpu?:number,ram?:number,hdd?:number,os?:string,version?:string,config_path?:string,script?:string}}\n' +
' (RAM/HDD are in MB/GB; method "type" defaults to "default" if the user does not name one.)\n\n' +
'Rules:\n' +
'- Only use fields/operations listed above. If the request needs something else, set clarification and operations=[].\n' +
'- "disable"/"enable" map to is_disabled true/false. If disabling and the user gave a reason, also set disable_message.\n' +
'- Resolve the target script to a slug from the list. If you cannot confidently match exactly one, set slug=null and ask via clarification.\n\n' +
'Known scripts (slug — name):\n' +
scripts.map(function (s) { return s.slug + ' — ' + s.name; }).join('\n');
const modelRes = await request('https://models.github.ai/inference/chat/completions', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + process.env.MODELS_TOKEN, 'Content-Type': 'application/json', 'Accept': 'application/json' },
body: JSON.stringify({
model: process.env.AI_MODEL || 'openai/gpt-4o',
temperature: 0.1,
response_format: { type: 'json_object' },
messages: [{ role: 'system', content: SYSTEM_PROMPT }, { role: 'user', content: instruction }]
})
});
if (!modelRes.ok) {
await addReaction('-1');
await postComment('❌ **PocketBase AI Bot**: Model request failed (' + modelRes.statusCode + ').\n```\n' + modelRes.body.slice(0, 500) + '\n```');
return;
}
let parsed;
try {
const content = JSON.parse(modelRes.body).choices[0].message.content;
const cleaned = content.replace(/^```(?:json)?\s*/i, '').replace(/```\s*$/i, '').trim();
parsed = JSON.parse(cleaned);
} catch (e) {
await addReaction('-1');
await postComment('❌ **PocketBase AI Bot**: Could not parse the model response. Please rephrase.');
return;
}
// ── 6. Validate ────────────────────────────────────────────────────
const knownSlugs = new Set(scripts.map(function (s) { return s.slug; }));
const problems = [];
if (parsed.clarification) problems.push(parsed.clarification);
if (!parsed.slug || !knownSlugs.has(parsed.slug)) problems.push('I could not match the request to a known script.');
const sanitized = sanitizeOperations(parsed.operations);
const validOps = sanitized.validOps;
problems.push.apply(problems, sanitized.problems);
if (validOps.length === 0) problems.push('No concrete, supported change was found.');
if (problems.length) {
await addReaction('confused');
await postComment(
'🤔 **PocketBase AI Bot**: I need a bit more to act on that.\n\n- ' + problems.join('\n- ') +
'\n\nTry naming the script and the exact change, e.g. `@pocketbase-bot set RAM to 4096 on zigbee2mqtt`.'
);
return;
}
// ── 7. Propose (do NOT apply yet) ──────────────────────────────────
const action = { slug: parsed.slug, operations: validOps };
const bullets = validOps.map(function (op) {
if (op.kind === 'field') return '- `' + op.field + '` → `' + JSON.stringify(op.value) + '`';
if (op.kind === 'note') return '- note ' + op.action + ' `' + op.type + '`' + (op.text ? ': ' + op.text : '');
return '- method ' + op.action + ' `' + op.type + '`: ' + JSON.stringify(op.changes);
}).join('\n');
const marker = '<!-- pocketbase-pending: ' + Buffer.from(JSON.stringify(action), 'utf8').toString('base64') + ' -->';
await addReaction('+1');
await postComment(
'🤖 **PocketBase AI Bot** — please confirm\n\n' +
(parsed.human_summary ? '> ' + parsed.human_summary + '\n\n' : '') +
'**Target:** `' + action.slug + '`\n**Proposed changes:**\n' + bullets + '\n\n' +
'Reply **`@pocketbase-bot confirm`** to apply, or restate the request to adjust.\n' + marker
);
})().catch(function (e) {
console.error('Fatal error:', e && (e.message || e));
process.exit(1);
});
ENDSCRIPT

24
.github/workflows/pocketbase-bot.yml generated vendored
View File

@@ -13,8 +13,8 @@ jobs:
pocketbase-bot: pocketbase-bot:
runs-on: self-hosted runs-on: self-hosted
# Only act on /pocketbase commands # Act on comments that contain a /pocketbase command line (precise line check happens in-script)
if: startsWith(github.event.comment.body, '/pocketbase') if: contains(github.event.comment.body, '/pocketbase')
steps: steps:
- name: Execute PocketBase bot command - name: Execute PocketBase bot command
@@ -257,6 +257,22 @@ jobs:
if (!res.ok) console.warn('Could not post comment:', res.body); if (!res.ok) console.warn('Could not post comment:', res.body);
} }
// ── Locate the command line ────────────────────────────────────────
// Accept /pocketbase at the start of ANY line (leading whitespace ok),
// so the command works even when preceded by other text. Mid-sentence
// mentions and blockquoted ("> ...") examples are ignored.
const commentBody = process.env.COMMENT_BODY || '';
const cmdLine = commentBody
.split('\n')
.map(l => l.trim())
.find(l => l.startsWith('/pocketbase'));
if (!cmdLine) {
console.log('No /pocketbase command line found — ignoring comment.');
process.exit(0);
}
const withoutCmd = cmdLine.replace(/^\/pocketbase\s*/, '').trim();
// ── Permission check ─────────────────────────────────────────────── // ── Permission check ───────────────────────────────────────────────
const association = process.env.ACTOR_ASSOCIATION; const association = process.env.ACTOR_ASSOCIATION;
if (association !== 'OWNER' && association !== 'MEMBER') { if (association !== 'OWNER' && association !== 'MEMBER') {
@@ -272,10 +288,6 @@ jobs:
await addReaction('eyes'); await addReaction('eyes');
// ── Parse command ────────────────────────────────────────────────── // ── Parse command ──────────────────────────────────────────────────
const commentBody = process.env.COMMENT_BODY || '';
const lines = commentBody.trim().split('\n');
const firstLine = lines[0].trim();
const withoutCmd = firstLine.replace(/^\/pocketbase\s+/, '').trim();
function extractCodeBlock(body) { function extractCodeBlock(body) {
const m = body.match(/```[^\n]*\n([\s\S]*?)```/); const m = body.match(/```[^\n]*\n([\s\S]*?)```/);

View File

@@ -56,6 +56,9 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
@@ -69,7 +72,7 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
<details> <details>
<summary><h4>May (23 entries)</h4></summary> <summary><h4>May (30 entries)</h4></summary>
[View May 2026 Changelog](.github/changelogs/2026/05.md) [View May 2026 Changelog](.github/changelogs/2026/05.md)
@@ -467,14 +470,124 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-06-02
### 🆕 New Scripts
- DDNS-Updater ([#14883](https://github.com/community-scripts/ProxmoxVE/pull/14883))
- InvoiceShelf ([#14882](https://github.com/community-scripts/ProxmoxVE/pull/14882))
- Certimate ([#14881](https://github.com/community-scripts/ProxmoxVE/pull/14881))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- OpenThread-BR: preserve config during update [@tomfrenzel](https://github.com/tomfrenzel) ([#14893](https://github.com/community-scripts/ProxmoxVE/pull/14893))
- infisical: fix update abort due to creds field mismatch (#14868) [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14870](https://github.com/community-scripts/ProxmoxVE/pull/14870))
- #### ✨ New Features
- feat(degoog): enable default valkey cache integration [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14871](https://github.com/community-scripts/ProxmoxVE/pull/14871))
- #### 🔧 Refactor
- chore: bump Node version in selected scripts [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14873](https://github.com/community-scripts/ProxmoxVE/pull/14873))
### 💾 Core
- #### ✨ New Features
- tools.func: add support for Rust installation profile in setup_rust [@MickLesk](https://github.com/MickLesk) ([#14872](https://github.com/community-scripts/ProxmoxVE/pull/14872))
### 📂 Github
- fix(workflow): only flag node drift when local is behind upstream [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14874](https://github.com/community-scripts/ProxmoxVE/pull/14874))
## 2026-06-01
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix(dispatcharr): forward nginx port for M3U URLs on new installs [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14862](https://github.com/community-scripts/ProxmoxVE/pull/14862))
- Set environment paths in service for apprise-api-install.sh [@SystemIdleProcess](https://github.com/SystemIdleProcess) ([#14805](https://github.com/community-scripts/ProxmoxVE/pull/14805))
- fix(fireshare): rebuild client on update to fix nginx 500 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14848](https://github.com/community-scripts/ProxmoxVE/pull/14848))
- Fix Kan build failure (TS7016 nodemailer) [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14856](https://github.com/community-scripts/ProxmoxVE/pull/14856))
- fix(firefly): set Data Importer APP_URL for subdirectory install [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14847](https://github.com/community-scripts/ProxmoxVE/pull/14847))
- kan: extend fetch_and_deploy_gh_tag to use 'latest' tag [@MickLesk](https://github.com/MickLesk) ([#14853](https://github.com/community-scripts/ProxmoxVE/pull/14853))
- Glance: preserve glance.yml across updates [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#14845](https://github.com/community-scripts/ProxmoxVE/pull/14845))
- NginxProxymanager: set Certbot version in npm.service environment variable (2.15.0) [@MickLesk](https://github.com/MickLesk) ([#14843](https://github.com/community-scripts/ProxmoxVE/pull/14843))
- [FileFlows] Fix service handling by using systemctl --all with quoted glob [@adrianmusante](https://github.com/adrianmusante) ([#14838](https://github.com/community-scripts/ProxmoxVE/pull/14838))
- #### ✨ New Features
- Kometa: also update Quickstart in update_script [@MickLesk](https://github.com/MickLesk) ([#14529](https://github.com/community-scripts/ProxmoxVE/pull/14529))
## 2026-05-31
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Manyfold: regenerate Rails credentials on update to fix encryption mimatch [@MickLesk](https://github.com/MickLesk) ([#14817](https://github.com/community-scripts/ProxmoxVE/pull/14817))
- OpenThread-BR: use correct ipv6 configuration [@tomfrenzel](https://github.com/tomfrenzel) ([#14829](https://github.com/community-scripts/ProxmoxVE/pull/14829))
- #### 🔧 Refactor
- Webtrees: use PHP CLI for initial setup instead of curl to setup wizard [@MickLesk](https://github.com/MickLesk) ([#14818](https://github.com/community-scripts/ProxmoxVE/pull/14818))
- Kima-Hub: use curl_with_retry for ML model downloads to fix possible timeout issues [@MickLesk](https://github.com/MickLesk) ([#14816](https://github.com/community-scripts/ProxmoxVE/pull/14816))
### 🧰 Tools
- #### 🔧 Refactor
- PBS4-Upgrade: update current PBS3 packages before switching to Trixie repos [@MickLesk](https://github.com/MickLesk) ([#14815](https://github.com/community-scripts/ProxmoxVE/pull/14815))
## 2026-05-30
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Flatnotes: fix empty package name in pyproject.toml [@MickLesk](https://github.com/MickLesk) ([#14814](https://github.com/community-scripts/ProxmoxVE/pull/14814))
## 2026-05-29
### 🆕 New Scripts
- Kan ([#14776](https://github.com/community-scripts/ProxmoxVE/pull/14776))
- Dynacat ([#14777](https://github.com/community-scripts/ProxmoxVE/pull/14777))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Fix lobehub docker path [@dannyyy](https://github.com/dannyyy) ([#14793](https://github.com/community-scripts/ProxmoxVE/pull/14793))
- karakeep: add more hdd space [@MickLesk](https://github.com/MickLesk) ([#14797](https://github.com/community-scripts/ProxmoxVE/pull/14797))
- Grist: Revert installation of EE [@tremor021](https://github.com/tremor021) ([#14784](https://github.com/community-scripts/ProxmoxVE/pull/14784))
- #### 🔧 Refactor
- Sure: Remove `$STD` for `systemctl enable -q` [@tremor021](https://github.com/tremor021) ([#14801](https://github.com/community-scripts/ProxmoxVE/pull/14801))
## 2026-05-28 ## 2026-05-28
### 🚀 Updated Scripts ### 🚀 Updated Scripts
- #### 🐞 Bug Fixes - #### 🐞 Bug Fixes
- RomM: remove nginx default.conf during installation [@MickLesk](https://github.com/MickLesk) ([#14766](https://github.com/community-scripts/ProxmoxVE/pull/14766))
- Open-Archiver: replace pnpm approve-builds --yes with --all [@MickLesk](https://github.com/MickLesk) ([#14765](https://github.com/community-scripts/ProxmoxVE/pull/14765))
- fix(hermesagent): set npm_config_yes=true to suppress interactive pro… [@steveonjava](https://github.com/steveonjava) ([#14763](https://github.com/community-scripts/ProxmoxVE/pull/14763)) - fix(hermesagent): set npm_config_yes=true to suppress interactive pro… [@steveonjava](https://github.com/steveonjava) ([#14763](https://github.com/community-scripts/ProxmoxVE/pull/14763))
- #### 🔧 Refactor
- Yamtrack: migrate to uv [@MickLesk](https://github.com/MickLesk) ([#14767](https://github.com/community-scripts/ProxmoxVE/pull/14767))
### ❔ Uncategorized
- chore(ct): sync adventurelog defaults with PocketBase [@github-actions[bot]](https://github.com/github-actions[bot]) ([#14772](https://github.com/community-scripts/ProxmoxVE/pull/14772))
## 2026-05-27 ## 2026-05-27
### 🆕 New Scripts ### 🆕 New Scripts
@@ -992,141 +1105,3 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- #### 🔧 Refactor - #### 🔧 Refactor
- Mail-Archiver: update dependencies [@tremor021](https://github.com/tremor021) ([#14152](https://github.com/community-scripts/ProxmoxVE/pull/14152)) - Mail-Archiver: update dependencies [@tremor021](https://github.com/tremor021) ([#14152](https://github.com/community-scripts/ProxmoxVE/pull/14152))
## 2026-04-30
### 🆕 New Scripts
- Nagios ([#14126](https://github.com/community-scripts/ProxmoxVE/pull/14126))
- Neko ([#14121](https://github.com/community-scripts/ProxmoxVE/pull/14121))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- alpine-docker: install openssl as core dependency | alpine-komodo: check & install openssl if missing [@MickLesk](https://github.com/MickLesk) ([#14134](https://github.com/community-scripts/ProxmoxVE/pull/14134))
- endurain: update source references to Codeberg [@MickLesk](https://github.com/MickLesk) ([#14128](https://github.com/community-scripts/ProxmoxVE/pull/14128))
### 💾 Core
- #### 🔧 Refactor
- tools.func: Manage minor versions for MongoDB 8.x [@tremor021](https://github.com/tremor021) ([#14131](https://github.com/community-scripts/ProxmoxVE/pull/14131))
## 2026-04-29
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- GrayLog: MongoDB update to 8.2.x [@tremor021](https://github.com/tremor021) ([#14114](https://github.com/community-scripts/ProxmoxVE/pull/14114))
- Graylog: Better information in the log file [@tremor021](https://github.com/tremor021) ([#14110](https://github.com/community-scripts/ProxmoxVE/pull/14110))
- #### 🔧 Refactor
- Refactor: checkMK [@MickLesk](https://github.com/MickLesk) ([#14105](https://github.com/community-scripts/ProxmoxVE/pull/14105))
- PatchMon: Unpin release [@tremor021](https://github.com/tremor021) ([#14097](https://github.com/community-scripts/ProxmoxVE/pull/14097))
### 💾 Core
- #### 🔧 Refactor
- core: add guidance when storage lacks rootdir support [@MickLesk](https://github.com/MickLesk) ([#14108](https://github.com/community-scripts/ProxmoxVE/pull/14108))
## 2026-04-28
### 🆕 New Scripts
- StoryBook ([#14081](https://github.com/community-scripts/ProxmoxVE/pull/14081))
- CoreDNS ([#14082](https://github.com/community-scripts/ProxmoxVE/pull/14082))
### 🚀 Updated Scripts
- Fix Dawarich Install/Update [@Jerry1098](https://github.com/Jerry1098) ([#14078](https://github.com/community-scripts/ProxmoxVE/pull/14078))
- #### ✨ New Features
- PatchMon Version 2.0.2 Script update [@9technologygroup](https://github.com/9technologygroup) ([#14095](https://github.com/community-scripts/ProxmoxVE/pull/14095))
## 2026-04-27
### 🚀 Updated Scripts
- Add pamUsername column to userOrgs table [@JVKeller](https://github.com/JVKeller) ([#14075](https://github.com/community-scripts/ProxmoxVE/pull/14075))
- #### 🐞 Bug Fixes
- Dawarich: run db:migrate before assets:precompile [@MickLesk](https://github.com/MickLesk) ([#14051](https://github.com/community-scripts/ProxmoxVE/pull/14051))
- TechnitiumDNS: always install .NET 10 if not already present [@MickLesk](https://github.com/MickLesk) ([#14049](https://github.com/community-scripts/ProxmoxVE/pull/14049))
- #### 💥 Breaking Changes
- PatchMon: v2.0.0 migration [@vhsdream](https://github.com/vhsdream) ([#14015](https://github.com/community-scripts/ProxmoxVE/pull/14015))
### 💾 Core
- #### 🔧 Refactor
- Update build.func - fixed spelling mistake [@m1ckywill](https://github.com/m1ckywill) ([#14047](https://github.com/community-scripts/ProxmoxVE/pull/14047))
### 🧰 Tools
- #### 🐞 Bug Fixes
- update-lxcs/apps: avoid pct exec on containers mid-shutdown [@MickLesk](https://github.com/MickLesk) ([#14050](https://github.com/community-scripts/ProxmoxVE/pull/14050))
- #### ✨ New Features
- Add patchmon-agent report execution in update script [@heinemannj](https://github.com/heinemannj) ([#14054](https://github.com/community-scripts/ProxmoxVE/pull/14054))
## 2026-04-26
### 🆕 New Scripts
- TREK ([#14017](https://github.com/community-scripts/ProxmoxVE/pull/14017))
### 🚀 Updated Scripts
- fix(2fauth): handle stale backup directory on update [@omertahaoztop](https://github.com/omertahaoztop) ([#14018](https://github.com/community-scripts/ProxmoxVE/pull/14018))
- #### 🐞 Bug Fixes
- Increase Frigate default CPU cores from 4 to 8 [@MickLesk](https://github.com/MickLesk) ([#14039](https://github.com/community-scripts/ProxmoxVE/pull/14039))
- Technitium DNS: Ensure directories exist before running service [@tremor021](https://github.com/tremor021) ([#14030](https://github.com/community-scripts/ProxmoxVE/pull/14030))
### 💾 Core
- #### 🐞 Bug Fixes
- core: Correct deb822 repository flat path detection [@MickLesk](https://github.com/MickLesk) ([#14037](https://github.com/community-scripts/ProxmoxVE/pull/14037))
## 2026-04-25
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- VictoriaMetrics: Stop vmagent/vmalert before update [@irishpadres](https://github.com/irishpadres) ([#14016](https://github.com/community-scripts/ProxmoxVE/pull/14016))
- Domain-Monitor: start apache2 after stop instead of reload [@omertahaoztop](https://github.com/omertahaoztop) ([#14019](https://github.com/community-scripts/ProxmoxVE/pull/14019))
- Transmute: Fix ffmpeg detection [@tremor021](https://github.com/tremor021) ([#14008](https://github.com/community-scripts/ProxmoxVE/pull/14008))
- #### 🔧 Refactor
- Refactor: Technitium DNS [@tremor021](https://github.com/tremor021) ([#14013](https://github.com/community-scripts/ProxmoxVE/pull/14013))
## 2026-04-24
### 🆕 New Scripts
- Apprise-API ([#13934](https://github.com/community-scripts/ProxmoxVE/pull/13934))
- fireshare ([#13995](https://github.com/community-scripts/ProxmoxVE/pull/13995))
- Transmute ([#13935](https://github.com/community-scripts/ProxmoxVE/pull/13935))
- Jitsi-Meet ([#13897](https://github.com/community-scripts/ProxmoxVE/pull/13897))
### 🚀 Updated Scripts
- Update wger.sh [@Soppster1029](https://github.com/Soppster1029) ([#13977](https://github.com/community-scripts/ProxmoxVE/pull/13977))
- #### 🔧 Refactor
- Refactor: Ghostfolio [@MickLesk](https://github.com/MickLesk) ([#13990](https://github.com/community-scripts/ProxmoxVE/pull/13990))

View File

@@ -9,7 +9,7 @@ APP="AdventureLog"
var_tags="${var_tags:-traveling}" var_tags="${var_tags:-traveling}"
var_disk="${var_disk:-7}" var_disk="${var_disk:-7}"
var_cpu="${var_cpu:-2}" var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}" var_ram="${var_ram:-4096}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-13}" var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}" var_arm64="${var_arm64:-no}"

64
ct/certimate.sh Normal file
View File

@@ -0,0 +1,64 @@
#!/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://certimate.me/
APP="Certimate"
var_tags="${var_tags:-ssl;certificates;acme;automation}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-256}"
var_disk="${var_disk:-2}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /opt/certimate/certimate ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "certimate" "certimate-go/certimate"; then
msg_info "Stopping Service"
systemctl stop certimate
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp -r /opt/certimate/pb_data /opt/certimate_pb_data_backup
msg_ok "Backed up Data"
fetch_and_deploy_gh_release "certimate" "certimate-go/certimate" "prebuild" "latest" "/opt/certimate" "certimate_*_linux_amd64.zip"
msg_info "Restoring Data"
cp -r /opt/certimate_pb_data_backup/. /opt/certimate/pb_data
rm -rf /opt/certimate_pb_data_backup
msg_ok "Restored Data"
msg_info "Starting Service"
systemctl start certimate
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}:8090${CL}"

View File

@@ -25,7 +25,7 @@ function update_script() {
check_container_storage check_container_storage
check_container_resources check_container_resources
NODE_VERSION="24" setup_nodejs NODE_VERSION="26" setup_nodejs
ensure_dependencies build-essential ensure_dependencies build-essential
if command -v cross-seed &>/dev/null; then if command -v cross-seed &>/dev/null; then

62
ct/ddns-updater.sh Normal file
View File

@@ -0,0 +1,62 @@
#!/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: reptil1990
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/qdm12/ddns-updater
APP="DDNS-Updater"
var_tags="${var_tags:-network}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-2}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
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/ddns-updater ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "ddns-updater" "qdm12/ddns-updater"; then
msg_info "Stopping Service"
systemctl stop ddns-updater
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp -r /opt/ddns-updater/data /opt/ddns-updater_data_backup
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "ddns-updater" "qdm12/ddns-updater" "singlefile" "latest" "/opt/ddns-updater" "ddns-updater_*_linux_amd64"
msg_info "Restoring Data"
cp -r /opt/ddns-updater_data_backup/. /opt/ddns-updater/data/
rm -rf /opt/ddns-updater_data_backup
msg_ok "Restored Data"
msg_info "Starting Service"
systemctl start ddns-updater
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}:8000${CL}"

View File

@@ -49,11 +49,21 @@ function update_script() {
msg_ok "Installed Bun" msg_ok "Installed Bun"
fi fi
msg_info "Updating Valkey"
ensure_dependencies valkey
msg_ok "Updated Valkey"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "degoog" "fccview/degoog" "prebuild" "latest" "/opt/degoog" "degoog_*_prebuild.tar.gz"
msg_info "Restoring Configuration & Data" msg_info "Restoring Configuration & Data"
[[ -f /opt/degoog.env.bak ]] && mv /opt/degoog.env.bak /opt/degoog/.env [[ -f /opt/degoog.env.bak ]] && mv /opt/degoog.env.bak /opt/degoog/.env
[[ -d /opt/degoog_data_backup ]] && mv /opt/degoog_data_backup /opt/degoog/data [[ -d /opt/degoog_data_backup ]] && mv /opt/degoog_data_backup /opt/degoog/data
if [[ -f /opt/degoog/.env ]]; then
grep -q "^DEGOOG_VALKEY_URL=" /opt/degoog/.env && sed -i "s|^DEGOOG_VALKEY_URL=.*|DEGOOG_VALKEY_URL=redis://valkey:6379|" /opt/degoog/.env || echo "DEGOOG_VALKEY_URL=redis://valkey:6379" >>/opt/degoog/.env
grep -q "^DEGOOG_CACHE_MAX_ENTRIES=" /opt/degoog/.env && sed -i "s|^DEGOOG_CACHE_MAX_ENTRIES=.*|DEGOOG_CACHE_MAX_ENTRIES=1000|" /opt/degoog/.env || echo "DEGOOG_CACHE_MAX_ENTRIES=1000" >>/opt/degoog/.env
grep -q "^DEGOOG_CACHE_TTL_MS=" /opt/degoog/.env && sed -i "s|^DEGOOG_CACHE_TTL_MS=.*|DEGOOG_CACHE_TTL_MS=43200000|" /opt/degoog/.env || echo "DEGOOG_CACHE_TTL_MS=43200000" >>/opt/degoog/.env
fi
msg_ok "Restored Configuration & Data" msg_ok "Restored Configuration & Data"
msg_info "Starting Service" msg_info "Starting Service"

69
ct/dynacat.sh Normal file
View File

@@ -0,0 +1,69 @@
#!/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/Panonim/dynacat
APP="Dynacat"
var_tags="${var_tags:-dashboard;homepage;monitoring}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-6}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /opt/dynacat/dynacat ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "dynacat" "Panonim/dynacat"; then
msg_info "Stopping Service"
systemctl stop dynacat
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp -r /opt/dynacat/config /opt/dynacat_config_backup
cp -r /opt/dynacat/assets /opt/dynacat_assets_backup
cp -r /opt/dynacat/data /opt/dynacat_data_backup
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "dynacat" "Panonim/dynacat" "prebuild" "latest" "/opt/dynacat" "dynacat-linux-amd64.tar.gz"
msg_info "Restoring Data"
cp -r /opt/dynacat_config_backup/. /opt/dynacat/config
cp -r /opt/dynacat_assets_backup/. /opt/dynacat/assets
cp -r /opt/dynacat_data_backup/. /opt/dynacat/data
rm -rf /opt/dynacat_config_backup /opt/dynacat_assets_backup /opt/dynacat_data_backup
chmod +x /opt/dynacat/dynacat
msg_ok "Restored Data"
msg_info "Starting Service"
systemctl start dynacat
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}:8080${CL}"

View File

@@ -34,7 +34,7 @@ function update_script() {
update_available=$(curl -fsSL -X 'GET' "http://localhost:19200/api/status/update-available" -H 'accept: application/json' | jq .UpdateAvailable) update_available=$(curl -fsSL -X 'GET' "http://localhost:19200/api/status/update-available" -H 'accept: application/json' | jq .UpdateAvailable)
if [[ "${update_available}" == "true" ]]; then if [[ "${update_available}" == "true" ]]; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop fileflows* systemctl --all stop 'fileflows*'
msg_info "Stopped Service" msg_info "Stopped Service"
msg_info "Creating Backup" msg_info "Creating Backup"
@@ -46,7 +46,7 @@ function update_script() {
fetch_and_deploy_from_url "https://fileflows.com/downloads/zip" "/opt/fileflows" fetch_and_deploy_from_url "https://fileflows.com/downloads/zip" "/opt/fileflows"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start fileflows* systemctl --all start 'fileflows*'
msg_ok "Started Service" msg_ok "Started Service"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
else else

View File

@@ -53,6 +53,12 @@ function update_script() {
export VIDEO_DIRECTORY=/opt/fireshare-videos export VIDEO_DIRECTORY=/opt/fireshare-videos
export PROCESSED_DIRECTORY=/opt/fireshare-processed export PROCESSED_DIRECTORY=/opt/fireshare-processed
$STD uv run flask db upgrade $STD uv run flask db upgrade
msg_info "Building Fireshare Client"
cd /opt/fireshare/app/client
$STD npm install
$STD npm run build
msg_ok "Built Fireshare Client"
msg_ok "Updated Fireshare" msg_ok "Updated Fireshare"
msg_info "Starting Service" msg_info "Starting Service"

View File

@@ -47,6 +47,7 @@ function update_script() {
$STD npm run build $STD npm run build
cd /opt/flatnotes cd /opt/flatnotes
rm -f uv.lock rm -f uv.lock
sed -i 's/^name = ""$/name = "flatnotes"/' pyproject.toml
$STD /usr/local/bin/uvx migrate-to-uv $STD /usr/local/bin/uvx migrate-to-uv
$STD /usr/local/bin/uv sync $STD /usr/local/bin/uv sync
msg_ok "Updated Flatnotes" msg_ok "Updated Flatnotes"

View File

@@ -34,8 +34,20 @@ function update_script() {
systemctl stop glance systemctl stop glance
msg_ok "Stopped Service" msg_ok "Stopped Service"
if [[ -f /opt/glance/glance.yml ]]; then
msg_info "Backing up glance.yml"
cp /opt/glance/glance.yml /tmp/glance.yml.bak
msg_ok "Backed up glance.yml"
fi
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "glance" "glanceapp/glance" "prebuild" "latest" "/opt/glance" "glance-linux-amd64.tar.gz" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "glance" "glanceapp/glance" "prebuild" "latest" "/opt/glance" "glance-linux-amd64.tar.gz"
if [[ -f /tmp/glance.yml.bak ]]; then
msg_info "Restoring glance.yml"
mv /tmp/glance.yml.bak /opt/glance/glance.yml
msg_ok "Restored glance.yml"
fi
msg_info "Starting Service" msg_info "Starting Service"
systemctl start glance systemctl start glance
msg_ok "Started Service" msg_ok "Started Service"

View File

@@ -54,7 +54,6 @@ function update_script() {
[[ -f /opt/grist_bak/landing.db ]] && cp /opt/grist_bak/landing.db /opt/grist/landing.db [[ -f /opt/grist_bak/landing.db ]] && cp /opt/grist_bak/landing.db /opt/grist/landing.db
cd /opt/grist cd /opt/grist
$STD yarn install $STD yarn install
$STD yarn run install:ee -y
$STD yarn run build:prod $STD yarn run build:prod
$STD yarn run install:python $STD yarn run install:python
msg_ok "Updated Grist" msg_ok "Updated Grist"

6
ct/headers/certimate Normal file
View File

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

6
ct/headers/ddns-updater Normal file
View File

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

6
ct/headers/dynacat Normal file
View File

@@ -0,0 +1,6 @@
____ __
/ __ \__ ______ ____ __________ _/ /_
/ / / / / / / __ \/ __ `/ ___/ __ `/ __/
/ /_/ / /_/ / / / / /_/ / /__/ /_/ / /_
/_____/\__, /_/ /_/\__,_/\___/\__,_/\__/
/____/

6
ct/headers/invoiceshelf Normal file
View File

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

6
ct/headers/kan Normal file
View File

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

View File

@@ -35,7 +35,7 @@ function update_script() {
msg_info "Creating backup" msg_info "Creating backup"
[[ -f /opt/infisical_backup.sql ]] && rm -f /opt/infisical_backup.sql [[ -f /opt/infisical_backup.sql ]] && rm -f /opt/infisical_backup.sql
DB_PASS=$(grep -Po '(?<=^Database Password:\s).*' ~/infisical.creds | head -n1) DB_PASS=$(grep -Po '(?<=^Password:\s).*' ~/infisical.creds | head -n1)
PGPASSWORD=$DB_PASS pg_dump -U infisical -h localhost -d infisical_db > /opt/infisical_backup.sql PGPASSWORD=$DB_PASS pg_dump -U infisical -h localhost -d infisical_db > /opt/infisical_backup.sql
msg_ok "Created backup" msg_ok "Created backup"

77
ct/invoiceshelf.sh Normal file
View File

@@ -0,0 +1,77 @@
#!/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://invoiceshelf.com/
APP="InvoiceShelf"
var_tags="${var_tags:-invoicing;finance;business}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-1024}"
var_disk="${var_disk:-4}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
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/invoiceshelf ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "invoiceshelf" "InvoiceShelf/InvoiceShelf"; then
msg_info "Stopping Services"
systemctl stop caddy
msg_ok "Stopped Services"
msg_info "Backing up Data"
cp /opt/invoiceshelf/.env /opt/invoiceshelf.env.bak
cp -r /opt/invoiceshelf/storage /opt/invoiceshelf_storage_backup
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "invoiceshelf" "InvoiceShelf/InvoiceShelf" "tarball"
msg_info "Restoring Data"
cp /opt/invoiceshelf.env.bak /opt/invoiceshelf/.env
rm -f /opt/invoiceshelf.env.bak
cp -r /opt/invoiceshelf_storage_backup/. /opt/invoiceshelf/storage
rm -rf /opt/invoiceshelf_storage_backup
msg_ok "Restored Data"
msg_info "Updating Application"
cd /opt/invoiceshelf
$STD composer install --no-dev --optimize-autoloader
$STD yarn install
$STD yarn build
$STD php artisan migrate --force
$STD php artisan optimize:clear
chown -R www-data:www-data /opt/invoiceshelf
msg_ok "Updated Application"
msg_info "Starting Services"
systemctl start caddy
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}${CL}"

86
ct/kan.sh Normal file
View File

@@ -0,0 +1,86 @@
#!/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/kanbn/kan
APP="Kan"
var_tags="${var_tags:-project-management;kanban}"
var_cpu="${var_cpu:-4}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-12}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}"
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/kan ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_tag "kan" "kanbn/kan"; then
msg_info "Stopping Service"
systemctl stop kan
msg_ok "Stopped Service"
msg_info "Backing up Data"
cp /opt/kan/.env /opt/kan.env.bak
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_tag "kan" "kanbn/kan" "latest"
msg_info "Restoring Configuration"
cp /opt/kan.env.bak /opt/kan/.env
rm -f /opt/kan.env.bak
msg_ok "Restored Configuration"
msg_info "Building Application"
cd /opt/kan
set -a && source /opt/kan/.env && set +a
export NEXT_PUBLIC_USE_STANDALONE_OUTPUT=true
$STD pnpm install --ignore-scripts --prod=false
export CI=true
find /opt/kan/packages /opt/kan/apps -name 'tsconfig.json' -exec sed -i 's|"@kan/tsconfig/|"../../tooling/typescript/|g' {} +
$STD pnpm build --filter=@kan/web
unset NEXT_PUBLIC_USE_STANDALONE_OUTPUT CI
msg_ok "Built Application"
msg_info "Setting up Standalone"
mkdir -p /opt/kan/apps/web/.next/standalone/apps/web/.next/static
cp -r /opt/kan/apps/web/.next/static/* /opt/kan/apps/web/.next/standalone/apps/web/.next/static/
cp -r /opt/kan/apps/web/public /opt/kan/apps/web/.next/standalone/apps/web/public
msg_ok "Set up Standalone"
msg_info "Running Database Migrations"
cd /opt/kan/packages/db
$STD pnpm exec drizzle-kit migrate
msg_ok "Ran Database Migrations"
msg_info "Starting Service"
systemctl start kan
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}:3000${CL}"

View File

@@ -9,7 +9,7 @@ APP="karakeep"
var_tags="${var_tags:-bookmark}" var_tags="${var_tags:-bookmark}"
var_cpu="${var_cpu:-2}" var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}" var_ram="${var_ram:-4096}"
var_disk="${var_disk:-10}" var_disk="${var_disk:-15}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-13}" var_version="${var_version:-13}"
var_arm64="${var_arm64:-no}" var_arm64="${var_arm64:-no}"

View File

@@ -53,7 +53,7 @@ function update_script() {
[[ -s /opt/koillection/.env.local && -n "$(tail -c 1 /opt/koillection/.env.local)" ]] && echo "" >>/opt/koillection/.env.local [[ -s /opt/koillection/.env.local && -n "$(tail -c 1 /opt/koillection/.env.local)" ]] && echo "" >>/opt/koillection/.env.local
echo 'APP_RUNTIME="Symfony\Component\Runtime\SymfonyRuntime"' >>/opt/koillection/.env.local echo 'APP_RUNTIME="Symfony\Component\Runtime\SymfonyRuntime"' >>/opt/koillection/.env.local
fi fi
NODE_VERSION="26" NODE_MODULE="yarn" setup_nodejs
export COMPOSER_ALLOW_SUPERUSER=1 export COMPOSER_ALLOW_SUPERUSER=1
export APP_RUNTIME='Symfony\Component\Runtime\SymfonyRuntime' export APP_RUNTIME='Symfony\Component\Runtime\SymfonyRuntime'
$STD composer install --no-dev -o --no-interaction --classmap-authoritative $STD composer install --no-dev -o --no-interaction --classmap-authoritative

View File

@@ -32,6 +32,7 @@ function update_script() {
if check_for_gh_release "kometa" "Kometa-Team/Kometa"; then if check_for_gh_release "kometa" "Kometa-Team/Kometa"; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop kometa systemctl stop kometa
[[ -d "/opt/kometa-quickstart" ]] && systemctl stop kometa-quickstart
msg_ok "Stopped Service" msg_ok "Stopped Service"
msg_info "Backing up data" msg_info "Backing up data"
@@ -50,9 +51,28 @@ function update_script() {
msg_info "Starting Service" msg_info "Starting Service"
systemctl start kometa systemctl start kometa
[[ -d "/opt/kometa-quickstart" ]] && systemctl start kometa-quickstart
msg_ok "Started Service" msg_ok "Started Service"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
if [[ -d "/opt/kometa-quickstart" ]] && check_for_gh_release "kometa-quickstart" "Kometa-Team/Quickstart"; then
msg_info "Stopping Quickstart Service"
systemctl stop kometa-quickstart
msg_ok "Stopped Quickstart Service"
fetch_and_deploy_gh_release "kometa-quickstart" "Kometa-Team/Quickstart" "tarball"
msg_info "Updating Kometa Quickstart"
cd /opt/kometa-quickstart
$STD uv pip install -r requirements.txt -p /opt/kometa-quickstart/.venv/bin/python
msg_ok "Updated Kometa Quickstart"
msg_info "Starting Quickstart Service"
systemctl start kometa-quickstart
msg_ok "Started Quickstart Service"
msg_ok "Updated Quickstart successfully!"
fi
exit exit
} }

View File

@@ -54,6 +54,13 @@ function update_script() {
unset NODE_OPTIONS unset NODE_OPTIONS
msg_ok "Built Application" msg_ok "Built Application"
msg_info "Setting Up Standalone"
cp -r /opt/lobehub/.next/static /opt/lobehub/.next/standalone/.next/static
cp -r /opt/lobehub/public /opt/lobehub/.next/standalone/public
cp -r /opt/lobehub/scripts/migrateServerDB/* /opt/lobehub/.next/standalone/
cp -r /opt/lobehub/packages/database/migrations /opt/lobehub/.next/standalone/migrations
msg_ok "Set Up Standalone"
msg_info "Running Database Migrations" msg_info "Running Database Migrations"
cd /opt/lobehub cd /opt/lobehub
set -a && source /opt/lobehub/.env && set +a set -a && source /opt/lobehub/.env && set +a

View File

@@ -40,8 +40,6 @@ function update_script() {
CURRENT_VERSION=$(grep -oP 'APP_VERSION=\K[^ ]+' /opt/manyfold/.env || echo "unknown") CURRENT_VERSION=$(grep -oP 'APP_VERSION=\K[^ ]+' /opt/manyfold/.env || echo "unknown")
cp -r /opt/manyfold/app/storage /opt/manyfold_storage_backup 2>/dev/null || true cp -r /opt/manyfold/app/storage /opt/manyfold_storage_backup 2>/dev/null || true
cp -r /opt/manyfold/app/tmp /opt/manyfold_tmp_backup 2>/dev/null || true cp -r /opt/manyfold/app/tmp /opt/manyfold_tmp_backup 2>/dev/null || true
cp /opt/manyfold/app/config/credentials.yml.enc /opt/manyfold_credentials.yml.enc 2>/dev/null || true
cp /opt/manyfold/app/config/master.key /opt/manyfold_master.key 2>/dev/null || true
$STD tar -czf "/opt/manyfold_${CURRENT_VERSION}_backup.tar.gz" -C /opt/manyfold app $STD tar -czf "/opt/manyfold_${CURRENT_VERSION}_backup.tar.gz" -C /opt/manyfold app
msg_ok "Backed up Data" msg_ok "Backed up Data"
@@ -57,14 +55,12 @@ function update_script() {
RUBY_VERSION=${RUBY_INSTALL_VERSION} RUBY_INSTALL_RAILS="true" HOME=/home/manyfold setup_ruby RUBY_VERSION=${RUBY_INSTALL_VERSION} RUBY_INSTALL_RAILS="true" HOME=/home/manyfold setup_ruby
msg_info "Restoring Data" msg_info "Restoring Data"
rm -rf /opt/manyfold/app/{storage,tmp,config/credentials.yml.enc,config/master.key} rm -rf /opt/manyfold/app/{storage,tmp}
cp -r /opt/manyfold_storage_backup /opt/manyfold/app/storage 2>/dev/null || true cp -r /opt/manyfold_storage_backup /opt/manyfold/app/storage 2>/dev/null || true
cp -r /opt/manyfold_tmp_backup /opt/manyfold/app/tmp 2>/dev/null || true cp -r /opt/manyfold_tmp_backup /opt/manyfold/app/tmp 2>/dev/null || true
cp /opt/manyfold_credentials.yml.enc /opt/manyfold/app/config/credentials.yml.enc 2>/dev/null || true
cp /opt/manyfold_master.key /opt/manyfold/app/config/master.key 2>/dev/null || true
chown -R manyfold:manyfold {/home/manyfold,/opt/manyfold} chown -R manyfold:manyfold {/home/manyfold,/opt/manyfold}
chown -R manyfold:manyfold /opt/manyfold/app/storage /opt/manyfold/app/tmp /opt/manyfold/app/config chown -R manyfold:manyfold /opt/manyfold/app/storage /opt/manyfold/app/tmp /opt/manyfold/app/config
rm -rf /opt/manyfold_storage_backup /opt/manyfold_tmp_backup /opt/manyfold_credentials.yml.enc /opt/manyfold_master.key rm -rf /opt/manyfold_storage_backup /opt/manyfold_tmp_backup
msg_ok "Restored Data" msg_ok "Restored Data"
msg_info "Installing Manyfold" msg_info "Installing Manyfold"
@@ -80,6 +76,8 @@ function update_script() {
bundle install bundle install
corepack prepare '"$YARN_VERSION"' --activate corepack prepare '"$YARN_VERSION"' --activate
corepack use '"$YARN_VERSION"' corepack use '"$YARN_VERSION"'
rm -f config/credentials.yml.enc config/master.key
EDITOR=/bin/true bin/rails credentials:edit
bin/rails db:migrate bin/rails db:migrate
bin/rails assets:precompile bin/rails assets:precompile
' '

View File

@@ -42,7 +42,7 @@ function update_script() {
PYTHON_VERSION="3.13" setup_uv PYTHON_VERSION="3.13" setup_uv
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "musicseerr" "HabiRabbu/Musicseerr" "tarball" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "musicseerr" "HabiRabbu/Musicseerr" "tarball"
NODE_VERSION="22" NODE_MODULE="pnpm@10.33.0" setup_nodejs NODE_VERSION="25" NODE_MODULE="pnpm@10.33.0" setup_nodejs
msg_info "Building Frontend" msg_info "Building Frontend"
cd /opt/musicseerr/frontend cd /opt/musicseerr/frontend

View File

@@ -216,6 +216,12 @@ EOF
msg_ok "Initialized Backend" msg_ok "Initialized Backend"
msg_info "Starting Services" msg_info "Starting Services"
CERTBOT_VER=$(/opt/certbot/bin/certbot --version 2>&1 | awk '{print $NF}')
if grep -q "Environment=CERTBOT_VERSION" /lib/systemd/system/npm.service; then
sed -i "s|Environment=CERTBOT_VERSION=.*|Environment=CERTBOT_VERSION=${CERTBOT_VER}|" /lib/systemd/system/npm.service
else
sed -i "/Environment=NODE_ENV=production/a Environment=CERTBOT_VERSION=${CERTBOT_VER}" /lib/systemd/system/npm.service
fi
sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf sed -i 's/user npm/user root/g; s/^pid/#pid/g' /usr/local/openresty/nginx/conf/nginx.conf
sed -r -i 's/^([[:space:]]*)su npm npm/\1#su npm npm/g;' /etc/logrotate.d/nginx-proxy-manager sed -r -i 's/^([[:space:]]*)su npm npm/\1#su npm npm/g;' /etc/logrotate.d/nginx-proxy-manager
systemctl daemon-reload systemctl daemon-reload

View File

@@ -47,6 +47,10 @@ function update_script() {
systemctl stop otbr-agent systemctl stop otbr-agent
msg_ok "Stopped Services" msg_ok "Stopped Services"
msg_info "Backing up Configuration"
cp /etc/default/otbr-agent /etc/default/otbr-agent.bak
msg_ok "Backed up Configuration"
msg_info "Updating Source" msg_info "Updating Source"
$STD git reset --hard origin/main $STD git reset --hard origin/main
$STD git submodule update --depth 1 --init --recursive $STD git submodule update --depth 1 --init --recursive
@@ -70,6 +74,31 @@ function update_script() {
$STD ninja install $STD ninja install
msg_ok "Rebuilt OpenThread Border Router" msg_ok "Rebuilt OpenThread Border Router"
if ! grep -q "net.ipv6.conf.all.accept_ra=2" /etc/sysctl.d/99-otbr.conf; then
msg_info "Configuring Network"
cat <<EOF >/etc/sysctl.d/99-otbr.conf
net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.accept_ra=2
net.ipv6.conf.all.accept_ra_rtr_pref=1
net.ipv6.conf.all.accept_ra_rt_info_max_plen=64
net.ipv6.conf.default.forwarding=1
net.ipv6.conf.default.accept_ra=2
net.ipv6.conf.default.accept_ra_rtr_pref=1
net.ipv6.conf.default.accept_ra_rt_info_max_plen=64
net.ipv6.conf.eth0.forwarding=1
net.ipv6.conf.eth0.accept_ra=2
net.ipv6.conf.eth0.accept_ra_rtr_pref=1
net.ipv6.conf.eth0.accept_ra_rt_info_max_plen=64
net.ipv4.ip_forward=1
EOF
$STD sysctl -p /etc/sysctl.d/99-otbr.conf
msg_ok "Configured Network"
fi
msg_info "Restoring Configuration"
mv /etc/default/otbr-agent.bak /etc/default/otbr-agent
msg_ok "Restored Configuration"
msg_info "Starting Services" msg_info "Starting Services"
systemctl start otbr-agent systemctl start otbr-agent
systemctl start otbr-web systemctl start otbr-web

View File

@@ -30,7 +30,7 @@ function update_script() {
exit exit
fi fi
NODE_VERSION="22" setup_nodejs NODE_VERSION="24" setup_nodejs
if check_for_gh_release "soulsync" "Nezreka/SoulSync"; then if check_for_gh_release "soulsync" "Nezreka/SoulSync"; then
msg_info "Stopping Service" msg_info "Stopping Service"

View File

@@ -81,7 +81,7 @@ EOF
msg_ok "Updated Sure" msg_ok "Updated Sure"
msg_info "Starting Services" msg_info "Starting Services"
$STD systemctl start sure sure-worker systemctl start sure sure-worker
msg_ok "Started Services" msg_ok "Started Services"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi

View File

@@ -44,8 +44,7 @@ function update_script() {
msg_info "Installing Python Dependencies" msg_info "Installing Python Dependencies"
cd /opt/yamtrack cd /opt/yamtrack
$STD uv venv --clear .venv $STD uv sync --locked
$STD uv pip install --no-cache-dir -r requirements.txt
msg_ok "Installed Python Dependencies" msg_ok "Installed Python Dependencies"
msg_info "Restoring Data" msg_info "Restoring Data"

View File

@@ -52,6 +52,9 @@ After=network-online.target
Type=simple Type=simple
WorkingDirectory=/opt/apprise WorkingDirectory=/opt/apprise
ExecStart=/opt/apprise/webapp/supervisord-startup ExecStart=/opt/apprise/webapp/supervisord-startup
Environment=APPRISE_CONFIG_DIR=/config
Environment=APPRISE_ATTACH_DIR=/attach
Environment=APPRISE_PLUGIN_PATHS=/plugin
Restart=always Restart=always
RestartSec=30 RestartSec=30

View File

@@ -0,0 +1,40 @@
#!/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://certimate.me/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
fetch_and_deploy_gh_release "certimate" "certimate-go/certimate" "prebuild" "latest" "/opt/certimate" "certimate_*_linux_amd64.zip"
msg_info "Creating Service"
cat <<'EOF' >/etc/systemd/system/certimate.service
[Unit]
Description=Certimate SSL Certificate Manager
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/certimate
ExecStart=/opt/certimate/certimate serve --http "0.0.0.0:8090"
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now certimate
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -17,7 +17,7 @@ msg_info "Installing Dependencies"
$STD apt install -y build-essential $STD apt install -y build-essential
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
NODE_VERSION="24" setup_nodejs NODE_VERSION="26" setup_nodejs
msg_info "Setup Cross-Seed" msg_info "Setup Cross-Seed"
$STD npm install cross-seed@latest -g $STD npm install cross-seed@latest -g

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: reptil1990
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/qdm12/ddns-updater
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
fetch_and_deploy_gh_release "ddns-updater" "qdm12/ddns-updater" "singlefile" "latest" "/opt/ddns-updater" "ddns-updater_*_linux_amd64"
msg_info "Configuring DDNS-Updater"
mkdir -p /opt/ddns-updater/data
cat <<EOF >/opt/ddns-updater/data/config.json
{
"settings": [
{
"provider": "namecheap",
"domain": "example.com",
"password": "e5322165c1d74692bfa6d807100c0310"
}
]
}
EOF
msg_ok "Configured DDNS-Updater"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/ddns-updater.service
[Unit]
Description=DDNS-Updater
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStartPre=/bin/bash -c 'for i in \$(seq 1 30); do curl -sf --max-time 5 https://1.1.1.1 >/dev/null 2>&1 && break || sleep 2; done'
ExecStart=/opt/ddns-updater/ddns-updater
Environment=DATADIR=/opt/ddns-updater/data
Environment=LISTENING_ADDRESS=:8000
Environment=LOG_LEVEL=info
Environment=PERIOD=5m
WorkingDirectory=/opt/ddns-updater
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now ddns-updater
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -16,7 +16,8 @@ update_os
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y \
git \ git \
unzip unzip \
valkey
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
msg_info "Installing Bun" msg_info "Installing Bun"
@@ -38,6 +39,9 @@ DEGOOG_PLUGINS_DIR=/opt/degoog/data/plugins
DEGOOG_THEMES_DIR=/opt/degoog/data/themes DEGOOG_THEMES_DIR=/opt/degoog/data/themes
DEGOOG_ALIASES_FILE=/opt/degoog/data/aliases.json DEGOOG_ALIASES_FILE=/opt/degoog/data/aliases.json
DEGOOG_PLUGIN_SETTINGS_FILE=/opt/degoog/data/plugin-settings.json DEGOOG_PLUGIN_SETTINGS_FILE=/opt/degoog/data/plugin-settings.json
DEGOOG_VALKEY_URL=redis://valkey:6379
DEGOOG_CACHE_MAX_ENTRIES=1000
DEGOOG_CACHE_TTL_MS=43200000
# DEGOOG_SETTINGS_PASSWORDS=changeme # DEGOOG_SETTINGS_PASSWORDS=changeme
# DEGOOG_PUBLIC_INSTANCE=false # DEGOOG_PUBLIC_INSTANCE=false
# LOGGER=debug # LOGGER=debug
@@ -62,11 +66,16 @@ EOF
fi fi
msg_ok "Set up degoog" msg_ok "Set up degoog"
msg_info "Starting Valkey Service"
systemctl enable -q --now valkey-server
msg_ok "Started Valkey Service"
msg_info "Creating Service" msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/degoog.service cat <<EOF >/etc/systemd/system/degoog.service
[Unit] [Unit]
Description=degoog Description=degoog
After=network.target After=network.target valkey-server.service
Wants=valkey-server.service
[Service] [Service]
Type=simple Type=simple

View File

@@ -121,6 +121,7 @@ server {
# All other requests proxy to uWSGI # All other requests proxy to uWSGI
location / { location / {
include proxy_params; include proxy_params;
proxy_set_header X-Forwarded-Port \$server_port;
proxy_pass http://127.0.0.1:5656; proxy_pass http://127.0.0.1:5656;
} }
} }

View File

@@ -0,0 +1,71 @@
#!/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/Panonim/dynacat
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
fetch_and_deploy_gh_release "dynacat" "Panonim/dynacat" "prebuild" "latest" "/opt/dynacat" "dynacat-linux-amd64.tar.gz"
msg_info "Setting up Dynacat"
mkdir -p /opt/dynacat/config /opt/dynacat/assets /opt/dynacat/data
chmod +x /opt/dynacat/dynacat
cat <<EOF >/opt/dynacat/config/dynacat.yml
server:
host: 0.0.0.0
port: 8080
assets-path: /opt/dynacat/assets
db-path: /opt/dynacat/data/dynacat.db
pages:
- name: Home
columns:
- size: small
widgets:
- type: calendar
- type: clock
- size: full
widgets:
- type: search
search-engine: duckduckgo
- type: monitor
title: Services
sites:
- title: Dynacat
url: http://127.0.0.1:8080
update-interval: 5m
EOF
msg_ok "Set up Dynacat"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/dynacat.service
[Unit]
Description=Dynacat Dashboard
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/dynacat
ExecStart=/opt/dynacat/dynacat -config /opt/dynacat/config/dynacat.yml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now dynacat
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -37,7 +37,13 @@ msg_ok "Configured Firefly III"
msg_info "Configuring Data Importer" msg_info "Configuring Data Importer"
cp /opt/firefly/dataimporter/.env.example /opt/firefly/dataimporter/.env cp /opt/firefly/dataimporter/.env.example /opt/firefly/dataimporter/.env
sed -i "s#FIREFLY_III_URL=#FIREFLY_III_URL=http://${LOCAL_IP}#g" /opt/firefly/dataimporter/.env sed -i \
-e "s#FIREFLY_III_URL=#FIREFLY_III_URL=http://${LOCAL_IP}#g" \
-e "s|^APP_URL=.*|APP_URL=http://${LOCAL_IP}/dataimporter|" \
-e "s|^ASSET_URL=.*|ASSET_URL=/dataimporter|" \
/opt/firefly/dataimporter/.env
cd /opt/firefly/dataimporter
$STD php artisan config:clear
chown -R www-data:www-data /opt/firefly chown -R www-data:www-data /opt/firefly
msg_ok "Configured Data Importer" msg_ok "Configured Data Importer"

View File

@@ -19,6 +19,7 @@ NODE_VERSION="22" setup_nodejs
msg_info "Setting up Flatnotes" msg_info "Setting up Flatnotes"
cd /opt/flatnotes cd /opt/flatnotes
sed -i 's/^name = ""$/name = "flatnotes"/' pyproject.toml
$STD /usr/local/bin/uvx migrate-to-uv $STD /usr/local/bin/uvx migrate-to-uv
$STD /usr/local/bin/uv sync $STD /usr/local/bin/uv sync
mkdir -p /opt/flatnotes/data mkdir -p /opt/flatnotes/data

View File

@@ -28,7 +28,6 @@ export CYPRESS_INSTALL_BINARY=0
export NODE_OPTIONS="--max-old-space-size=2048" export NODE_OPTIONS="--max-old-space-size=2048"
cd /opt/grist cd /opt/grist
$STD yarn install $STD yarn install
$STD yarn run install:ee -y
$STD yarn run build:prod $STD yarn run build:prod
$STD yarn run install:python $STD yarn run install:python
cat <<EOF >/opt/grist/.env cat <<EOF >/opt/grist/.env

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://invoiceshelf.com/
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 caddy
msg_ok "Installed Dependencies"
PHP_VERSION="8.4" PHP_FPM="YES" PHP_MODULES="bcmath,gd,intl,xml,zip,pdo_pgsql,mbstring,curl,exif" setup_php
setup_composer
NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs
PG_VERSION="16" setup_postgresql
PG_DB_NAME="invoiceshelf" PG_DB_USER="invoiceshelf" setup_postgresql_db
fetch_and_deploy_gh_release "invoiceshelf" "InvoiceShelf/InvoiceShelf" "tarball"
msg_info "Setting up InvoiceShelf"
cd /opt/invoiceshelf
cp .env.example .env
sed -i "s|^APP_ENV=.*|APP_ENV=production|" .env
sed -i "s|^APP_DEBUG=.*|APP_DEBUG=false|" .env
sed -i "s|^APP_URL=.*|APP_URL=http://${LOCAL_IP}|" .env
sed -i "s|^DB_CONNECTION=.*|DB_CONNECTION=pgsql|" .env
sed -i "s|^DB_HOST=.*|DB_HOST=127.0.0.1|" .env
sed -i "s|^DB_PORT=.*|DB_PORT=5432|" .env
sed -i "s|^DB_DATABASE=.*|DB_DATABASE=${PG_DB_NAME}|" .env
sed -i "s|^DB_USERNAME=.*|DB_USERNAME=${PG_DB_USER}|" .env
sed -i "s|^DB_PASSWORD=.*|DB_PASSWORD=${PG_DB_PASS}|" .env
COMPOSER_ALLOW_SUPERUSER=1 $STD composer install --no-dev --optimize-autoloader --no-interaction
$STD php artisan key:generate
$STD yarn install
$STD yarn build
mkdir -p storage/framework/{cache,sessions,views} storage/logs bootstrap/cache
chown -R www-data:www-data /opt/invoiceshelf
chmod -R 775 storage bootstrap/cache
$STD php artisan migrate --force
$STD php artisan storage:link
msg_ok "Set up InvoiceShelf"
msg_info "Configuring Caddy"
PHP_VER=$(php -r 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;')
cat <<EOF >/etc/caddy/Caddyfile
:80 {
root * /opt/invoiceshelf/public
php_fastcgi unix//run/php/php${PHP_VER}-fpm.sock
file_server
encode gzip
}
EOF
usermod -aG www-data caddy
msg_ok "Configured Caddy"
systemctl enable -q --now php${PHP_VER}-fpm
systemctl restart caddy
motd_ssh
customize
cleanup_lxc

90
install/kan-install.sh Normal file
View File

@@ -0,0 +1,90 @@
#!/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/kanbn/kan
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 \
build-essential \
git
msg_ok "Installed Dependencies"
PG_VERSION="16" setup_postgresql
PG_DB_NAME="kan" PG_DB_USER="kan" setup_postgresql_db
NODE_VERSION="20" NODE_MODULE="pnpm" setup_nodejs
fetch_and_deploy_gh_tag "kan" "kanbn/kan" "latest"
msg_info "Configuring Application"
AUTH_SECRET=$(openssl rand -base64 32)
cat <<EOF >/opt/kan/.env
NEXT_PUBLIC_BASE_URL=http://${LOCAL_IP}:3000
BETTER_AUTH_SECRET=${AUTH_SECRET}
BETTER_AUTH_TRUSTED_ORIGINS=http://${LOCAL_IP}:3000
POSTGRES_URL=postgres://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}
NEXT_PUBLIC_ALLOW_CREDENTIALS=true
TRELLO_APP_API_KEY=
TRELLO_APP_API_SECRET=
HOSTNAME=0.0.0.0
PORT=3000
NODE_ENV=production
EOF
msg_ok "Configured Application"
msg_info "Building Application"
cd /opt/kan
set -a && source /opt/kan/.env && set +a
export NEXT_PUBLIC_USE_STANDALONE_OUTPUT=true NEXT_PUBLIC_BASE_URL BETTER_AUTH_TRUSTED_ORIGINS NEXT_PUBLIC_ALLOW_CREDENTIALS BETTER_AUTH_SECRET
$STD pnpm install --ignore-scripts --prod=false
export CI=true
find /opt/kan/packages /opt/kan/apps -name 'tsconfig.json' -exec sed -i 's|"@kan/tsconfig/|"../../tooling/typescript/|g' {} +
$STD pnpm build --filter=@kan/web
unset NEXT_PUBLIC_USE_STANDALONE_OUTPUT CI
msg_ok "Built Application"
msg_info "Setting up Standalone"
mkdir -p /opt/kan/apps/web/.next/standalone/apps/web/.next/static
cp -r /opt/kan/apps/web/.next/static/* /opt/kan/apps/web/.next/standalone/apps/web/.next/static/
cp -r /opt/kan/apps/web/public /opt/kan/apps/web/.next/standalone/apps/web/public
msg_ok "Set up Standalone"
msg_info "Running Database Migrations"
cd /opt/kan/packages/db
POSTGRES_URL="postgres://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}" $STD pnpm exec drizzle-kit migrate
msg_ok "Ran Database Migrations"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/kan.service
[Unit]
Description=Kan Board
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=root
WorkingDirectory=/opt/kan/apps/web/.next/standalone
EnvironmentFile=/opt/kan/.env
ExecStart=/usr/bin/node apps/web/server.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now kan
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc

View File

@@ -56,20 +56,20 @@ msg_ok "Installed Python Dependencies"
msg_info "Downloading Essentia ML Models" msg_info "Downloading Essentia ML Models"
mkdir -p /opt/kima-hub/models mkdir -p /opt/kima-hub/models
cd /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_with_retry "https://essentia.upf.edu/models/autotagging/msd/msd-musicnn-1.pb" "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_with_retry "https://essentia.upf.edu/models/classification-heads/mood_happy/mood_happy-msd-musicnn-1.pb" "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_with_retry "https://essentia.upf.edu/models/classification-heads/mood_sad/mood_sad-msd-musicnn-1.pb" "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_with_retry "https://essentia.upf.edu/models/classification-heads/mood_relaxed/mood_relaxed-msd-musicnn-1.pb" "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_with_retry "https://essentia.upf.edu/models/classification-heads/mood_aggressive/mood_aggressive-msd-musicnn-1.pb" "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_with_retry "https://essentia.upf.edu/models/classification-heads/mood_party/mood_party-msd-musicnn-1.pb" "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_with_retry "https://essentia.upf.edu/models/classification-heads/mood_acoustic/mood_acoustic-msd-musicnn-1.pb" "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_with_retry "https://essentia.upf.edu/models/classification-heads/mood_electronic/mood_electronic-msd-musicnn-1.pb" "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_with_retry "https://essentia.upf.edu/models/classification-heads/danceability/danceability-msd-musicnn-1.pb" "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" curl_with_retry "https://essentia.upf.edu/models/classification-heads/voice_instrumental/voice_instrumental-msd-musicnn-1.pb" "voice_instrumental-msd-musicnn-1.pb"
msg_ok "Downloaded Essentia ML Models" msg_ok "Downloaded Essentia ML Models"
msg_info "Downloading CLAP Model" 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" CURL_TIMEOUT=600 curl_with_retry "https://huggingface.co/lukewys/laion_clap/resolve/main/music_audioset_epoch_15_esc_90.14.pt" "/opt/kima-hub/models/music_audioset_epoch_15_esc_90.14.pt"
msg_ok "Downloaded CLAP Model" msg_ok "Downloaded CLAP Model"
msg_info "Building Backend" msg_info "Building Backend"

View File

@@ -13,7 +13,7 @@ setting_up_container
network_check network_check
update_os update_os
NODE_VERSION="24" NODE_MODULE="yarn" setup_nodejs NODE_VERSION="26" NODE_MODULE="yarn" setup_nodejs
PG_VERSION="16" setup_postgresql PG_VERSION="16" setup_postgresql
PHP_VERSION="8.5" PHP_APACHE="YES" setup_php PHP_VERSION="8.5" PHP_APACHE="YES" setup_php
setup_composer setup_composer

View File

@@ -15,7 +15,7 @@ update_os
PYTHON_VERSION="3.13" setup_uv PYTHON_VERSION="3.13" setup_uv
fetch_and_deploy_gh_release "musicseerr" "HabiRabbu/Musicseerr" "tarball" fetch_and_deploy_gh_release "musicseerr" "HabiRabbu/Musicseerr" "tarball"
NODE_VERSION="22" NODE_MODULE="pnpm@10.33.0" setup_nodejs NODE_VERSION="25" NODE_MODULE="pnpm@10.33.0" setup_nodejs
msg_info "Building Frontend" msg_info "Building Frontend"
cd /opt/musicseerr/frontend cd /opt/musicseerr/frontend

View File

@@ -160,7 +160,8 @@ $STD yarn install --network-timeout 600000
msg_ok "Initialized Backend" msg_ok "Initialized Backend"
msg_info "Creating Service" msg_info "Creating Service"
cat <<'EOF' >/lib/systemd/system/npm.service CERTBOT_VER=$(/opt/certbot/bin/certbot --version 2>&1 | awk '{print $NF}')
cat <<EOF >/lib/systemd/system/npm.service
[Unit] [Unit]
Description=Nginx Proxy Manager Description=Nginx Proxy Manager
After=network.target After=network.target
@@ -169,6 +170,7 @@ Wants=openresty.service
[Service] [Service]
Type=simple Type=simple
Environment=NODE_ENV=production Environment=NODE_ENV=production
Environment=CERTBOT_VERSION=${CERTBOT_VER}
ExecStartPre=-mkdir -p /tmp/nginx/body /data/letsencrypt-acme-challenge ExecStartPre=-mkdir -p /tmp/nginx/body /data/letsencrypt-acme-challenge
ExecStart=/usr/bin/node index.js --abort_on_uncaught_exception --max_old_space_size=250 ExecStart=/usr/bin/node index.js --abort_on_uncaught_exception --max_old_space_size=250
WorkingDirectory=/app WorkingDirectory=/app

View File

@@ -46,7 +46,7 @@ sed -i "s|^ENCRYPTION_KEY=.*|ENCRYPTION_KEY=$SECRET_KEY|g" /opt/openarchiver/.en
sed -i "s|^TIKA_URL=.*|TIKA_URL=|g" /opt/openarchiver/.env sed -i "s|^TIKA_URL=.*|TIKA_URL=|g" /opt/openarchiver/.env
sed -i "s|^ORIGIN=.*|ORIGIN=http://$LOCAL_IP:3000|g" /opt/openarchiver/.env sed -i "s|^ORIGIN=.*|ORIGIN=http://$LOCAL_IP:3000|g" /opt/openarchiver/.env
$STD pnpm install --shamefully-hoist --frozen-lockfile --prod=false $STD pnpm install --shamefully-hoist --frozen-lockfile --prod=false
$STD pnpm approve-builds --yes $STD pnpm approve-builds
$STD pnpm run build:oss $STD pnpm run build:oss
$STD pnpm db:migrate $STD pnpm db:migrate
msg_ok "Setup Open Archiver" msg_ok "Setup Open Archiver"

View File

@@ -67,6 +67,17 @@ msg_ok "Built OpenThread Border Router"
msg_info "Configuring Network" msg_info "Configuring Network"
cat <<EOF >/etc/sysctl.d/99-otbr.conf cat <<EOF >/etc/sysctl.d/99-otbr.conf
net.ipv6.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1
net.ipv6.conf.all.accept_ra=2
net.ipv6.conf.all.accept_ra_rtr_pref=1
net.ipv6.conf.all.accept_ra_rt_info_max_plen=64
net.ipv6.conf.default.forwarding=1
net.ipv6.conf.default.accept_ra=2
net.ipv6.conf.default.accept_ra_rtr_pref=1
net.ipv6.conf.default.accept_ra_rt_info_max_plen=64
net.ipv6.conf.eth0.forwarding=1
net.ipv6.conf.eth0.accept_ra=2
net.ipv6.conf.eth0.accept_ra_rtr_pref=1
net.ipv6.conf.eth0.accept_ra_rt_info_max_plen=64
net.ipv4.ip_forward=1 net.ipv4.ip_forward=1
EOF EOF
$STD sysctl -p /etc/sysctl.d/99-otbr.conf $STD sysctl -p /etc/sysctl.d/99-otbr.conf

View File

@@ -265,6 +265,7 @@ EOF
sed -i "s|alias /var/lib/romm/library/;|alias ${ROMM_BASE}/library/;|" /etc/nginx/sites-available/romm sed -i "s|alias /var/lib/romm/library/;|alias ${ROMM_BASE}/library/;|" /etc/nginx/sites-available/romm
rm -f /etc/nginx/sites-enabled/default rm -f /etc/nginx/sites-enabled/default
rm -f /etc/nginx/conf.d/default.conf
ln -sf /etc/nginx/sites-available/romm /etc/nginx/sites-enabled/romm ln -sf /etc/nginx/sites-available/romm /etc/nginx/sites-enabled/romm
systemctl restart nginx systemctl restart nginx
systemctl enable -q --now nginx systemctl enable -q --now nginx

View File

@@ -23,7 +23,7 @@ $STD apt install -y \
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
UV_PYTHON="3.11" setup_uv UV_PYTHON="3.11" setup_uv
NODE_VERSION="22" setup_nodejs NODE_VERSION="24" setup_nodejs
fetch_and_deploy_gh_release "soulsync" "Nezreka/SoulSync" "tarball" fetch_and_deploy_gh_release "soulsync" "Nezreka/SoulSync" "tarball"

View File

@@ -103,7 +103,7 @@ StandardError=journal
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
$STD systemctl enable -q --now sure sure-worker systemctl enable -q --now sure sure-worker
msg_ok "Created Services" msg_ok "Created Services"
motd_ssh motd_ssh

View File

@@ -41,29 +41,27 @@ cat <<EOF >/etc/caddy/Caddyfile
} }
EOF EOF
usermod -aG www-data caddy usermod -aG www-data caddy
msg_ok "Configured Caddy"
systemctl enable -q --now php${PHP_VER}-fpm systemctl enable -q --now php${PHP_VER}-fpm
systemctl restart caddy systemctl restart caddy
msg_ok "Configured Caddy"
msg_info "Automating Webtrees Setup" msg_info "Automating Webtrees Setup"
sleep 5 cd /opt/webtrees
WT_ADMIN_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c15) WT_ADMIN_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c15)
curl -sS -X POST "http://127.0.0.1/" \ $STD sudo -u www-data php /opt/webtrees/index.php config-ini \
-d "step=6" \ --dbhost=127.0.0.1 \
--data-urlencode "baseurl=http://${LOCAL_IP}" \ --dbport=3306 \
-d "lang=en-US" \ --dbuser=webtrees \
-d "dbtype=mysql" \ --dbpass="${MARIADB_DB_PASS}" \
-d "dbhost=127.0.0.1" \ --dbname=webtrees \
-d "dbport=3306" \ --tblpfx=wt_ \
-d "dbuser=webtrees" \ --base-url="http://${LOCAL_IP}"
--data-urlencode "dbpass=${MARIADB_DB_PASS}" \ $STD sudo -u www-data php /opt/webtrees/index.php user Admin \
-d "dbname=webtrees" \ --create \
-d "tblpfx=wt_" \ --real-name="Administrator" \
-d "wtname=Administrator" \ --email="admin@example.com" \
-d "wtuser=Admin" \ --password="${WT_ADMIN_PASS}"
--data-urlencode "wtpass=${WT_ADMIN_PASS}" \ $STD sudo -u www-data php /opt/webtrees/index.php user-setting Admin canadmin 1
-d "wtemail=admin@example.com" >/dev/null
cat <<EOF >>~/webtrees.creds cat <<EOF >>~/webtrees.creds

View File

@@ -27,8 +27,7 @@ fetch_and_deploy_gh_release "yamtrack" "FuzzyGrim/Yamtrack" "tarball"
msg_info "Installing Python Dependencies" msg_info "Installing Python Dependencies"
cd /opt/yamtrack cd /opt/yamtrack
$STD uv venv .venv $STD uv sync --locked
$STD uv pip install --no-cache-dir -r requirements.txt
msg_ok "Installed Python Dependencies" msg_ok "Installed Python Dependencies"
msg_info "Configuring Yamtrack" msg_info "Configuring Yamtrack"

View File

@@ -8227,11 +8227,13 @@ setup_ruby() {
# #
# Variables: # Variables:
# RUST_TOOLCHAIN - Rust toolchain to install (default: stable) # RUST_TOOLCHAIN - Rust toolchain to install (default: stable)
# RUST_PROFILE - Rust installation profile (default: default, e.g. minimal)
# RUST_CRATES - Comma-separated list of crates (e.g. "cargo-edit,wasm-pack@0.12.1") # RUST_CRATES - Comma-separated list of crates (e.g. "cargo-edit,wasm-pack@0.12.1")
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
setup_rust() { setup_rust() {
local RUST_TOOLCHAIN="${RUST_TOOLCHAIN:-stable}" local RUST_TOOLCHAIN="${RUST_TOOLCHAIN:-stable}"
local RUST_PROFILE="${RUST_PROFILE:-default}"
local RUST_CRATES="${RUST_CRATES:-}" local RUST_CRATES="${RUST_CRATES:-}"
local CARGO_BIN="${HOME}/.cargo/bin" local CARGO_BIN="${HOME}/.cargo/bin"
@@ -8243,8 +8245,8 @@ setup_rust() {
# Scenario 1: Rustup not installed - fresh install # Scenario 1: Rustup not installed - fresh install
if ! command -v rustup &>/dev/null; then if ! command -v rustup &>/dev/null; then
msg_info "Setup Rust ($RUST_TOOLCHAIN)" msg_info "Setup Rust ($RUST_TOOLCHAIN, profile: $RUST_PROFILE)"
curl -fsSL https://sh.rustup.rs | $STD sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" || { curl -fsSL https://sh.rustup.rs | $STD sh -s -- -y --profile "$RUST_PROFILE" --default-toolchain "$RUST_TOOLCHAIN" || {
msg_error "Failed to install Rust" msg_error "Failed to install Rust"
msg_error "Hint: Check connectivity to sh.rustup.rs and static.rust-lang.org" msg_error "Hint: Check connectivity to sh.rustup.rs and static.rust-lang.org"
return 7 return 7

View File

@@ -50,6 +50,19 @@ start_routines() {
no) msg_error "Selected no to Backup" ;; no) msg_error "Selected no to Backup" ;;
esac esac
# --- Update Current PBS 3 System ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS 3 UPDATE" --menu \
"\nUpdate current PBS 3 (Bookworm) packages before upgrade?" 14 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3)
case $CHOICE in
yes)
msg_info "Updating current PBS 3 packages"
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get -y dist-upgrade
msg_ok "Updated current PBS 3 packages"
;;
no) msg_error "Skipped updating current packages" ;;
esac
# --- Debian 13 Sources --- # --- Debian 13 Sources ---
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS 4 SOURCES" --menu \ CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PBS 4 SOURCES" --menu \
"Switch to Debian 13 (Trixie) sources for PBS 4?" 14 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3) "Switch to Debian 13 (Trixie) sources for PBS 4?" 14 58 2 "yes" " " "no" " " 3>&2 2>&1 1>&3)