mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-02-05 21:03:24 +01:00
Compare commits
64 Commits
add-script
...
update_doc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c18646d82 | ||
|
|
30bc127011 | ||
|
|
33149f3bf8 | ||
|
|
f5103852f5 | ||
|
|
464cabc035 | ||
|
|
8640dd97cd | ||
|
|
6ed9afb40b | ||
|
|
fbf04bee6a | ||
|
|
c9bb2788be | ||
|
|
93e4eb5b22 | ||
|
|
f4d4a00180 | ||
|
|
101f882022 | ||
|
|
8f97908896 | ||
|
|
833a6a248b | ||
|
|
9a65218900 | ||
|
|
b61abacb76 | ||
|
|
273c5c75ee | ||
|
|
06d9199d89 | ||
|
|
5d5c273fb6 | ||
|
|
92506cdc34 | ||
|
|
5db509eb16 | ||
|
|
129f2f6329 | ||
|
|
be9d26885a | ||
|
|
ddd130dbe3 | ||
|
|
93c52abebd | ||
|
|
a74f6ee3c3 | ||
|
|
b36051375b | ||
|
|
7b8a3a111d | ||
|
|
be994ce84f | ||
|
|
4bd5c7b54b | ||
|
|
868446a4b6 | ||
|
|
5f31954d91 | ||
|
|
b025fd049c | ||
|
|
3046eb000d | ||
|
|
472439ce6e | ||
|
|
43044c60f0 | ||
|
|
36bf5cb57e | ||
|
|
338c054112 | ||
|
|
17ac4f5ae7 | ||
|
|
5210d1bb71 | ||
|
|
c599fd7551 | ||
|
|
0644bef572 | ||
|
|
27ab446926 | ||
|
|
81abf70851 | ||
|
|
c570cbe0be | ||
|
|
fa86809863 | ||
|
|
c6dfa052ee | ||
|
|
2e9624fdfb | ||
|
|
e99702977c | ||
|
|
757a54e23a | ||
|
|
0029ad0dee | ||
|
|
65e50542b0 | ||
|
|
b87fddbf6a | ||
|
|
959bbb3a26 | ||
|
|
e72c7d8f7f | ||
|
|
8677104d68 | ||
|
|
7db01be0a7 | ||
|
|
e4ffc478fb | ||
|
|
9671c9f391 | ||
|
|
8f23297604 | ||
|
|
acdf4dbb2a | ||
|
|
5a975901ea | ||
|
|
affd9c81e1 | ||
|
|
ebe0eeef8e |
310
.github/changelogs/2026/01.md
generated
vendored
310
.github/changelogs/2026/01.md
generated
vendored
@@ -1,14 +1,156 @@
|
|||||||
## 2026-01-27
|
## 2026-01-31
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- shelfmark ([#11371](https://github.com/community-scripts/ProxmoxVE/pull/11371))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix: yubal: add git [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11394](https://github.com/community-scripts/ProxmoxVE/pull/11394))
|
||||||
|
|
||||||
|
## 2026-01-30
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- languagetool ([#11370](https://github.com/community-scripts/ProxmoxVE/pull/11370))
|
||||||
|
- Ampache ([#11369](https://github.com/community-scripts/ProxmoxVE/pull/11369))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Refactor: remove redundant PHP_MODULE entries in several scripts [@MickLesk](https://github.com/MickLesk) ([#11362](https://github.com/community-scripts/ProxmoxVE/pull/11362))
|
||||||
|
- Refactor: Koillection [@MickLesk](https://github.com/MickLesk) ([#11361](https://github.com/community-scripts/ProxmoxVE/pull/11361))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- core: meilisearch - add data migration for version upgrades [@MickLesk](https://github.com/MickLesk) ([#11356](https://github.com/community-scripts/ProxmoxVE/pull/11356))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- [tools] Add `fetch_and_deploy_from_url()` [@tremor021](https://github.com/tremor021) ([#11376](https://github.com/community-scripts/ProxmoxVE/pull/11376))
|
||||||
|
- core: php - improve module handling and prevent installation failures [@MickLesk](https://github.com/MickLesk) ([#11358](https://github.com/community-scripts/ProxmoxVE/pull/11358))
|
||||||
|
|
||||||
|
## 2026-01-29
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Alpine-Valkey [@MickLesk](https://github.com/MickLesk) ([#11320](https://github.com/community-scripts/ProxmoxVE/pull/11320))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Immich: Pin version to 2.5.2 [@vhsdream](https://github.com/vhsdream) ([#11335](https://github.com/community-scripts/ProxmoxVE/pull/11335))
|
||||||
|
- Kollection: Update to php 8.5 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11315](https://github.com/community-scripts/ProxmoxVE/pull/11315))
|
||||||
|
- Notifiarr: change installation check from apt to systemd service [@MickLesk](https://github.com/MickLesk) ([#11319](https://github.com/community-scripts/ProxmoxVE/pull/11319))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- [FEAT] Immich: Enable Maintenance Mode before update [@vhsdream](https://github.com/vhsdream) ([#11342](https://github.com/community-scripts/ProxmoxVE/pull/11342))
|
||||||
|
- jellyfin: add logrotate instead of reducing log level [@MickLesk](https://github.com/MickLesk) ([#11326](https://github.com/community-scripts/ProxmoxVE/pull/11326))
|
||||||
|
- core: Add config file handling options | Fix Vikunja update with interactive overwrite [@MickLesk](https://github.com/MickLesk) ([#11317](https://github.com/community-scripts/ProxmoxVE/pull/11317))
|
||||||
|
- Immich: v2.5.0 [@vhsdream](https://github.com/vhsdream) ([#11240](https://github.com/community-scripts/ProxmoxVE/pull/11240))
|
||||||
|
|
||||||
|
- #### 💥 Breaking Changes
|
||||||
|
|
||||||
|
- fix: vikunja v1 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11308](https://github.com/community-scripts/ProxmoxVE/pull/11308))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Refactor: Byparr [@vhsdream](https://github.com/vhsdream) ([#11338](https://github.com/community-scripts/ProxmoxVE/pull/11338))
|
||||||
|
- cloudflare: Remove deprecated DNS-over-HTTPS proxy option [@MickLesk](https://github.com/MickLesk) ([#11068](https://github.com/community-scripts/ProxmoxVE/pull/11068))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- build.func: Replace storage variable with searchdomain variable [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11322](https://github.com/community-scripts/ProxmoxVE/pull/11322))
|
||||||
|
|
||||||
|
### 📂 Github
|
||||||
|
|
||||||
|
- Add workflow to lock closed issues [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11316](https://github.com/community-scripts/ProxmoxVE/pull/11316))
|
||||||
|
|
||||||
|
## 2026-01-28
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- nodecast-tv ([#11287](https://github.com/community-scripts/ProxmoxVE/pull/11287))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Ubuntu 25.04 VM - Change default start from yes to no [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11292](https://github.com/community-scripts/ProxmoxVE/pull/11292))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- various scripts: use setup_meilisearch function [@MickLesk](https://github.com/MickLesk) ([#11259](https://github.com/community-scripts/ProxmoxVE/pull/11259))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Refactor: NPMPlus / Default Login [@MickLesk](https://github.com/MickLesk) ([#11262](https://github.com/community-scripts/ProxmoxVE/pull/11262))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- core: sed patch for ram [@lavacano](https://github.com/lavacano) ([#11285](https://github.com/community-scripts/ProxmoxVE/pull/11285))
|
||||||
|
- Fix installer loop caused by invalid whiptail menu separator [@Mesteriis](https://github.com/Mesteriis) ([#11237](https://github.com/community-scripts/ProxmoxVE/pull/11237))
|
||||||
|
- core: fix Debian 13 LXC template root ownership bug [@MickLesk](https://github.com/MickLesk) ([#11277](https://github.com/community-scripts/ProxmoxVE/pull/11277))
|
||||||
|
- tools.func: prevent systemd-tmpfiles failure in unprivileged LXC during deb install [@MickLesk](https://github.com/MickLesk) ([#11271](https://github.com/community-scripts/ProxmoxVE/pull/11271))
|
||||||
|
- tools.func: fix php "wait_for" hint [@MickLesk](https://github.com/MickLesk) ([#11254](https://github.com/community-scripts/ProxmoxVE/pull/11254))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: update dynamic values in LXC profile on update_motd_ip [@MickLesk](https://github.com/MickLesk) ([#11268](https://github.com/community-scripts/ProxmoxVE/pull/11268))
|
||||||
|
- tools.func: add new function - setup_meilisearch [@MickLesk](https://github.com/MickLesk) ([#11258](https://github.com/community-scripts/ProxmoxVE/pull/11258))
|
||||||
|
|
||||||
|
### 📂 Github
|
||||||
|
|
||||||
|
- github: add GitHub-based versions.json updater [@MickLesk](https://github.com/MickLesk) ([#10021](https://github.com/community-scripts/ProxmoxVE/pull/10021))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Frontend: use github-versions.json for version display [@MickLesk](https://github.com/MickLesk) ([#11281](https://github.com/community-scripts/ProxmoxVE/pull/11281))
|
||||||
|
|
||||||
|
- #### 📝 Script Information
|
||||||
|
|
||||||
|
- fix: homarr: conf location [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11253](https://github.com/community-scripts/ProxmoxVE/pull/11253))
|
||||||
|
|
||||||
|
## 2026-01-27
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
- [FIX] Jotty: backup and restore custom config [@vhsdream](https://github.com/vhsdream) ([#11212](https://github.com/community-scripts/ProxmoxVE/pull/11212))
|
- [FIX] Jotty: backup and restore custom config [@vhsdream](https://github.com/vhsdream) ([#11212](https://github.com/community-scripts/ProxmoxVE/pull/11212))
|
||||||
|
- Immich: update libraw [@vhsdream](https://github.com/vhsdream) ([#11233](https://github.com/community-scripts/ProxmoxVE/pull/11233))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- grist: enable optional enterprise features toggle [@MickLesk](https://github.com/MickLesk) ([#11239](https://github.com/community-scripts/ProxmoxVE/pull/11239))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Termix: use nginx.conf from upstream repo [@MickLesk](https://github.com/MickLesk) ([#11228](https://github.com/community-scripts/ProxmoxVE/pull/11228))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- feat: add NVIDIA driver install prompt for GPU-enabled containers [@devdecrux](https://github.com/devdecrux) ([#11184](https://github.com/community-scripts/ProxmoxVE/pull/11184))
|
||||||
|
|
||||||
### 📚 Documentation
|
### 📚 Documentation
|
||||||
|
|
||||||
- doc setup_deb822_repo arg order [@chrnie](https://github.com/chrnie) ([#11215](https://github.com/community-scripts/ProxmoxVE/pull/11215))
|
- doc setup_deb822_repo arg order [@chrnie](https://github.com/chrnie) ([#11215](https://github.com/community-scripts/ProxmoxVE/pull/11215))
|
||||||
|
- changelog: archive old entries to year/month files [@MickLesk](https://github.com/MickLesk) ([#11225](https://github.com/community-scripts/ProxmoxVE/pull/11225))
|
||||||
|
|
||||||
## 2026-01-26
|
## 2026-01-26
|
||||||
|
|
||||||
@@ -100,7 +242,7 @@
|
|||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|
||||||
- Tracearr ([#11079](https://github.com/community-scripts/ProxmoxVE/pull/11079))
|
- Tracearr ([#11079](https://github.com/community-scripts/ProxmoxVE/pull/11079))
|
||||||
- Dawarich ([#11075](https://github.com/community-scripts/ProxmoxVE/pull/11075))
|
- Dawarich ([#11075](https://github.com/community-scripts/ProxmoxVE/pull/11075))
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
@@ -250,7 +392,7 @@
|
|||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|
||||||
- Termix ([#10887](https://github.com/community-scripts/ProxmoxVE/pull/10887))
|
- Termix ([#10887](https://github.com/community-scripts/ProxmoxVE/pull/10887))
|
||||||
- ThingsBoard ([#10904](https://github.com/community-scripts/ProxmoxVE/pull/10904))
|
- ThingsBoard ([#10904](https://github.com/community-scripts/ProxmoxVE/pull/10904))
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
@@ -319,7 +461,7 @@
|
|||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|
||||||
- Flatnotes ([#10857](https://github.com/community-scripts/ProxmoxVE/pull/10857))
|
- Flatnotes ([#10857](https://github.com/community-scripts/ProxmoxVE/pull/10857))
|
||||||
- Unifi OS Server ([#10856](https://github.com/community-scripts/ProxmoxVE/pull/10856))
|
- Unifi OS Server ([#10856](https://github.com/community-scripts/ProxmoxVE/pull/10856))
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
@@ -385,7 +527,7 @@
|
|||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
|
|
||||||
- Investbrain ([#10774](https://github.com/community-scripts/ProxmoxVE/pull/10774))
|
- Investbrain ([#10774](https://github.com/community-scripts/ProxmoxVE/pull/10774))
|
||||||
- Fladder ([#10768](https://github.com/community-scripts/ProxmoxVE/pull/10768))
|
- Fladder ([#10768](https://github.com/community-scripts/ProxmoxVE/pull/10768))
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
@@ -574,7 +716,7 @@
|
|||||||
### 📚 Documentation
|
### 📚 Documentation
|
||||||
|
|
||||||
- [gh] New Script template update [@tremor021](https://github.com/tremor021) ([#10607](https://github.com/community-scripts/ProxmoxVE/pull/10607))
|
- [gh] New Script template update [@tremor021](https://github.com/tremor021) ([#10607](https://github.com/community-scripts/ProxmoxVE/pull/10607))
|
||||||
- chore: bump copyright to 2026 - happy new year [@CrazyWolf13](https://github.com/CrazyWolf13) ([#10585](https://github.com/community-scripts/ProxmoxVE/pull/10585))
|
- chore: bump copyright to 2026 - happy new year [@CrazyWolf13](https://github.com/CrazyWolf13) ([#10585](https://github.com/community-scripts/ProxmoxVE/pull/10585))
|
||||||
|
|
||||||
### 📂 Github
|
### 📂 Github
|
||||||
|
|
||||||
@@ -655,7 +797,7 @@
|
|||||||
### ❔ Uncategorized
|
### ❔ Uncategorized
|
||||||
|
|
||||||
- Wireguard: Update WGDashboard notes URL to the new link [@tremor021](https://github.com/tremor021) ([#10496](https://github.com/community-scripts/ProxmoxVE/pull/10496))
|
- Wireguard: Update WGDashboard notes URL to the new link [@tremor021](https://github.com/tremor021) ([#10496](https://github.com/community-scripts/ProxmoxVE/pull/10496))
|
||||||
- InvoiceNinja: Update database credentias information [@tremor021](https://github.com/tremor021) ([#10497](https://github.com/community-scripts/ProxmoxVE/pull/10497))
|
- InvoiceNinja: Update database credentias information [@tremor021](https://github.com/tremor021) ([#10497](https://github.com/community-scripts/ProxmoxVE/pull/10497))
|
||||||
|
|
||||||
## 2026-01-02
|
## 2026-01-02
|
||||||
|
|
||||||
@@ -684,157 +826,3 @@
|
|||||||
- #### 🐞 Bug Fixes
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
- Fix MariaDB runtime directory persistence on container reboot [@Copilot](https://github.com/Copilot) ([#10468](https://github.com/community-scripts/ProxmoxVE/pull/10468))
|
- Fix MariaDB runtime directory persistence on container reboot [@Copilot](https://github.com/Copilot) ([#10468](https://github.com/community-scripts/ProxmoxVE/pull/10468))
|
||||||
|
|
||||||
|
|
||||||
## 2026-01-31
|
|
||||||
|
|
||||||
### 🆕 New Scripts
|
|
||||||
|
|
||||||
- shelfmark ([#11371](https://github.com/community-scripts/ProxmoxVE/pull/11371))
|
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- fix: yubal: add git [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11394](https://github.com/community-scripts/ProxmoxVE/pull/11394))
|
|
||||||
|
|
||||||
## 2026-01-30
|
|
||||||
|
|
||||||
### 🆕 New Scripts
|
|
||||||
|
|
||||||
- languagetool ([#11370](https://github.com/community-scripts/ProxmoxVE/pull/11370))
|
|
||||||
- Ampache ([#11369](https://github.com/community-scripts/ProxmoxVE/pull/11369))
|
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
|
||||||
|
|
||||||
- #### 🔧 Refactor
|
|
||||||
|
|
||||||
- Refactor: remove redundant PHP_MODULE entries in several scripts [@MickLesk](https://github.com/MickLesk) ([#11362](https://github.com/community-scripts/ProxmoxVE/pull/11362))
|
|
||||||
- Refactor: Koillection [@MickLesk](https://github.com/MickLesk) ([#11361](https://github.com/community-scripts/ProxmoxVE/pull/11361))
|
|
||||||
|
|
||||||
### 💾 Core
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- core: meilisearch - add data migration for version upgrades [@MickLesk](https://github.com/MickLesk) ([#11356](https://github.com/community-scripts/ProxmoxVE/pull/11356))
|
|
||||||
|
|
||||||
- #### ✨ New Features
|
|
||||||
|
|
||||||
- [tools] Add `fetch_and_deploy_from_url()` [@tremor021](https://github.com/tremor021) ([#11376](https://github.com/community-scripts/ProxmoxVE/pull/11376))
|
|
||||||
- core: php - improve module handling and prevent installation failures [@MickLesk](https://github.com/MickLesk) ([#11358](https://github.com/community-scripts/ProxmoxVE/pull/11358))
|
|
||||||
|
|
||||||
## 2026-01-29
|
|
||||||
|
|
||||||
### 🆕 New Scripts
|
|
||||||
|
|
||||||
- Alpine-Valkey [@MickLesk](https://github.com/MickLesk) ([#11320](https://github.com/community-scripts/ProxmoxVE/pull/11320))
|
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- Immich: Pin version to 2.5.2 [@vhsdream](https://github.com/vhsdream) ([#11335](https://github.com/community-scripts/ProxmoxVE/pull/11335))
|
|
||||||
- Kollection: Update to php 8.5 [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11315](https://github.com/community-scripts/ProxmoxVE/pull/11315))
|
|
||||||
- Notifiarr: change installation check from apt to systemd service [@MickLesk](https://github.com/MickLesk) ([#11319](https://github.com/community-scripts/ProxmoxVE/pull/11319))
|
|
||||||
|
|
||||||
- #### ✨ New Features
|
|
||||||
|
|
||||||
- [FEAT] Immich: Enable Maintenance Mode before update [@vhsdream](https://github.com/vhsdream) ([#11342](https://github.com/community-scripts/ProxmoxVE/pull/11342))
|
|
||||||
- jellyfin: add logrotate instead of reducing log level [@MickLesk](https://github.com/MickLesk) ([#11326](https://github.com/community-scripts/ProxmoxVE/pull/11326))
|
|
||||||
- core: Add config file handling options | Fix Vikunja update with interactive overwrite [@MickLesk](https://github.com/MickLesk) ([#11317](https://github.com/community-scripts/ProxmoxVE/pull/11317))
|
|
||||||
- Immich: v2.5.0 [@vhsdream](https://github.com/vhsdream) ([#11240](https://github.com/community-scripts/ProxmoxVE/pull/11240))
|
|
||||||
|
|
||||||
- #### 💥 Breaking Changes
|
|
||||||
|
|
||||||
- fix: vikunja v1 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11308](https://github.com/community-scripts/ProxmoxVE/pull/11308))
|
|
||||||
|
|
||||||
- #### 🔧 Refactor
|
|
||||||
|
|
||||||
- Refactor: Byparr [@vhsdream](https://github.com/vhsdream) ([#11338](https://github.com/community-scripts/ProxmoxVE/pull/11338))
|
|
||||||
- cloudflare: Remove deprecated DNS-over-HTTPS proxy option [@MickLesk](https://github.com/MickLesk) ([#11068](https://github.com/community-scripts/ProxmoxVE/pull/11068))
|
|
||||||
|
|
||||||
### 💾 Core
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- build.func: Replace storage variable with searchdomain variable [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11322](https://github.com/community-scripts/ProxmoxVE/pull/11322))
|
|
||||||
|
|
||||||
### 📂 Github
|
|
||||||
|
|
||||||
- Add workflow to lock closed issues [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11316](https://github.com/community-scripts/ProxmoxVE/pull/11316))
|
|
||||||
|
|
||||||
## 2026-01-28
|
|
||||||
|
|
||||||
### 🆕 New Scripts
|
|
||||||
|
|
||||||
- nodecast-tv ([#11287](https://github.com/community-scripts/ProxmoxVE/pull/11287))
|
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- Ubuntu 25.04 VM - Change default start from yes to no [@michelroegl-brunner](https://github.com/michelroegl-brunner) ([#11292](https://github.com/community-scripts/ProxmoxVE/pull/11292))
|
|
||||||
|
|
||||||
- #### ✨ New Features
|
|
||||||
|
|
||||||
- various scripts: use setup_meilisearch function [@MickLesk](https://github.com/MickLesk) ([#11259](https://github.com/community-scripts/ProxmoxVE/pull/11259))
|
|
||||||
|
|
||||||
- #### 🔧 Refactor
|
|
||||||
|
|
||||||
- Refactor: NPMPlus / Default Login [@MickLesk](https://github.com/MickLesk) ([#11262](https://github.com/community-scripts/ProxmoxVE/pull/11262))
|
|
||||||
|
|
||||||
### 💾 Core
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- core: sed patch for ram [@lavacano](https://github.com/lavacano) ([#11285](https://github.com/community-scripts/ProxmoxVE/pull/11285))
|
|
||||||
- Fix installer loop caused by invalid whiptail menu separator [@Mesteriis](https://github.com/Mesteriis) ([#11237](https://github.com/community-scripts/ProxmoxVE/pull/11237))
|
|
||||||
- core: fix Debian 13 LXC template root ownership bug [@MickLesk](https://github.com/MickLesk) ([#11277](https://github.com/community-scripts/ProxmoxVE/pull/11277))
|
|
||||||
- tools.func: prevent systemd-tmpfiles failure in unprivileged LXC during deb install [@MickLesk](https://github.com/MickLesk) ([#11271](https://github.com/community-scripts/ProxmoxVE/pull/11271))
|
|
||||||
- tools.func: fix php "wait_for" hint [@MickLesk](https://github.com/MickLesk) ([#11254](https://github.com/community-scripts/ProxmoxVE/pull/11254))
|
|
||||||
|
|
||||||
- #### ✨ New Features
|
|
||||||
|
|
||||||
- core: update dynamic values in LXC profile on update_motd_ip [@MickLesk](https://github.com/MickLesk) ([#11268](https://github.com/community-scripts/ProxmoxVE/pull/11268))
|
|
||||||
- tools.func: add new function - setup_meilisearch [@MickLesk](https://github.com/MickLesk) ([#11258](https://github.com/community-scripts/ProxmoxVE/pull/11258))
|
|
||||||
|
|
||||||
### 📂 Github
|
|
||||||
|
|
||||||
- github: add GitHub-based versions.json updater [@MickLesk](https://github.com/MickLesk) ([#10021](https://github.com/community-scripts/ProxmoxVE/pull/10021))
|
|
||||||
|
|
||||||
### 🌐 Website
|
|
||||||
|
|
||||||
- #### ✨ New Features
|
|
||||||
|
|
||||||
- Frontend: use github-versions.json for version display [@MickLesk](https://github.com/MickLesk) ([#11281](https://github.com/community-scripts/ProxmoxVE/pull/11281))
|
|
||||||
|
|
||||||
- #### 📝 Script Information
|
|
||||||
|
|
||||||
- fix: homarr: conf location [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11253](https://github.com/community-scripts/ProxmoxVE/pull/11253))
|
|
||||||
|
|
||||||
## 2026-01-27
|
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- Immich: update libraw [@vhsdream](https://github.com/vhsdream) ([#11233](https://github.com/community-scripts/ProxmoxVE/pull/11233))
|
|
||||||
|
|
||||||
- #### ✨ New Features
|
|
||||||
|
|
||||||
- grist: enable optional enterprise features toggle [@MickLesk](https://github.com/MickLesk) ([#11239](https://github.com/community-scripts/ProxmoxVE/pull/11239))
|
|
||||||
|
|
||||||
- #### 🔧 Refactor
|
|
||||||
|
|
||||||
- Termix: use nginx.conf from upstream repo [@MickLesk](https://github.com/MickLesk) ([#11228](https://github.com/community-scripts/ProxmoxVE/pull/11228))
|
|
||||||
|
|
||||||
### 💾 Core
|
|
||||||
|
|
||||||
- #### ✨ New Features
|
|
||||||
|
|
||||||
- feat: add NVIDIA driver install prompt for GPU-enabled containers [@devdecrux](https://github.com/devdecrux) ([#11184](https://github.com/community-scripts/ProxmoxVE/pull/11184))
|
|
||||||
|
|
||||||
### 📚 Documentation
|
|
||||||
|
|
||||||
- doc setup_deb822_repo arg order [@chrnie](https://github.com/chrnie) ([#11215](https://github.com/community-scripts/ProxmoxVE/pull/11215))
|
|
||||||
- changelog: archive old entries to year/month files [@MickLesk](https://github.com/MickLesk) ([#11225](https://github.com/community-scripts/ProxmoxVE/pull/11225))
|
|
||||||
121
.github/changelogs/2026/02.md
generated
vendored
Normal file
121
.github/changelogs/2026/02.md
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
## 2026-02-04
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Wishlist ([#11527](https://github.com/community-scripts/ProxmoxVE/pull/11527))
|
||||||
|
- WriteFreely ([#11524](https://github.com/community-scripts/ProxmoxVE/pull/11524))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: create vm-core.func from dev [@MickLesk](https://github.com/MickLesk) ([#11528](https://github.com/community-scripts/ProxmoxVE/pull/11528))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix(frontend): implement weighted search scoring for command menu [@ls-root](https://github.com/ls-root) ([#11534](https://github.com/community-scripts/ProxmoxVE/pull/11534))
|
||||||
|
|
||||||
|
## 2026-02-03
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Wealthfolio ([#11511](https://github.com/community-scripts/ProxmoxVE/pull/11511))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- [FIX] Shelfmark: unpin Chromium version [@vhsdream](https://github.com/vhsdream) ([#11505](https://github.com/community-scripts/ProxmoxVE/pull/11505))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- [FEAT] Scanopy: automatically update integrated daemon [@vhsdream](https://github.com/vhsdream) ([#11506](https://github.com/community-scripts/ProxmoxVE/pull/11506))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- [FIX] tools.func: trim spaces in app_lc when checking for gh release [@vhsdream](https://github.com/vhsdream) ([#11512](https://github.com/community-scripts/ProxmoxVE/pull/11512))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix(frontend): decouple table pagination from summary fetching [@ls-root](https://github.com/ls-root) ([#11495](https://github.com/community-scripts/ProxmoxVE/pull/11495))
|
||||||
|
|
||||||
|
## 2026-02-02
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- rustypaste | Alpine-rustypaste ([#11457](https://github.com/community-scripts/ProxmoxVE/pull/11457))
|
||||||
|
- KitchenOwl ([#11453](https://github.com/community-scripts/ProxmoxVE/pull/11453))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- Grist: Update dependencies [@tremor021](https://github.com/tremor021) ([#11489](https://github.com/community-scripts/ProxmoxVE/pull/11489))
|
||||||
|
- Allow "downgrade" of libigdgmm12 [@vhsdream](https://github.com/vhsdream) ([#11478](https://github.com/community-scripts/ProxmoxVE/pull/11478))
|
||||||
|
- Disable NPM install and update due to OpenResty SHA-1 signature issues [@MickLesk](https://github.com/MickLesk) ([#11471](https://github.com/community-scripts/ProxmoxVE/pull/11471))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- Refactor: Forgejo & readeck - migrate to codeberg functions [@MickLesk](https://github.com/MickLesk) ([#11460](https://github.com/community-scripts/ProxmoxVE/pull/11460))
|
||||||
|
|
||||||
|
- #### 💥 Breaking Changes
|
||||||
|
|
||||||
|
- [FIX] Scanopy: remove daemon build [@vhsdream](https://github.com/vhsdream) ([#11444](https://github.com/community-scripts/ProxmoxVE/pull/11444))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- Refactor: Vaultwarden [@MickLesk](https://github.com/MickLesk) ([#11445](https://github.com/community-scripts/ProxmoxVE/pull/11445))
|
||||||
|
- various scripts: use ensure_dependencies instead of apt [@MickLesk](https://github.com/MickLesk) ([#11463](https://github.com/community-scripts/ProxmoxVE/pull/11463))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- cleanup(frontend): remove unused /category-view route [@ls-root](https://github.com/ls-root) ([#11461](https://github.com/community-scripts/ProxmoxVE/pull/11461))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- feat(frontend): preview tab [@ls-root](https://github.com/ls-root) ([#11475](https://github.com/community-scripts/ProxmoxVE/pull/11475))
|
||||||
|
|
||||||
|
## 2026-02-01
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- fix headers [@CrazyWolf13](https://github.com/CrazyWolf13) ([#11422](https://github.com/community-scripts/ProxmoxVE/pull/11422))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- 2fauth: export PHP_VERSION for nginx config [@MickLesk](https://github.com/MickLesk) ([#11441](https://github.com/community-scripts/ProxmoxVE/pull/11441))
|
||||||
|
- Prometheus Paperless NGX Exporter: Set correct binary path in systemd unit file [@andygrunwald](https://github.com/andygrunwald) ([#11438](https://github.com/community-scripts/ProxmoxVE/pull/11438))
|
||||||
|
- tracearr: install/update new prestart script from upstream [@durzo](https://github.com/durzo) ([#11433](https://github.com/community-scripts/ProxmoxVE/pull/11433))
|
||||||
|
- n8n: Fix dependencies [@tremor021](https://github.com/tremor021) ([#11429](https://github.com/community-scripts/ProxmoxVE/pull/11429))
|
||||||
|
- [Hotfix] Bunkerweb update [@vhsdream](https://github.com/vhsdream) ([#11402](https://github.com/community-scripts/ProxmoxVE/pull/11402))
|
||||||
|
- [Hotfix] Immich: revert healthcheck feature [@vhsdream](https://github.com/vhsdream) ([#11427](https://github.com/community-scripts/ProxmoxVE/pull/11427))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- tools.func: add codeberg functions & autocaliweb: migrate from GitHub to Codeberg [@MickLesk](https://github.com/MickLesk) ([#11440](https://github.com/community-scripts/ProxmoxVE/pull/11440))
|
||||||
|
- Immich Refactor #2 [@vhsdream](https://github.com/vhsdream) ([#11375](https://github.com/community-scripts/ProxmoxVE/pull/11375))
|
||||||
|
|
||||||
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
|
- WordPress: Refactor [@tremor021](https://github.com/tremor021) ([#11408](https://github.com/community-scripts/ProxmoxVE/pull/11408))
|
||||||
|
- Refactor: Whisparr [@tremor021](https://github.com/tremor021) ([#11411](https://github.com/community-scripts/ProxmoxVE/pull/11411))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- [tools]: Update `fetch_and_deply_from_url()` [@tremor021](https://github.com/tremor021) ([#11410](https://github.com/community-scripts/ProxmoxVE/pull/11410))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- feat(frontend): implement UX refinements and syntax highlighting [@ls-root](https://github.com/ls-root) ([#11423](https://github.com/community-scripts/ProxmoxVE/pull/11423))
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- feat(frontend): add contribution CTA to empty search state [@ls-root](https://github.com/ls-root) ([#11412](https://github.com/community-scripts/ProxmoxVE/pull/11412))
|
||||||
95
.github/workflows/changelog-archive.yml
generated
vendored
95
.github/workflows/changelog-archive.yml
generated
vendored
@@ -54,8 +54,9 @@ jobs:
|
|||||||
|
|
||||||
console.log(`Cutoff date: ${cutoffDate.toISOString().split('T')[0]}`);
|
console.log(`Cutoff date: ${cutoffDate.toISOString().split('T')[0]}`);
|
||||||
|
|
||||||
// Read changelog
|
// Read changelog and normalize line endings
|
||||||
const content = await fs.readFile(CHANGELOG_PATH, 'utf-8');
|
let content = await fs.readFile(CHANGELOG_PATH, 'utf-8');
|
||||||
|
content = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
||||||
const lines = content.split('\n');
|
const lines = content.split('\n');
|
||||||
|
|
||||||
// Parse entries
|
// Parse entries
|
||||||
@@ -66,9 +67,39 @@ jobs:
|
|||||||
let currentDate = null;
|
let currentDate = null;
|
||||||
let currentContent = [];
|
let currentContent = [];
|
||||||
let inHeader = true;
|
let inHeader = true;
|
||||||
|
let inOldHistory = false;
|
||||||
|
let historyDetailsDepth = 0;
|
||||||
|
|
||||||
for (const line of lines) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const line = lines[i];
|
||||||
const match = line.match(datePattern);
|
const match = line.match(datePattern);
|
||||||
|
|
||||||
|
// Detect the start of History section: <details> followed by line with 📜 History
|
||||||
|
if (inHeader && !inOldHistory && line.trim() === '<details>') {
|
||||||
|
// Look ahead to see if this is the History section
|
||||||
|
const nextLine = lines[i + 1] || '';
|
||||||
|
if (nextLine.includes('📜 History')) {
|
||||||
|
inOldHistory = true;
|
||||||
|
historyDetailsDepth = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track nested details tags to find the end of History section
|
||||||
|
if (inOldHistory) {
|
||||||
|
if (line.trim() === '<details>') {
|
||||||
|
historyDetailsDepth++;
|
||||||
|
}
|
||||||
|
if (line.trim() === '</details>') {
|
||||||
|
historyDetailsDepth--;
|
||||||
|
if (historyDetailsDepth === 0) {
|
||||||
|
// We've closed the main History details tag
|
||||||
|
inOldHistory = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
inHeader = false;
|
inHeader = false;
|
||||||
|
|
||||||
@@ -148,30 +179,55 @@ jobs:
|
|||||||
let existingContent = '';
|
let existingContent = '';
|
||||||
try {
|
try {
|
||||||
existingContent = await fs.readFile(monthPath, 'utf-8');
|
existingContent = await fs.readFile(monthPath, 'utf-8');
|
||||||
|
// Normalize line endings to prevent regex issues
|
||||||
|
existingContent = existingContent.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// File doesn't exist
|
// File doesn't exist
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge new entries with existing (avoid duplicates)
|
// Parse existing entries into a Map (date -> content) for deduplication
|
||||||
const existingDates = new Set();
|
const allEntries = new Map();
|
||||||
const existingDatePattern = /^## (\d{4}-\d{2}-\d{2})$/gm;
|
|
||||||
let match;
|
// Helper function to parse entries from content
|
||||||
while ((match = existingDatePattern.exec(existingContent)) !== null) {
|
const parseEntries = (content) => {
|
||||||
existingDates.add(match[1]);
|
const entries = new Map();
|
||||||
|
const parts = content.split(/(?=^## \d{4}-\d{2}-\d{2}$)/m);
|
||||||
|
for (const part of parts) {
|
||||||
|
const trimmed = part.trim();
|
||||||
|
if (!trimmed) continue;
|
||||||
|
const dateMatch = trimmed.match(/^## (\d{4}-\d{2}-\d{2})/);
|
||||||
|
if (dateMatch) {
|
||||||
|
entries.set(dateMatch[1], trimmed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse existing content
|
||||||
|
if (existingContent) {
|
||||||
|
const existingEntries = parseEntries(existingContent);
|
||||||
|
for (const [date, content] of existingEntries) {
|
||||||
|
allEntries.set(date, content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const newEntries = archiveData[year][month].filter(entry => {
|
// Add new entries (existing entries take precedence to avoid overwriting)
|
||||||
|
let addedCount = 0;
|
||||||
|
for (const entry of archiveData[year][month]) {
|
||||||
const dateMatch = entry.match(/^## (\d{4}-\d{2}-\d{2})/);
|
const dateMatch = entry.match(/^## (\d{4}-\d{2}-\d{2})/);
|
||||||
return dateMatch && !existingDates.has(dateMatch[1]);
|
if (dateMatch && !allEntries.has(dateMatch[1])) {
|
||||||
});
|
allEntries.set(dateMatch[1], entry.trim());
|
||||||
|
addedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (newEntries.length > 0) {
|
// Sort entries by date (newest first) and write
|
||||||
const allContent = existingContent
|
const sortedDates = [...allEntries.keys()].sort().reverse();
|
||||||
? existingContent + '\n\n' + newEntries.join('\n\n')
|
const sortedContent = sortedDates.map(date => allEntries.get(date)).join('\n\n');
|
||||||
: newEntries.join('\n\n');
|
|
||||||
|
|
||||||
await fs.writeFile(monthPath, allContent, 'utf-8');
|
if (addedCount > 0 || !existingContent) {
|
||||||
console.log(`Updated: ${monthPath} (+${newEntries.length} entries)`);
|
await fs.writeFile(monthPath, sortedContent + '\n', 'utf-8');
|
||||||
|
console.log(`Updated: ${monthPath} (${allEntries.size} total entries, +${addedCount} new)`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,7 +274,8 @@ jobs:
|
|||||||
// Count entries in month file
|
// Count entries in month file
|
||||||
let entryCount = 0;
|
let entryCount = 0;
|
||||||
try {
|
try {
|
||||||
const monthContent = await fs.readFile(monthPath, 'utf-8');
|
let monthContent = await fs.readFile(monthPath, 'utf-8');
|
||||||
|
monthContent = monthContent.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
||||||
entryCount = (monthContent.match(/^## \d{4}-\d{2}-\d{2}$/gm) || []).length;
|
entryCount = (monthContent.match(/^## \d{4}-\d{2}-\d{2}$/gm) || []).length;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
entryCount = (archiveData[year]?.[month] || []).length;
|
entryCount = (archiveData[year]?.[month] || []).length;
|
||||||
|
|||||||
489
CHANGELOG.md
489
CHANGELOG.md
@@ -21,7 +21,14 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><h4>January - 27 entries</h4></summary>
|
<summary><h4>February (4 entries)</h4></summary>
|
||||||
|
|
||||||
|
[View February 2026 Changelog](.github/changelogs/2026/02.md)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><h4>January (31 entries)</h4></summary>
|
||||||
|
|
||||||
[View January 2026 Changelog](.github/changelogs/2026/01.md)
|
[View January 2026 Changelog](.github/changelogs/2026/01.md)
|
||||||
|
|
||||||
@@ -391,389 +398,70 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
## 2026-02-05
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
<details>
|
- OpenCloud ([#11538](https://github.com/community-scripts/ProxmoxVE/pull/11538))
|
||||||
<summary><h2>📜 History</h2></summary>
|
- Nginx-UI ([#11573](https://github.com/community-scripts/ProxmoxVE/pull/11573))
|
||||||
|
- New: SQL-Server 2025 | Refactor SQL-Server 2022 [@MickLesk](https://github.com/MickLesk) ([#11546](https://github.com/community-scripts/ProxmoxVE/pull/11546))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
<details>
|
- #### ✨ New Features
|
||||||
<summary><h3>2026</h3></summary>
|
|
||||||
|
|
||||||
|
- Refactor: Docker-VM (Multi-OS / Cloud-Init / Stabilization) [@MickLesk](https://github.com/MickLesk) ([#9047](https://github.com/community-scripts/ProxmoxVE/pull/9047))
|
||||||
|
|
||||||
<details>
|
### 💾 Core
|
||||||
<summary><h4>January (31 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View January 2026 Changelog](.github/changelogs/2026/01.md)
|
- #### ✨ New Features
|
||||||
|
|
||||||
</details>
|
- cloud-init: add interactive SSH key discovery and selection [@MickLesk](https://github.com/MickLesk) ([#11547](https://github.com/community-scripts/ProxmoxVE/pull/11547))
|
||||||
|
|
||||||
</details>
|
### 🌐 Website
|
||||||
|
|
||||||
<details>
|
- #### 🐞 Bug Fixes
|
||||||
<summary><h3>2025</h3></summary>
|
|
||||||
|
|
||||||
|
- fix(frontend): theme respective syntax highlighting [@ls-root](https://github.com/ls-root) ([#11565](https://github.com/community-scripts/ProxmoxVE/pull/11565))
|
||||||
<details>
|
|
||||||
<summary><h4>December (31 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View December 2025 Changelog](.github/changelogs/2025/12.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>November (29 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View November 2025 Changelog](.github/changelogs/2025/11.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>October (30 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View October 2025 Changelog](.github/changelogs/2025/10.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>September (29 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View September 2025 Changelog](.github/changelogs/2025/09.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>August (30 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View August 2025 Changelog](.github/changelogs/2025/08.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>July (29 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View July 2025 Changelog](.github/changelogs/2025/07.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>June (29 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View June 2025 Changelog](.github/changelogs/2025/06.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>May (30 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View May 2025 Changelog](.github/changelogs/2025/05.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>April (25 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View April 2025 Changelog](.github/changelogs/2025/04.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>March (30 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View March 2025 Changelog](.github/changelogs/2025/03.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>February (26 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View February 2025 Changelog](.github/changelogs/2025/02.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>January (27 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View January 2025 Changelog](.github/changelogs/2025/01.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h3>2024</h3></summary>
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>December (22 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View December 2024 Changelog](.github/changelogs/2024/12.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>November (15 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View November 2024 Changelog](.github/changelogs/2024/11.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>October (9 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View October 2024 Changelog](.github/changelogs/2024/10.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>September (1 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View September 2024 Changelog](.github/changelogs/2024/09.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>August (2 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View August 2024 Changelog](.github/changelogs/2024/08.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>July (0 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View July 2024 Changelog](.github/changelogs/2024/07.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>June (8 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View June 2024 Changelog](.github/changelogs/2024/06.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>May (16 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View May 2024 Changelog](.github/changelogs/2024/05.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>April (14 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View April 2024 Changelog](.github/changelogs/2024/04.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>March (5 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View March 2024 Changelog](.github/changelogs/2024/03.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>February (9 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View February 2024 Changelog](.github/changelogs/2024/02.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>January (9 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View January 2024 Changelog](.github/changelogs/2024/01.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h3>2023</h3></summary>
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>December (3 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View December 2023 Changelog](.github/changelogs/2023/12.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>November (3 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View November 2023 Changelog](.github/changelogs/2023/11.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>October (7 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View October 2023 Changelog](.github/changelogs/2023/10.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>September (10 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View September 2023 Changelog](.github/changelogs/2023/09.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>August (7 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View August 2023 Changelog](.github/changelogs/2023/08.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>July (5 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View July 2023 Changelog](.github/changelogs/2023/07.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>June (5 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View June 2023 Changelog](.github/changelogs/2023/06.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>May (8 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View May 2023 Changelog](.github/changelogs/2023/05.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>April (8 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View April 2023 Changelog](.github/changelogs/2023/04.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>March (8 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View March 2023 Changelog](.github/changelogs/2023/03.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>February (6 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View February 2023 Changelog](.github/changelogs/2023/02.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>January (15 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View January 2023 Changelog](.github/changelogs/2023/01.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h3>2022</h3></summary>
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>December (7 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View December 2022 Changelog](.github/changelogs/2022/12.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>November (7 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View November 2022 Changelog](.github/changelogs/2022/11.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>October (2 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View October 2022 Changelog](.github/changelogs/2022/10.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>September (9 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View September 2022 Changelog](.github/changelogs/2022/09.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>August (7 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View August 2022 Changelog](.github/changelogs/2022/08.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>July (10 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View July 2022 Changelog](.github/changelogs/2022/07.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>June (1 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View June 2022 Changelog](.github/changelogs/2022/06.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>May (8 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View May 2022 Changelog](.github/changelogs/2022/05.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>April (13 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View April 2022 Changelog](.github/changelogs/2022/04.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>March (20 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View March 2022 Changelog](.github/changelogs/2022/03.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>February (15 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View February 2022 Changelog](.github/changelogs/2022/02.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><h4>January (3 entries)</h4></summary>
|
|
||||||
|
|
||||||
[View January 2022 Changelog](.github/changelogs/2022/01.md)
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## 2026-02-04
|
## 2026-02-04
|
||||||
|
|
||||||
|
### 🆕 New Scripts
|
||||||
|
|
||||||
|
- Wishlist ([#11527](https://github.com/community-scripts/ProxmoxVE/pull/11527))
|
||||||
|
- WriteFreely ([#11524](https://github.com/community-scripts/ProxmoxVE/pull/11524))
|
||||||
|
|
||||||
|
### 🚀 Updated Scripts
|
||||||
|
|
||||||
|
- Add log directory and permissions for koillection [@shineangelic](https://github.com/shineangelic) ([#11553](https://github.com/community-scripts/ProxmoxVE/pull/11553))
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- [FIX] Scanopy: ensure Scanopy Daemon update [@vhsdream](https://github.com/vhsdream) ([#11541](https://github.com/community-scripts/ProxmoxVE/pull/11541))
|
||||||
|
- Immich: pin version to 2.5.3 [@vhsdream](https://github.com/vhsdream) ([#11515](https://github.com/community-scripts/ProxmoxVE/pull/11515))
|
||||||
|
|
||||||
|
### 💾 Core
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- core: create vm-core.func from dev [@MickLesk](https://github.com/MickLesk) ([#11528](https://github.com/community-scripts/ProxmoxVE/pull/11528))
|
||||||
|
|
||||||
|
### 🧰 Tools
|
||||||
|
|
||||||
|
- #### ✨ New Features
|
||||||
|
|
||||||
|
- [ADDON] Immich Public Proxy addon [@vhsdream](https://github.com/vhsdream) ([#11518](https://github.com/community-scripts/ProxmoxVE/pull/11518))
|
||||||
|
|
||||||
|
### 🌐 Website
|
||||||
|
|
||||||
|
- #### 🐞 Bug Fixes
|
||||||
|
|
||||||
|
- fix(frontend): implement weighted search scoring for command menu [@ls-root](https://github.com/ls-root) ([#11534](https://github.com/community-scripts/ProxmoxVE/pull/11534))
|
||||||
|
|
||||||
|
### ❔ Uncategorized
|
||||||
|
|
||||||
|
- [FIX] Immich Public Proxy docs link [@vhsdream](https://github.com/vhsdream) ([#11543](https://github.com/community-scripts/ProxmoxVE/pull/11543))
|
||||||
|
|
||||||
## 2026-02-03
|
## 2026-02-03
|
||||||
|
|
||||||
### 🆕 New Scripts
|
### 🆕 New Scripts
|
||||||
@@ -1627,64 +1315,3 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
|||||||
- #### 🔧 Refactor
|
- #### 🔧 Refactor
|
||||||
|
|
||||||
- Refactor: IP-Tag (Multiple IP / Performance / Execution Time) [@MickLesk](https://github.com/MickLesk) ([#10558](https://github.com/community-scripts/ProxmoxVE/pull/10558))
|
- Refactor: IP-Tag (Multiple IP / Performance / Execution Time) [@MickLesk](https://github.com/MickLesk) ([#10558](https://github.com/community-scripts/ProxmoxVE/pull/10558))
|
||||||
|
|
||||||
## 2026-01-04
|
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- PocketID: Update PocketID for 2.x [@tremor021](https://github.com/tremor021) ([#10506](https://github.com/community-scripts/ProxmoxVE/pull/10506))
|
|
||||||
- fix: reitti: nginx [@CrazyWolf13](https://github.com/CrazyWolf13) ([#10511](https://github.com/community-scripts/ProxmoxVE/pull/10511))
|
|
||||||
- MagicMirror: bump to nodejs 24 [@MickLesk](https://github.com/MickLesk) ([#10534](https://github.com/community-scripts/ProxmoxVE/pull/10534))
|
|
||||||
|
|
||||||
- #### 🔧 Refactor
|
|
||||||
|
|
||||||
- Refactor: SFTPGo [@tremor021](https://github.com/tremor021) ([#10518](https://github.com/community-scripts/ProxmoxVE/pull/10518))
|
|
||||||
- Refactor: Pelican Wings [@tremor021](https://github.com/tremor021) ([#10517](https://github.com/community-scripts/ProxmoxVE/pull/10517))
|
|
||||||
- Refactor: Pelican Panel [@tremor021](https://github.com/tremor021) ([#10516](https://github.com/community-scripts/ProxmoxVE/pull/10516))
|
|
||||||
- Refactor: Audiobookshelf [@tremor021](https://github.com/tremor021) ([#10519](https://github.com/community-scripts/ProxmoxVE/pull/10519))
|
|
||||||
|
|
||||||
### 💾 Core
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- Export IPV6_METHOD to trigger verb_ip6() function [@remz1337](https://github.com/remz1337) ([#10538](https://github.com/community-scripts/ProxmoxVE/pull/10538))
|
|
||||||
|
|
||||||
### 🌐 Website
|
|
||||||
|
|
||||||
- #### 📝 Script Information
|
|
||||||
|
|
||||||
- Prowlarr: Update config_path [@tremor021](https://github.com/tremor021) ([#10504](https://github.com/community-scripts/ProxmoxVE/pull/10504))
|
|
||||||
|
|
||||||
## 2026-01-03
|
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- Fix ownership and permissions for InvoiceNinja setup [@twinzdragonz](https://github.com/twinzdragonz) ([#10298](https://github.com/community-scripts/ProxmoxVE/pull/10298))
|
|
||||||
- Fix headscale Caddyfile to pass non-API URLs [@IlyaSemenov](https://github.com/IlyaSemenov) ([#10493](https://github.com/community-scripts/ProxmoxVE/pull/10493))
|
|
||||||
|
|
||||||
### 💾 Core
|
|
||||||
|
|
||||||
- #### 🔧 Refactor
|
|
||||||
|
|
||||||
- [core]: Preserve log files [@tremor021](https://github.com/tremor021) ([#10509](https://github.com/community-scripts/ProxmoxVE/pull/10509))
|
|
||||||
|
|
||||||
### ❔ Uncategorized
|
|
||||||
|
|
||||||
- Wireguard: Update WGDashboard notes URL to the new link [@tremor021](https://github.com/tremor021) ([#10496](https://github.com/community-scripts/ProxmoxVE/pull/10496))
|
|
||||||
- InvoiceNinja: Update database credentias information [@tremor021](https://github.com/tremor021) ([#10497](https://github.com/community-scripts/ProxmoxVE/pull/10497))
|
|
||||||
|
|
||||||
## 2026-01-02
|
|
||||||
|
|
||||||
### 🚀 Updated Scripts
|
|
||||||
|
|
||||||
- #### 🐞 Bug Fixes
|
|
||||||
|
|
||||||
- Fix Intel Level Zero package conflict on Debian 13 [@Copilot](https://github.com/Copilot) ([#10467](https://github.com/community-scripts/ProxmoxVE/pull/10467))
|
|
||||||
|
|
||||||
### ❔ Uncategorized
|
|
||||||
|
|
||||||
- Extend guidance for changing the immich upload location for #10447 [@jshprentz](https://github.com/jshprentz) ([#10475](https://github.com/community-scripts/ProxmoxVE/pull/10475))
|
|
||||||
6
ct/headers/nginx-ui
Normal file
6
ct/headers/nginx-ui
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
_ __ _ __ ______
|
||||||
|
/ | / /___ _(_)___ _ __ / / / / _/
|
||||||
|
/ |/ / __ `/ / __ \| |/_/_____/ / / // /
|
||||||
|
/ /| / /_/ / / / / /> </_____/ /_/ // /
|
||||||
|
/_/ |_/\__, /_/_/ /_/_/|_| \____/___/
|
||||||
|
/____/
|
||||||
6
ct/headers/opencloud
Normal file
6
ct/headers/opencloud
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
____ ________ __
|
||||||
|
/ __ \____ ___ ____ / ____/ /___ __ ______/ /
|
||||||
|
/ / / / __ \/ _ \/ __ \/ / / / __ \/ / / / __ /
|
||||||
|
/ /_/ / /_/ / __/ / / / /___/ / /_/ / /_/ / /_/ /
|
||||||
|
\____/ .___/\___/_/ /_/\____/_/\____/\__,_/\__,_/
|
||||||
|
/_/
|
||||||
6
ct/headers/sqlserver2025
Normal file
6
ct/headers/sqlserver2025
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
_____ ____ __ _____ ___ ____ ___ ______
|
||||||
|
/ ___// __ \ / / / ___/___ ______ _____ _____ |__ \ / __ \__ \ / ____/
|
||||||
|
\__ \/ / / / / / \__ \/ _ \/ ___/ | / / _ \/ ___/ __/ // / / /_/ //___ \
|
||||||
|
___/ / /_/ / / /___ ___/ / __/ / | |/ / __/ / / __// /_/ / __/____/ /
|
||||||
|
/____/\___\_\/_____/ /____/\___/_/ |___/\___/_/ /____/\____/____/_____/
|
||||||
|
|
||||||
6
ct/headers/wishlist
Normal file
6
ct/headers/wishlist
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
_ ___ __ ___ __
|
||||||
|
| | / (_)____/ /_ / (_)____/ /_
|
||||||
|
| | /| / / / ___/ __ \/ / / ___/ __/
|
||||||
|
| |/ |/ / (__ ) / / / / (__ ) /_
|
||||||
|
|__/|__/_/____/_/ /_/_/_/____/\__/
|
||||||
|
|
||||||
6
ct/headers/writefreely
Normal file
6
ct/headers/writefreely
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
_ __ _ __ ______ __
|
||||||
|
| | / /____(_) /____ / ____/_______ ___ / /_ __
|
||||||
|
| | /| / / ___/ / __/ _ \/ /_ / ___/ _ \/ _ \/ / / / /
|
||||||
|
| |/ |/ / / / / /_/ __/ __/ / / / __/ __/ / /_/ /
|
||||||
|
|__/|__/_/ /_/\__/\___/_/ /_/ \___/\___/_/\__, /
|
||||||
|
/____/
|
||||||
@@ -36,10 +36,6 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
setup_uv
|
|
||||||
PNPM_VERSION="$(curl -fsSL "https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/package.json" | jq -r '.packageManager | split("@")[1]')"
|
|
||||||
NODE_VERSION="24" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
|
|
||||||
|
|
||||||
if [[ ! -f /etc/apt/preferences.d/preferences ]]; then
|
if [[ ! -f /etc/apt/preferences.d/preferences ]]; then
|
||||||
msg_info "Adding Debian Testing repo"
|
msg_info "Adding Debian Testing repo"
|
||||||
sed -i 's/ trixie-updates/ trixie-updates testing/g' /etc/apt/sources.list.d/debian.sources
|
sed -i 's/ trixie-updates/ trixie-updates testing/g' /etc/apt/sources.list.d/debian.sources
|
||||||
@@ -109,7 +105,7 @@ EOF
|
|||||||
msg_ok "Image-processing libraries up to date"
|
msg_ok "Image-processing libraries up to date"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
RELEASE="2.5.2"
|
RELEASE="2.5.3"
|
||||||
if check_for_gh_release "immich" "immich-app/immich" "${RELEASE}"; then
|
if check_for_gh_release "immich" "immich-app/immich" "${RELEASE}"; then
|
||||||
if [[ $(cat ~/.immich) > "2.5.1" ]]; then
|
if [[ $(cat ~/.immich) > "2.5.1" ]]; then
|
||||||
msg_info "Enabling Maintenance Mode"
|
msg_info "Enabling Maintenance Mode"
|
||||||
@@ -164,7 +160,10 @@ EOF
|
|||||||
rm -rf "${APP_DIR:?}"/*
|
rm -rf "${APP_DIR:?}"/*
|
||||||
)
|
)
|
||||||
|
|
||||||
|
setup_uv
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v${RELEASE}" "$SRC_DIR"
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v${RELEASE}" "$SRC_DIR"
|
||||||
|
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1]' ${SRC_DIR}/package.json)"
|
||||||
|
NODE_VERSION="24" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
|
||||||
|
|
||||||
msg_info "Updating Immich web and microservices"
|
msg_info "Updating Immich web and microservices"
|
||||||
cd "$SRC_DIR"/server
|
cd "$SRC_DIR"/server
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ function update_script() {
|
|||||||
$STD yarn install
|
$STD yarn install
|
||||||
$STD yarn build
|
$STD yarn build
|
||||||
mkdir -p /opt/koillection/public/uploads
|
mkdir -p /opt/koillection/public/uploads
|
||||||
|
mkdir -p /opt/koillection/var/log
|
||||||
|
chown -R www-data:www-data /opt/koillection/var/log
|
||||||
chown -R www-data:www-data /opt/koillection/public/uploads
|
chown -R www-data:www-data /opt/koillection/public/uploads
|
||||||
rm -r /opt/koillection-backup
|
rm -r /opt/koillection-backup
|
||||||
|
|
||||||
|
|||||||
68
ct/nginx-ui.sh
Normal file
68
ct/nginx-ui.sh
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/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://nginxui.com
|
||||||
|
|
||||||
|
APP="Nginx-UI"
|
||||||
|
var_tags="${var_tags:-webserver;nginx;proxy}"
|
||||||
|
var_cpu="${var_cpu:-1}"
|
||||||
|
var_ram="${var_ram:-512}"
|
||||||
|
var_disk="${var_disk:-4}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
if [[ ! -f /usr/local/bin/nginx-ui ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "nginx-ui" "0xJacky/nginx-ui"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop nginx-ui
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Backing up Configuration"
|
||||||
|
cp /usr/local/etc/nginx-ui/app.ini /tmp/nginx-ui-app.ini.bak
|
||||||
|
msg_ok "Backed up Configuration"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "nginx-ui" "0xJacky/nginx-ui" "prebuild" "latest" "/opt/nginx-ui" "nginx-ui-linux-64.tar.gz"
|
||||||
|
|
||||||
|
msg_info "Updating Binary"
|
||||||
|
cp /opt/nginx-ui/nginx-ui /usr/local/bin/nginx-ui
|
||||||
|
chmod +x /usr/local/bin/nginx-ui
|
||||||
|
rm -rf /opt/nginx-ui
|
||||||
|
msg_ok "Updated Binary"
|
||||||
|
|
||||||
|
msg_info "Restoring Configuration"
|
||||||
|
mv /tmp/nginx-ui-app.ini.bak /usr/local/etc/nginx-ui/app.ini
|
||||||
|
msg_ok "Restored Configuration"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start nginx-ui
|
||||||
|
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}:9000${CL}"
|
||||||
60
ct/opencloud.sh
Normal file
60
ct/opencloud.sh
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/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: vhsdream
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://opencloud.eu
|
||||||
|
|
||||||
|
APP="OpenCloud"
|
||||||
|
var_tags="${var_tags:-files;cloud}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-20}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
if [[ ! -d /etc/opencloud ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
RELEASE="v5.0.1"
|
||||||
|
if check_for_gh_release "opencloud" "opencloud-eu/opencloud" "${RELEASE}"; then
|
||||||
|
msg_info "Stopping services"
|
||||||
|
systemctl stop opencloud opencloud-wopi
|
||||||
|
msg_ok "Stopped services"
|
||||||
|
|
||||||
|
msg_info "Updating packages"
|
||||||
|
$STD apt-get update
|
||||||
|
$STD apt-get dist-upgrade -y
|
||||||
|
msg_ok "Updated packages"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "opencloud" "opencloud-eu/opencloud" "singlefile" "${RELEASE}" "/usr/bin" "opencloud-*-linux-amd64"
|
||||||
|
|
||||||
|
msg_info "Starting services"
|
||||||
|
systemctl start opencloud opencloud-wopi
|
||||||
|
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}https://<your-OpenCloud-FQDN>${CL}"
|
||||||
@@ -29,7 +29,7 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_for_gh_release "scanopy" "scanopy/scanopy"; then
|
if check_for_gh_release "Scanopy" "scanopy/scanopy"; then
|
||||||
msg_info "Stopping services"
|
msg_info "Stopping services"
|
||||||
systemctl stop scanopy-server
|
systemctl stop scanopy-server
|
||||||
[[ -f /etc/systemd/system/scanopy-daemon.service ]] && systemctl stop scanopy-daemon
|
[[ -f /etc/systemd/system/scanopy-daemon.service ]] && systemctl stop scanopy-daemon
|
||||||
@@ -40,7 +40,7 @@ function update_script() {
|
|||||||
[[ -f /opt/scanopy/oidc.toml ]] && cp /opt/scanopy/oidc.toml /opt/scanopy.oidc.toml
|
[[ -f /opt/scanopy/oidc.toml ]] && cp /opt/scanopy/oidc.toml /opt/scanopy.oidc.toml
|
||||||
msg_ok "Backed up configurations"
|
msg_ok "Backed up configurations"
|
||||||
|
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "scanopy" "scanopy/scanopy" "tarball" "latest" "/opt/scanopy"
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Scanopy" "scanopy/scanopy" "tarball" "latest" "/opt/scanopy"
|
||||||
|
|
||||||
ensure_dependencies pkg-config libssl-dev
|
ensure_dependencies pkg-config libssl-dev
|
||||||
TOOLCHAIN="$(grep "channel" /opt/scanopy/backend/rust-toolchain.toml | awk -F\" '{print $2}')"
|
TOOLCHAIN="$(grep "channel" /opt/scanopy/backend/rust-toolchain.toml | awk -F\" '{print $2}')"
|
||||||
@@ -61,19 +61,22 @@ function update_script() {
|
|||||||
$STD npm run build
|
$STD npm run build
|
||||||
msg_ok "Created frontend UI"
|
msg_ok "Created frontend UI"
|
||||||
|
|
||||||
msg_info "Building scanopy-server (patience)"
|
msg_info "Building Scanopy Server (patience)"
|
||||||
cd /opt/scanopy/backend
|
cd /opt/scanopy/backend
|
||||||
$STD cargo build --release --bin server
|
$STD cargo build --release --bin server
|
||||||
mv ./target/release/server /usr/bin/scanopy-server
|
mv ./target/release/server /usr/bin/scanopy-server
|
||||||
msg_ok "Built scanopy-server"
|
msg_ok "Built Scanopy Server"
|
||||||
|
|
||||||
[[ -f /etc/systemd/system/scanopy-daemon.service ]] &&
|
if [[ -f /etc/systemd/system/scanopy-daemon.service ]]; then
|
||||||
fetch_and_deploy_gh_release "scanopy" "scanopy/scanopy" "singlefile" "latest" "/usr/local/bin" "scanopy-daemon-linux-amd64" &&
|
fetch_and_deploy_gh_release "Scanopy Daemon" "scanopy/scanopy" "singlefile" "latest" "/usr/local/bin" "scanopy-daemon-linux-amd64"
|
||||||
rm -f /usr/bin/scanopy-daemon ~/configure_daemon.sh &&
|
mv "/usr/local/bin/Scanopy Daemon" /usr/local/bin/scanopy-daemon
|
||||||
|
rm -f /usr/bin/scanopy-daemon ~/configure_daemon.sh
|
||||||
sed -i -e 's|usr/bin|usr/local/bin|' \
|
sed -i -e 's|usr/bin|usr/local/bin|' \
|
||||||
-e 's/push/daemon_poll/' \
|
-e 's/push/daemon_poll/' \
|
||||||
-e 's/pull/server_poll/' /etc/systemd/system/scanopy-daemon.service &&
|
-e 's/pull/server_poll/' /etc/systemd/system/scanopy-daemon.service
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
|
msg_ok "Updated Scanopy Daemon"
|
||||||
|
fi
|
||||||
|
|
||||||
msg_info "Starting services"
|
msg_info "Starting services"
|
||||||
systemctl start scanopy-server
|
systemctl start scanopy-server
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ function update_script() {
|
|||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
msg_info "Updating ${APP} LXC"
|
msg_info "Updating SQL Server 2022"
|
||||||
|
rm -f /etc/profile.d/debuginfod.sh /etc/profile.d/debuginfod.csh
|
||||||
$STD apt update
|
$STD apt update
|
||||||
$STD apt -y upgrade
|
$STD apt -y upgrade
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
|
|||||||
45
ct/sqlserver2025.sh
Normal file
45
ct/sqlserver2025.sh
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/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://www.microsoft.com/en-us/sql-server/sql-server-2025
|
||||||
|
|
||||||
|
APP="SQL Server 2025"
|
||||||
|
var_tags="${var_tags:-sql;database}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-10}"
|
||||||
|
var_os="${var_os:-ubuntu}"
|
||||||
|
var_version="${var_version:-24.04}"
|
||||||
|
var_unprivileged="${var_unprivileged:-0}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
if [[ ! -d /opt/mssql ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
msg_info "Updating SQL Server 2025"
|
||||||
|
rm -f /etc/profile.d/debuginfod.sh /etc/profile.d/debuginfod.csh
|
||||||
|
$STD apt update
|
||||||
|
$STD apt -y upgrade
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
start
|
||||||
|
build_container
|
||||||
|
description
|
||||||
|
|
||||||
|
msg_ok "Completed successfully!\n"
|
||||||
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
|
echo -e "${INFO}${YW} Access it using the following IP:${CL}"
|
||||||
|
echo -e "${TAB}${GATEWAY}${BGN}${IP}:1433${CL}"
|
||||||
82
ct/wishlist.sh
Normal file
82
ct/wishlist.sh
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#!/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: Dunky13
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/cmintey/wishlist
|
||||||
|
|
||||||
|
APP="Wishlist"
|
||||||
|
var_tags="${var_tags:-sharing}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-5}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
|
||||||
|
header_info "$APP"
|
||||||
|
variables
|
||||||
|
color
|
||||||
|
catch_errors
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
if [[ ! -d /opt/wishlist ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "wishlist" "cmintey/wishlist"; then
|
||||||
|
NODE_VERSION="24" NODE_MODULE="pnpm" setup_nodejs
|
||||||
|
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop wishlist
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Creating Backup"
|
||||||
|
mkdir -p /opt/wishlist-backup
|
||||||
|
cp /opt/wishlist/.env /opt/wishlist-backup/.env
|
||||||
|
cp -a /opt/wishlist/uploads /opt/wishlist-backup
|
||||||
|
cp -a /opt/wishlist/data /opt/wishlist-backup
|
||||||
|
msg_ok "Created Backup"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "wishlist" "cmintey/wishlist" "tarball"
|
||||||
|
LATEST_APP_VERSION=$(get_latest_github_release "cmintey/wishlist")
|
||||||
|
|
||||||
|
msg_info "Updating Wishlist"
|
||||||
|
cd /opt/wishlist
|
||||||
|
$STD pnpm install
|
||||||
|
$STD pnpm svelte-kit sync
|
||||||
|
$STD pnpm prisma generate
|
||||||
|
sed -i 's|/usr/src/app/|/opt/wishlist/|g' $(grep -rl '/usr/src/app/' /opt/wishlist)
|
||||||
|
export VERSION="v${LATEST_APP_VERSION}"
|
||||||
|
export SHA="v${LATEST_APP_VERSION}"
|
||||||
|
$STD pnpm run build
|
||||||
|
$STD pnpm prune --prod
|
||||||
|
chmod +x /opt/wishlist/entrypoint.sh
|
||||||
|
|
||||||
|
msg_info "Restoring Backup"
|
||||||
|
cp /opt/wishlist-backup/.env /opt/wishlist/.env
|
||||||
|
cp -a /opt/wishlist-backup/uploads /opt/wishlist
|
||||||
|
cp -a /opt/wishlist-backup/data /opt/wishlist
|
||||||
|
rm -rf /opt/wishlist-backup
|
||||||
|
msg_ok "Restored Backup"
|
||||||
|
|
||||||
|
msg_ok "Updated Wishlist"
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start wishlist
|
||||||
|
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}:3280${CL}"
|
||||||
868
docs/contribution/AI.md
Normal file
868
docs/contribution/AI.md
Normal file
@@ -0,0 +1,868 @@
|
|||||||
|
# 🤖 AI Contribution Guidelines for ProxmoxVE
|
||||||
|
|
||||||
|
> **This documentation is intended for all AI assistants (GitHub Copilot, Claude, ChatGPT, etc.) contributing to this project.**
|
||||||
|
|
||||||
|
## 🎯 Core Principles
|
||||||
|
|
||||||
|
### 1. **Maximum Use of `tools.func` Functions**
|
||||||
|
|
||||||
|
We have an extensive library of helper functions. **NEVER** implement your own solutions when a function already exists!
|
||||||
|
|
||||||
|
### 2. **No Pointless Variables**
|
||||||
|
|
||||||
|
Only create variables when they:
|
||||||
|
|
||||||
|
- Are used multiple times
|
||||||
|
- Improve readability
|
||||||
|
- Are intended for configuration
|
||||||
|
|
||||||
|
### 3. **Consistent Script Structure**
|
||||||
|
|
||||||
|
All scripts follow an identical structure. Deviations are not acceptable.
|
||||||
|
|
||||||
|
### 4. **Bare-Metal Installation**
|
||||||
|
|
||||||
|
We do **NOT use Docker** for our installation scripts. All applications are installed directly on the system.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 Script Types and Their Structure
|
||||||
|
|
||||||
|
### CT Script (`ct/AppName.sh`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/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: AuthorName (GitHubUsername)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://application-url.com
|
||||||
|
|
||||||
|
APP="AppName"
|
||||||
|
var_tags="${var_tags:-tag1;tag2;tag3}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-8}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_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/appname ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if check_for_gh_release "appname" "YourUsername/YourRepo"; then
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop appname
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
msg_info "Backing up Data"
|
||||||
|
cp -r /opt/appname/data /opt/appname_data_backup
|
||||||
|
msg_ok "Backed up Data"
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/appname"
|
||||||
|
|
||||||
|
# Build steps...
|
||||||
|
|
||||||
|
msg_info "Restoring Data"
|
||||||
|
cp -r /opt/appname_data_backup/. /opt/appname/data
|
||||||
|
rm -rf /opt/appname_data_backup
|
||||||
|
msg_ok "Restored Data"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start appname
|
||||||
|
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}:PORT${CL}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install Script (`install/AppName-install.sh`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: AuthorName (GitHubUsername)
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://application-url.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-get install -y \
|
||||||
|
dependency1 \
|
||||||
|
dependency2
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
# Runtime Setup (ALWAYS use our functions!)
|
||||||
|
NODE_VERSION="22" setup_nodejs
|
||||||
|
# or
|
||||||
|
PG_VERSION="16" setup_postgresql
|
||||||
|
# or
|
||||||
|
setup_uv
|
||||||
|
# etc.
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/appname"
|
||||||
|
|
||||||
|
msg_info "Setting up Application"
|
||||||
|
cd /opt/appname
|
||||||
|
# Build/Setup Schritte...
|
||||||
|
msg_ok "Set up Application"
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/appname.service
|
||||||
|
[Unit]
|
||||||
|
Description=AppName Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/opt/appname
|
||||||
|
ExecStart=/path/to/executable
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now appname
|
||||||
|
msg_ok "Created Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Available Helper Functions
|
||||||
|
|
||||||
|
### Release Management
|
||||||
|
|
||||||
|
| Function | Description | Example |
|
||||||
|
| ----------------------------- | ----------------------------------- | ------------------------------------------------------------- |
|
||||||
|
| `fetch_and_deploy_gh_release` | Fetches and installs GitHub Release | `fetch_and_deploy_gh_release "app" "owner/repo"` |
|
||||||
|
| `check_for_gh_release` | Checks for new version | `if check_for_gh_release "app" "YourUsername/YourRepo"; then` |
|
||||||
|
|
||||||
|
**Modes for `fetch_and_deploy_gh_release`:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Tarball/Source (Standard)
|
||||||
|
fetch_and_deploy_gh_release "appname" "owner/repo"
|
||||||
|
|
||||||
|
# Binary (.deb)
|
||||||
|
fetch_and_deploy_gh_release "appname" "owner/repo" "binary"
|
||||||
|
|
||||||
|
# Prebuilt Archive
|
||||||
|
fetch_and_deploy_gh_release "appname" "owner/repo" "prebuild" "latest" "/opt/appname" "filename.tar.gz"
|
||||||
|
|
||||||
|
# Single Binary
|
||||||
|
fetch_and_deploy_gh_release "appname" "owner/repo" "singlefile" "latest" "/opt/appname" "binary-linux-amd64"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Clean Install Flag:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Runtime/Language Setup
|
||||||
|
|
||||||
|
| Function | Variable(s) | Example |
|
||||||
|
| -------------- | ----------------------------- | ---------------------------------------------------- |
|
||||||
|
| `setup_nodejs` | `NODE_VERSION`, `NODE_MODULE` | `NODE_VERSION="22" setup_nodejs` |
|
||||||
|
| `setup_uv` | `PYTHON_VERSION` | `PYTHON_VERSION="3.12" setup_uv` |
|
||||||
|
| `setup_go` | `GO_VERSION` | `GO_VERSION="1.22" setup_go` |
|
||||||
|
| `setup_rust` | `RUST_VERSION`, `RUST_CRATES` | `RUST_CRATES="monolith" setup_rust` |
|
||||||
|
| `setup_ruby` | `RUBY_VERSION` | `RUBY_VERSION="3.3" setup_ruby` |
|
||||||
|
| `setup_java` | `JAVA_VERSION` | `JAVA_VERSION="21" setup_java` |
|
||||||
|
| `setup_php` | `PHP_VERSION`, `PHP_MODULES` | `PHP_VERSION="8.3" PHP_MODULES="redis,gd" setup_php` |
|
||||||
|
|
||||||
|
### Database Setup
|
||||||
|
|
||||||
|
| Function | Variable(s) | Example |
|
||||||
|
| --------------------- | ------------------------------------ | ----------------------------------------------------------- |
|
||||||
|
| `setup_postgresql` | `PG_VERSION`, `PG_MODULES` | `PG_VERSION="16" setup_postgresql` |
|
||||||
|
| `setup_postgresql_db` | `PG_DB_NAME`, `PG_DB_USER` | `PG_DB_NAME="mydb" PG_DB_USER="myuser" setup_postgresql_db` |
|
||||||
|
| `setup_mariadb_db` | `MARIADB_DB_NAME`, `MARIADB_DB_USER` | `MARIADB_DB_NAME="mydb" setup_mariadb_db` |
|
||||||
|
| `setup_mysql` | `MYSQL_VERSION` | `setup_mysql` |
|
||||||
|
| `setup_mongodb` | `MONGO_VERSION` | `setup_mongodb` |
|
||||||
|
| `setup_clickhouse` | - | `setup_clickhouse` |
|
||||||
|
|
||||||
|
### Tools & Utilities
|
||||||
|
|
||||||
|
| Function | Description |
|
||||||
|
| ------------------- | ---------------------------------- |
|
||||||
|
| `setup_adminer` | Installs Adminer for DB management |
|
||||||
|
| `setup_composer` | Install PHP Composer |
|
||||||
|
| `setup_ffmpeg` | Install FFmpeg |
|
||||||
|
| `setup_imagemagick` | Install ImageMagick |
|
||||||
|
| `setup_gs` | Install Ghostscript |
|
||||||
|
| `setup_hwaccel` | Configure hardware acceleration |
|
||||||
|
|
||||||
|
### Helper Utilities
|
||||||
|
|
||||||
|
| Function | Description | Example |
|
||||||
|
| ----------------------------- | ---------------------------- | ----------------------------------------- |
|
||||||
|
| `import_local_ip` | Sets `$LOCAL_IP` variable | `import_local_ip` |
|
||||||
|
| `ensure_dependencies` | Checks/installs dependencies | `ensure_dependencies curl jq` |
|
||||||
|
| `install_packages_with_retry` | APT install with retry | `install_packages_with_retry nginx redis` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ❌ Anti-Patterns (NEVER use!)
|
||||||
|
|
||||||
|
### 1. Pointless Variables
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - unnecessary variables
|
||||||
|
APP_NAME="myapp"
|
||||||
|
APP_DIR="/opt/${APP_NAME}"
|
||||||
|
APP_USER="root"
|
||||||
|
APP_PORT="3000"
|
||||||
|
cd $APP_DIR
|
||||||
|
|
||||||
|
# ✅ CORRECT - use directly
|
||||||
|
cd /opt/myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Custom Download Logic
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - custom wget/curl logic
|
||||||
|
RELEASE=$(curl -s https://api.github.com/repos/YourUsername/YourRepo/releases/latest | jq -r '.tag_name')
|
||||||
|
wget https://github.com/YourUsername/YourRepo/archive/${RELEASE}.tar.gz
|
||||||
|
tar -xzf ${RELEASE}.tar.gz
|
||||||
|
mv repo-${RELEASE} /opt/myapp
|
||||||
|
|
||||||
|
# ✅ CORRECT - use our function
|
||||||
|
fetch_and_deploy_gh_release "myapp" "YourUsername/YourRepo" "tarball" "latest" "/opt/myapp"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Custom Version-Check Logic
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - custom version check
|
||||||
|
CURRENT=$(cat /opt/myapp/version.txt)
|
||||||
|
LATEST=$(curl -s https://api.github.com/repos/YourUsername/YourRepo/releases/latest | jq -r '.tag_name')
|
||||||
|
if [[ "$CURRENT" != "$LATEST" ]]; then
|
||||||
|
# update...
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ✅ CORRECT - use our function
|
||||||
|
if check_for_gh_release "myapp" "YourUsername/YourRepo"; then
|
||||||
|
# update...
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Docker-based Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - using Docker
|
||||||
|
docker pull myapp/myapp:latest
|
||||||
|
docker run -d --name myapp myapp/myapp:latest
|
||||||
|
|
||||||
|
# ✅ CORRECT - Bare-Metal Installation
|
||||||
|
fetch_and_deploy_gh_release "myapp" "YourUsername/YourRepo"
|
||||||
|
npm install && npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Custom Runtime Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - custom Node.js installation
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
||||||
|
apt install -y nodejs
|
||||||
|
|
||||||
|
# ✅ CORRECT - use our function
|
||||||
|
NODE_VERSION="22" setup_nodejs
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Redundant echo Statements
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - custom logging messages
|
||||||
|
echo "Installing dependencies..."
|
||||||
|
apt install -y curl
|
||||||
|
echo "Done!"
|
||||||
|
|
||||||
|
# ✅ CORRECT - use msg_info/msg_ok
|
||||||
|
msg_info "Installing Dependencies"
|
||||||
|
$STD apt install -y curl
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Missing $STD Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - apt without $STD
|
||||||
|
apt install -y nginx
|
||||||
|
|
||||||
|
# ✅ CORRECT - with $STD for silent output
|
||||||
|
$STD apt install -y nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. Wrapping `tools.func` Functions in msg Blocks
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - tools.func functions have their own msg_info/msg_ok!
|
||||||
|
msg_info "Installing Node.js"
|
||||||
|
NODE_VERSION="22" setup_nodejs
|
||||||
|
msg_ok "Installed Node.js"
|
||||||
|
|
||||||
|
msg_info "Updating Application"
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/appname"
|
||||||
|
msg_ok "Updated Application"
|
||||||
|
|
||||||
|
# ✅ CORRECT - call directly without msg wrapper
|
||||||
|
NODE_VERSION="22" setup_nodejs
|
||||||
|
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/appname"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Functions with built-in messages (NEVER wrap in msg blocks):**
|
||||||
|
|
||||||
|
- `fetch_and_deploy_gh_release`
|
||||||
|
- `check_for_gh_release`
|
||||||
|
- `setup_nodejs`
|
||||||
|
- `setup_postgresql` / `setup_postgresql_db`
|
||||||
|
- `setup_mariadb` / `setup_mariadb_db`
|
||||||
|
- `setup_mongodb`
|
||||||
|
- `setup_mysql`
|
||||||
|
- `setup_ruby`
|
||||||
|
- `setup_go`
|
||||||
|
- `setup_java`
|
||||||
|
- `setup_php`
|
||||||
|
- `setup_uv`
|
||||||
|
- `setup_rust`
|
||||||
|
- `setup_composer`
|
||||||
|
- `setup_ffmpeg`
|
||||||
|
- `setup_imagemagick`
|
||||||
|
- `setup_gs`
|
||||||
|
- `setup_adminer`
|
||||||
|
- `setup_hwaccel`
|
||||||
|
|
||||||
|
### 9. Creating Unnecessary System Users
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - LXC containers run as root, no separate user needed
|
||||||
|
useradd -m -s /usr/bin/bash appuser
|
||||||
|
chown -R appuser:appuser /opt/appname
|
||||||
|
sudo -u appuser npm install
|
||||||
|
|
||||||
|
# ✅ CORRECT - run directly as root
|
||||||
|
cd /opt/appname
|
||||||
|
$STD npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10. Using `export` in .env Files
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - export is unnecessary in .env files
|
||||||
|
cat <<EOF >/opt/appname/.env
|
||||||
|
export DATABASE_URL=postgres://...
|
||||||
|
export SECRET_KEY=abc123
|
||||||
|
export NODE_ENV=production
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# ✅ CORRECT - simple KEY=VALUE format (files are sourced with set -a)
|
||||||
|
cat <<EOF >/opt/appname/.env
|
||||||
|
DATABASE_URL=postgres://...
|
||||||
|
SECRET_KEY=abc123
|
||||||
|
NODE_ENV=production
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11. Using External Shell Scripts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - external script that gets executed
|
||||||
|
cat <<'EOF' >/opt/appname/install_script.sh
|
||||||
|
#!/bin/bash
|
||||||
|
cd /opt/appname
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
EOF
|
||||||
|
chmod +x /opt/appname/install_script.sh
|
||||||
|
$STD bash /opt/appname/install_script.sh
|
||||||
|
rm -f /opt/appname/install_script.sh
|
||||||
|
|
||||||
|
# ✅ CORRECT - run commands directly
|
||||||
|
cd /opt/appname
|
||||||
|
$STD npm install
|
||||||
|
$STD npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### 12. Using `sudo` in LXC Containers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - sudo is unnecessary in LXC (already root)
|
||||||
|
sudo -u postgres psql -c "CREATE DATABASE mydb;"
|
||||||
|
sudo -u appuser npm install
|
||||||
|
|
||||||
|
# ✅ CORRECT - use functions or run directly as root
|
||||||
|
PG_DB_NAME="mydb" PG_DB_USER="myuser" setup_postgresql_db
|
||||||
|
|
||||||
|
cd /opt/appname
|
||||||
|
$STD npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 13. Unnecessary `systemctl daemon-reload`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - daemon-reload is only needed when MODIFYING existing services
|
||||||
|
cat <<EOF >/etc/systemd/system/appname.service
|
||||||
|
# ... service config ...
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload # Unnecessary for new services!
|
||||||
|
systemctl enable -q --now appname
|
||||||
|
|
||||||
|
# ✅ CORRECT - new services don't need daemon-reload
|
||||||
|
cat <<EOF >/etc/systemd/system/appname.service
|
||||||
|
# ... service config ...
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now appname
|
||||||
|
```
|
||||||
|
|
||||||
|
### 14. Creating Custom Credentials Files
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - custom credentials file is not part of the standard template
|
||||||
|
msg_info "Saving Credentials"
|
||||||
|
cat <<EOF >~/appname.creds
|
||||||
|
Database User: ${DB_USER}
|
||||||
|
Database Pass: ${DB_PASS}
|
||||||
|
EOF
|
||||||
|
msg_ok "Saved Credentials"
|
||||||
|
|
||||||
|
# ✅ CORRECT - credentials are stored in .env or shown in final message only
|
||||||
|
# If you use setup_postgresql_db / setup_mariadb_db, a standard ~/[appname].creds is created automatically
|
||||||
|
```
|
||||||
|
|
||||||
|
### 15. Wrong Footer Pattern
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - old cleanup pattern with msg blocks
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
|
||||||
|
msg_info "Cleaning up"
|
||||||
|
$STD apt-get -y autoremove
|
||||||
|
$STD apt-get -y autoclean
|
||||||
|
msg_ok "Cleaned"
|
||||||
|
|
||||||
|
# ✅ CORRECT - use cleanup_lxc function
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
|
```
|
||||||
|
|
||||||
|
### 16. Manual Database Creation Instead of Functions
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - manual database creation
|
||||||
|
DB_USER="myuser"
|
||||||
|
DB_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | cut -c1-13)
|
||||||
|
$STD sudo -u postgres psql -c "CREATE ROLE $DB_USER WITH LOGIN PASSWORD '$DB_PASS';"
|
||||||
|
$STD sudo -u postgres psql -c "CREATE DATABASE mydb WITH OWNER $DB_USER;"
|
||||||
|
$STD sudo -u postgres psql -d mydb -c "CREATE EXTENSION IF NOT EXISTS postgis;"
|
||||||
|
|
||||||
|
# ✅ CORRECT - use setup_postgresql_db function
|
||||||
|
# This sets PG_DB_USER, PG_DB_PASS, PG_DB_NAME automatically
|
||||||
|
PG_DB_NAME="mydb" PG_DB_USER="myuser" PG_DB_EXTENSIONS="postgis" setup_postgresql_db
|
||||||
|
```
|
||||||
|
|
||||||
|
### 17. Writing Files Without Heredocs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ❌ WRONG - echo / printf / tee
|
||||||
|
echo "# Config" > /opt/app/config.yml
|
||||||
|
echo "port: 3000" >> /opt/app/config.yml
|
||||||
|
|
||||||
|
printf "# Config\nport: 3000\n" > /opt/app/config.yml
|
||||||
|
cat config.yml | tee /opt/app/config.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ✅ CORRECT - always use a single heredoc
|
||||||
|
cat <<EOF >/opt/app/config.yml
|
||||||
|
# Config
|
||||||
|
port: 3000
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Important Rules
|
||||||
|
|
||||||
|
### Variable Declarations (CT Script)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Standard declarations (ALWAYS present)
|
||||||
|
APP="AppName"
|
||||||
|
var_tags="${var_tags:-tag1;tag2}"
|
||||||
|
var_cpu="${var_cpu:-2}"
|
||||||
|
var_ram="${var_ram:-2048}"
|
||||||
|
var_disk="${var_disk:-8}"
|
||||||
|
var_os="${var_os:-debian}"
|
||||||
|
var_version="${var_version:-13}"
|
||||||
|
var_unprivileged="${var_unprivileged:-1}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update-Script Pattern
|
||||||
|
|
||||||
|
```bash
|
||||||
|
function update_script() {
|
||||||
|
header_info
|
||||||
|
check_container_storage
|
||||||
|
check_container_resources
|
||||||
|
|
||||||
|
# 1. Check if installation exists
|
||||||
|
if [[ ! -d /opt/appname ]]; then
|
||||||
|
msg_error "No ${APP} Installation Found!"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. Check for update
|
||||||
|
if check_for_gh_release "appname" "YourUsername/YourRepo"; then
|
||||||
|
# 3. Stop service
|
||||||
|
msg_info "Stopping Service"
|
||||||
|
systemctl stop appname
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
|
# 4. Backup data (if present)
|
||||||
|
msg_info "Backing up Data"
|
||||||
|
cp -r /opt/appname/data /opt/appname_data_backup
|
||||||
|
msg_ok "Backed up Data"
|
||||||
|
|
||||||
|
# 5. Perform clean install
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/appname"
|
||||||
|
|
||||||
|
# 6. Rebuild (if needed)
|
||||||
|
cd /opt/appname
|
||||||
|
$STD npm install
|
||||||
|
$STD npm run build
|
||||||
|
|
||||||
|
# 7. Restore data
|
||||||
|
msg_info "Restoring Data"
|
||||||
|
cp -r /opt/appname_data_backup/. /opt/appname/data
|
||||||
|
rm -rf /opt/appname_data_backup
|
||||||
|
msg_ok "Restored Data"
|
||||||
|
|
||||||
|
# 8. Start service
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl start appname
|
||||||
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
|
fi
|
||||||
|
exit # IMPORTANT: Always end with exit!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Systemd Service Pattern
|
||||||
|
|
||||||
|
```bash
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/appname.service
|
||||||
|
[Unit]
|
||||||
|
Description=AppName Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/opt/appname
|
||||||
|
Environment=NODE_ENV=production
|
||||||
|
ExecStart=/usr/bin/node /opt/appname/server.js
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now appname
|
||||||
|
msg_ok "Created Service"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Installation Script Footer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ALWAYS at the end of the install script:
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📖 Reference: Good Example Scripts
|
||||||
|
|
||||||
|
Look at these recent well-implemented applications as reference:
|
||||||
|
|
||||||
|
### Container Scripts (Latest 10)
|
||||||
|
|
||||||
|
- [ct/thingsboard.sh](../ct/thingsboard.sh) - IoT platform with proper update_script
|
||||||
|
- [ct/unifi-os-server.sh](../ct/unifi-os-server.sh) - Complex setup with podman
|
||||||
|
- [ct/trip.sh](../ct/trip.sh) - Simple Ruby app
|
||||||
|
- [ct/fladder.sh](../ct/fladder.sh) - Media app with database
|
||||||
|
- [ct/qui.sh](../ct/qui.sh) - Lightweight utility
|
||||||
|
- [ct/kutt.sh](../ct/kutt.sh) - Node.js with PostgreSQL
|
||||||
|
- [ct/flatnotes.sh](../ct/flatnotes.sh) - Python notes app
|
||||||
|
- [ct/investbrain.sh](../ct/investbrain.sh) - Finance app
|
||||||
|
- [ct/gwn-manager.sh](../ct/gwn-manager.sh) - Network management
|
||||||
|
- [ct/sportarr.sh](../ct/sportarr.sh) - Specialized \*Arr variant
|
||||||
|
|
||||||
|
### Install Scripts (Latest)
|
||||||
|
|
||||||
|
- [install/unifi-os-server-install.sh](../install/unifi-os-server-install.sh) - Complex setup with API integration
|
||||||
|
- [install/trip-install.sh](../install/trip-install.sh) - Rails application setup
|
||||||
|
- [install/mail-archiver-install.sh](../install/mail-archiver-install.sh) - Email-related service
|
||||||
|
|
||||||
|
**Key things to notice:**
|
||||||
|
|
||||||
|
- Proper error handling with `catch_errors`
|
||||||
|
- Use of `check_for_gh_release` and `fetch_and_deploy_gh_release`
|
||||||
|
- Correct backup/restore patterns in `update_script`
|
||||||
|
- Footer always ends with `motd_ssh`, `customize`, `cleanup_lxc`
|
||||||
|
- JSON metadata files created for each app
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## <20> JSON Metadata Files
|
||||||
|
|
||||||
|
Every application requires a JSON metadata file in `frontend/public/json/<appname>.json`.
|
||||||
|
|
||||||
|
### JSON Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "AppName",
|
||||||
|
"slug": "appname",
|
||||||
|
"categories": [1],
|
||||||
|
"date_created": "2026-01-16",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 3000,
|
||||||
|
"documentation": "https://docs.appname.com/",
|
||||||
|
"website": "https://appname.com/",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/appname.webp",
|
||||||
|
"config_path": "/opt/appname/.env",
|
||||||
|
"description": "Short description of the application and its purpose.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/appname.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 2,
|
||||||
|
"ram": 2048,
|
||||||
|
"hdd": 8,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Required Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
| --------------------- | ------- | -------------------------------------------------- |
|
||||||
|
| `name` | string | Display name of the application |
|
||||||
|
| `slug` | string | Lowercase, no spaces, used for filenames |
|
||||||
|
| `categories` | array | Category ID(s) - see category list below |
|
||||||
|
| `date_created` | string | Creation date (YYYY-MM-DD) |
|
||||||
|
| `type` | string | `ct` for container, `vm` for virtual machine |
|
||||||
|
| `updateable` | boolean | Whether update_script is implemented |
|
||||||
|
| `privileged` | boolean | Whether container needs privileged mode |
|
||||||
|
| `interface_port` | number | Primary web interface port (or `null`) |
|
||||||
|
| `documentation` | string | Link to official docs |
|
||||||
|
| `website` | string | Link to official website |
|
||||||
|
| `logo` | string | URL to application logo (preferably selfhst icons) |
|
||||||
|
| `config_path` | string | Path to main config file (or empty string) |
|
||||||
|
| `description` | string | Brief description of the application |
|
||||||
|
| `install_methods` | array | Installation configurations |
|
||||||
|
| `default_credentials` | object | Default username/password (or null) |
|
||||||
|
| `notes` | array | Additional notes/warnings |
|
||||||
|
|
||||||
|
### Categories
|
||||||
|
|
||||||
|
| ID | Category |
|
||||||
|
| --- | ------------------------- |
|
||||||
|
| 0 | Miscellaneous |
|
||||||
|
| 1 | Proxmox & Virtualization |
|
||||||
|
| 2 | Operating Systems |
|
||||||
|
| 3 | Containers & Docker |
|
||||||
|
| 4 | Network & Firewall |
|
||||||
|
| 5 | Adblock & DNS |
|
||||||
|
| 6 | Authentication & Security |
|
||||||
|
| 7 | Backup & Recovery |
|
||||||
|
| 8 | Databases |
|
||||||
|
| 9 | Monitoring & Analytics |
|
||||||
|
| 10 | Dashboards & Frontends |
|
||||||
|
| 11 | Files & Downloads |
|
||||||
|
| 12 | Documents & Notes |
|
||||||
|
| 13 | Media & Streaming |
|
||||||
|
| 14 | \*Arr Suite |
|
||||||
|
| 15 | NVR & Cameras |
|
||||||
|
| 16 | IoT & Smart Home |
|
||||||
|
| 17 | ZigBee, Z-Wave & Matter |
|
||||||
|
| 18 | MQTT & Messaging |
|
||||||
|
| 19 | Automation & Scheduling |
|
||||||
|
| 20 | AI / Coding & Dev-Tools |
|
||||||
|
| 21 | Webservers & Proxies |
|
||||||
|
| 22 | Bots & ChatOps |
|
||||||
|
| 23 | Finance & Budgeting |
|
||||||
|
| 24 | Gaming & Leisure |
|
||||||
|
| 25 | Business & ERP |
|
||||||
|
|
||||||
|
### Notes Format
|
||||||
|
|
||||||
|
```json
|
||||||
|
"notes": [
|
||||||
|
{
|
||||||
|
"text": "Change the default password after first login!",
|
||||||
|
"type": "warning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Requires at least 4GB RAM for optimal performance.",
|
||||||
|
"type": "info"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note types:** `info`, `warning`, `error`
|
||||||
|
|
||||||
|
### Examples with Credentials
|
||||||
|
|
||||||
|
```json
|
||||||
|
"default_credentials": {
|
||||||
|
"username": "admin",
|
||||||
|
"password": "admin"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or no credentials:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Checklist Before PR Creation
|
||||||
|
|
||||||
|
- [ ] No Docker installation used
|
||||||
|
- [ ] `fetch_and_deploy_gh_release` used for GitHub releases
|
||||||
|
- [ ] `check_for_gh_release` used for update checks
|
||||||
|
- [ ] `setup_*` functions used for runtimes (nodejs, postgresql, etc.)
|
||||||
|
- [ ] **`tools.func` functions NOT wrapped in msg_info/msg_ok blocks**
|
||||||
|
- [ ] No redundant variables (only when used multiple times)
|
||||||
|
- [ ] `$STD` before all apt/npm/build commands
|
||||||
|
- [ ] `msg_info`/`msg_ok`/`msg_error` for logging (only for custom code)
|
||||||
|
- [ ] Correct script structure followed (see templates)
|
||||||
|
- [ ] Update function present and functional (CT scripts)
|
||||||
|
- [ ] Data backup implemented in update function (if applicable)
|
||||||
|
- [ ] `motd_ssh`, `customize`, `cleanup_lxc` at the end of install scripts
|
||||||
|
- [ ] No custom download/version-check logic
|
||||||
|
- [ ] All links point to `community-scripts/ProxmoxVE` (not `ProxmoxVED`!)
|
||||||
|
- [ ] JSON metadata file created in `frontend/public/json/<appname>.json`
|
||||||
|
- [ ] Category IDs are valid (0-25)
|
||||||
|
- [ ] Default OS version is Debian 13 or newer (unless special requirement)
|
||||||
|
- [ ] Default resources are reasonable for the application
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 Tips for AI Assistants
|
||||||
|
|
||||||
|
1. **ALWAYS search `tools.func` first** before implementing custom solutions
|
||||||
|
2. **Use recent scripts as reference** (Thingsboard, UniFi OS, Trip, Flatnotes, etc.)
|
||||||
|
3. **Ask when uncertain** instead of introducing wrong patterns
|
||||||
|
4. **Test via GitHub** - push to your fork and test with curl (not local bash)
|
||||||
|
```bash
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
# Wait 10-30 seconds after pushing - GitHub takes time to update files
|
||||||
|
```
|
||||||
|
5. **Consistency > Creativity** - follow established patterns strictly
|
||||||
|
6. **Check the templates** - they show the correct structure
|
||||||
|
7. **Don't wrap tools.func functions** - they handle their own msg_info/msg_ok output
|
||||||
|
8. **Minimal variables** - only create variables that are truly reused multiple times
|
||||||
|
9. **Always use $STD** - ensures silent/non-interactive execution
|
||||||
|
10. **Reference good examples** - look at recent additions in each category
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🍒 Important: Cherry-Picking Your Files for PR Submission
|
||||||
|
|
||||||
|
⚠️ **CRITICAL**: When you submit your PR, you must use git cherry-pick to send ONLY your 3-4 files!
|
||||||
|
|
||||||
|
Why? Because `setup-fork.sh` modifies 600+ files to update links. If you commit all changes, your PR will be impossible to merge.
|
||||||
|
|
||||||
|
**See**: [README.md - Cherry-Pick Section](README.md#-cherry-pick-submitting-only-your-changes) for complete instructions on:
|
||||||
|
|
||||||
|
- Creating a clean submission branch
|
||||||
|
- Cherry-picking only your files (ct/myapp.sh, install/myapp-install.sh, frontend/public/json/myapp.json)
|
||||||
|
- Verifying your PR has only 3 file changes (not 600+)
|
||||||
|
|
||||||
|
**Quick reference**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create clean branch from upstream
|
||||||
|
git fetch upstream
|
||||||
|
git checkout -b submit/myapp upstream/main
|
||||||
|
|
||||||
|
# Cherry-pick your commit(s) or manually add your 3-4 files
|
||||||
|
# Then push to your fork and create PR
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Further Documentation
|
||||||
|
|
||||||
|
- [CONTRIBUTING.md](CONTRIBUTING.md) - General contribution guidelines
|
||||||
|
- [GUIDE.md](GUIDE.md) - Detailed developer documentation
|
||||||
|
- [HELPER_FUNCTIONS.md](HELPER_FUNCTIONS.md) - Complete tools.func reference
|
||||||
|
- [README.md](README.md) - Cherry-pick guide and workflow instructions
|
||||||
|
- [../TECHNICAL_REFERENCE.md](../TECHNICAL_REFERENCE.md) - Technical deep dive
|
||||||
|
- [../EXIT_CODES.md](../EXIT_CODES.md) - Exit code reference
|
||||||
|
- [templates_ct/](templates_ct/) - CT script templates
|
||||||
|
- [templates_install/](templates_install/) - Install script templates
|
||||||
|
- [templates_json/](templates_json/) - JSON metadata templates
|
||||||
@@ -1,14 +1,41 @@
|
|||||||
<div align="center">
|
# 🧪 Code Audit: LXC Script Flow
|
||||||
<img src="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo.png" height="100px" />
|
|
||||||
</div>
|
|
||||||
<h2><div align="center">Exploring the Scripts and Steps Involved in an Application LXC Installation</div></h2>
|
|
||||||
|
|
||||||
1) [adguard.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/adguard.sh): This script collects system parameters. (Also holds the function to update the application.)
|
This guide explains the current execution flow and what to verify during reviews.
|
||||||
2) [build.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/build.func): Adds user settings and integrates collected information.
|
|
||||||
3) [create_lxc.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/create_lxc.sh): Constructs the LXC container.
|
|
||||||
4) [adguard-install.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/install/adguard-install.sh): Executes functions from [install.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/install.func), and installs the application.
|
|
||||||
5) [adguard.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/adguard.sh) (again): To display the completion message.
|
|
||||||
|
|
||||||
The installation process uses reusable scripts: [build.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/build.func), [create_lxc.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/create_lxc.sh), and [install.func](https://github.com/community-scripts/ProxmoxVE/blob/main/misc/install.func), which are not specific to any particular application.
|
## Execution Flow (CT + Install)
|
||||||
|
|
||||||
To gain a better understanding, focus on reviewing [adguard-install.sh](https://github.com/community-scripts/ProxmoxVE/blob/main/install/adguard-install.sh). This script contains the commands and configurations for installing and configuring AdGuard Home within the LXC container.
|
1. `ct/appname.sh` runs on the Proxmox host and sources `misc/build.func`.
|
||||||
|
2. `build.func` orchestrates prompts, container creation, and invokes the install script.
|
||||||
|
3. Inside the container, `misc/install.func` exposes helper functions via `$FUNCTIONS_FILE_PATH`.
|
||||||
|
4. `install/appname-install.sh` performs the application install.
|
||||||
|
5. The CT script prints the completion message.
|
||||||
|
|
||||||
|
## Audit Checklist
|
||||||
|
|
||||||
|
### CT Script (ct/)
|
||||||
|
|
||||||
|
- Sources `misc/build.func` from `community-scripts/ProxmoxVE/main` (setup-fork.sh updates for forks).
|
||||||
|
- Uses `check_for_gh_release` + `fetch_and_deploy_gh_release` for updates.
|
||||||
|
- No Docker-based installs.
|
||||||
|
|
||||||
|
### Install Script (install/)
|
||||||
|
|
||||||
|
- Sources `$FUNCTIONS_FILE_PATH`.
|
||||||
|
- Uses `tools.func` helpers (setup\_\*).
|
||||||
|
- Ends with `motd_ssh`, `customize`, `cleanup_lxc`.
|
||||||
|
|
||||||
|
### JSON Metadata
|
||||||
|
|
||||||
|
- File in `frontend/public/json/<appname>.json` matches template schema.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
- Test via curl from your fork (CT script only).
|
||||||
|
- Wait 10-30 seconds after push.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- `docs/contribution/templates_ct/AppName.sh`
|
||||||
|
- `docs/contribution/templates_install/AppName-install.sh`
|
||||||
|
- `docs/contribution/templates_json/AppName.json`
|
||||||
|
- `docs/contribution/GUIDE.md`
|
||||||
|
|||||||
@@ -81,11 +81,22 @@ git clone https://github.com/yourUserName/ForkName
|
|||||||
git switch -c your-feature-branch
|
git switch -c your-feature-branch
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Change paths in build.func install.func and AppName.sh
|
### 4. Run setup-fork.sh to auto-configure your fork
|
||||||
|
|
||||||
To be able to develop from your own branch you need to change `https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main` to `https://raw.githubusercontent.com/[USER]/[REPOSITORY]/refs/heads/[BRANCH]`. You need to make this change atleast in misc/build.func misc/install.func and in your ct/AppName.sh. This change is only for testing. Before opening a Pull Request you should change this line change all this back to point to `https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main`.
|
```bash
|
||||||
|
bash docs/contribution/setup-fork.sh --full
|
||||||
|
```
|
||||||
|
|
||||||
### 4. Commit changes (without build.func and install.func!)
|
This script automatically:
|
||||||
|
|
||||||
|
- Detects your GitHub username
|
||||||
|
- Updates ALL curl URLs to point to your fork (for testing)
|
||||||
|
- Creates `.git-setup-info` with your config
|
||||||
|
- Backs up all modified files (\*.backup)
|
||||||
|
|
||||||
|
**IMPORTANT**: This modifies 600+ files! Use cherry-pick when submitting your PR (see below).
|
||||||
|
|
||||||
|
### 5. Commit ONLY your new application files
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git commit -m "Your commit message"
|
git commit -m "Your commit message"
|
||||||
@@ -97,9 +108,66 @@ git commit -m "Your commit message"
|
|||||||
git push origin your-feature-branch
|
git push origin your-feature-branch
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. Create a Pull Request
|
### 6. Cherry-Pick: Submit Only Your Files for PR
|
||||||
|
|
||||||
Open a Pull Request from your feature branch to the main repository branch. You must only include your **$AppName.sh**, **$AppName-install.sh** and **$AppName.json** files in the pull request.
|
⚠️ **IMPORTANT**: setup-fork.sh modified 600+ files. You MUST only submit your 3 new files!
|
||||||
|
|
||||||
|
See [README.md - Cherry-Pick Guide](README.md#-cherry-pick-submitting-only-your-changes) for step-by-step instructions.
|
||||||
|
|
||||||
|
Quick version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create clean branch from upstream
|
||||||
|
git fetch upstream
|
||||||
|
git checkout -b submit/myapp upstream/main
|
||||||
|
|
||||||
|
# Copy only your files
|
||||||
|
cp ../your-work-branch/ct/myapp.sh ct/myapp.sh
|
||||||
|
cp ../your-work-branch/install/myapp-install.sh install/myapp-install.sh
|
||||||
|
cp ../your-work-branch/frontend/public/json/myapp.json frontend/public/json/myapp.json
|
||||||
|
|
||||||
|
# Commit and verify
|
||||||
|
git add ct/myapp.sh install/myapp-install.sh frontend/public/json/myapp.json
|
||||||
|
git commit -m "feat: add MyApp"
|
||||||
|
git diff upstream/main --name-only # Should show ONLY your 3 files
|
||||||
|
|
||||||
|
# Push and create PR
|
||||||
|
git push origin submit/myapp
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Create a Pull Request
|
||||||
|
|
||||||
|
Open a Pull Request from `submit/myapp` → `community-scripts/ProxmoxVE/main`.
|
||||||
|
|
||||||
|
Verify the PR shows ONLY these 3 files:
|
||||||
|
|
||||||
|
- `ct/myapp.sh`
|
||||||
|
- `install/myapp-install.sh`
|
||||||
|
- `frontend/public/json/myapp.json`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🛠️ Developer Mode & Debugging
|
||||||
|
|
||||||
|
When building or testing scripts, you can use the `dev_mode` variable to enable powerful debugging features. These flags can be combined (comma-separated).
|
||||||
|
|
||||||
|
**Usage**:
|
||||||
|
```bash
|
||||||
|
# Example: Run with trace and keep the container even if it fails
|
||||||
|
dev_mode="trace,keep" bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Available Flags:
|
||||||
|
|
||||||
|
| Flag | Description |
|
||||||
|
| :--- | :--- |
|
||||||
|
| `trace` | Enables `set -x` for maximum verbosity during execution. |
|
||||||
|
| `keep` | Prevents the container from being deleted if the build fails. |
|
||||||
|
| `pause` | Pauses execution at key points (e.g., before customization). |
|
||||||
|
| `breakpoint` | Allows hardcoded `breakpoint` calls in scripts to drop to a shell. |
|
||||||
|
| `logs` | Saves detailed build logs to `/var/log/community-scripts/`. |
|
||||||
|
| `dryrun` | Bypasses actual container creation (limited support). |
|
||||||
|
| `motd` | Forces an update of the Message of the Day (MOTD). |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ git clone https://github.com/YOUR_USERNAME/ProxmoxVE.git
|
|||||||
cd ProxmoxVE
|
cd ProxmoxVE
|
||||||
|
|
||||||
# Run setup script (auto-detects your username from git)
|
# Run setup script (auto-detects your username from git)
|
||||||
bash setup-fork.sh
|
bash docs/contribution/setup-fork.sh --full
|
||||||
```
|
```
|
||||||
|
|
||||||
That's it! ✅
|
That's it! ✅
|
||||||
@@ -22,64 +22,101 @@ That's it! ✅
|
|||||||
The `setup-fork.sh` script automatically:
|
The `setup-fork.sh` script automatically:
|
||||||
|
|
||||||
1. **Detects** your GitHub username from git config
|
1. **Detects** your GitHub username from git config
|
||||||
2. **Updates** 22 hardcoded links in documentation to point to your fork
|
2. **Updates ALL hardcoded links** to point to your fork:
|
||||||
3. **Creates** `.git-setup-info` with recommended git workflows
|
- Documentation links pointing to `community-scripts/ProxmoxVE`
|
||||||
4. **Backs up** all modified files (*.backup)
|
- **Curl download URLs** in scripts (e.g., `curl ... github.com/community-scripts/ProxmoxVE/main/...`)
|
||||||
|
3. **Creates** `.git-setup-info` with your configuration details
|
||||||
|
4. **Backs up** all modified files (\*.backup for safety)
|
||||||
|
|
||||||
|
### Why Updating Curl Links Matters
|
||||||
|
|
||||||
|
Your scripts contain `curl` commands that download dependencies from GitHub (build.func, tools.func, etc.):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# First line of ct/myapp.sh
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
```
|
||||||
|
|
||||||
|
**WITHOUT setup-fork.sh:**
|
||||||
|
|
||||||
|
- Script URLs still point to `community-scripts/ProxmoxVE/main`
|
||||||
|
- If you test locally with `bash ct/myapp.sh`, you're testing local files, but the script's curl commands would download from **upstream** repo
|
||||||
|
- Your modifications aren't actually being tested via the curl commands! ❌
|
||||||
|
|
||||||
|
**AFTER setup-fork.sh:**
|
||||||
|
|
||||||
|
- Script URLs are updated to `YourUsername/ProxmoxVE/main`
|
||||||
|
- When you test via curl from GitHub: `bash -c "$(curl ... YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"`, it downloads from **your fork**
|
||||||
|
- The script's curl commands also point to your fork, so you're actually testing your changes! ✅
|
||||||
|
- ⏱️ **Important:** GitHub takes 10-30 seconds to recognize pushed files - wait before testing!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Example: What setup-fork.sh changes
|
||||||
|
|
||||||
|
# BEFORE (points to upstream):
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
|
||||||
|
# AFTER (points to your fork):
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/john/ProxmoxVE/main/misc/build.func)
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Auto-Detect (Recommended)
|
### Auto-Detect (Recommended)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash setup-fork.sh
|
bash docs/contribution/setup-fork.sh --full
|
||||||
```
|
```
|
||||||
|
|
||||||
Automatically reads your GitHub username from `git remote origin url`
|
Automatically reads your GitHub username from `git remote origin url`
|
||||||
|
|
||||||
### Specify Username
|
### Specify Username
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash setup-fork.sh john
|
bash docs/contribution/setup-fork.sh --full john
|
||||||
```
|
```
|
||||||
|
|
||||||
Updates links to `github.com/john/ProxmoxVE`
|
Updates links to `github.com/john/ProxmoxVE`
|
||||||
|
|
||||||
### Custom Repository Name
|
### Custom Repository Name
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash setup-fork.sh john my-fork
|
bash docs/contribution/setup-fork.sh --full john my-fork
|
||||||
```
|
```
|
||||||
|
|
||||||
Updates links to `github.com/john/my-fork`
|
Updates links to `github.com/john/my-fork`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## What Gets Updated?
|
## What Gets Updated?
|
||||||
|
|
||||||
The script updates these documentation files:
|
The script updates hardcoded links in these areas when using `--full`:
|
||||||
- `docs/CONTRIBUTION_GUIDE.md` (4 links)
|
|
||||||
- `docs/README.md` (1 link)
|
- `ct/`, `install/`, `vm/` scripts
|
||||||
- `docs/INDEX.md` (3 links)
|
- `misc/` function libraries
|
||||||
- `docs/EXIT_CODES.md` (2 links)
|
- `docs/` (including `docs/contribution/`)
|
||||||
- `docs/DEFAULTS_SYSTEM_GUIDE.md` (2 links)
|
- Code examples in documentation
|
||||||
- `docs/api/README.md` (1 link)
|
|
||||||
- `docs/APP-ct.md` (1 link)
|
|
||||||
- `docs/APP-install.md` (1 link)
|
|
||||||
- `docs/alpine-install.func.md` (2 links)
|
|
||||||
- `docs/install.func.md` (1 link)
|
|
||||||
- And code examples in documentation
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## After Setup
|
## After Setup
|
||||||
|
|
||||||
1. **Review changes**
|
1. **Review changes**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git diff docs/
|
git diff docs/
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Read git workflow tips**
|
2. **Read git workflow tips**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cat .git-setup-info
|
cat .git-setup-info
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Start contributing**
|
3. **Start contributing**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git checkout -b feature/my-app
|
git checkout -b feature/my-app
|
||||||
# Make your changes...
|
# Make your changes...
|
||||||
@@ -88,7 +125,7 @@ The script updates these documentation files:
|
|||||||
|
|
||||||
4. **Follow the guide**
|
4. **Follow the guide**
|
||||||
```bash
|
```bash
|
||||||
cat docs/CONTRIBUTION_GUIDE.md
|
cat docs/contribution/GUIDE.md
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -96,6 +133,7 @@ The script updates these documentation files:
|
|||||||
## Common Workflows
|
## Common Workflows
|
||||||
|
|
||||||
### Keep Your Fork Updated
|
### Keep Your Fork Updated
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Add upstream if you haven't already
|
# Add upstream if you haven't already
|
||||||
git remote add upstream https://github.com/community-scripts/ProxmoxVE.git
|
git remote add upstream https://github.com/community-scripts/ProxmoxVE.git
|
||||||
@@ -107,6 +145,7 @@ git push origin main
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Create a Feature Branch
|
### Create a Feature Branch
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git checkout -b feature/docker-improvements
|
git checkout -b feature/docker-improvements
|
||||||
# Make changes...
|
# Make changes...
|
||||||
@@ -115,6 +154,7 @@ git push origin feature/docker-improvements
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Sync Before Contributing
|
### Sync Before Contributing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git fetch upstream
|
git fetch upstream
|
||||||
git rebase upstream/main
|
git rebase upstream/main
|
||||||
@@ -127,14 +167,16 @@ git checkout -b feature/my-feature
|
|||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### "Git is not installed" or "not a git repository"
|
### "Git is not installed" or "not a git repository"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Make sure you cloned the repo first
|
# Make sure you cloned the repo first
|
||||||
git clone https://github.com/YOUR_USERNAME/ProxmoxVE.git
|
git clone https://github.com/YOUR_USERNAME/ProxmoxVE.git
|
||||||
cd ProxmoxVE
|
cd ProxmoxVE
|
||||||
bash setup-fork.sh
|
bash docs/contribution/setup-fork.sh --full
|
||||||
```
|
```
|
||||||
|
|
||||||
### "Could not auto-detect GitHub username"
|
### "Could not auto-detect GitHub username"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Your git origin URL isn't set up correctly
|
# Your git origin URL isn't set up correctly
|
||||||
git remote -v
|
git remote -v
|
||||||
@@ -142,29 +184,32 @@ git remote -v
|
|||||||
|
|
||||||
# Fix it:
|
# Fix it:
|
||||||
git remote set-url origin https://github.com/YOUR_USERNAME/ProxmoxVE.git
|
git remote set-url origin https://github.com/YOUR_USERNAME/ProxmoxVE.git
|
||||||
bash setup-fork.sh
|
bash docs/contribution/setup-fork.sh --full
|
||||||
```
|
```
|
||||||
|
|
||||||
### "Permission denied"
|
### "Permission denied"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Make script executable
|
# Make script executable
|
||||||
chmod +x setup-fork.sh
|
chmod +x docs/contribution/setup-fork.sh
|
||||||
bash setup-fork.sh
|
bash docs/contribution/setup-fork.sh --full
|
||||||
```
|
```
|
||||||
|
|
||||||
### Reverted Changes by Accident?
|
### Reverted Changes by Accident?
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Backups are created automatically
|
# Backups are created automatically
|
||||||
git checkout docs/*.backup
|
git checkout docs/*.backup
|
||||||
# Or just re-run setup-fork.sh
|
# Or just re-run setup-fork.sh
|
||||||
|
bash docs/contribution/setup-fork.sh --full
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
1. ✅ Run `bash setup-fork.sh`
|
1. ✅ Run `bash docs/contribution/setup-fork.sh --full`
|
||||||
2. 📖 Read [docs/CONTRIBUTION_GUIDE.md](docs/CONTRIBUTION_GUIDE.md)
|
2. 📖 Read [docs/contribution/GUIDE.md](GUIDE.md)
|
||||||
3. 🍴 Choose your contribution path:
|
3. 🍴 Choose your contribution path:
|
||||||
- **Containers** → [docs/ct/README.md](docs/ct/README.md)
|
- **Containers** → [docs/ct/README.md](docs/ct/README.md)
|
||||||
- **Installation** → [docs/install/README.md](docs/install/README.md)
|
- **Installation** → [docs/install/README.md](docs/install/README.md)
|
||||||
@@ -177,10 +222,10 @@ git checkout docs/*.backup
|
|||||||
## Questions?
|
## Questions?
|
||||||
|
|
||||||
- **Fork Setup Issues?** → See [Troubleshooting](#troubleshooting) above
|
- **Fork Setup Issues?** → See [Troubleshooting](#troubleshooting) above
|
||||||
- **How to Contribute?** → [docs/CONTRIBUTION_GUIDE.md](docs/CONTRIBUTION_GUIDE.md)
|
- **How to Contribute?** → [docs/contribution/GUIDE.md](GUIDE.md)
|
||||||
- **Git Workflows?** → `cat .git-setup-info`
|
- **Git Workflows?** → `cat .git-setup-info`
|
||||||
- **Project Structure?** → [docs/README.md](docs/README.md)
|
- **Project Structure?** → [docs/README.md](docs/README.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Happy Contributing! 🚀**
|
## Happy Contributing! 🚀
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ git clone https://github.com/YOUR_USERNAME/ProxmoxVE.git
|
|||||||
cd ProxmoxVE
|
cd ProxmoxVE
|
||||||
|
|
||||||
# 3. Run fork setup script (automatically configures everything)
|
# 3. Run fork setup script (automatically configures everything)
|
||||||
bash setup-fork.sh
|
bash docs/contribution/setup-fork.sh --full
|
||||||
# This auto-detects your username and updates all documentation links
|
# --full updates ct/, install/, vm/, docs/, misc/ links for fork testing
|
||||||
|
|
||||||
# 4. Read the git workflow tips
|
# 4. Read the git workflow tips
|
||||||
cat .git-setup-info
|
cat .git-setup-info
|
||||||
@@ -51,28 +51,29 @@ cat .git-setup-info
|
|||||||
# 1. Create feature branch
|
# 1. Create feature branch
|
||||||
git checkout -b add/my-awesome-app
|
git checkout -b add/my-awesome-app
|
||||||
|
|
||||||
# 2. Create application scripts
|
# 2. Create application scripts from templates
|
||||||
cp ct/example.sh ct/myapp.sh
|
cp docs/contribution/templates_ct/AppName.sh ct/myapp.sh
|
||||||
cp install/example-install.sh install/myapp-install.sh
|
cp docs/contribution/templates_install/AppName-install.sh install/myapp-install.sh
|
||||||
|
cp docs/contribution/templates_json/AppName.json frontend/public/json/myapp.json
|
||||||
|
|
||||||
# 3. Edit your scripts
|
# 3. Edit your scripts
|
||||||
nano ct/myapp.sh
|
nano ct/myapp.sh
|
||||||
nano install/myapp-install.sh
|
nano install/myapp-install.sh
|
||||||
|
nano frontend/public/json/myapp.json
|
||||||
|
|
||||||
# 4. Test locally
|
# 4. Commit and push to your fork
|
||||||
bash ct/myapp.sh # Will prompt for container creation
|
git add ct/myapp.sh install/myapp-install.sh frontend/public/json/myapp.json
|
||||||
|
git commit -m "feat: add MyApp container and install scripts"
|
||||||
# 5. Commit and push
|
|
||||||
git add ct/myapp.sh install/myapp-install.sh
|
|
||||||
git commit -m "feat: add MyApp container"
|
|
||||||
git push origin add/my-awesome-app
|
git push origin add/my-awesome-app
|
||||||
|
|
||||||
# 6. Open Pull Request on GitHub
|
# 5. Test via curl from your fork (GitHub may take 10-30 seconds)
|
||||||
# Click: New Pull Request (GitHub will show this automatically)
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
|
||||||
# 7. Keep your fork updated
|
# 6. Use cherry-pick to submit only your files (see Cherry-Pick section)
|
||||||
git fetch upstream
|
# DO NOT submit the 600+ files modified by setup-fork.sh!
|
||||||
git rebase upstream/main
|
|
||||||
|
# 7. Open Pull Request on GitHub
|
||||||
|
# Create PR from: your-fork/add/my-awesome-app → community-scripts/ProxmoxVE/main
|
||||||
```
|
```
|
||||||
|
|
||||||
**💡 Tip**: See `../FORK_SETUP.md` for detailed fork setup and troubleshooting
|
**💡 Tip**: See `../FORK_SETUP.md` for detailed fork setup and troubleshooting
|
||||||
@@ -112,9 +113,9 @@ ProxmoxVE/
|
|||||||
│ └── alpine-tools.func # Alpine tools
|
│ └── alpine-tools.func # Alpine tools
|
||||||
│
|
│
|
||||||
├── docs/ # 📚 Documentation
|
├── docs/ # 📚 Documentation
|
||||||
│ ├── UPDATED_APP-ct.md # Container script guide
|
│ ├── ct/DETAILED_GUIDE.md # Container script guide
|
||||||
│ ├── UPDATED_APP-install.md # Install script guide
|
│ ├── install/DETAILED_GUIDE.md # Install script guide
|
||||||
│ └── CONTRIBUTING.md # (This file!)
|
│ └── contribution/README.md # Contribution overview
|
||||||
│
|
│
|
||||||
├── tools/ # 🔧 Proxmox management tools
|
├── tools/ # 🔧 Proxmox management tools
|
||||||
│ └── pve/
|
│ └── pve/
|
||||||
@@ -137,6 +138,7 @@ Examples:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Rules**:
|
**Rules**:
|
||||||
|
|
||||||
- Container script name: **Title Case** (PiHole, Docker, NextCloud)
|
- Container script name: **Title Case** (PiHole, Docker, NextCloud)
|
||||||
- Install script name: **lowercase** with **hyphens** (pihole-install, docker-install)
|
- Install script name: **lowercase** with **hyphens** (pihole-install, docker-install)
|
||||||
- Must match: `ct/AppName.sh` ↔ `install/appname-install.sh`
|
- Must match: `ct/AppName.sh` ↔ `install/appname-install.sh`
|
||||||
@@ -156,6 +158,7 @@ Examples:
|
|||||||
- Ubuntu 20.04 / Debian 11+ on host
|
- Ubuntu 20.04 / Debian 11+ on host
|
||||||
|
|
||||||
2. **Git** installed
|
2. **Git** installed
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
apt-get install -y git
|
apt-get install -y git
|
||||||
```
|
```
|
||||||
@@ -198,32 +201,33 @@ git rebase upstream/main
|
|||||||
git push origin feat/add-myapp
|
git push origin feat/add-myapp
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Option B: Local Testing on Proxmox Host
|
#### Option B: Testing on a Proxmox Host (still via curl)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. SSH into Proxmox host
|
# 1. SSH into Proxmox host
|
||||||
ssh root@192.168.1.100
|
ssh root@192.168.1.100
|
||||||
|
|
||||||
# 2. Download your script
|
# 2. Test via curl from your fork (CT script only)
|
||||||
curl -O https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/feat/myapp/ct/myapp.sh
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
# ⏱️ Wait 10-30 seconds after pushing - GitHub takes time to update
|
||||||
# 3. Make it executable
|
|
||||||
chmod +x myapp.sh
|
|
||||||
|
|
||||||
# 4. Update URLs to your fork
|
|
||||||
# Edit: curl -s https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/feat/myapp/...
|
|
||||||
|
|
||||||
# 5. Run and test
|
|
||||||
bash myapp.sh
|
|
||||||
|
|
||||||
# 6. If container created successfully, script is working!
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Option C: Docker Testing (Without Proxmox)
|
> **Note:** Do not edit URLs manually or run install scripts directly. The CT script calls the install script inside the container.
|
||||||
|
|
||||||
|
#### Option C: Using Curl (Recommended for Real Testing)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# You can test script syntax/functionality locally
|
# Always test via curl from your fork (GitHub takes 10-30 seconds after push)
|
||||||
# Note: Won't fully test (no Proxmox, no actual container)
|
git push origin feature/myapp
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
# This tests the actual GitHub URLs, not local files
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Option D: Static Checks (Without Proxmox)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# You can validate syntax and linting locally (limited)
|
||||||
|
# Note: This does NOT replace real Proxmox testing
|
||||||
|
|
||||||
# Run ShellCheck
|
# Run ShellCheck
|
||||||
shellcheck ct/myapp.sh
|
shellcheck ct/myapp.sh
|
||||||
@@ -241,18 +245,18 @@ bash -n install/myapp-install.sh
|
|||||||
### Step 1: Choose Your Template
|
### Step 1: Choose Your Template
|
||||||
|
|
||||||
**For Simple Web Apps** (Node.js, Python, PHP):
|
**For Simple Web Apps** (Node.js, Python, PHP):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp ct/example.sh ct/myapp.sh
|
cp ct/example.sh ct/myapp.sh
|
||||||
cp install/example-install.sh install/myapp-install.sh
|
cp install/example-install.sh install/myapp-install.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
**For Database Apps** (PostgreSQL, MongoDB):
|
**For Database Apps** (PostgreSQL, MariaDB, MongoDB):
|
||||||
```bash
|
|
||||||
cp ct/docker.sh ct/myapp.sh # Use Docker container
|
Use the standard templates and the database helpers from `tools.func` (no Docker).
|
||||||
# OR manual setup for more control
|
|
||||||
```
|
|
||||||
|
|
||||||
**For Alpine Linux Apps** (lightweight):
|
**For Alpine Linux Apps** (lightweight):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Use ct/alpine.sh as reference
|
# Use ct/alpine.sh as reference
|
||||||
# Edit install script to use Alpine packages (apk not apt)
|
# Edit install script to use Alpine packages (apk not apt)
|
||||||
@@ -264,7 +268,7 @@ cp ct/docker.sh ct/myapp.sh # Use Docker container
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/feat/myapp/misc/build.func)
|
source <(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/misc/build.func)
|
||||||
|
|
||||||
# Update these:
|
# Update these:
|
||||||
APP="MyAwesomeApp" # Display name
|
APP="MyAwesomeApp" # Display name
|
||||||
@@ -291,17 +295,19 @@ function update_script() {
|
|||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get latest version
|
if check_for_gh_release "myapp" "owner/repo"; then
|
||||||
RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | \
|
msg_info "Stopping Service"
|
||||||
grep "tag_name" | awk '{print substr($2, 2, length($2)-3)}')
|
systemctl stop myapp
|
||||||
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "myapp" "owner/repo" "tarball" "latest" "/opt/myapp"
|
||||||
msg_info "Updating ${APP} to v${RELEASE}"
|
|
||||||
# ... update logic ...
|
# ... update logic (migrations, rebuilds, etc.) ...
|
||||||
echo "${RELEASE}" > /opt/${APP}_version.txt
|
|
||||||
msg_ok "Updated ${APP}"
|
msg_info "Starting Service"
|
||||||
else
|
systemctl start myapp
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}."
|
msg_ok "Started Service"
|
||||||
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
@@ -317,6 +323,7 @@ echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:PORT${CL}"
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Checklist**:
|
**Checklist**:
|
||||||
|
|
||||||
- [ ] APP variable matches filename
|
- [ ] APP variable matches filename
|
||||||
- [ ] var_tags semicolon-separated (no spaces)
|
- [ ] var_tags semicolon-separated (no spaces)
|
||||||
- [ ] Realistic CPU/RAM/disk values
|
- [ ] Realistic CPU/RAM/disk values
|
||||||
@@ -345,24 +352,12 @@ update_os
|
|||||||
|
|
||||||
msg_info "Installing Dependencies"
|
msg_info "Installing Dependencies"
|
||||||
$STD apt-get install -y \
|
$STD apt-get install -y \
|
||||||
curl \
|
|
||||||
wget \
|
|
||||||
git \
|
|
||||||
build-essential
|
build-essential
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
msg_info "Setting up Node.js"
|
|
||||||
NODE_VERSION="22" setup_nodejs
|
NODE_VERSION="22" setup_nodejs
|
||||||
msg_ok "Node.js installed"
|
|
||||||
|
|
||||||
msg_info "Downloading Application"
|
fetch_and_deploy_gh_release "myapp" "owner/repo" "tarball" "latest" "/opt/myapp"
|
||||||
cd /opt
|
|
||||||
wget -q "https://github.com/user/repo/releases/download/v1.0.0/myapp.tar.gz"
|
|
||||||
tar -xzf myapp.tar.gz
|
|
||||||
rm -f myapp.tar.gz
|
|
||||||
msg_ok "Application installed"
|
|
||||||
|
|
||||||
echo "1.0.0" > /opt/${APP}_version.txt
|
|
||||||
|
|
||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
@@ -370,6 +365,7 @@ cleanup_lxc
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Checklist**:
|
**Checklist**:
|
||||||
|
|
||||||
- [ ] Functions loaded from `$FUNCTIONS_FILE_PATH`
|
- [ ] Functions loaded from `$FUNCTIONS_FILE_PATH`
|
||||||
- [ ] All installation phases present (deps, tools, app, config, cleanup)
|
- [ ] All installation phases present (deps, tools, app, config, cleanup)
|
||||||
- [ ] Using `$STD` for output suppression
|
- [ ] Using `$STD` for output suppression
|
||||||
@@ -437,26 +433,44 @@ $STD apt-get install -y newdependency
|
|||||||
# 4. Test thoroughly before committing
|
# 4. Test thoroughly before committing
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3: Update Update Function (if applicable)
|
### Step 3: The Standard Update Pattern
|
||||||
|
|
||||||
|
The `update_script()` function in `ct/appname.sh` should follow a robust pattern:
|
||||||
|
|
||||||
|
1. **Check for updates**: Use `check_for_gh_release` to skip logic if no new version exists.
|
||||||
|
2. **Stop services**: Stop all relevant services (`systemctl stop appname`).
|
||||||
|
3. **Backup existing installation**: Move the old folder (e.g., `mv /opt/app /opt/app_bak`).
|
||||||
|
4. **Deploy new version**: Use `CLEAN_INSTALL=1 fetch_and_deploy_gh_release`.
|
||||||
|
5. **Restore configuration**: Copy `.env` or config files back from the backup.
|
||||||
|
6. **Rebuild/Migrate**: Run `npm install`, `composer install`, or DB migrations.
|
||||||
|
7. **Start services**: Restart services and cleanup the backup.
|
||||||
|
|
||||||
|
**Example from `ct/bookstack.sh`**:
|
||||||
```bash
|
```bash
|
||||||
# Edit: ct/existingapp.sh → update_script()
|
function update_script() {
|
||||||
|
if check_for_gh_release "bookstack" "BookStackApp/BookStack"; then
|
||||||
|
msg_info "Stopping Services"
|
||||||
|
systemctl stop apache2
|
||||||
|
|
||||||
# 1. Update GitHub API URL if repo changed
|
msg_info "Backing up data"
|
||||||
RELEASE=$(curl -fsSL https://api.github.com/repos/user/repo/releases/latest | ...)
|
mv /opt/bookstack /opt/bookstack-backup
|
||||||
|
|
||||||
# 2. Update backup/restore logic (if structure changed)
|
fetch_and_deploy_gh_release "bookstack" "BookStackApp/BookStack" "tarball"
|
||||||
# 3. Update cleanup paths
|
|
||||||
|
|
||||||
# 4. Test update on existing installation
|
msg_info "Restoring backup"
|
||||||
```
|
cp /opt/bookstack-backup/.env /opt/bookstack/.env
|
||||||
|
# ... restore uploads ...
|
||||||
|
|
||||||
### Step 4: Document Your Changes
|
msg_info "Configuring"
|
||||||
|
cd /opt/bookstack
|
||||||
|
$STD composer install --no-dev
|
||||||
|
$STD php artisan migrate --force
|
||||||
|
|
||||||
```bash
|
systemctl start apache2
|
||||||
# Add comment at top of script
|
rm -rf /opt/bookstack-backup
|
||||||
# Co-Author: YourUsername
|
msg_ok "Updated successfully!"
|
||||||
# Updated: YYYY-MM-DD - Description of changes
|
fi
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -656,27 +670,19 @@ shellcheck install/myapp-install.sh
|
|||||||
# 1. SSH into Proxmox host
|
# 1. SSH into Proxmox host
|
||||||
ssh root@YOUR_PROXMOX_IP
|
ssh root@YOUR_PROXMOX_IP
|
||||||
|
|
||||||
# 2. Download your script
|
# 2. Test via curl from your fork (CT script only)
|
||||||
curl -O https://raw.githubusercontent.com/YOUR_USER/ProxmoxVE/feat/myapp/ct/myapp.sh
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
# ⏱️ Wait 10-30 seconds after pushing - GitHub takes time to update
|
||||||
|
|
||||||
# 3. Make executable
|
# 3. Test interaction:
|
||||||
chmod +x myapp.sh
|
|
||||||
|
|
||||||
# 4. UPDATE URLS IN SCRIPT to point to your fork
|
|
||||||
sed -i 's|community-scripts|YOUR_USER|g' myapp.sh
|
|
||||||
|
|
||||||
# 5. Run script
|
|
||||||
bash myapp.sh
|
|
||||||
|
|
||||||
# 6. Test interaction:
|
|
||||||
# - Select installation mode
|
# - Select installation mode
|
||||||
# - Confirm settings
|
# - Confirm settings
|
||||||
# - Monitor installation
|
# - Monitor installation
|
||||||
|
|
||||||
# 7. Verify container created
|
# 4. Verify container created
|
||||||
pct list | grep myapp
|
pct list | grep myapp
|
||||||
|
|
||||||
# 8. Log into container and verify app
|
# 5. Log into container and verify app
|
||||||
pct exec 100 bash
|
pct exec 100 bash
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -697,9 +703,9 @@ pct exec 100 bash
|
|||||||
# Verify script handles gracefully
|
# Verify script handles gracefully
|
||||||
|
|
||||||
# Test 4: Update function
|
# Test 4: Update function
|
||||||
# Create initial container
|
# Create initial container (via curl from fork)
|
||||||
# Wait for new release
|
# Wait for new release
|
||||||
# Run update: bash ct/myapp.sh
|
# Test update: bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
# Verify it detects and applies update
|
# Verify it detects and applies update
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -774,16 +780,19 @@ Use this template:
|
|||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
Brief description of what this PR adds/fixes
|
Brief description of what this PR adds/fixes
|
||||||
|
|
||||||
## Type of Change
|
## Type of Change
|
||||||
|
|
||||||
- [ ] New application (ct/AppName.sh + install/appname-install.sh)
|
- [ ] New application (ct/AppName.sh + install/appname-install.sh)
|
||||||
- [ ] Update existing application
|
- [ ] Update existing application
|
||||||
- [ ] Bug fix
|
- [ ] Bug fix
|
||||||
- [ ] Documentation update
|
- [ ] Documentation update
|
||||||
- [ ] Other: _______
|
- [ ] Other: **\_\_\_**
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
- [ ] Tested on Proxmox VE 8.x
|
- [ ] Tested on Proxmox VE 8.x
|
||||||
- [ ] Container creation successful
|
- [ ] Container creation successful
|
||||||
- [ ] Application installation successful
|
- [ ] Application installation successful
|
||||||
@@ -792,6 +801,7 @@ Brief description of what this PR adds/fixes
|
|||||||
- [ ] No temporary files left after installation
|
- [ ] No temporary files left after installation
|
||||||
|
|
||||||
## Application Details (for new apps only)
|
## Application Details (for new apps only)
|
||||||
|
|
||||||
- **App Name**: MyApp
|
- **App Name**: MyApp
|
||||||
- **Source**: https://github.com/app/repo
|
- **Source**: https://github.com/app/repo
|
||||||
- **Default OS**: Debian 12
|
- **Default OS**: Debian 12
|
||||||
@@ -800,9 +810,11 @@ Brief description of what this PR adds/fixes
|
|||||||
- **Access URL**: http://IP:PORT/path
|
- **Access URL**: http://IP:PORT/path
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
- [ ] My code follows the style guidelines
|
- [ ] My code follows the style guidelines
|
||||||
- [ ] I have performed a self-review
|
- [ ] I have performed a self-review
|
||||||
- [ ] I have tested the script locally
|
- [ ] I have tested the script via curl from my fork (after git push)
|
||||||
|
- [ ] GitHub had time to update (waited 10-30 seconds)
|
||||||
- [ ] ShellCheck shows no critical warnings
|
- [ ] ShellCheck shows no critical warnings
|
||||||
- [ ] Documentation is accurate and complete
|
- [ ] Documentation is accurate and complete
|
||||||
- [ ] I have added/updated relevant documentation
|
- [ ] I have added/updated relevant documentation
|
||||||
@@ -811,6 +823,7 @@ Brief description of what this PR adds/fixes
|
|||||||
### Step 5: Respond to Review Comments
|
### Step 5: Respond to Review Comments
|
||||||
|
|
||||||
**Maintainers may request changes**:
|
**Maintainers may request changes**:
|
||||||
|
|
||||||
- Fix syntax/style issues
|
- Fix syntax/style issues
|
||||||
- Add better error handling
|
- Add better error handling
|
||||||
- Optimize resource usage
|
- Optimize resource usage
|
||||||
@@ -922,6 +935,7 @@ pct exec CTID netstat -tlnp | grep LISTEN
|
|||||||
### Q: Can I test without a Proxmox system?
|
### Q: Can I test without a Proxmox system?
|
||||||
|
|
||||||
**A**: Partially. You can verify syntax and ShellCheck compliance locally, but real container testing requires Proxmox. Consider using:
|
**A**: Partially. You can verify syntax and ShellCheck compliance locally, but real container testing requires Proxmox. Consider using:
|
||||||
|
|
||||||
- Proxmox in a VM (VirtualBox/KVM)
|
- Proxmox in a VM (VirtualBox/KVM)
|
||||||
- Test instances on Hetzner/DigitalOcean
|
- Test instances on Hetzner/DigitalOcean
|
||||||
- Ask maintainers to test for you
|
- Ask maintainers to test for you
|
||||||
@@ -929,6 +943,7 @@ pct exec CTID netstat -tlnp | grep LISTEN
|
|||||||
### Q: My update function is very complex - is that OK?
|
### Q: My update function is very complex - is that OK?
|
||||||
|
|
||||||
**A**: Yes! Update functions can be complex if needed. Just ensure:
|
**A**: Yes! Update functions can be complex if needed. Just ensure:
|
||||||
|
|
||||||
- Backup user data before updating
|
- Backup user data before updating
|
||||||
- Restore user data after update
|
- Restore user data after update
|
||||||
- Test thoroughly before submitting
|
- Test thoroughly before submitting
|
||||||
@@ -937,6 +952,7 @@ pct exec CTID netstat -tlnp | grep LISTEN
|
|||||||
### Q: Can I add new dependencies to build.func?
|
### Q: Can I add new dependencies to build.func?
|
||||||
|
|
||||||
**A**: Generally no. build.func is the orchestrator and should remain stable. New functions should go in:
|
**A**: Generally no. build.func is the orchestrator and should remain stable. New functions should go in:
|
||||||
|
|
||||||
- `tools.func` - Tool installation
|
- `tools.func` - Tool installation
|
||||||
- `core.func` - Utility functions
|
- `core.func` - Utility functions
|
||||||
- `install.func` - Container setup
|
- `install.func` - Container setup
|
||||||
@@ -948,11 +964,13 @@ Ask in an issue first if you're unsure.
|
|||||||
**A**: You have options:
|
**A**: You have options:
|
||||||
|
|
||||||
**Option 1**: Use Advanced mode (19-step wizard)
|
**Option 1**: Use Advanced mode (19-step wizard)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Extend advanced_settings() if app needs special vars
|
# Extend advanced_settings() if app needs special vars
|
||||||
```
|
```
|
||||||
|
|
||||||
**Option 2**: Create custom setup menu
|
**Option 2**: Create custom setup menu
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
function custom_config() {
|
function custom_config() {
|
||||||
OPTION=$(whiptail --inputbox "Enter database name:" 8 60)
|
OPTION=$(whiptail --inputbox "Enter database name:" 8 60)
|
||||||
@@ -961,6 +979,7 @@ function custom_config() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Option 3**: Leave as defaults + documentation
|
**Option 3**: Leave as defaults + documentation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# In success message:
|
# In success message:
|
||||||
echo "Edit /opt/myapp/config.json to customize settings"
|
echo "Edit /opt/myapp/config.json to customize settings"
|
||||||
@@ -969,9 +988,10 @@ echo "Edit /opt/myapp/config.json to customize settings"
|
|||||||
### Q: Can I contribute Windows/macOS/ARM support?
|
### Q: Can I contribute Windows/macOS/ARM support?
|
||||||
|
|
||||||
**A**:
|
**A**:
|
||||||
|
|
||||||
- **Windows**: Not planned (ProxmoxVE is Linux/Proxmox focused)
|
- **Windows**: Not planned (ProxmoxVE is Linux/Proxmox focused)
|
||||||
- **macOS**: Can contribute Docker-based alternatives
|
- **macOS**: Can contribute Docker-based alternatives
|
||||||
- **ARM**: Yes! Many apps work on ARM. Add to vm/pimox-*.sh scripts
|
- **ARM**: Yes! Many apps work on ARM. Add to vm/pimox-\*.sh scripts
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -995,6 +1015,7 @@ echo "Edit /opt/myapp/config.json to customize settings"
|
|||||||
### Report Bugs
|
### Report Bugs
|
||||||
|
|
||||||
When reporting bugs, include:
|
When reporting bugs, include:
|
||||||
|
|
||||||
- Which application
|
- Which application
|
||||||
- What happened (error message)
|
- What happened (error message)
|
||||||
- What you expected
|
- What you expected
|
||||||
@@ -1002,6 +1023,7 @@ When reporting bugs, include:
|
|||||||
- Container OS and version
|
- Container OS and version
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```
|
```
|
||||||
Title: pihole-install.sh fails on Alpine 3.20
|
Title: pihole-install.sh fails on Alpine 3.20
|
||||||
|
|
||||||
@@ -1025,6 +1047,7 @@ Error Output:
|
|||||||
## Contribution Statistics
|
## Contribution Statistics
|
||||||
|
|
||||||
**ProxmoxVE by the Numbers**:
|
**ProxmoxVE by the Numbers**:
|
||||||
|
|
||||||
- 🎯 40+ applications supported
|
- 🎯 40+ applications supported
|
||||||
- 👥 100+ contributors
|
- 👥 100+ contributors
|
||||||
- 📊 10,000+ GitHub stars
|
- 📊 10,000+ GitHub stars
|
||||||
@@ -1038,6 +1061,7 @@ Error Output:
|
|||||||
## Code of Conduct
|
## Code of Conduct
|
||||||
|
|
||||||
By contributing, you agree to:
|
By contributing, you agree to:
|
||||||
|
|
||||||
- ✅ Be respectful and inclusive
|
- ✅ Be respectful and inclusive
|
||||||
- ✅ Follow the style guidelines
|
- ✅ Follow the style guidelines
|
||||||
- ✅ Test your changes thoroughly
|
- ✅ Test your changes thoroughly
|
||||||
|
|||||||
@@ -30,61 +30,79 @@
|
|||||||
|
|
||||||
> ⚠️ **Both files are ALWAYS required!** The CT script calls the install script automatically during container creation.
|
> ⚠️ **Both files are ALWAYS required!** The CT script calls the install script automatically during container creation.
|
||||||
|
|
||||||
|
Install scripts are **not** run directly by users; they are invoked by the CT script inside the container.
|
||||||
|
|
||||||
### Node.js + PostgreSQL
|
### Node.js + PostgreSQL
|
||||||
|
|
||||||
**Koel** - Music streaming with PHP + Node.js + PostgreSQL
|
**Koel** - Music streaming with PHP + Node.js + PostgreSQL
|
||||||
| File | Link |
|
| File | Link |
|
||||||
| ----------------- | -------------------------------------------------------- |
|
| ----------------- | -------------------------------------------------------- |
|
||||||
| CT (update logic) | [ct/koel.sh](../../ct/koel.sh) |
|
| CT (update logic) | [ct/koel.sh](../../ct/koel.sh) |
|
||||||
| Install | [install/koel-install.sh](../../install/koel-install.sh) |
|
| Install | [install/koel-install.sh](../../install/koel-install.sh) |
|
||||||
|
|
||||||
**Actual Budget** - Finance app with npm global install
|
**Actual Budget** - Finance app with npm global install
|
||||||
| File | Link |
|
| File | Link |
|
||||||
| ----------------- | ------------------------------------------------------------------------ |
|
| ----------------- | ------------------------------------------------------------------------ |
|
||||||
| CT (update logic) | [ct/actualbudget.sh](../../ct/actualbudget.sh) |
|
| CT (update logic) | [ct/actualbudget.sh](../../ct/actualbudget.sh) |
|
||||||
| Install | [install/actualbudget-install.sh](../../install/actualbudget-install.sh) |
|
| Install | [install/actualbudget-install.sh](../../install/actualbudget-install.sh) |
|
||||||
|
|
||||||
### Python + uv
|
### Python + uv
|
||||||
|
|
||||||
**MeTube** - YouTube downloader with Python uv + Node.js + Deno
|
**MeTube** - YouTube downloader with Python uv + Node.js + Deno
|
||||||
| File | Link |
|
| File | Link |
|
||||||
| ----------------- | ------------------------------------------------------------ |
|
| ----------------- | ------------------------------------------------------------ |
|
||||||
| CT (update logic) | [ct/metube.sh](../../ct/metube.sh) |
|
| CT (update logic) | [ct/metube.sh](../../ct/metube.sh) |
|
||||||
| Install | [install/metube-install.sh](../../install/metube-install.sh) |
|
| Install | [install/metube-install.sh](../../install/metube-install.sh) |
|
||||||
|
|
||||||
**Endurain** - Fitness tracker with Python uv + PostgreSQL/PostGIS
|
**Endurain** - Fitness tracker with Python uv + PostgreSQL/PostGIS
|
||||||
| File | Link |
|
| File | Link |
|
||||||
| ----------------- | ---------------------------------------------------------------- |
|
| ----------------- | ---------------------------------------------------------------- |
|
||||||
| CT (update logic) | [ct/endurain.sh](../../ct/endurain.sh) |
|
| CT (update logic) | [ct/endurain.sh](../../ct/endurain.sh) |
|
||||||
| Install | [install/endurain-install.sh](../../install/endurain-install.sh) |
|
| Install | [install/endurain-install.sh](../../install/endurain-install.sh) |
|
||||||
|
|
||||||
|
### Java + Gradle
|
||||||
|
|
||||||
|
**BookLore** - Book management with Java 21 + Gradle + MariaDB + Nginx
|
||||||
|
| File | Link |
|
||||||
|
| ----------------- | -------------------------------------------------------------- |
|
||||||
|
| CT (update logic) | [ct/booklore.sh](../../ct/booklore.sh) |
|
||||||
|
| Install | [install/booklore-install.sh](../../install/booklore-install.sh) |
|
||||||
|
|
||||||
|
### Pnpm + Meilisearch
|
||||||
|
|
||||||
|
**KaraKeep** - Bookmark manager with Pnpm + Meilisearch + Puppeteer
|
||||||
|
| File | Link |
|
||||||
|
| ----------------- | -------------------------------------------------------------- |
|
||||||
|
| CT (update logic) | [ct/karakeep.sh](../../ct/karakeep.sh) |
|
||||||
|
| Install | [install/karakeep-install.sh](../../install/karakeep-install.sh) |
|
||||||
|
|
||||||
### PHP + MariaDB/MySQL
|
### PHP + MariaDB/MySQL
|
||||||
|
|
||||||
**Wallabag** - Read-it-later with PHP + MariaDB + Redis + Nginx
|
**Wallabag** - Read-it-later with PHP + MariaDB + Redis + Nginx
|
||||||
| File | Link |
|
| File | Link |
|
||||||
| ----------------- | ---------------------------------------------------------------- |
|
| ----------------- | ---------------------------------------------------------------- |
|
||||||
| CT (update logic) | [ct/wallabag.sh](../../ct/wallabag.sh) |
|
| CT (update logic) | [ct/wallabag.sh](../../ct/wallabag.sh) |
|
||||||
| Install | [install/wallabag-install.sh](../../install/wallabag-install.sh) |
|
| Install | [install/wallabag-install.sh](../../install/wallabag-install.sh) |
|
||||||
|
|
||||||
**InvoiceNinja** - Invoicing with PHP + MariaDB + Supervisor
|
**InvoiceNinja** - Invoicing with PHP + MariaDB + Supervisor
|
||||||
| File | Link |
|
| File | Link |
|
||||||
| ----------------- | ------------------------------------------------------------------------ |
|
| ----------------- | ------------------------------------------------------------------------ |
|
||||||
| CT (update logic) | [ct/invoiceninja.sh](../../ct/invoiceninja.sh) |
|
| CT (update logic) | [ct/invoiceninja.sh](../../ct/invoiceninja.sh) |
|
||||||
| Install | [install/invoiceninja-install.sh](../../install/invoiceninja-install.sh) |
|
| Install | [install/invoiceninja-install.sh](../../install/invoiceninja-install.sh) |
|
||||||
|
|
||||||
**BookStack** - Wiki/Docs with PHP + MariaDB + Apache
|
**BookStack** - Wiki/Docs with PHP + MariaDB + Apache
|
||||||
| File | Link |
|
| File | Link |
|
||||||
| ----------------- | ------------------------------------------------------------------ |
|
| ----------------- | ------------------------------------------------------------------ |
|
||||||
| CT (update logic) | [ct/bookstack.sh](../../ct/bookstack.sh) |
|
| CT (update logic) | [ct/bookstack.sh](../../ct/bookstack.sh) |
|
||||||
| Install | [install/bookstack-install.sh](../../install/bookstack-install.sh) |
|
| Install | [install/bookstack-install.sh](../../install/bookstack-install.sh) |
|
||||||
|
|
||||||
### PHP + SQLite (Simple)
|
### PHP + SQLite (Simple)
|
||||||
|
|
||||||
**Speedtest Tracker** - Speedtest with PHP + SQLite + Nginx
|
**Speedtest Tracker** - Speedtest with PHP + SQLite + Nginx
|
||||||
| File | Link |
|
| File | Link |
|
||||||
| ----------------- | ---------------------------------------------------------------------------------- |
|
| ----------------- | ---------------------------------------------------------------------------------- |
|
||||||
| CT (update logic) | [ct/speedtest-tracker.sh](../../ct/speedtest-tracker.sh) |
|
| CT (update logic) | [ct/speedtest-tracker.sh](../../ct/speedtest-tracker.sh) |
|
||||||
| Install | [install/speedtest-tracker-install.sh](../../install/speedtest-tracker-install.sh) |
|
| Install | [install/speedtest-tracker-install.sh](../../install/speedtest-tracker-install.sh) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -95,7 +113,7 @@
|
|||||||
Install Node.js from NodeSource repository.
|
Install Node.js from NodeSource repository.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Default (Node.js 22)
|
# Default (Node.js 24)
|
||||||
setup_nodejs
|
setup_nodejs
|
||||||
|
|
||||||
# Specific version
|
# Specific version
|
||||||
@@ -135,8 +153,12 @@ $STD cargo build --release
|
|||||||
Install Python uv package manager (fast pip/venv replacement).
|
Install Python uv package manager (fast pip/venv replacement).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Default
|
||||||
setup_uv
|
setup_uv
|
||||||
|
|
||||||
|
# Install a specific Python version
|
||||||
|
PYTHON_VERSION="3.12" setup_uv
|
||||||
|
|
||||||
# Use in script
|
# Use in script
|
||||||
setup_uv
|
setup_uv
|
||||||
cd /opt/myapp
|
cd /opt/myapp
|
||||||
@@ -160,7 +182,7 @@ Install PHP with configurable modules and FPM/Apache support.
|
|||||||
setup_php
|
setup_php
|
||||||
|
|
||||||
# Full configuration
|
# Full configuration
|
||||||
PHP_VERSION="8.3" \
|
PHP_VERSION="8.4" \
|
||||||
PHP_MODULE="mysqli,gd,curl,mbstring,xml,zip,ldap" \
|
PHP_MODULE="mysqli,gd,curl,mbstring,xml,zip,ldap" \
|
||||||
PHP_FPM="YES" \
|
PHP_FPM="YES" \
|
||||||
PHP_APACHE="YES" \
|
PHP_APACHE="YES" \
|
||||||
@@ -168,12 +190,12 @@ setup_php
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Environment Variables:**
|
**Environment Variables:**
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
| ------------- | ------- | ------------------------------- |
|
| ------------- | ------- | ------------------------------- |
|
||||||
| `PHP_VERSION` | `8.3` | PHP version to install |
|
| `PHP_VERSION` | `8.4` | PHP version to install |
|
||||||
| `PHP_MODULE` | `""` | Comma-separated list of modules |
|
| `PHP_MODULE` | `""` | Comma-separated list of modules |
|
||||||
| `PHP_FPM` | `NO` | Install PHP-FPM |
|
| `PHP_FPM` | `NO` | Install PHP-FPM |
|
||||||
| `PHP_APACHE` | `NO` | Install Apache module |
|
| `PHP_APACHE` | `NO` | Install Apache module |
|
||||||
|
|
||||||
### `setup_composer`
|
### `setup_composer`
|
||||||
|
|
||||||
@@ -239,12 +261,12 @@ setup_mysql
|
|||||||
Install PostgreSQL server.
|
Install PostgreSQL server.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Default (PostgreSQL 17)
|
# Default (PostgreSQL 16)
|
||||||
setup_postgresql
|
setup_postgresql
|
||||||
|
|
||||||
# Specific version
|
# Specific version
|
||||||
PG_VERSION="16" setup_postgresql
|
PG_VERSION="16" setup_postgresql
|
||||||
PG_VERSION="17" setup_postgresql
|
PG_VERSION="16" setup_postgresql
|
||||||
```
|
```
|
||||||
|
|
||||||
### `setup_postgresql_db`
|
### `setup_postgresql_db`
|
||||||
@@ -279,6 +301,43 @@ setup_clickhouse
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Advanced Repository Management
|
||||||
|
|
||||||
|
### `setup_deb822_repo`
|
||||||
|
|
||||||
|
The modern standard (Debian 12+) for adding external repositories. Automatically handles GPG keys and sources.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
setup_deb822_repo \
|
||||||
|
"nodejs" \
|
||||||
|
"https://deb.nodesource.com/gpgkey/nodesource.gpg.key" \
|
||||||
|
"https://deb.nodesource.com/node_22.x" \
|
||||||
|
"bookworm" \
|
||||||
|
"main"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `prepare_repository_setup`
|
||||||
|
|
||||||
|
A high-level helper that performs three critical tasks before adding a new repo:
|
||||||
|
1. Cleans up old repo files matching the names provided.
|
||||||
|
2. Removes old GPG keyrings from all standard locations.
|
||||||
|
3. Ensures APT is in a working state (fixes locks, runs update).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clean up old mysql/mariadb artifacts before setup
|
||||||
|
prepare_repository_setup "mariadb" "mysql"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `cleanup_tool_keyrings`
|
||||||
|
|
||||||
|
Force-removes GPG keys for specific tools from `/usr/share/keyrings/`, `/etc/apt/keyrings/`, and `/etc/apt/trusted.gpg.d/`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cleanup_tool_keyrings "docker" "kubernetes"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## GitHub Release Helpers
|
## GitHub Release Helpers
|
||||||
|
|
||||||
> **Note**: `fetch_and_deploy_gh_release` is the **preferred method** for downloading GitHub releases. It handles version tracking automatically. Only use `get_latest_github_release` if you need the version number separately.
|
> **Note**: `fetch_and_deploy_gh_release` is the **preferred method** for downloading GitHub releases. It handles version tracking automatically. Only use `get_latest_github_release` if you need the version number separately.
|
||||||
@@ -302,17 +361,17 @@ CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "la
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
| Parameter | Default | Description |
|
| Parameter | Default | Description |
|
||||||
| --------------- | ------------- | ----------------------------------------------------------------- |
|
| --------------- | ------------- | ----------------------------------------------------------------- |
|
||||||
| `name` | required | App name (for version tracking) |
|
| `name` | required | App name (for version tracking) |
|
||||||
| `repo` | required | GitHub repo (`owner/repo`) |
|
| `repo` | required | GitHub repo (`owner/repo`) |
|
||||||
| `type` | `tarball` | Release type: `tarball`, `zipball`, `prebuild`, `binary` |
|
| `type` | `tarball` | Release type: `tarball`, `zipball`, `prebuild`, `binary` |
|
||||||
| `version` | `latest` | Version tag or `latest` |
|
| `version` | `latest` | Version tag or `latest` |
|
||||||
| `dest` | `/opt/[name]` | Destination directory |
|
| `dest` | `/opt/[name]` | Destination directory |
|
||||||
| `asset_pattern` | `""` | For `prebuild`: glob pattern to match asset (e.g. `app-*.tar.gz`) |
|
| `asset_pattern` | `""` | For `prebuild`: glob pattern to match asset (e.g. `app-*.tar.gz`) |
|
||||||
|
|
||||||
**Environment Variables:**
|
**Environment Variables:**
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
| ----------------- | ------------------------------------------------------------ |
|
| ----------------- | ------------------------------------------------------------ |
|
||||||
| `CLEAN_INSTALL=1` | Remove destination directory before extracting (for updates) |
|
| `CLEAN_INSTALL=1` | Remove destination directory before extracting (for updates) |
|
||||||
|
|
||||||
@@ -339,26 +398,21 @@ RELEASE=$(get_latest_github_release "owner/repo")
|
|||||||
echo "Latest version: $RELEASE"
|
echo "Latest version: $RELEASE"
|
||||||
```
|
```
|
||||||
|
|
||||||
# Examples
|
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "bookstack" "BookStackApp/BookStack"
|
|
||||||
fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/myapp"
|
|
||||||
|
|
||||||
````
|
|
||||||
|
|
||||||
**Parameters:**
|
|
||||||
| Parameter | Default | Description |
|
|
||||||
| --------- | ------------- | -------------------------------------------- |
|
|
||||||
| `name` | required | App name (for version tracking) |
|
|
||||||
| `repo` | required | GitHub repo (`owner/repo`) |
|
|
||||||
| `type` | `tarball` | Release type: `tarball`, `zipball`, `binary` |
|
|
||||||
| `version` | `latest` | Version tag or `latest` |
|
|
||||||
| `dest` | `/opt/[name]` | Destination directory |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Tools & Utilities
|
## Tools & Utilities
|
||||||
|
|
||||||
|
### `setup_meilisearch`
|
||||||
|
|
||||||
|
Install Meilisearch, a lightning-fast search engine.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
setup_meilisearch
|
||||||
|
|
||||||
|
# Use in script
|
||||||
|
$STD php artisan scout:sync-index-settings
|
||||||
|
```
|
||||||
|
|
||||||
### `setup_yq`
|
### `setup_yq`
|
||||||
|
|
||||||
Install yq YAML processor.
|
Install yq YAML processor.
|
||||||
@@ -434,6 +488,15 @@ create_self_signed_cert
|
|||||||
|
|
||||||
## Utility Functions
|
## Utility Functions
|
||||||
|
|
||||||
|
### `verify_tool_version`
|
||||||
|
|
||||||
|
Validate that the installed major version matches the expected version. Useful during upgrades or troubleshooting.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verify Node.js is version 22
|
||||||
|
verify_tool_version "nodejs" "22" "$(node -v | grep -oP '^v\K[0-9]+')"
|
||||||
|
```
|
||||||
|
|
||||||
### `get_lxc_ip`
|
### `get_lxc_ip`
|
||||||
|
|
||||||
Set the `$LOCAL_IP` variable with the container's IP address.
|
Set the `$LOCAL_IP` variable with the container's IP address.
|
||||||
@@ -526,7 +589,7 @@ msg_ok "Installed Dependencies"
|
|||||||
|
|
||||||
# Setup runtimes and databases FIRST
|
# Setup runtimes and databases FIRST
|
||||||
NODE_VERSION="22" setup_nodejs
|
NODE_VERSION="22" setup_nodejs
|
||||||
PG_VERSION="17" setup_postgresql
|
PG_VERSION="16" setup_postgresql
|
||||||
PG_DB_NAME="myapp" PG_DB_USER="myapp" setup_postgresql_db
|
PG_DB_NAME="myapp" PG_DB_USER="myapp" setup_postgresql_db
|
||||||
get_lxc_ip
|
get_lxc_ip
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ Complete guide to contributing to the ProxmoxVE project - from your first fork t
|
|||||||
|
|
||||||
## 🚀 Quick Start
|
## 🚀 Quick Start
|
||||||
|
|
||||||
### 60 Seconds to Contributing
|
### 60 Seconds to Contributing (Development)
|
||||||
|
|
||||||
|
When developing and testing **in your fork**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Fork on GitHub
|
# 1. Fork on GitHub
|
||||||
@@ -27,8 +29,8 @@ Complete guide to contributing to the ProxmoxVE project - from your first fork t
|
|||||||
git clone https://github.com/YOUR_USERNAME/ProxmoxVE.git
|
git clone https://github.com/YOUR_USERNAME/ProxmoxVE.git
|
||||||
cd ProxmoxVE
|
cd ProxmoxVE
|
||||||
|
|
||||||
# 3. Auto-configure your fork
|
# 3. Auto-configure your fork (IMPORTANT - updates all links!)
|
||||||
bash docs/contribution/setup-fork.sh
|
bash docs/contribution/setup-fork.sh --full
|
||||||
|
|
||||||
# 4. Create a feature branch
|
# 4. Create a feature branch
|
||||||
git checkout -b feature/my-awesome-app
|
git checkout -b feature/my-awesome-app
|
||||||
@@ -39,19 +41,73 @@ cat docs/ct/DETAILED_GUIDE.md # For container scripts
|
|||||||
cat docs/install/DETAILED_GUIDE.md # For install scripts
|
cat docs/install/DETAILED_GUIDE.md # For install scripts
|
||||||
|
|
||||||
# 6. Create your contribution
|
# 6. Create your contribution
|
||||||
cp ct/example.sh ct/myapp.sh
|
cp docs/contribution/templates_ct/AppName.sh ct/myapp.sh
|
||||||
cp install/example-install.sh install/myapp-install.sh
|
cp docs/contribution/templates_install/AppName-install.sh install/myapp-install.sh
|
||||||
# ... edit files ...
|
# ... edit files ...
|
||||||
|
|
||||||
# 7. Test and commit
|
# 7. Push to your fork and test via GitHub
|
||||||
bash ct/myapp.sh
|
git push origin feature/my-awesome-app
|
||||||
git add ct/myapp.sh install/myapp-install.sh
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
git commit -m "feat: add MyApp"
|
# ⏱️ GitHub may take 10-30 seconds to update files - be patient!
|
||||||
|
|
||||||
|
# 8. Create your JSON metadata file
|
||||||
|
cp docs/contribution/templates_json/AppName.json frontend/public/json/myapp.json
|
||||||
|
# Edit metadata: name, slug, categories, description, resources, etc.
|
||||||
|
|
||||||
|
# 9. No direct install-script test
|
||||||
|
# Install scripts are executed by the CT script inside the container
|
||||||
|
|
||||||
|
# 10. Commit ONLY your new files (see Cherry-Pick section below!)
|
||||||
|
git add ct/myapp.sh install/myapp-install.sh frontend/public/json/myapp.json
|
||||||
|
git commit -m "feat: add MyApp container and install scripts"
|
||||||
git push origin feature/my-awesome-app
|
git push origin feature/my-awesome-app
|
||||||
|
|
||||||
# 8. Create Pull Request on GitHub
|
# 11. Create Pull Request on GitHub
|
||||||
```
|
```
|
||||||
|
|
||||||
|
⚠️ **IMPORTANT: After setup-fork.sh, many files are modified!**
|
||||||
|
|
||||||
|
See the **Cherry-Pick: Submitting Only Your Changes** section below to learn how to push ONLY your 3-4 files instead of 600+ modified files!
|
||||||
|
|
||||||
|
### How Users Run Scripts (After Merged)
|
||||||
|
|
||||||
|
Once your script is merged to the main repository, users download and run it from GitHub like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ✅ Users run from GitHub (normal usage after PR merged)
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
|
||||||
|
# Install scripts are called by the CT script and are not run directly by users
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development vs. Production Execution
|
||||||
|
|
||||||
|
**During Development (you, in your fork):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# You MUST test via curl from your GitHub fork (not local files!)
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
|
||||||
|
# The script's curl commands are updated by setup-fork.sh to point to YOUR fork
|
||||||
|
# This ensures you're testing your actual changes
|
||||||
|
# ⏱️ Wait 10-30 seconds after pushing - GitHub updates slowly
|
||||||
|
```
|
||||||
|
|
||||||
|
**After Merge (users, from GitHub):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Users download the script from upstream via curl
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
|
||||||
|
# The script's curl commands now point back to upstream (community-scripts)
|
||||||
|
# This is the stable, tested version
|
||||||
|
```
|
||||||
|
|
||||||
|
**Summary:**
|
||||||
|
|
||||||
|
- **Development**: Push to fork, test via curl → setup-fork.sh changes curl URLs to your fork
|
||||||
|
- **Production**: curl | bash from upstream → curl URLs point to community-scripts repo
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🍴 Setting Up Your Fork
|
## 🍴 Setting Up Your Fork
|
||||||
@@ -61,14 +117,35 @@ git push origin feature/my-awesome-app
|
|||||||
When you clone your fork, run the setup script to automatically configure everything:
|
When you clone your fork, run the setup script to automatically configure everything:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash docs/contribution/setup-fork.sh
|
bash docs/contribution/setup-fork.sh --full
|
||||||
```
|
```
|
||||||
|
|
||||||
This will:
|
**What it does:**
|
||||||
|
|
||||||
- Auto-detect your GitHub username
|
- Auto-detects your GitHub username from git config
|
||||||
- Update all documentation links to point to your fork
|
- Auto-detects your fork repository name
|
||||||
- Create `.git-setup-info` with recommended git workflows
|
- Updates **ALL** hardcoded links to point to your fork instead of the main repo (`--full`)
|
||||||
|
- Creates `.git-setup-info` with your configuration
|
||||||
|
- Allows you to develop and test independently in your fork
|
||||||
|
|
||||||
|
**Why this matters:**
|
||||||
|
|
||||||
|
Without running this script, all links in your fork will still point to the upstream repository (community-scripts). This is a problem when testing because:
|
||||||
|
|
||||||
|
- Installation links will pull from upstream, not your fork
|
||||||
|
- Updates will target the wrong repository
|
||||||
|
- Your contributions won't be properly tested
|
||||||
|
|
||||||
|
**After running setup-fork.sh:**
|
||||||
|
|
||||||
|
Your fork is fully configured and ready to develop. You can:
|
||||||
|
|
||||||
|
- Push changes to your fork
|
||||||
|
- Test via curl: `bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"`
|
||||||
|
- All links will reference your fork for development
|
||||||
|
- ⏱️ Wait 10-30 seconds after pushing - GitHub takes time to update
|
||||||
|
- Commit and push with confidence
|
||||||
|
- Create a PR to merge into upstream
|
||||||
|
|
||||||
**See**: [FORK_SETUP.md](FORK_SETUP.md) for detailed instructions
|
**See**: [FORK_SETUP.md](FORK_SETUP.md) for detailed instructions
|
||||||
|
|
||||||
@@ -81,11 +158,12 @@ If the script doesn't work, manually configure:
|
|||||||
git config user.name "Your Name"
|
git config user.name "Your Name"
|
||||||
git config user.email "your.email@example.com"
|
git config user.email "your.email@example.com"
|
||||||
|
|
||||||
# Add upstream remote for syncing
|
# Add upstream remote for syncing with main repo
|
||||||
git remote add upstream https://github.com/community-scripts/ProxmoxVE.git
|
git remote add upstream https://github.com/community-scripts/ProxmoxVE.git
|
||||||
|
|
||||||
# Verify remotes
|
# Verify remotes
|
||||||
git remote -v
|
git remote -v
|
||||||
|
# Should show: origin (your fork) and upstream (main repo)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -102,7 +180,7 @@ All scripts and configurations must follow our coding standards to ensure consis
|
|||||||
- **[HELPER_FUNCTIONS.md](HELPER_FUNCTIONS.md)** - Reference for all tools.func helper functions
|
- **[HELPER_FUNCTIONS.md](HELPER_FUNCTIONS.md)** - Reference for all tools.func helper functions
|
||||||
- **Container Scripts** - `/ct/` templates and guidelines
|
- **Container Scripts** - `/ct/` templates and guidelines
|
||||||
- **Install Scripts** - `/install/` templates and guidelines
|
- **Install Scripts** - `/install/` templates and guidelines
|
||||||
- **JSON Configurations** - `/json/` structure and format
|
- **JSON Configurations** - `frontend/public/json/` structure and format
|
||||||
|
|
||||||
### Quick Checklist
|
### Quick Checklist
|
||||||
|
|
||||||
@@ -112,7 +190,7 @@ All scripts and configurations must follow our coding standards to ensure consis
|
|||||||
- ✅ Include proper shebang: `#!/usr/bin/env bash`
|
- ✅ Include proper shebang: `#!/usr/bin/env bash`
|
||||||
- ✅ Add copyright header with author
|
- ✅ Add copyright header with author
|
||||||
- ✅ Handle errors properly with `msg_error`, `msg_ok`, etc.
|
- ✅ Handle errors properly with `msg_error`, `msg_ok`, etc.
|
||||||
- ✅ Test before submitting PR
|
- ✅ Test before submitting PR (via curl from your fork, not local bash)
|
||||||
- ✅ Update documentation if needed
|
- ✅ Update documentation if needed
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -133,7 +211,172 @@ Key points:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📚 Guides & Resources
|
## 🍒 Cherry-Pick: Submitting Only Your Changes
|
||||||
|
|
||||||
|
**Problem**: `setup-fork.sh` modifies 600+ files to update links. You don't want to submit all of those changes - only your new 3-4 files!
|
||||||
|
|
||||||
|
**Solution**: Use git cherry-pick to select only YOUR files.
|
||||||
|
|
||||||
|
### Step-by-Step Cherry-Pick Guide
|
||||||
|
|
||||||
|
#### 1. Check what changed
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# See all modified files
|
||||||
|
git status
|
||||||
|
|
||||||
|
# Verify your files are there
|
||||||
|
git status | grep -E "ct/myapp|install/myapp|json/myapp"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Create a clean feature branch for submission
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Go back to upstream main (clean slate)
|
||||||
|
git fetch upstream
|
||||||
|
git checkout -b submit/myapp upstream/main
|
||||||
|
|
||||||
|
# Don't use your modified main branch!
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Cherry-pick ONLY your files
|
||||||
|
|
||||||
|
Cherry-picking extracts specific changes from commits:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Option A: Cherry-pick commits that added your files
|
||||||
|
# (if you committed your files separately)
|
||||||
|
git cherry-pick <commit-hash-of-your-files>
|
||||||
|
|
||||||
|
# Option B: Manually copy and commit only your files
|
||||||
|
# From your work branch, get the file contents
|
||||||
|
git show feature/my-awesome-app:ct/myapp.sh > /tmp/myapp.sh
|
||||||
|
git show feature/my-awesome-app:install/myapp-install.sh > /tmp/myapp-install.sh
|
||||||
|
git show feature/my-awesome-app:frontend/public/json/myapp.json > /tmp/myapp.json
|
||||||
|
|
||||||
|
# Add them to the clean branch
|
||||||
|
cp /tmp/myapp.sh ct/myapp.sh
|
||||||
|
cp /tmp/myapp-install.sh install/myapp-install.sh
|
||||||
|
cp /tmp/myapp.json frontend/public/json/myapp.json
|
||||||
|
|
||||||
|
# Commit
|
||||||
|
git add ct/myapp.sh install/myapp-install.sh frontend/public/json/myapp.json
|
||||||
|
git commit -m "feat: add MyApp"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. Verify only your files are in the PR
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check git diff against upstream
|
||||||
|
git diff upstream/main --name-only
|
||||||
|
# Should show ONLY:
|
||||||
|
# ct/myapp.sh
|
||||||
|
# install/myapp-install.sh
|
||||||
|
# frontend/public/json/myapp.json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. Push and create PR
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Push your clean submission branch
|
||||||
|
git push origin submit/myapp
|
||||||
|
|
||||||
|
# Create PR on GitHub from: submit/myapp → main
|
||||||
|
```
|
||||||
|
|
||||||
|
### Why This Matters
|
||||||
|
|
||||||
|
- ✅ Clean PR with only your changes
|
||||||
|
- ✅ Easier for maintainers to review
|
||||||
|
- ✅ Faster merge without conflicts
|
||||||
|
- ❌ Without cherry-pick: PR has 600+ file changes (won't merge!)
|
||||||
|
|
||||||
|
### If You Made a Mistake
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Delete the messy branch
|
||||||
|
git branch -D submit/myapp
|
||||||
|
|
||||||
|
# Go back to clean branch
|
||||||
|
git checkout -b submit/myapp upstream/main
|
||||||
|
|
||||||
|
# Try cherry-picking again
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
If you're using **Visual Studio Code** with an AI assistant, you can leverage our detailed guidelines to generate high-quality contributions automatically.
|
||||||
|
|
||||||
|
### How to Use AI Assistance
|
||||||
|
|
||||||
|
1. **Open the AI Guidelines**
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/contribution/AI.md
|
||||||
|
```
|
||||||
|
|
||||||
|
This file contains all requirements, patterns, and examples for writing proper scripts.
|
||||||
|
|
||||||
|
2. **Prepare Your Information**
|
||||||
|
|
||||||
|
Before asking the AI to generate code, gather:
|
||||||
|
- **Repository URL**: e.g., `https://github.com/owner/myapp`
|
||||||
|
- **Dockerfile/Script**: Paste the app's installation instructions (if available)
|
||||||
|
- **Dependencies**: What packages does it need? (Node, Python, Java, PostgreSQL, etc.)
|
||||||
|
- **Ports**: What port does it listen on? (e.g., 3000, 8080, 5000)
|
||||||
|
- **Configuration**: Any environment variables or config files?
|
||||||
|
|
||||||
|
3. **Tell the AI Assistant**
|
||||||
|
|
||||||
|
Share with the AI:
|
||||||
|
- The repository URL
|
||||||
|
- The Dockerfile or install instructions
|
||||||
|
- Link to [docs/contribution/AI.md](AI.md) with instructions to follow
|
||||||
|
|
||||||
|
**Example prompt:**
|
||||||
|
|
||||||
|
```
|
||||||
|
I want to contribute a container script for MyApp to ProxmoxVE.
|
||||||
|
Repository: https://github.com/owner/myapp
|
||||||
|
|
||||||
|
Here's the Dockerfile:
|
||||||
|
[paste Dockerfile content]
|
||||||
|
|
||||||
|
Please follow the guidelines in docs/contribution/AI.md to create:
|
||||||
|
1. ct/myapp.sh (container script)
|
||||||
|
2. install/myapp-install.sh (installation script)
|
||||||
|
3. frontend/public/json/myapp.json (metadata)
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **AI Will Generate**
|
||||||
|
|
||||||
|
The AI will produce scripts that:
|
||||||
|
- Follow all ProxmoxVE patterns and conventions
|
||||||
|
- Use helper functions from `tools.func` correctly
|
||||||
|
- Include proper error handling and messages
|
||||||
|
- Have correct update mechanisms
|
||||||
|
- Are ready to submit as a PR
|
||||||
|
|
||||||
|
### Key Points for AI Assistants
|
||||||
|
|
||||||
|
- **Templates Location**: `docs/contribution/templates_ct/AppName.sh`, `templates_install/`, `templates_json/`
|
||||||
|
- **Guidelines**: Must follow `docs/contribution/AI.md` exactly
|
||||||
|
- **Helper Functions**: Use only functions from `misc/tools.func` - never write custom ones
|
||||||
|
- **Testing**: Always test before submission via curl from your fork
|
||||||
|
```bash
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
# Wait 10-30 seconds after pushing changes
|
||||||
|
```
|
||||||
|
- **No Docker**: Container scripts must be bare-metal, not Docker-based
|
||||||
|
|
||||||
|
### Benefits
|
||||||
|
|
||||||
|
- **Speed**: AI generates boilerplate in seconds
|
||||||
|
- **Consistency**: Follows same patterns as 200+ existing scripts
|
||||||
|
- **Quality**: Less bugs and more maintainable code
|
||||||
|
- **Learning**: See how your app should be structured
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
@@ -221,15 +464,15 @@ git push origin feature/my-feature
|
|||||||
git rebase upstream/main
|
git rebase upstream/main
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Test your changes**
|
2. **Test your changes** (via curl from your fork)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash ct/my-app.sh
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/my-app.sh)"
|
||||||
# Follow prompts and test the container
|
# Follow prompts and test the container
|
||||||
|
# ⏱️ Wait 10-30 seconds after pushing - GitHub takes time to update
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Check code standards**
|
3. **Check code standards**
|
||||||
|
|
||||||
- [ ] Follows template structure
|
- [ ] Follows template structure
|
||||||
- [ ] Proper error handling
|
- [ ] Proper error handling
|
||||||
- [ ] Documentation updated (if needed)
|
- [ ] Documentation updated (if needed)
|
||||||
@@ -260,23 +503,66 @@ Before opening a PR:
|
|||||||
|
|
||||||
## ❓ FAQ
|
## ❓ FAQ
|
||||||
|
|
||||||
### How do I test my changes?
|
### ❌ Why can't I test with `bash ct/myapp.sh` locally?
|
||||||
|
|
||||||
|
You might try:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# For container scripts
|
# ❌ WRONG - This won't test your actual changes!
|
||||||
bash ct/my-app.sh
|
bash ct/myapp.sh
|
||||||
|
./ct/myapp.sh
|
||||||
# For install scripts (runs inside container)
|
sh ct/myapp.sh
|
||||||
# The ct script will call it automatically
|
|
||||||
|
|
||||||
# For advanced debugging
|
|
||||||
VERBOSE=yes bash ct/my-app.sh
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Why this fails:**
|
||||||
|
|
||||||
|
- `bash ct/myapp.sh` uses the LOCAL clone file
|
||||||
|
- The LOCAL file doesn't execute the curl commands - it's already on disk
|
||||||
|
- The curl URLs INSIDE the script are modified by setup-fork.sh, but they're not executed
|
||||||
|
- So you can't verify if your curl URLs actually work
|
||||||
|
- Users will get the curl URL version (which may be broken)
|
||||||
|
|
||||||
|
**Solution:** Always test via curl from GitHub:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ✅ CORRECT - Tests the actual GitHub URLs
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/myapp.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### ❓ How do I test my changes?
|
||||||
|
|
||||||
|
You **cannot** test locally with `bash ct/myapp.sh` from your cloned directory!
|
||||||
|
|
||||||
|
You **must** push to GitHub and test via curl from your fork:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Push your changes to your fork
|
||||||
|
git push origin feature/my-awesome-app
|
||||||
|
|
||||||
|
# 2. Test via curl (this loads the script from GitHub, not local files)
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/my-app.sh)"
|
||||||
|
|
||||||
|
# 3. For verbose/debug output, pass environment variables
|
||||||
|
VERBOSE=yes bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/my-app.sh)"
|
||||||
|
DEV_MODE_LOGS=true bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/my-app.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why?**
|
||||||
|
|
||||||
|
- Local `bash ct/myapp.sh` uses local files from your clone
|
||||||
|
- But the script's INTERNAL curl commands have been modified by setup-fork.sh to point to your fork
|
||||||
|
- This discrepancy means you're not actually testing the curl URLs
|
||||||
|
- Testing via curl ensures the script downloads from YOUR fork GitHub URLs
|
||||||
|
- ⏱️ **Important:** GitHub takes 10-30 seconds to recognize newly pushed files. Wait before testing!
|
||||||
|
|
||||||
|
**What if local bash worked?**
|
||||||
|
|
||||||
|
You'd be testing local files only, not the actual GitHub URLs that users will download. This means broken curl links wouldn't be caught during testing.
|
||||||
|
|
||||||
### What if my PR has conflicts?
|
### What if my PR has conflicts?
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Sync with upstream
|
# Sync with upstream main repository
|
||||||
git fetch upstream
|
git fetch upstream
|
||||||
git rebase upstream/main
|
git rebase upstream/main
|
||||||
|
|
||||||
@@ -288,17 +574,27 @@ git push -f origin your-branch
|
|||||||
|
|
||||||
### How do I keep my fork updated?
|
### How do I keep my fork updated?
|
||||||
|
|
||||||
See "Keep Your Fork Updated" section above, or run:
|
Two ways:
|
||||||
|
|
||||||
|
**Option 1: Run setup script again**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash docs/contribution/setup-fork.sh
|
bash docs/contribution/setup-fork.sh --full
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option 2: Manual sync**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git fetch upstream
|
||||||
|
git rebase upstream/main
|
||||||
|
git push -f origin main
|
||||||
```
|
```
|
||||||
|
|
||||||
### Where do I ask questions?
|
### Where do I ask questions?
|
||||||
|
|
||||||
- **GitHub Issues**: For bugs and feature requests
|
- **GitHub Issues**: For bugs and feature requests
|
||||||
- **GitHub Discussions**: For general questions
|
- **GitHub Discussions**: For general questions and ideas
|
||||||
- **Discord**: Community-scripts server
|
- **Discord**: Community-scripts server for real-time chat
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -307,7 +603,7 @@ bash docs/contribution/setup-fork.sh
|
|||||||
### For First-Time Contributors
|
### For First-Time Contributors
|
||||||
|
|
||||||
1. Read: [docs/README.md](../README.md) - Documentation overview
|
1. Read: [docs/README.md](../README.md) - Documentation overview
|
||||||
2. Read: [docs/contribution/FORK_SETUP.md](FORK_SETUP.md) - Fork setup guide
|
2. Read: [CONTRIBUTING.md](CONTRIBUTING.md) - Essential coding standards
|
||||||
3. Choose your path:
|
3. Choose your path:
|
||||||
- Containers → [docs/ct/DETAILED_GUIDE.md](../ct/DETAILED_GUIDE.md)
|
- Containers → [docs/ct/DETAILED_GUIDE.md](../ct/DETAILED_GUIDE.md)
|
||||||
- Installation → [docs/install/DETAILED_GUIDE.md](../install/DETAILED_GUIDE.md)
|
- Installation → [docs/install/DETAILED_GUIDE.md](../install/DETAILED_GUIDE.md)
|
||||||
@@ -318,21 +614,24 @@ bash docs/contribution/setup-fork.sh
|
|||||||
|
|
||||||
1. Review [CONTRIBUTING.md](CONTRIBUTING.md) - Coding standards
|
1. Review [CONTRIBUTING.md](CONTRIBUTING.md) - Coding standards
|
||||||
2. Review [CODE_AUDIT.md](CODE_AUDIT.md) - Audit checklist
|
2. Review [CODE_AUDIT.md](CODE_AUDIT.md) - Audit checklist
|
||||||
3. Check templates in `/ct/` and `/install/`
|
3. Check templates in `/docs/contribution/templates_*/`
|
||||||
4. Submit PR with confidence
|
4. Use AI assistants with [AI.md](AI.md) for code generation
|
||||||
|
5. Submit PR with confidence
|
||||||
|
|
||||||
### For Reviewers/Maintainers
|
### For Using AI Assistants
|
||||||
|
|
||||||
1. Use [CODE_AUDIT.md](CODE_AUDIT.md) as review guide
|
See "Using AI Assistants" section above for:
|
||||||
2. Reference [docs/TECHNICAL_REFERENCE.md](../TECHNICAL_REFERENCE.md) for architecture
|
|
||||||
3. Check [docs/EXIT_CODES.md](../EXIT_CODES.md) for error handling
|
- How to structure prompts
|
||||||
|
- What information to provide
|
||||||
|
- How to validate AI output
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Ready to Contribute?
|
## 🚀 Ready to Contribute?
|
||||||
|
|
||||||
1. **Fork** the repository
|
1. **Fork** the repository
|
||||||
2. **Clone** your fork and **setup** with `bash docs/contribution/setup-fork.sh`
|
2. **Clone** your fork and **setup** with `bash docs/contribution/setup-fork.sh --full`
|
||||||
3. **Choose** your contribution type (container, installation, tools, etc.)
|
3. **Choose** your contribution type (container, installation, tools, etc.)
|
||||||
4. **Read** the appropriate detailed guide
|
4. **Read** the appropriate detailed guide
|
||||||
5. **Create** your feature branch
|
5. **Create** your feature branch
|
||||||
@@ -345,9 +644,9 @@ bash docs/contribution/setup-fork.sh
|
|||||||
|
|
||||||
## 📞 Contact & Support
|
## 📞 Contact & Support
|
||||||
|
|
||||||
- **GitHub**: https://github.com/community-scripts/ProxmoxVE
|
- **GitHub**: [community-scripts/ProxmoxVE](https://github.com/community-scripts/ProxmoxVE)
|
||||||
- **Issues**: https://github.com/community-scripts/ProxmoxVE/issues
|
- **Issues**: [GitHub Issues](https://github.com/community-scripts/ProxmoxVE/issues)
|
||||||
- **Discussions**: https://github.com/community-scripts/ProxmoxVE/discussions
|
- **Discussions**: [GitHub Discussions](https://github.com/community-scripts/ProxmoxVE/discussions)
|
||||||
- **Discord**: [Join Server](https://discord.gg/UHrpNWGwkH)
|
- **Discord**: [Join Server](https://discord.gg/UHrpNWGwkH)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -8,13 +8,15 @@
|
|||||||
# Updates all hardcoded links to point to your fork
|
# Updates all hardcoded links to point to your fork
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# ./setup-fork.sh # Auto-detect from git config
|
# ./setup-fork.sh # Auto-detect from git config (updates misc/ only)
|
||||||
# ./setup-fork.sh YOUR_USERNAME # Specify username
|
# ./setup-fork.sh YOUR_USERNAME # Specify username (updates misc/ only)
|
||||||
# ./setup-fork.sh YOUR_USERNAME REPO_NAME # Specify both
|
# ./setup-fork.sh YOUR_USERNAME REPO_NAME # Specify both (updates misc/ only)
|
||||||
|
# ./setup-fork.sh --full # Update all files including ct/, install/, vm/, etc.
|
||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# ./setup-fork.sh john # Uses john/ProxmoxVE
|
# ./setup-fork.sh john # Uses john/ProxmoxVE, updates misc/ only
|
||||||
# ./setup-fork.sh john my-fork # Uses john/my-fork
|
# ./setup-fork.sh john my-fork # Uses john/my-fork, updates misc/ only
|
||||||
|
# ./setup-fork.sh --full # Auto-detect + update all files
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@@ -30,131 +32,136 @@ NC='\033[0m' # No Color
|
|||||||
REPO_NAME="ProxmoxVE"
|
REPO_NAME="ProxmoxVE"
|
||||||
USERNAME=""
|
USERNAME=""
|
||||||
AUTO_DETECT=true
|
AUTO_DETECT=true
|
||||||
|
UPDATE_ALL=false
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# FUNCTIONS
|
# FUNCTIONS
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
print_header() {
|
print_header() {
|
||||||
echo -e "\n${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
|
echo -e "\n${BLUE}╔════════════════════════════════════════════════════════════╗${NC}"
|
||||||
echo -e "${BLUE}║${NC} ProxmoxVE Fork Setup Script"
|
echo -e "${BLUE}║${NC} ProxmoxVE Fork Setup Script"
|
||||||
echo -e "${BLUE}║${NC} Configuring for your fork..."
|
echo -e "${BLUE}║${NC} Configuring for your fork..."
|
||||||
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}\n"
|
echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_info() {
|
print_info() {
|
||||||
echo -e "${BLUE}ℹ${NC} $1"
|
echo -e "${BLUE}ℹ${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_success() {
|
print_success() {
|
||||||
echo -e "${GREEN}✓${NC} $1"
|
echo -e "${GREEN}✓${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_warning() {
|
print_warning() {
|
||||||
echo -e "${YELLOW}⚠${NC} $1"
|
echo -e "${YELLOW}⚠${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
print_error() {
|
print_error() {
|
||||||
echo -e "${RED}✗${NC} $1"
|
echo -e "${RED}✗${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Detect username from git remote
|
# Detect username from git remote
|
||||||
detect_username() {
|
detect_username() {
|
||||||
local remote_url
|
local remote_url
|
||||||
|
|
||||||
# Try to get from origin
|
# Try to get from origin
|
||||||
if ! remote_url=$(git config --get remote.origin.url 2>/dev/null); then
|
if ! remote_url=$(git config --get remote.origin.url 2>/dev/null); then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Extract username from SSH or HTTPS URL
|
# Extract username from SSH or HTTPS URL
|
||||||
if [[ $remote_url =~ git@github.com:([^/]+) ]]; then
|
if [[ $remote_url =~ git@github.com:([^/]+) ]]; then
|
||||||
echo "${BASH_REMATCH[1]}"
|
echo "${BASH_REMATCH[1]}"
|
||||||
elif [[ $remote_url =~ github.com/([^/]+) ]]; then
|
elif [[ $remote_url =~ github.com/([^/]+) ]]; then
|
||||||
echo "${BASH_REMATCH[1]}"
|
echo "${BASH_REMATCH[1]}"
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Detect repo name from git remote
|
# Detect repo name from git remote
|
||||||
detect_repo_name() {
|
detect_repo_name() {
|
||||||
local remote_url
|
local remote_url
|
||||||
|
|
||||||
if ! remote_url=$(git config --get remote.origin.url 2>/dev/null); then
|
if ! remote_url=$(git config --get remote.origin.url 2>/dev/null); then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Extract repo name (remove .git if present)
|
# Extract repo name (remove .git if present)
|
||||||
if [[ $remote_url =~ /([^/]+?)(.git)?$ ]]; then
|
if [[ $remote_url =~ /([^/]+?)(.git)?$ ]]; then
|
||||||
local repo="${BASH_REMATCH[1]}"
|
local repo="${BASH_REMATCH[1]}"
|
||||||
echo "${repo%.git}"
|
echo "${repo%.git}"
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ask user for confirmation
|
# Ask user for confirmation
|
||||||
confirm() {
|
confirm() {
|
||||||
local prompt="$1"
|
local prompt="$1"
|
||||||
local response
|
local response
|
||||||
|
|
||||||
read -p "$(echo -e ${YELLOW})$prompt (y/n)${NC} " -r response
|
echo -ne "${YELLOW}${prompt} (y/n)${NC} "
|
||||||
[[ $response =~ ^[Yy]$ ]]
|
read -r response
|
||||||
|
[[ $response =~ ^[Yy]$ ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Update links in files
|
# Update links in files
|
||||||
update_links() {
|
update_links() {
|
||||||
local old_repo="community-scripts"
|
local old_repo="community-scripts"
|
||||||
local old_name="ProxmoxVE"
|
local old_name="ProxmoxVE"
|
||||||
local new_owner="$1"
|
local new_owner="$1"
|
||||||
local new_repo="$2"
|
local new_repo="$2"
|
||||||
local files_updated=0
|
local files_updated=0
|
||||||
|
|
||||||
print_info "Scanning for hardcoded links..."
|
print_info "Scanning for hardcoded links..."
|
||||||
|
|
||||||
# Find all markdown and shell files
|
# Change to repo root
|
||||||
local -a files_to_update=(
|
local repo_root=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
||||||
"docs/DEFAULTS_SYSTEM_GUIDE.md"
|
|
||||||
"docs/alpine-install.func.md"
|
|
||||||
"docs/install.func.md"
|
|
||||||
"docs/APP-install.md"
|
|
||||||
"docs/APP-ct.md"
|
|
||||||
"docs/CONTRIBUTION_GUIDE.md"
|
|
||||||
"docs/INDEX.md"
|
|
||||||
"docs/README.md"
|
|
||||||
"docs/EXIT_CODES.md"
|
|
||||||
"docs/api/README.md"
|
|
||||||
)
|
|
||||||
|
|
||||||
echo ""
|
# Determine search path
|
||||||
|
local search_path="$repo_root/misc"
|
||||||
|
if [[ "$UPDATE_ALL" == "true" ]]; then
|
||||||
|
search_path="$repo_root"
|
||||||
|
print_info "Searching all files (--full mode)"
|
||||||
|
else
|
||||||
|
print_info "Searching misc/ directory only (core functions)"
|
||||||
|
fi
|
||||||
|
|
||||||
for file in "${files_to_update[@]}"; do
|
echo ""
|
||||||
if [[ -f "$file" ]]; then
|
|
||||||
# Count occurrences
|
|
||||||
local count=$(grep -c "github.com/$old_repo/$old_name" "$file" 2>/dev/null || echo 0)
|
|
||||||
|
|
||||||
if [[ $count -gt 0 ]]; then
|
# Find all files containing the old repo reference
|
||||||
# Backup original
|
while IFS= read -r file; do
|
||||||
cp "$file" "$file.backup"
|
# Count occurrences
|
||||||
|
local count=$(grep -c "github.com/$old_repo/$old_name" "$file" 2>/dev/null || echo 0)
|
||||||
|
|
||||||
# Replace links
|
if [[ $count -gt 0 ]]; then
|
||||||
sed -i "s|github.com/$old_repo/$old_name|github.com/$new_owner/$new_repo|g" "$file"
|
# Backup original
|
||||||
|
cp "$file" "$file.backup"
|
||||||
|
|
||||||
((files_updated++))
|
# Replace links - use different sed syntax for BSD/macOS vs GNU sed
|
||||||
print_success "Updated $file ($count links)"
|
if sed --version &>/dev/null 2>&1; then
|
||||||
fi
|
# GNU sed
|
||||||
fi
|
sed -i "s|github.com/$old_repo/$old_name|github.com/$new_owner/$new_repo|g" "$file"
|
||||||
done
|
else
|
||||||
|
# BSD sed (macOS)
|
||||||
|
sed -i '' "s|github.com/$old_repo/$old_name|github.com/$new_owner/$new_repo|g" "$file"
|
||||||
|
fi
|
||||||
|
|
||||||
return $files_updated
|
((files_updated++))
|
||||||
|
print_success "Updated $file ($count links)"
|
||||||
|
fi
|
||||||
|
done < <(find "$search_path" -type f \( -name "*.md" -o -name "*.sh" -o -name "*.func" -o -name "*.json" \) -not -path "*/.git/*" 2>/dev/null | xargs grep -l "github.com/$old_repo/$old_name" 2>/dev/null)
|
||||||
|
|
||||||
|
return $files_updated
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create user git config setup info
|
# Create user git config setup info
|
||||||
create_git_setup_info() {
|
create_git_setup_info() {
|
||||||
local username="$1"
|
local username="$1"
|
||||||
|
|
||||||
cat >.git-setup-info <<'EOF'
|
cat >.git-setup-info <<'EOF'
|
||||||
# Git Configuration for ProxmoxVE Development
|
# Git Configuration for ProxmoxVE Development
|
||||||
|
|
||||||
## Recommended Git Configuration
|
## Recommended Git Configuration
|
||||||
@@ -213,10 +220,10 @@ git merge upstream/main
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
For more help, see: docs/CONTRIBUTION_GUIDE.md
|
For more help, see: docs/contribution/README.md
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
print_success "Created .git-setup-info file"
|
print_success "Created .git-setup-info file"
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -227,65 +234,79 @@ print_header
|
|||||||
|
|
||||||
# Parse command line arguments
|
# Parse command line arguments
|
||||||
if [[ $# -gt 0 ]]; then
|
if [[ $# -gt 0 ]]; then
|
||||||
|
# Check for --full flag
|
||||||
|
if [[ "$1" == "--full" ]]; then
|
||||||
|
UPDATE_ALL=true
|
||||||
|
AUTO_DETECT=true
|
||||||
|
shift # Remove --full from arguments
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Process remaining arguments
|
||||||
|
if [[ $# -gt 0 ]]; then
|
||||||
USERNAME="$1"
|
USERNAME="$1"
|
||||||
AUTO_DETECT=false
|
AUTO_DETECT=false
|
||||||
|
|
||||||
if [[ $# -gt 1 ]]; then
|
if [[ $# -gt 1 ]]; then
|
||||||
REPO_NAME="$2"
|
REPO_NAME="$2"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
# Try auto-detection
|
# Try auto-detection
|
||||||
if username=$(detect_username); then
|
if username=$(detect_username); then
|
||||||
USERNAME="$username"
|
USERNAME="$username"
|
||||||
print_success "Detected GitHub username: $USERNAME"
|
print_success "Detected GitHub username: $USERNAME"
|
||||||
else
|
else
|
||||||
print_error "Could not auto-detect GitHub username from git config"
|
print_error "Could not auto-detect GitHub username from git config"
|
||||||
echo -e "${YELLOW}Please run:${NC}"
|
echo -e "${YELLOW}Please run:${NC}"
|
||||||
echo " ./setup-fork.sh YOUR_USERNAME"
|
echo " ./setup-fork.sh YOUR_USERNAME"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if repo_name=$(detect_repo_name); then
|
if repo_name=$(detect_repo_name); then
|
||||||
REPO_NAME="$repo_name"
|
REPO_NAME="$repo_name"
|
||||||
if [[ "$REPO_NAME" != "ProxmoxVE" ]]; then
|
if [[ "$REPO_NAME" != "ProxmoxVE" ]]; then
|
||||||
print_info "Detected custom repo name: $REPO_NAME"
|
print_info "Detected custom repo name: $REPO_NAME"
|
||||||
else
|
else
|
||||||
print_success "Using default repo name: ProxmoxVE"
|
print_success "Using default repo name: ProxmoxVE"
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Validate inputs
|
# Validate inputs
|
||||||
if [[ -z "$USERNAME" ]]; then
|
if [[ -z "$USERNAME" ]]; then
|
||||||
print_error "Username cannot be empty"
|
print_error "Username cannot be empty"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z "$REPO_NAME" ]]; then
|
if [[ -z "$REPO_NAME" ]]; then
|
||||||
print_error "Repository name cannot be empty"
|
print_error "Repository name cannot be empty"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Show what we'll do
|
# Show what we'll do
|
||||||
echo -e "${BLUE}Configuration Summary:${NC}"
|
echo -e "${BLUE}Configuration Summary:${NC}"
|
||||||
echo " Repository URL: https://github.com/$USERNAME/$REPO_NAME"
|
echo " Repository URL: https://github.com/$USERNAME/$REPO_NAME"
|
||||||
echo " Files to update: 10 files with documentation"
|
if [[ "$UPDATE_ALL" == "true" ]]; then
|
||||||
|
echo " Files to update: ALL files (ct/, install/, vm/, misc/, docs/, etc.)"
|
||||||
|
else
|
||||||
|
echo " Files to update: misc/ directory only (core functions)"
|
||||||
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Ask for confirmation
|
# Ask for confirmation
|
||||||
if ! confirm "Apply these changes?"; then
|
if ! confirm "Apply these changes?"; then
|
||||||
print_warning "Setup cancelled"
|
print_warning "Setup cancelled"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Update all links
|
# Update all links
|
||||||
if update_links "$USERNAME" "$REPO_NAME"; then
|
if update_links "$USERNAME" "$REPO_NAME"; then
|
||||||
links_changed=$?
|
links_changed=$?
|
||||||
print_success "Updated $links_changed files"
|
print_success "Updated $links_changed files"
|
||||||
else
|
else
|
||||||
print_warning "No links needed updating or some files not found"
|
print_warning "No links needed updating or some files not found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create git setup info file
|
# Create git setup info file
|
||||||
@@ -307,7 +328,7 @@ echo -e "${BLUE}Next Steps:${NC}"
|
|||||||
echo " 1. Review the changes: git diff"
|
echo " 1. Review the changes: git diff"
|
||||||
echo " 2. Check .git-setup-info for recommended git workflow"
|
echo " 2. Check .git-setup-info for recommended git workflow"
|
||||||
echo " 3. Start developing: git checkout -b feature/my-app"
|
echo " 3. Start developing: git checkout -b feature/my-app"
|
||||||
echo " 4. Read: docs/CONTRIBUTION_GUIDE.md"
|
echo " 4. Read: docs/contribution/README.md"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
print_success "Happy contributing! 🚀"
|
print_success "Happy contributing! 🚀"
|
||||||
|
|||||||
@@ -1,197 +1,189 @@
|
|||||||
# **AppName<span></span>.sh Scripts**
|
# CT Container Scripts - Quick Reference
|
||||||
|
|
||||||
`AppName.sh` scripts found in the `/ct` directory. These scripts are responsible for the installation of the desired application. For this guide we take `/ct/snipeit.sh` as example.
|
> [!WARNING]
|
||||||
|
> **This is legacy documentation.** Refer to the **modern template** at [templates_ct/AppName.sh](AppName.sh) for best practices.
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
- [**AppName.sh Scripts**](#appnamesh-scripts)
|
|
||||||
- [Table of Contents](#table-of-contents)
|
|
||||||
- [1. **File Header**](#1-file-header)
|
|
||||||
- [1.1 **Shebang**](#11-shebang)
|
|
||||||
- [1.2 **Import Functions**](#12-import-functions)
|
|
||||||
- [1.3 **Metadata**](#13-metadata)
|
|
||||||
- [2 **Variables and function import**](#2-variables-and-function-import)
|
|
||||||
- [2.1 **Default Values**](#21-default-values)
|
|
||||||
- [2.2 **📋 App output \& base settings**](#22--app-output--base-settings)
|
|
||||||
- [2.3 **🛠 Core functions**](#23--core-functions)
|
|
||||||
- [3 **Update function**](#3-update-function)
|
|
||||||
- [3.1 **Function Header**](#31-function-header)
|
|
||||||
- [3.2 **Check APP**](#32-check-app)
|
|
||||||
- [3.3 **Check version**](#33-check-version)
|
|
||||||
- [3.4 **Verbosity**](#34-verbosity)
|
|
||||||
- [3.5 **Backups**](#35-backups)
|
|
||||||
- [3.6 **Cleanup**](#36-cleanup)
|
|
||||||
- [3.7 **No update function**](#37-no-update-function)
|
|
||||||
- [4 **End of the script**](#4-end-of-the-script)
|
|
||||||
- [5. **Contribution checklist**](#5-contribution-checklist)
|
|
||||||
|
|
||||||
## 1. **File Header**
|
|
||||||
|
|
||||||
### 1.1 **Shebang**
|
|
||||||
|
|
||||||
- Use `#!/usr/bin/env bash` as the shebang.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
```
|
|
||||||
|
|
||||||
### 1.2 **Import Functions**
|
|
||||||
|
|
||||||
- Import the build.func file.
|
|
||||||
- When developing your own script, change the URL to your own repository.
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
|
||||||
> You also need to change all apperances of this URL in `misc/build.func` and `misc/install.func`
|
|
||||||
|
|
||||||
Example for development:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/[USER]/[REPO]/refs/heads/[BRANCH]/misc/build.func)
|
|
||||||
```
|
|
||||||
|
|
||||||
Final script:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!CAUTION]
|
|
||||||
> Before opening a Pull Request, change the URLs to point to the community-scripts repo.
|
|
||||||
|
|
||||||
### 1.3 **Metadata**
|
|
||||||
|
|
||||||
- Add clear comments for script metadata, including author, copyright, and license information.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
|
||||||
# Author: [YourUserName]
|
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
|
||||||
# Source: [SOURCE_URL]
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!NOTE]:
|
|
||||||
>
|
>
|
||||||
> - Add your username and source URL
|
> Current templates use:
|
||||||
> - For existing scripts, add "| Co-Author [YourUserName]" after the current author
|
>
|
||||||
|
> - `tools.func` helpers instead of manual patterns
|
||||||
|
> - `check_for_gh_release` and `fetch_and_deploy_gh_release` from build.func
|
||||||
|
> - Automatic setup-fork.sh configuration
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2 **Variables and function import**
|
## Before Creating a Script
|
||||||
>
|
|
||||||
> [!NOTE]
|
|
||||||
> You need to have all this set in your script, otherwise it will not work!
|
|
||||||
|
|
||||||
### 2.1 **Default Values**
|
1. **Fork & Clone:**
|
||||||
|
|
||||||
- This section sets the default values for the container.
|
```bash
|
||||||
- `APP` needs to be set to the application name and must be equal to the filenames of your scripts.
|
git clone https://github.com/YOUR_USERNAME/ProxmoxVE.git
|
||||||
- `var_tags`: You can set Tags for the CT wich show up in the Proxmox UI. Don´t overdo it!
|
cd ProxmoxVE
|
||||||
|
```
|
||||||
|
|
||||||
>[!NOTE]
|
2. **Run setup-fork.sh** (updates all curl URLs to your fork):
|
||||||
>Description for all Default Values
|
|
||||||
>
|
|
||||||
>| Variable | Description | Notes |
|
|
||||||
>|----------|-------------|-------|
|
|
||||||
>| `APP` | Application name | Must match ct\AppName.sh |
|
|
||||||
>| `var_tags` | Proxmox display tags without Spaces, only ; | Limit the number |
|
|
||||||
>| `var_cpu` | CPU cores | Number of cores |
|
|
||||||
>| `var_ram` | RAM | In MB |
|
|
||||||
>| `var_disk` | Disk capacity | In GB |
|
|
||||||
>| `var_os` | Operating system | alpine, debian, ubuntu |
|
|
||||||
>| `var_version` | OS version | e.g., 3.20, 11, 12, 20.04 |
|
|
||||||
>| `var_unprivileged` | Container type | 1 = Unprivileged, 0 = Privileged |
|
|
||||||
|
|
||||||
Example:
|
```bash
|
||||||
|
bash docs/contribution/setup-fork.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Copy the Modern Template:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp templates_ct/AppName.sh ct/MyApp.sh
|
||||||
|
# Edit ct/MyApp.sh with your app details
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Test Your Script (via GitHub):**
|
||||||
|
|
||||||
|
⚠️ **Important:** You must push to GitHub and test via curl, not `bash ct/MyApp.sh`!
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Push your changes to your fork first
|
||||||
|
git push origin feature/my-awesome-app
|
||||||
|
|
||||||
|
# Then test via curl (this loads from YOUR fork, not local files)
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/MyApp.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
|
> 💡 **Why?** The script's curl commands are modified by setup-fork.sh, but local execution uses local files, not the updated GitHub URLs. Testing via curl ensures your script actually works.
|
||||||
|
>
|
||||||
|
> ⏱️ **Note:** GitHub sometimes takes 10-30 seconds to update files. If you don't see your changes, wait and try again.
|
||||||
|
|
||||||
|
5. **Cherry-Pick for PR** (submit ONLY your 3-4 files):
|
||||||
|
- See [Cherry-Pick Guide](../README.md) for step-by-step git commands
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Template Structure
|
||||||
|
|
||||||
|
The modern template includes:
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
APP="SnipeIT"
|
#!/usr/bin/env bash
|
||||||
var_tags="asset-management;foss"
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
|
||||||
|
# (Note: setup-fork.sh changes this URL to point to YOUR fork during development)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Metadata
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: YourUsername
|
||||||
|
# License: MIT
|
||||||
|
APP="MyApp"
|
||||||
|
var_tags="app-category;foss"
|
||||||
var_cpu="2"
|
var_cpu="2"
|
||||||
var_ram="2048"
|
var_ram="2048"
|
||||||
var_disk="4"
|
var_disk="4"
|
||||||
var_os="debian"
|
var_os="alpine"
|
||||||
var_version="12"
|
var_version="3.20"
|
||||||
var_unprivileged="1"
|
var_unprivileged="1"
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2.2 **📋 App output & base settings**
|
### Core Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
header_info "$APP"
|
header_info "$APP"
|
||||||
```
|
|
||||||
- `header_info`: Generates ASCII header for APP
|
|
||||||
|
|
||||||
## 2.3 **🛠 Core functions**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
variables
|
variables
|
||||||
color
|
color
|
||||||
catch_errors
|
catch_errors
|
||||||
```
|
```
|
||||||
|
|
||||||
- `variables`: Processes input and prepares variables
|
### Update Function
|
||||||
- `color`: Sets icons, colors, and formatting
|
|
||||||
- `catch_errors`: Enables error handling
|
|
||||||
|
|
||||||
---
|
The modern template provides a standard update pattern:
|
||||||
|
|
||||||
## 3 **Update function**
|
|
||||||
|
|
||||||
### 3.1 **Function Header**
|
|
||||||
|
|
||||||
- If applicable write a function that updates the application and the OS in the container.
|
|
||||||
- Each update function starts with the same code:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
function update_script() {
|
function update_script() {
|
||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
check_container_resources
|
check_container_resources
|
||||||
```
|
|
||||||
|
|
||||||
### 3.2 **Check APP**
|
# Use tools.func helpers:
|
||||||
|
check_for_gh_release "myapp" "owner/repo"
|
||||||
- Before doing anything update-wise, check if the app is installed in the container.
|
fetch_and_deploy_gh_release "myapp" "owner/repo" "tarball" "latest" "/opt/myapp"
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
if [[ ! -d /opt/snipe-it ]]; then
|
|
||||||
msg_error "No ${APP} Installation Found!"
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.3 **Check version**
|
|
||||||
|
|
||||||
- Before updating, check if a new version exists.
|
|
||||||
- We use the `${APPLICATION}_version.txt` file created in `/opt` during the install to compare new versions against the currently installed version.
|
|
||||||
|
|
||||||
Example with a Github Release:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
RELEASE=$(curl -fsSL https://api.github.com/repos/snipe/snipe-it/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
|
|
||||||
if [[ ! -f /opt/${APP}_version.txt ]] || [[ "${RELEASE}" != "$(cat /opt/${APP}_version.txt)" ]]; then
|
|
||||||
msg_info "Updating ${APP} to v${RELEASE}"
|
|
||||||
#DO UPDATE
|
|
||||||
else
|
|
||||||
msg_ok "No update required. ${APP} is already at v${RELEASE}."
|
|
||||||
fi
|
|
||||||
exit
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Patterns
|
||||||
|
|
||||||
|
### Check for Updates (App Repository)
|
||||||
|
|
||||||
|
Use `check_for_gh_release` with the **app repo**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
check_for_gh_release "myapp" "owner/repo"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deploy External App
|
||||||
|
|
||||||
|
Use `fetch_and_deploy_gh_release` with the **app repo**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fetch_and_deploy_gh_release "myapp" "owner/repo"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Avoid Manual Version Checking
|
||||||
|
|
||||||
|
❌ OLD (manual):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RELEASE=$(curl -fsSL https://api.github.com/repos/myapp/myapp/releases/latest | grep tag_name)
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ NEW (use tools.func):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
fetch_and_deploy_gh_release "myapp" "owner/repo"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use tools.func helpers** - Don't manually curl for versions
|
||||||
|
2. **Only add app-specific dependencies** - Don't add ca-certificates, curl, gnupg (handled by build.func)
|
||||||
|
3. **Test via curl from your fork** - Push first, then: `bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/MyApp.sh)"`
|
||||||
|
4. **Wait for GitHub to update** - Takes 10-30 seconds after git push
|
||||||
|
5. **Cherry-pick only YOUR files** - Submit only ct/MyApp.sh, install/MyApp-install.sh, frontend/public/json/myapp.json (3 files)
|
||||||
|
6. **Verify before PR** - Run `git diff upstream/main --name-only` to confirm only your files changed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Update Patterns
|
||||||
|
|
||||||
|
See the [modern template](AppName.sh) and [AI.md](../AI.md) for complete working examples.
|
||||||
|
|
||||||
|
Recent reference scripts with good update functions:
|
||||||
|
|
||||||
|
- [Trip](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/trip.sh)
|
||||||
|
- [Thingsboard](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/thingsboard.sh)
|
||||||
|
- [UniFi](https://github.com/community-scripts/ProxmoxVE/blob/main/ct/unifi.sh)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Need Help?
|
||||||
|
|
||||||
|
- **[README.md](../README.md)** - Full contribution workflow
|
||||||
|
- **[AI.md](../AI.md)** - AI-generated script guidelines
|
||||||
|
- **[FORK_SETUP.md](../FORK_SETUP.md)** - Why setup-fork.sh is important
|
||||||
|
- **[Slack Community](https://discord.gg/your-link)** - Ask questions
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
### 3.4 **Verbosity**
|
### 3.4 **Verbosity**
|
||||||
|
|
||||||
- Use the appropriate flag (**-q** in the examples) for a command to suppress its output.
|
- Use the appropriate flag (**-q** in the examples) for a command to suppress its output.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL
|
curl -fsSL
|
||||||
unzip -q
|
unzip -q
|
||||||
```
|
````
|
||||||
|
|
||||||
- If a command does not come with this functionality use `$STD` to suppress it's output.
|
- If a command does not come with this functionality use `$STD` to suppress it's output.
|
||||||
|
|
||||||
@@ -207,8 +199,8 @@ $STD php artisan config:clear
|
|||||||
- Backup user data if necessary.
|
- Backup user data if necessary.
|
||||||
- Move all user data back in the directory when the update is finished.
|
- Move all user data back in the directory when the update is finished.
|
||||||
|
|
||||||
>[!NOTE]
|
> [!NOTE]
|
||||||
>This is not meant to be a permanent backup
|
> This is not meant to be a permanent backup
|
||||||
|
|
||||||
Example backup:
|
Example backup:
|
||||||
|
|
||||||
@@ -227,7 +219,7 @@ Example config restore:
|
|||||||
### 3.6 **Cleanup**
|
### 3.6 **Cleanup**
|
||||||
|
|
||||||
- Do not forget to remove any temporary files/folders such as zip-files or temporary backups.
|
- Do not forget to remove any temporary files/folders such as zip-files or temporary backups.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
rm -rf /opt/v${RELEASE}.zip
|
rm -rf /opt/v${RELEASE}.zip
|
||||||
@@ -277,7 +269,7 @@ echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"
|
|||||||
## 5. **Contribution checklist**
|
## 5. **Contribution checklist**
|
||||||
|
|
||||||
- [ ] Shebang is correctly set (`#!/usr/bin/env bash`).
|
- [ ] Shebang is correctly set (`#!/usr/bin/env bash`).
|
||||||
- [ ] Correct link to *build.func*
|
- [ ] Correct link to _build.func_
|
||||||
- [ ] Metadata (author, license) is included at the top.
|
- [ ] Metadata (author, license) is included at the top.
|
||||||
- [ ] Variables follow naming conventions.
|
- [ ] Variables follow naming conventions.
|
||||||
- [ ] Update function exists.
|
- [ ] Update function exists.
|
||||||
|
|||||||
@@ -5,89 +5,133 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
|
|||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: [SOURCE_URL e.g. https://github.com/example/app]
|
# Source: [SOURCE_URL e.g. https://github.com/example/app]
|
||||||
|
|
||||||
# App Default Values
|
# ============================================================================
|
||||||
|
# APP CONFIGURATION
|
||||||
|
# ============================================================================
|
||||||
|
# These values are sent to build.func and define default container resources.
|
||||||
|
# Users can customize these during installation via the interactive prompts.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
APP="[AppName]"
|
APP="[AppName]"
|
||||||
var_tags="${var_tags:-[category]}"
|
var_tags="${var_tags:-[category1];[category2]}" # Max 2 tags, semicolon-separated
|
||||||
var_cpu="${var_cpu:-2}"
|
var_cpu="${var_cpu:-2}" # CPU cores: 1-4 typical
|
||||||
var_ram="${var_ram:-2048}"
|
var_ram="${var_ram:-2048}" # RAM in MB: 512, 1024, 2048, etc.
|
||||||
var_disk="${var_disk:-4}"
|
var_disk="${var_disk:-8}" # Disk in GB: 6, 8, 10, 20 typical
|
||||||
var_os="${var_os:-debian}"
|
var_os="${var_os:-debian}" # OS: debian, ubuntu, alpine
|
||||||
var_version="${var_version:-12}"
|
var_version="${var_version:-13}" # OS Version: 13 (Debian), 24.04 (Ubuntu), 3.21 (Alpine)
|
||||||
var_unprivileged="${var_unprivileged:-1}"
|
var_unprivileged="${var_unprivileged:-1}" # 1=unprivileged (secure), 0=privileged (for Docker/Podman)
|
||||||
|
|
||||||
# =============================================================================
|
# ============================================================================
|
||||||
# CONFIGURATION GUIDE
|
# INITIALIZATION - These are required in all CT scripts
|
||||||
# =============================================================================
|
# ============================================================================
|
||||||
# APP - Display name, title case (e.g. "Koel", "Wallabag", "Actual Budget")
|
header_info "$APP" # Display app name and setup header
|
||||||
# var_tags - Max 2 tags, semicolon separated (e.g. "music;streaming", "finance")
|
variables # Initialize build.func variables
|
||||||
# var_cpu - CPU cores: 1-4 typical
|
color # Load color variables for output
|
||||||
# var_ram - RAM in MB: 512, 1024, 2048, 4096 typical
|
catch_errors # Enable error handling with automatic exit on failure
|
||||||
# var_disk - Disk in GB: 4, 6, 8, 10, 20 typical
|
|
||||||
# var_os - OS: debian, ubuntu, alpine
|
|
||||||
# var_version - OS version: 12/13 (debian), 22.04/24.04 (ubuntu), 3.20/3.21 (alpine)
|
|
||||||
# var_unprivileged - 1 = unprivileged (secure, default), 0 = privileged (for docker etc.)
|
|
||||||
|
|
||||||
header_info "$APP"
|
# ============================================================================
|
||||||
variables
|
# UPDATE SCRIPT - Called when user selects "Update" from web interface
|
||||||
color
|
# ============================================================================
|
||||||
catch_errors
|
# This function is triggered by the web interface to update the application.
|
||||||
|
# It should:
|
||||||
|
# 1. Check if installation exists
|
||||||
|
# 2. Check for new GitHub releases
|
||||||
|
# 3. Stop running services
|
||||||
|
# 4. Backup critical data
|
||||||
|
# 5. Deploy new version
|
||||||
|
# 6. Run post-update commands (migrations, config updates, etc.)
|
||||||
|
# 7. Restore data if needed
|
||||||
|
# 8. Start services
|
||||||
|
#
|
||||||
|
# Exit with `exit` at the end to prevent container restart.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
function update_script() {
|
function update_script() {
|
||||||
header_info
|
header_info
|
||||||
check_container_storage
|
check_container_storage
|
||||||
check_container_resources
|
check_container_resources
|
||||||
|
|
||||||
# Check if installation exists
|
# Step 1: Verify installation exists
|
||||||
if [[ ! -d /opt/[appname] ]]; then
|
if [[ ! -d /opt/[appname] ]]; then
|
||||||
msg_error "No ${APP} Installation Found!"
|
msg_error "No ${APP} Installation Found!"
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# check_for_gh_release returns 0 (true) if update available, 1 (false) if not
|
# Step 2: Check if update is available
|
||||||
if check_for_gh_release "[appname]" "[owner/repo]"; then
|
if check_for_gh_release "[appname]" "YourUsername/YourRepo"; then
|
||||||
msg_info "Stopping Services"
|
|
||||||
|
# Step 3: Stop services before update
|
||||||
|
msg_info "Stopping Service"
|
||||||
systemctl stop [appname]
|
systemctl stop [appname]
|
||||||
msg_ok "Stopped Services"
|
msg_ok "Stopped Service"
|
||||||
|
|
||||||
# Optional: Backup important data before update
|
# Step 4: Backup critical data before overwriting
|
||||||
msg_info "Creating Backup"
|
msg_info "Backing up Data"
|
||||||
mkdir -p /tmp/[appname]_backup
|
cp -r /opt/[appname]/data /opt/[appname]_data_backup 2>/dev/null || true
|
||||||
cp /opt/[appname]/.env /tmp/[appname]_backup/ 2>/dev/null || true
|
msg_ok "Backed up Data"
|
||||||
cp -r /opt/[appname]/data /tmp/[appname]_backup/ 2>/dev/null || true
|
|
||||||
msg_ok "Created Backup"
|
|
||||||
|
|
||||||
# CLEAN_INSTALL=1 removes old directory before extracting new version
|
# Step 5: Download and deploy new version
|
||||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "[appname]" "[owner/repo]" "tarball" "latest" "/opt/[appname]"
|
# CLEAN_INSTALL=1 removes old directory before extracting
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "[appname]" "owner/repo" "tarball" "latest" "/opt/[appname]"
|
||||||
|
|
||||||
# Restore configuration and data
|
# Step 6: Run post-update commands (uncomment as needed)
|
||||||
|
# These examples show common patterns - use what applies to your app:
|
||||||
|
#
|
||||||
|
# For Node.js apps:
|
||||||
|
# msg_info "Installing Dependencies"
|
||||||
|
# cd /opt/[appname]
|
||||||
|
# $STD npm ci --production
|
||||||
|
# msg_ok "Installed Dependencies"
|
||||||
|
#
|
||||||
|
# For Python apps:
|
||||||
|
# msg_info "Installing Dependencies"
|
||||||
|
# cd /opt/[appname]
|
||||||
|
# $STD uv sync --frozen
|
||||||
|
# msg_ok "Installed Dependencies"
|
||||||
|
#
|
||||||
|
# For database migrations:
|
||||||
|
# msg_info "Running Database Migrations"
|
||||||
|
# cd /opt/[appname]
|
||||||
|
# $STD npm run migrate
|
||||||
|
# msg_ok "Ran Database Migrations"
|
||||||
|
#
|
||||||
|
# For PHP apps:
|
||||||
|
# msg_info "Installing Dependencies"
|
||||||
|
# cd /opt/[appname]
|
||||||
|
# $STD composer install --no-dev
|
||||||
|
# msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
# Step 7: Restore data from backup
|
||||||
msg_info "Restoring Data"
|
msg_info "Restoring Data"
|
||||||
cp /tmp/[appname]_backup/.env /opt/[appname]/ 2>/dev/null || true
|
cp -r /opt/[appname]_data_backup/. /opt/[appname]/data/ 2>/dev/null || true
|
||||||
cp -r /tmp/[appname]_backup/data/* /opt/[appname]/data/ 2>/dev/null || true
|
rm -rf /opt/[appname]_data_backup
|
||||||
rm -rf /tmp/[appname]_backup
|
|
||||||
msg_ok "Restored Data"
|
msg_ok "Restored Data"
|
||||||
|
|
||||||
# Optional: Run any post-update commands
|
# Step 8: Restart service with new version
|
||||||
msg_info "Running Post-Update Tasks"
|
msg_info "Starting Service"
|
||||||
cd /opt/[appname]
|
|
||||||
# Examples:
|
|
||||||
# $STD npm ci --production
|
|
||||||
# $STD php artisan migrate --force
|
|
||||||
# $STD composer install --no-dev
|
|
||||||
msg_ok "Ran Post-Update Tasks"
|
|
||||||
|
|
||||||
msg_info "Starting Services"
|
|
||||||
systemctl start [appname]
|
systemctl start [appname]
|
||||||
msg_ok "Started Services"
|
msg_ok "Started Service"
|
||||||
|
|
||||||
msg_ok "Updated successfully!"
|
msg_ok "Updated successfully!"
|
||||||
fi
|
fi
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# MAIN EXECUTION - Container creation flow
|
||||||
|
# ============================================================================
|
||||||
|
# These are called by build.func and handle the full installation process:
|
||||||
|
# 1. start - Initialize container creation
|
||||||
|
# 2. build_container - Execute the install script inside container
|
||||||
|
# 3. description - Display completion info and access details
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
start
|
start
|
||||||
build_container
|
build_container
|
||||||
description
|
description
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# COMPLETION MESSAGE
|
||||||
|
# ============================================================================
|
||||||
msg_ok "Completed successfully!\n"
|
msg_ok "Completed successfully!\n"
|
||||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||||
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
|
||||||
|
|||||||
@@ -1,54 +1,195 @@
|
|||||||
|
# Install Scripts - Quick Reference
|
||||||
|
|
||||||
# **AppName<span></span>-install.sh Scripts**
|
> [!WARNING]
|
||||||
|
> **This is legacy documentation.** Refer to the **modern template** at [templates_install/AppName-install.sh](AppName-install.sh) for best practices.
|
||||||
|
>
|
||||||
|
> Current templates use:
|
||||||
|
>
|
||||||
|
> - `tools.func` helpers (setup_nodejs, setup_uv, setup_postgresql_db, etc.)
|
||||||
|
> - Automatic dependency installation via build.func
|
||||||
|
> - Standardized environment variable patterns
|
||||||
|
|
||||||
`AppName-install.sh` scripts found in the `/install` directory. These scripts are responsible for the installation of the application. For this guide we take `/install/snipeit-install.sh` as example.
|
---
|
||||||
|
|
||||||
## Table of Contents
|
## Before Creating a Script
|
||||||
|
|
||||||
- [**AppName-install.sh Scripts**](#appname-installsh-scripts)
|
1. **Copy the Modern Template:**
|
||||||
- [Table of Contents](#table-of-contents)
|
|
||||||
- [1. **File header**](#1-file-header)
|
|
||||||
- [1.1 **Shebang**](#11-shebang)
|
|
||||||
- [1.2 **Comments**](#12-comments)
|
|
||||||
- [1.3 **Variables and function import**](#13-variables-and-function-import)
|
|
||||||
- [2. **Variable naming and management**](#2-variable-naming-and-management)
|
|
||||||
- [2.1 **Naming conventions**](#21-naming-conventions)
|
|
||||||
- [3. **Dependencies**](#3-dependencies)
|
|
||||||
- [3.1 **Install all at once**](#31-install-all-at-once)
|
|
||||||
- [3.2 **Collapse dependencies**](#32-collapse-dependencies)
|
|
||||||
- [4. **Paths to application files**](#4-paths-to-application-files)
|
|
||||||
- [5. **Version management**](#5-version-management)
|
|
||||||
- [5.1 **Install the latest release**](#51-install-the-latest-release)
|
|
||||||
- [5.2 **Save the version for update checks**](#52-save-the-version-for-update-checks)
|
|
||||||
- [6. **Input and output management**](#6-input-and-output-management)
|
|
||||||
- [6.1 **User feedback**](#61-user-feedback)
|
|
||||||
- [6.2 **Verbosity**](#62-verbosity)
|
|
||||||
- [7. **String/File Manipulation**](#7-stringfile-manipulation)
|
|
||||||
- [7.1 **File Manipulation**](#71-file-manipulation)
|
|
||||||
- [8. **Security practices**](#8-security-practices)
|
|
||||||
- [8.1 **Password generation**](#81-password-generation)
|
|
||||||
- [8.2 **File permissions**](#82-file-permissions)
|
|
||||||
- [9. **Service Configuration**](#9-service-configuration)
|
|
||||||
- [9.1 **Configuration files**](#91-configuration-files)
|
|
||||||
- [9.2 **Credential management**](#92-credential-management)
|
|
||||||
- [9.3 **Enviroment files**](#93-enviroment-files)
|
|
||||||
- [9.4 **Services**](#94-services)
|
|
||||||
- [10. **Cleanup**](#10-cleanup)
|
|
||||||
- [10.1 **Remove temporary files**](#101-remove-temporary-files)
|
|
||||||
- [10.2 **Autoremove and autoclean**](#102-autoremove-and-autoclean)
|
|
||||||
- [11. **Best Practices Checklist**](#11-best-practices-checklist)
|
|
||||||
- [Example: High-Level Script Flow](#example-high-level-script-flow)
|
|
||||||
|
|
||||||
## 1. **File header**
|
```bash
|
||||||
|
cp templates_install/AppName-install.sh install/MyApp-install.sh
|
||||||
|
# Edit install/MyApp-install.sh
|
||||||
|
```
|
||||||
|
|
||||||
### 1.1 **Shebang**
|
2. **Key Pattern:**
|
||||||
|
- CT scripts source build.func and call the install script
|
||||||
|
- Install scripts use sourced FUNCTIONS_FILE_PATH (via build.func)
|
||||||
|
- Both scripts work together in the container
|
||||||
|
|
||||||
- Use `#!/usr/bin/env bash` as the shebang.
|
3. **Test via GitHub:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Push your changes to your fork first
|
||||||
|
git push origin feature/my-awesome-app
|
||||||
|
|
||||||
|
# Test the CT script via curl (it will call the install script)
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/YOUR_USERNAME/ProxmoxVE/main/ct/MyApp.sh)"
|
||||||
|
# ⏱️ Wait 10-30 seconds after pushing - GitHub takes time to update
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Template Structure
|
||||||
|
|
||||||
|
### Header
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/install.func)
|
||||||
|
# (setup-fork.sh modifies this URL to point to YOUR fork during development)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Dependencies (App-Specific Only)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Don't add: ca-certificates, curl, gnupg, wget, git, jq
|
||||||
|
# These are handled by build.func
|
||||||
|
msg_info "Installing dependencies"
|
||||||
|
$STD apt-get install -y app-specific-deps
|
||||||
|
msg_ok "Installed dependencies"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Runtime Setup
|
||||||
|
|
||||||
|
Use tools.func helpers instead of manual installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# ✅ NEW (use tools.func):
|
||||||
|
NODE_VERSION="20"
|
||||||
|
setup_nodejs
|
||||||
|
# OR
|
||||||
|
PYTHON_VERSION="3.12"
|
||||||
|
setup_uv
|
||||||
|
# OR
|
||||||
|
PG_DB_NAME="myapp_db"
|
||||||
|
PG_DB_USER="myapp"
|
||||||
|
setup_postgresql_db
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create .env file
|
||||||
|
msg_info "Configuring MyApp"
|
||||||
|
cat << EOF > /opt/myapp/.env
|
||||||
|
DEBUG=false
|
||||||
|
PORT=8080
|
||||||
|
DATABASE_URL=postgresql://...
|
||||||
|
EOF
|
||||||
|
msg_ok "Configuration complete"
|
||||||
|
|
||||||
|
# Create systemd service
|
||||||
|
msg_info "Creating systemd service"
|
||||||
|
cat << EOF > /etc/systemd/system/myapp.service
|
||||||
|
[Unit]
|
||||||
|
Description=MyApp
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/node /opt/myapp/app.js
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
msg_ok "Service created"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Finalization
|
||||||
|
|
||||||
|
```bash
|
||||||
|
msg_info "Finalizing MyApp installation"
|
||||||
|
systemctl enable --now myapp
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
msg_ok "MyApp installation complete"
|
||||||
|
cleanup_lxc
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Patterns
|
||||||
|
|
||||||
|
### Avoid Manual Version Checking
|
||||||
|
|
||||||
|
❌ OLD (manual):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RELEASE=$(curl -fsSL https://api.github.com/repos/app/repo/releases/latest | grep tag_name)
|
||||||
|
wget https://github.com/app/repo/releases/download/$RELEASE/app.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ NEW (use tools.func via CT script's fetch_and_deploy_gh_release):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In CT script, not install script:
|
||||||
|
fetch_and_deploy_gh_release "myapp" "app/repo" "app.tar.gz" "latest" "/opt/myapp"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Use setup_postgresql_db, setup_mysql_db, etc.
|
||||||
|
PG_DB_NAME="myapp"
|
||||||
|
PG_DB_USER="myapp"
|
||||||
|
setup_postgresql_db
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node.js Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
NODE_VERSION="20"
|
||||||
|
setup_nodejs
|
||||||
|
npm install --no-save
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Only add app-specific dependencies**
|
||||||
|
- Don't add: ca-certificates, curl, gnupg, wget, git, jq
|
||||||
|
- These are handled by build.func
|
||||||
|
|
||||||
|
2. **Use tools.func helpers**
|
||||||
|
- setup_nodejs, setup_python, setup_uv, setup_postgresql_db, setup_mysql_db, etc.
|
||||||
|
|
||||||
|
3. **Don't do version checks in install script**
|
||||||
|
- Version checking happens in CT script's update_script()
|
||||||
|
- Install script just installs the latest
|
||||||
|
|
||||||
|
4. **Structure:**
|
||||||
|
- Dependencies
|
||||||
|
- Runtime setup (tools.func)
|
||||||
|
- Deployment (fetch from CT script)
|
||||||
|
- Configuration files
|
||||||
|
- Systemd service
|
||||||
|
- Finalization
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference Scripts
|
||||||
|
|
||||||
|
See working examples:
|
||||||
|
|
||||||
|
- [Trip](https://github.com/community-scripts/ProxmoxVE/blob/main/install/trip-install.sh)
|
||||||
|
- [Thingsboard](https://github.com/community-scripts/ProxmoxVE/blob/main/install/thingsboard-install.sh)
|
||||||
|
- [UniFi](https://github.com/community-scripts/ProxmoxVE/blob/main/install/unifi-install.sh)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Need Help?
|
||||||
|
|
||||||
|
- **[Modern Template](AppName-install.sh)** - Start here
|
||||||
|
- **[CT Template](../templates_ct/AppName.sh)** - How CT scripts work
|
||||||
|
- **[README.md](../README.md)** - Full contribution workflow
|
||||||
|
- **[AI.md](../AI.md)** - AI-generated script guidelines
|
||||||
|
|
||||||
### 1.2 **Comments**
|
### 1.2 **Comments**
|
||||||
|
|
||||||
- Add clear comments for script metadata, including author, copyright, and license information.
|
- Add clear comments for script metadata, including author, copyright, and license information.
|
||||||
@@ -189,7 +330,7 @@ msg_ok "Installed Dependencies"
|
|||||||
### 6.2 **Verbosity**
|
### 6.2 **Verbosity**
|
||||||
|
|
||||||
- Use the appropiate flag (**-q** in the examples) for a command to suppres its output
|
- Use the appropiate flag (**-q** in the examples) for a command to suppres its output
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL
|
curl -fsSL
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
# Source: [SOURCE_URL e.g. https://github.com/example/app]
|
# Source: [SOURCE_URL e.g. https://github.com/example/app]
|
||||||
|
|
||||||
# Import Functions and Setup
|
|
||||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
color
|
color
|
||||||
verb_ip6
|
verb_ip6
|
||||||
@@ -15,48 +14,51 @@ network_check
|
|||||||
update_os
|
update_os
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# DEPENDENCIES
|
# DEPENDENCIES - Only add app-specific dependencies here!
|
||||||
|
# Don't add: ca-certificates, curl, gnupg, git, build-essential (handled by build.func)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Only install what's actually needed - curl/sudo/mc are already in the base image
|
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
msg_info "Installing Dependencies"
|
||||||
$STD apt install -y \
|
$STD apt install -y \
|
||||||
nginx \
|
libharfbuzz0b \
|
||||||
build-essential
|
fontconfig
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# HELPER FUNCTIONS FROM tools.func
|
# SETUP RUNTIMES & DATABASES (if needed)
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# These functions are available via $FUNCTIONS_FILE_PATH (tools.func)
|
# Examples (uncomment as needed):
|
||||||
# Call them with optional environment variables for configuration
|
|
||||||
#
|
#
|
||||||
# --- Runtime & Language Setup ---
|
# NODE_VERSION="22" setup_nodejs
|
||||||
# NODE_VERSION="22" setup_nodejs # Install Node.js (22, 24)
|
# NODE_VERSION="22" NODE_MODULE="pnpm" setup_nodejs # Installs pnpm
|
||||||
# NODE_VERSION="24" NODE_MODULE="pnpm" setup_nodejs # With pnpm
|
# PYTHON_VERSION="3.13" setup_uv
|
||||||
# PYTHON_VERSION="3.13" setup_uv # Python with uv package manager
|
# JAVA_VERSION="21" setup_java
|
||||||
# setup_go # Install Go (latest)
|
# GO_VERSION="1.22" setup_go
|
||||||
# setup_rust # Install Rust via rustup
|
# PHP_VERSION="8.4" PHP_FPM="YES" setup_php
|
||||||
# setup_ruby # Install Ruby
|
# setup_postgresql # Server only
|
||||||
# PHP_VERSION="8.4" PHP_FPM="YES" PHP_MODULE="mysqli,gd" setup_php
|
# setup_mariadb # Server only
|
||||||
# PHP_VERSION="8.3" PHP_FPM="YES" PHP_APACHE="YES" PHP_MODULE="bcmath,curl,gd,intl,mbstring,mysql,xml,zip" setup_php
|
# setup_meilisearch # Search engine
|
||||||
# setup_composer # Install PHP Composer
|
|
||||||
# JAVA_VERSION="21" setup_java # Install Java (17, 21)
|
|
||||||
#
|
#
|
||||||
# --- Database Setup ---
|
# Then set up DB and user (sets $[DB]_DB_PASS):
|
||||||
# setup_mariadb # Install MariaDB server
|
# PG_DB_NAME="myapp" PG_DB_USER="myapp" setup_postgresql_db
|
||||||
# MARIADB_DB_NAME="mydb" MARIADB_DB_USER="myuser" setup_mariadb_db
|
# MARIADB_DB_NAME="myapp" MARIADB_DB_USER="myapp" setup_mariadb_db
|
||||||
# setup_mysql # Install MySQL server
|
|
||||||
# PG_VERSION="17" setup_postgresql # Install PostgreSQL (16, 17)
|
# =============================================================================
|
||||||
# PG_VERSION="17" PG_MODULES="postgis" setup_postgresql # With extensions
|
# DOWNLOAD & DEPLOY APPLICATION
|
||||||
# PG_DB_NAME="mydb" PG_DB_USER="myuser" setup_postgresql_db
|
# =============================================================================
|
||||||
# setup_mongodb # Install MongoDB
|
# fetch_and_deploy_gh_release modes:
|
||||||
#
|
# "tarball" - Source tarball (default if omitted)
|
||||||
# --- GitHub Release (PREFERRED METHOD) ---
|
# "binary" - .deb package (auto-detects amd64/arm64)
|
||||||
# fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" # Downloads, extracts, tracks version
|
# "prebuild" - Pre-built archive (.tar.gz)
|
||||||
# fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/appname"
|
# "singlefile" - Single binary file
|
||||||
# fetch_and_deploy_gh_release "appname" "owner/repo" "prebuild" "latest" "/opt/appname" "app-*.tar.gz"
|
|
||||||
#
|
#
|
||||||
|
# Examples:
|
||||||
|
# fetch_and_deploy_gh_release "myapp" "YourUsername/myapp" "tarball" "latest" "/opt/myapp"
|
||||||
|
# fetch_and_deploy_gh_release "myapp" "YourUsername/myapp" "binary" "latest" "/tmp"
|
||||||
|
# fetch_and_deploy_gh_release "myapp" "YourUsername/myapp" "prebuild" "latest" "/opt/myapp" "myapp-*.tar.gz"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "[appname]" "owner/repo" "tarball" "latest" "/opt/[appname]"
|
||||||
|
|
||||||
# --- Tools & Utilities ---
|
# --- Tools & Utilities ---
|
||||||
# get_lxc_ip # Sets $LOCAL_IP variable (call early!)
|
# get_lxc_ip # Sets $LOCAL_IP variable (call early!)
|
||||||
# setup_ffmpeg # Install FFmpeg with codecs
|
# setup_ffmpeg # Install FFmpeg with codecs
|
||||||
@@ -67,8 +69,11 @@ msg_ok "Installed Dependencies"
|
|||||||
# create_self_signed_cert # Creates cert in /etc/ssl/[appname]/
|
# create_self_signed_cert # Creates cert in /etc/ssl/[appname]/
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# EXAMPLE 1: Node.js Application with PostgreSQL
|
# EXAMPLES
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# EXAMPLE 1: Node.js Application with PostgreSQL
|
||||||
|
# ---------------------------------------------
|
||||||
# NODE_VERSION="22" setup_nodejs
|
# NODE_VERSION="22" setup_nodejs
|
||||||
# PG_VERSION="17" setup_postgresql
|
# PG_VERSION="17" setup_postgresql
|
||||||
# PG_DB_NAME="myapp" PG_DB_USER="myapp" setup_postgresql_db
|
# PG_DB_NAME="myapp" PG_DB_USER="myapp" setup_postgresql_db
|
||||||
@@ -84,10 +89,9 @@ msg_ok "Installed Dependencies"
|
|||||||
# PORT=3000
|
# PORT=3000
|
||||||
# EOF
|
# EOF
|
||||||
# msg_ok "Configured MyApp"
|
# msg_ok "Configured MyApp"
|
||||||
|
#
|
||||||
# =============================================================================
|
|
||||||
# EXAMPLE 2: Python Application with uv
|
# EXAMPLE 2: Python Application with uv
|
||||||
# =============================================================================
|
# ------------------------------------
|
||||||
# PYTHON_VERSION="3.13" setup_uv
|
# PYTHON_VERSION="3.13" setup_uv
|
||||||
# get_lxc_ip
|
# get_lxc_ip
|
||||||
# fetch_and_deploy_gh_release "myapp" "owner/myapp" "tarball" "latest" "/opt/myapp"
|
# fetch_and_deploy_gh_release "myapp" "owner/myapp" "tarball" "latest" "/opt/myapp"
|
||||||
@@ -141,7 +145,7 @@ fetch_and_deploy_gh_release "[appname]" "[owner/repo]" "tarball" "latest" "/opt/
|
|||||||
|
|
||||||
msg_info "Setting up [AppName]"
|
msg_info "Setting up [AppName]"
|
||||||
cd /opt/[appname]
|
cd /opt/[appname]
|
||||||
$STD npm ci
|
# $STD npm ci
|
||||||
msg_ok "Setup [AppName]"
|
msg_ok "Setup [AppName]"
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -149,14 +153,25 @@ msg_ok "Setup [AppName]"
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
msg_info "Configuring [AppName]"
|
msg_info "Configuring [AppName]"
|
||||||
|
cd /opt/[appname]
|
||||||
|
|
||||||
|
# Install application dependencies (uncomment as needed):
|
||||||
|
# $STD npm ci --production # Node.js apps
|
||||||
|
# $STD uv sync --frozen # Python apps
|
||||||
|
# $STD composer install --no-dev # PHP apps
|
||||||
|
# $STD cargo build --release # Rust apps
|
||||||
|
|
||||||
|
# Create .env file if needed:
|
||||||
cat <<EOF >/opt/[appname]/.env
|
cat <<EOF >/opt/[appname]/.env
|
||||||
HOST=${LOCAL_IP}
|
# Use import_local_ip to get container IP, or hardcode if building on Proxmox
|
||||||
|
APP_URL=http://localhost
|
||||||
PORT=8080
|
PORT=8080
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
msg_ok "Configured [AppName]"
|
msg_ok "Configured [AppName]"
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# SERVICE CREATION
|
# CREATE SYSTEMD SERVICE
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
msg_info "Creating Service"
|
msg_info "Creating Service"
|
||||||
@@ -182,9 +197,11 @@ msg_ok "Created Service"
|
|||||||
# =============================================================================
|
# =============================================================================
|
||||||
# CLEANUP & FINALIZATION
|
# CLEANUP & FINALIZATION
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
# These are called automatically, but shown here for clarity:
|
||||||
|
# motd_ssh - Displays service info on SSH login
|
||||||
|
# customize - Enables optional customizations
|
||||||
|
# cleanup_lxc - Removes temp files, bash history, logs
|
||||||
|
|
||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
|
|
||||||
# cleanup_lxc handles: apt autoremove, autoclean, temp files, bash history
|
|
||||||
cleanup_lxc
|
cleanup_lxc
|
||||||
|
|||||||
28
docs/contribution/templates_json/AppName.json
generated
28
docs/contribution/templates_json/AppName.json
generated
@@ -4,25 +4,26 @@
|
|||||||
"categories": [
|
"categories": [
|
||||||
0
|
0
|
||||||
],
|
],
|
||||||
"date_created": "DATE CREATED",
|
"date_created": "2026-01-18",
|
||||||
"type": "ct",
|
"type": "ct",
|
||||||
"updateable": true,
|
"updateable": true,
|
||||||
"privileged": false,
|
"privileged": false,
|
||||||
"interface_port": "DEFAULT-PORT",
|
"interface_port": 3000,
|
||||||
"documentation": null,
|
"documentation": "https://docs.example.com/",
|
||||||
"website": "LINK TO WEBSITE",
|
"website": "https://example.com/",
|
||||||
"logo": "LINK TO LOGO",
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/appname.webp",
|
||||||
"description": "Description of the app",
|
"config_path": "/opt/appname/.env",
|
||||||
|
"description": "Short description of what AppName does and its main features.",
|
||||||
"install_methods": [
|
"install_methods": [
|
||||||
{
|
{
|
||||||
"type": "default",
|
"type": "default",
|
||||||
"script": "ct/AppName.sh",
|
"script": "ct/appname.sh",
|
||||||
"resources": {
|
"resources": {
|
||||||
"cpu": 2,
|
"cpu": 2,
|
||||||
"ram": 2048,
|
"ram": 2048,
|
||||||
"hdd": 4,
|
"hdd": 8,
|
||||||
"os": "debian",
|
"os": "Debian",
|
||||||
"version": "12"
|
"version": "13"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -30,5 +31,10 @@
|
|||||||
"username": null,
|
"username": null,
|
||||||
"password": null
|
"password": null
|
||||||
},
|
},
|
||||||
"notes": []
|
"notes": [
|
||||||
|
{
|
||||||
|
"text": "Change the default password after first login!",
|
||||||
|
"type": "warning"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,165 @@
|
|||||||
# **AppName<span></span>.json Files**
|
# JSON Metadata Files - Quick Reference
|
||||||
|
|
||||||
`AppName.json` files found in the `/json` directory. These files are used to provide informations for the website. For this guide we take `/json/snipeit.json` as example.
|
The metadata file (`frontend/public/json/myapp.json`) tells the web interface how to display your application.
|
||||||
|
|
||||||
## Table of Contents
|
---
|
||||||
|
|
||||||
- [**AppName.json Files**](#appnamejson-files)
|
## Quick Start
|
||||||
- [Table of Contents](#table-of-contents)
|
|
||||||
- [1. JSON Generator](#1-json-generator)
|
|
||||||
|
|
||||||
## 1. JSON Generator
|
**Use the JSON Generator Tool:**
|
||||||
|
[https://community-scripts.github.io/ProxmoxVE/json-editor](https://community-scripts.github.io/ProxmoxVE/json-editor)
|
||||||
|
|
||||||
Use the [JSON Generator](https://community-scripts.github.io/ProxmoxVE/json-editor) to create this file for your application.
|
1. Enter application details
|
||||||
|
2. Generator creates `frontend/public/json/myapp.json`
|
||||||
|
3. Copy the output to your contribution
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "MyApp",
|
||||||
|
"slug": "myapp",
|
||||||
|
"categories": [1],
|
||||||
|
"date_created": "2026-01-18",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 3000,
|
||||||
|
"documentation": "https://docs.example.com/",
|
||||||
|
"website": "https://example.com/",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/myapp.webp",
|
||||||
|
"config_path": "/opt/myapp/.env",
|
||||||
|
"description": "Brief description of what MyApp does",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/myapp.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 2,
|
||||||
|
"ram": 2048,
|
||||||
|
"hdd": 8,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
{
|
||||||
|
"text": "Change the default password after first login!",
|
||||||
|
"type": "warning"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Field Reference
|
||||||
|
|
||||||
|
| Field | Required | Example | Notes |
|
||||||
|
| --------------------- | -------- | ----------------- | ---------------------------------------------- |
|
||||||
|
| `name` | Yes | "MyApp" | Display name |
|
||||||
|
| `slug` | Yes | "myapp" | URL-friendly identifier (lowercase, no spaces) |
|
||||||
|
| `categories` | Yes | [1] | One or more category IDs |
|
||||||
|
| `date_created` | Yes | "2026-01-18" | Format: YYYY-MM-DD |
|
||||||
|
| `type` | Yes | "ct" | Container type: "ct" or "vm" |
|
||||||
|
| `interface_port` | Yes | 3000 | Default web interface port |
|
||||||
|
| `logo` | No | "https://..." | Logo URL (64px x 64px PNG) |
|
||||||
|
| `config_path` | Yes | "/opt/myapp/.env" | Main config file location |
|
||||||
|
| `description` | Yes | "App description" | Brief description (100 chars) |
|
||||||
|
| `install_methods` | Yes | See below | Installation resources (array) |
|
||||||
|
| `default_credentials` | No | See below | Optional default login |
|
||||||
|
| `notes` | No | See below | Additional notes (array) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Install Methods
|
||||||
|
|
||||||
|
Each installation method specifies resource requirements:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/myapp.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 2,
|
||||||
|
"ram": 2048,
|
||||||
|
"hdd": 8,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Resource Defaults:**
|
||||||
|
|
||||||
|
- CPU: Cores (1-8)
|
||||||
|
- RAM: Megabytes (256-4096)
|
||||||
|
- Disk: Gigabytes (4-50)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Categories
|
||||||
|
|
||||||
|
- `0` Miscellaneous
|
||||||
|
- `1` Proxmox & Virtualization
|
||||||
|
- `2` Operating Systems
|
||||||
|
- `3` Containers & Docker
|
||||||
|
- `4` Network & Firewall
|
||||||
|
- `5` Adblock & DNS
|
||||||
|
- `6` Authentication & Security
|
||||||
|
- `7` Backup & Recovery
|
||||||
|
- `8` Databases
|
||||||
|
- `9` Monitoring & Analytics
|
||||||
|
- `10` Dashboards & Frontends
|
||||||
|
- `11` Files & Downloads
|
||||||
|
- `12` Documents & Notes
|
||||||
|
- `13` Media & Streaming
|
||||||
|
- `14` \*Arr Suite
|
||||||
|
- `15` NVR & Cameras
|
||||||
|
- `16` IoT & Smart Home
|
||||||
|
- `17` ZigBee, Z-Wave & Matter
|
||||||
|
- `18` MQTT & Messaging
|
||||||
|
- `19` Automation & Scheduling
|
||||||
|
- `20` AI / Coding & Dev-Tools
|
||||||
|
- `21` Webservers & Proxies
|
||||||
|
- `22` Bots & ChatOps
|
||||||
|
- `23` Finance & Budgeting
|
||||||
|
- `24` Gaming & Leisure
|
||||||
|
- `25` Business & ERP
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use the JSON Generator** - It validates structure
|
||||||
|
2. **Keep descriptions short** - 100 characters max
|
||||||
|
3. **Use real resource requirements** - Based on your testing
|
||||||
|
4. **Include sensible defaults** - Pre-filled in install_methods
|
||||||
|
5. **Slug must be lowercase** - No spaces, use hyphens
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference Examples
|
||||||
|
|
||||||
|
See actual examples in the repo:
|
||||||
|
|
||||||
|
- [frontend/public/json/trip.json](https://github.com/community-scripts/ProxmoxVE/blob/main/frontend/public/json/trip.json)
|
||||||
|
- [frontend/public/json/thingsboard.json](https://github.com/community-scripts/ProxmoxVE/blob/main/frontend/public/json/thingsboard.json)
|
||||||
|
- [frontend/public/json/unifi.json](https://github.com/community-scripts/ProxmoxVE/blob/main/frontend/public/json/unifi.json)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Need Help?
|
||||||
|
|
||||||
|
- **[JSON Generator](https://community-scripts.github.io/ProxmoxVE/json-editor)** - Interactive tool
|
||||||
|
- **[README.md](../README.md)** - Full contribution workflow
|
||||||
|
- **[Quick Start](../README.md)** - Step-by-step guide
|
||||||
|
|||||||
@@ -539,6 +539,69 @@ var_nesting=0 # Nested containers disabled
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### var_diagnostics
|
||||||
|
|
||||||
|
**Type:** Boolean (yes or no)
|
||||||
|
**Default:** `yes`
|
||||||
|
**Description:** Determines if anonymous telemetry and diagnostic data is sent to Community-Scripts API.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
var_diagnostics=yes # Allow telemetry (helps us improve scripts)
|
||||||
|
var_diagnostics=no # Disable all telemetry
|
||||||
|
```
|
||||||
|
|
||||||
|
**Privacy & Usage:**
|
||||||
|
- Data is strictly anonymous (random session ID)
|
||||||
|
- Reports success/failure of installations
|
||||||
|
- Maps error codes (e.g., APT lock, out of RAM)
|
||||||
|
- No user-specific data, hostnames, or secret keys are ever sent
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### var_gpu
|
||||||
|
|
||||||
|
**Type:** Boolean/Toggle
|
||||||
|
**Options:** `yes` or `no`
|
||||||
|
**Default:** `no`
|
||||||
|
**Description:** Enable GPU passthrough for the container.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
var_gpu=yes # Enable GPU passthrough (auto-detect)
|
||||||
|
var_gpu=no # Disable GPU passthrough (default)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Features enabled:**
|
||||||
|
- Auto-detects Intel (QuickSync), NVIDIA, and AMD GPUs
|
||||||
|
- Passes through `/dev/dri` and render nodes
|
||||||
|
- Configures appropriate container permissions
|
||||||
|
- Crucial for media servers (Plex, Jellyfin, Immich)
|
||||||
|
|
||||||
|
**Prerequisites:**
|
||||||
|
- Host drivers installed correctly
|
||||||
|
- Hardware present and visible to Proxmox
|
||||||
|
- IOMMU enabled (for some configurations)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### var_tun
|
||||||
|
|
||||||
|
**Type:** Boolean/Toggle
|
||||||
|
**Options:** `yes` or `no`
|
||||||
|
**Default:** `no`
|
||||||
|
**Description:** Enable TUN/TAP device support.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
var_tun=yes # Enable TUN/TAP support
|
||||||
|
var_tun=no # Disable TUN/TAP support (default)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Required for:**
|
||||||
|
- VPN software (WireGuard, OpenVPN)
|
||||||
|
- Network tunneling (Tailscale, ZeroTier)
|
||||||
|
- Custom network bridges
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### var_keyctl
|
### var_keyctl
|
||||||
|
|
||||||
**Type:** Boolean (0 or 1)
|
**Type:** Boolean (0 or 1)
|
||||||
@@ -560,13 +623,14 @@ var_keyctl=0 # Keyctl disabled
|
|||||||
|
|
||||||
### var_fuse
|
### var_fuse
|
||||||
|
|
||||||
**Type:** Boolean (0 or 1)
|
**Type:** Boolean/Toggle
|
||||||
**Default:** `0`
|
**Options:** `yes` or `no`
|
||||||
|
**Default:** `no`
|
||||||
**Description:** Enable FUSE filesystem support.
|
**Description:** Enable FUSE filesystem support.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
var_fuse=1 # FUSE enabled
|
var_fuse=yes # FUSE enabled
|
||||||
var_fuse=0 # FUSE disabled
|
var_fuse=no # FUSE disabled
|
||||||
```
|
```
|
||||||
|
|
||||||
**Required for:**
|
**Required for:**
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ pveversion
|
|||||||
### 2. Network Connectivity
|
### 2. Network Connectivity
|
||||||
```bash
|
```bash
|
||||||
# Test GitHub access
|
# Test GitHub access
|
||||||
curl -I https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/debian.sh
|
curl -I https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/debian.sh
|
||||||
|
|
||||||
# Test internet connectivity
|
# Test internet connectivity
|
||||||
ping -c 1 1.1.1.1
|
ping -c 1 1.1.1.1
|
||||||
@@ -108,6 +108,8 @@ var_cpu=4 \
|
|||||||
var_ram=4096 \
|
var_ram=4096 \
|
||||||
var_disk=30 \
|
var_disk=30 \
|
||||||
var_hostname=production-app \
|
var_hostname=production-app \
|
||||||
|
var_os=debian \
|
||||||
|
var_version=13 \
|
||||||
var_brg=vmbr0 \
|
var_brg=vmbr0 \
|
||||||
var_net=dhcp \
|
var_net=dhcp \
|
||||||
var_ipv6_method=none \
|
var_ipv6_method=none \
|
||||||
@@ -117,7 +119,7 @@ var_nesting=1 \
|
|||||||
var_tags=production,automated \
|
var_tags=production,automated \
|
||||||
var_protection=yes \
|
var_protection=yes \
|
||||||
var_verbose=no \
|
var_verbose=no \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/debian.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/debian.sh)"
|
||||||
|
|
||||||
echo "✓ Container deployed successfully"
|
echo "✓ Container deployed successfully"
|
||||||
```
|
```
|
||||||
@@ -151,7 +153,7 @@ var_gateway=192.168.1.1 \
|
|||||||
|
|
||||||
**Step 1: Create defaults once (interactive)**
|
**Step 1: Create defaults once (interactive)**
|
||||||
```bash
|
```bash
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/pihole.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/pihole.sh)"
|
||||||
# Select "Advanced Settings" → Configure → Save as "App Defaults"
|
# Select "Advanced Settings" → Configure → Save as "App Defaults"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -161,10 +163,30 @@ bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/Proxmo
|
|||||||
# deploy-with-defaults.sh
|
# deploy-with-defaults.sh
|
||||||
|
|
||||||
# App defaults are loaded automatically
|
# App defaults are loaded automatically
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/pihole.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/pihole.sh)"
|
||||||
# Script will use /usr/local/community-scripts/defaults/pihole.vars
|
# Script will use /usr/local/community-scripts/defaults/pihole.vars
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Advanced Configuration Variables
|
||||||
|
|
||||||
|
Beyond the basic resource settings, you can control advanced container features:
|
||||||
|
|
||||||
|
| Variable | Description | Options |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `var_os` | Operating system template | `debian`, `ubuntu`, `alpine` |
|
||||||
|
| `var_version` | OS version | `12`, `13` (Debian), `22.04`, `24.04` (Ubuntu) |
|
||||||
|
| `var_gpu` | Enable GPU passthrough | `yes`, `no` (Default: `no`) |
|
||||||
|
| `var_tun` | Enable TUN/TAP device | `yes`, `no` (Default: `no`) |
|
||||||
|
| `var_nesting` | Enable nesting | `1`, `0` (Default: `1`) |
|
||||||
|
|
||||||
|
**Example with GPU and TUN:**
|
||||||
|
```bash
|
||||||
|
var_gpu=yes \
|
||||||
|
var_tun=yes \
|
||||||
|
var_hostname=transcoder \
|
||||||
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/plex.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Batch Deployments
|
## Batch Deployments
|
||||||
@@ -177,14 +199,14 @@ bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/Proxmo
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# batch-deploy-simple.sh
|
# batch-deploy-simple.sh
|
||||||
|
|
||||||
apps=("debian" "ubuntu" "alpine")
|
apps=("thingsboard" "qui" "flatnotes")
|
||||||
|
|
||||||
for app in "${apps[@]}"; do
|
for app in "${apps[@]}"; do
|
||||||
echo "Deploying $app..."
|
echo "Deploying $app..."
|
||||||
var_hostname="$app-container" \
|
var_hostname="$app-server" \
|
||||||
var_cpu=2 \
|
var_cpu=2 \
|
||||||
var_ram=2048 \
|
var_ram=2048 \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/${app}.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)"
|
||||||
|
|
||||||
echo "✓ $app deployed"
|
echo "✓ $app deployed"
|
||||||
sleep 5 # Wait between deployments
|
sleep 5 # Wait between deployments
|
||||||
@@ -198,10 +220,10 @@ done
|
|||||||
# batch-deploy-advanced.sh - Deploy multiple containers with individual configs
|
# batch-deploy-advanced.sh - Deploy multiple containers with individual configs
|
||||||
|
|
||||||
declare -A CONTAINERS=(
|
declare -A CONTAINERS=(
|
||||||
["pihole"]="2:1024:8:vmbr0:dns,network"
|
["beszel"]="1:512:8:vmbr0:monitoring"
|
||||||
["homeassistant"]="4:4096:20:vmbr0:automation,ha"
|
["qui"]="2:1024:10:vmbr0:torrent,ui"
|
||||||
["docker"]="6:8192:50:vmbr1:containers,docker"
|
["thingsboard"]="6:8192:50:vmbr1:iot,industrial"
|
||||||
["nginx"]="2:2048:10:vmbr0:webserver,proxy"
|
["dockge"]="2:2048:10:vmbr0:docker,management"
|
||||||
)
|
)
|
||||||
|
|
||||||
for app in "${!CONTAINERS[@]}"; do
|
for app in "${!CONTAINERS[@]}"; do
|
||||||
@@ -228,7 +250,7 @@ for app in "${!CONTAINERS[@]}"; do
|
|||||||
var_ipv6_method=none \
|
var_ipv6_method=none \
|
||||||
var_ssh=yes \
|
var_ssh=yes \
|
||||||
var_tags="$tags,automated" \
|
var_tags="$tags,automated" \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/${app}.sh)" 2>&1 | tee "deploy-${app}.log"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)" 2>&1 | tee "deploy-${app}.log"
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "✓ $app deployed successfully"
|
echo "✓ $app deployed successfully"
|
||||||
@@ -263,7 +285,7 @@ deploy_container() {
|
|||||||
var_disk="$disk" \
|
var_disk="$disk" \
|
||||||
var_hostname="$app" \
|
var_hostname="$app" \
|
||||||
var_net=dhcp \
|
var_net=dhcp \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/${app}.sh)" \
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)" \
|
||||||
&> "deploy-${app}.log"
|
&> "deploy-${app}.log"
|
||||||
|
|
||||||
echo "[$app] ✓ Completed"
|
echo "[$app] ✓ Completed"
|
||||||
@@ -294,7 +316,7 @@ echo "All deployments complete!"
|
|||||||
```yaml
|
```yaml
|
||||||
---
|
---
|
||||||
# playbook-proxmox.yml
|
# playbook-proxmox.yml
|
||||||
- name: Deploy ProxmoxVED Containers
|
- name: Deploy ProxmoxVE Containers
|
||||||
hosts: proxmox_hosts
|
hosts: proxmox_hosts
|
||||||
become: yes
|
become: yes
|
||||||
tasks:
|
tasks:
|
||||||
@@ -308,7 +330,7 @@ echo "All deployments complete!"
|
|||||||
var_net=dhcp \
|
var_net=dhcp \
|
||||||
var_ssh=yes \
|
var_ssh=yes \
|
||||||
var_tags=ansible,automated \
|
var_tags=ansible,automated \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/debian.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/debian.sh)"
|
||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
register: deploy_result
|
register: deploy_result
|
||||||
@@ -365,7 +387,7 @@ echo "All deployments complete!"
|
|||||||
var_ssh=yes \
|
var_ssh=yes \
|
||||||
var_ssh_authorized_key="{{ ssh_key }}" \
|
var_ssh_authorized_key="{{ ssh_key }}" \
|
||||||
var_tags="{{ item.tags }},ansible" \
|
var_tags="{{ item.tags }},ansible" \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/{{ item.name }}.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/{{ item.name }}.sh)"
|
||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
loop: "{{ containers }}"
|
loop: "{{ containers }}"
|
||||||
@@ -417,7 +439,7 @@ resource "null_resource" "deploy_container" {
|
|||||||
"var_disk=${each.value.disk}",
|
"var_disk=${each.value.disk}",
|
||||||
"var_hostname=${each.key}",
|
"var_hostname=${each.key}",
|
||||||
"var_net=dhcp",
|
"var_net=dhcp",
|
||||||
"bash -c \"$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/${each.value.template}.sh)\""
|
"bash -c \"$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${each.value.template}.sh)\""
|
||||||
]
|
]
|
||||||
|
|
||||||
connection {
|
connection {
|
||||||
@@ -498,7 +520,7 @@ jobs:
|
|||||||
var_net=dhcp \
|
var_net=dhcp \
|
||||||
var_ssh=yes \
|
var_ssh=yes \
|
||||||
var_tags=ci-cd,automated \
|
var_tags=ci-cd,automated \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/${{ github.event.inputs.container_type }}.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${{ github.event.inputs.container_type }}.sh)"
|
||||||
|
|
||||||
- name: Notify deployment status
|
- name: Notify deployment status
|
||||||
if: success()
|
if: success()
|
||||||
@@ -532,7 +554,7 @@ deploy_container:
|
|||||||
var_hostname=gitlab-ci-container \
|
var_hostname=gitlab-ci-container \
|
||||||
var_net=dhcp \
|
var_net=dhcp \
|
||||||
var_tags=gitlab-ci,automated \
|
var_tags=gitlab-ci,automated \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/debian.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/debian.sh)"
|
||||||
EOF
|
EOF
|
||||||
only:
|
only:
|
||||||
- main
|
- main
|
||||||
@@ -564,7 +586,7 @@ deploy_container() {
|
|||||||
var_hostname="$HOSTNAME" \
|
var_hostname="$HOSTNAME" \
|
||||||
var_net=dhcp \
|
var_net=dhcp \
|
||||||
var_ssh=yes \
|
var_ssh=yes \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/${APP}.sh)" 2>&1 | tee deploy.log
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${APP}.sh)" 2>&1 | tee deploy.log
|
||||||
|
|
||||||
return ${PIPESTATUS[0]}
|
return ${PIPESTATUS[0]}
|
||||||
}
|
}
|
||||||
@@ -656,7 +678,7 @@ deploy() {
|
|||||||
var_hostname="$HOSTNAME" \
|
var_hostname="$HOSTNAME" \
|
||||||
var_cpu=4 \
|
var_cpu=4 \
|
||||||
var_ram=4096 \
|
var_ram=4096 \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/${APP}.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${APP}.sh)"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,7 +781,7 @@ deploy_secure() {
|
|||||||
var_protection=yes \
|
var_protection=yes \
|
||||||
var_tags=production,secure,automated \
|
var_tags=production,secure,automated \
|
||||||
var_verbose=no \
|
var_verbose=no \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/${APP}.sh)" 2>&1 | tee -a "$LOG_FILE"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${APP}.sh)" 2>&1 | tee -a "$LOG_FILE"
|
||||||
|
|
||||||
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
if [ ${PIPESTATUS[0]} -eq 0 ]; then
|
||||||
log "✓ Deployment successful"
|
log "✓ Deployment successful"
|
||||||
@@ -824,7 +846,7 @@ SSH_KEYS=$(load_ssh_keys)
|
|||||||
var_ssh=yes \
|
var_ssh=yes \
|
||||||
var_ssh_authorized_key="$SSH_KEYS" \
|
var_ssh_authorized_key="$SSH_KEYS" \
|
||||||
var_hostname=multi-key-server \
|
var_hostname=multi-key-server \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/debian.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/debian.sh)"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -903,7 +925,7 @@ deploy_from_config() {
|
|||||||
var_ssh=yes \
|
var_ssh=yes \
|
||||||
var_tags="$tags,automated" \
|
var_tags="$tags,automated" \
|
||||||
var_protection=yes \
|
var_protection=yes \
|
||||||
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/ct/${app}.sh)"
|
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/${app}.sh)"
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
log_success "Deployed: $name"
|
log_success "Deployed: $name"
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ get_error_description 255 # "Unknown critical error, often due to missing perm
|
|||||||
- `DIAGNOSTICS` must be set to "yes"
|
- `DIAGNOSTICS` must be set to "yes"
|
||||||
- `RANDOM_UUID` must be set and not empty
|
- `RANDOM_UUID` must be set and not empty
|
||||||
|
|
||||||
**API Endpoint**: `http://api.community-scripts.org/dev/upload`
|
**API Endpoint**: `https://api.community-scripts.org/dev/upload`
|
||||||
|
|
||||||
**JSON Payload Structure**:
|
**JSON Payload Structure**:
|
||||||
```json
|
```json
|
||||||
@@ -110,7 +110,7 @@ post_to_api
|
|||||||
- `curl` command must be available
|
- `curl` command must be available
|
||||||
- `RANDOM_UUID` must be set and not empty
|
- `RANDOM_UUID` must be set and not empty
|
||||||
|
|
||||||
**API Endpoint**: `http://api.community-scripts.org/dev/upload`
|
**API Endpoint**: `https://api.community-scripts.org/dev/upload`
|
||||||
|
|
||||||
**JSON Payload Structure**:
|
**JSON Payload Structure**:
|
||||||
```json
|
```json
|
||||||
@@ -167,7 +167,7 @@ post_to_api_vm
|
|||||||
- `RANDOM_UUID` must be set and not empty
|
- `RANDOM_UUID` must be set and not empty
|
||||||
- POST_UPDATE_DONE must be false (prevents duplicates)
|
- POST_UPDATE_DONE must be false (prevents duplicates)
|
||||||
|
|
||||||
**API Endpoint**: `http://api.community-scripts.org/dev/upload/updatestatus`
|
**API Endpoint**: `https://api.community-scripts.org/dev/upload/updatestatus`
|
||||||
|
|
||||||
**JSON Payload Structure**:
|
**JSON Payload Structure**:
|
||||||
```json
|
```json
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ check_api_health() {
|
|||||||
echo "Error description test: $test_error"
|
echo "Error description test: $test_error"
|
||||||
|
|
||||||
# Test API connectivity (without sending data)
|
# Test API connectivity (without sending data)
|
||||||
local api_url="http://api.community-scripts.org/dev/upload"
|
local api_url="https://api.community-scripts.org/dev/upload"
|
||||||
if curl -s --head "$api_url" >/dev/null 2>&1; then
|
if curl -s --head "$api_url" >/dev/null 2>&1; then
|
||||||
echo "API endpoint is reachable"
|
echo "API endpoint is reachable"
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -438,6 +438,34 @@ default_var_settings() # Save global defaults
|
|||||||
maybe_offer_save_app_defaults() # Save app defaults
|
maybe_offer_save_app_defaults() # Save app defaults
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Container Resource & ID Management
|
||||||
|
|
||||||
|
#### `validate_container_id()`
|
||||||
|
**Purpose**: Validates if a container ID is available for use.
|
||||||
|
**Parameters**: `ctid` (Integer)
|
||||||
|
**Returns**: `0` if available, `1` if already in use or invalid.
|
||||||
|
**Description**: Checks for existing config files in `/etc/pve/lxc/` or `/etc/pve/qemu-server/`, and verifies LVM logical volumes.
|
||||||
|
|
||||||
|
#### `get_valid_container_id()`
|
||||||
|
**Purpose**: Returns the next available, unused container ID.
|
||||||
|
**Parameters**: `suggested_id` (Optional)
|
||||||
|
**Returns**: A valid container ID string.
|
||||||
|
**Description**: If the suggested ID is taken, it increments until it finds an available one.
|
||||||
|
|
||||||
|
#### `maxkeys_check()`
|
||||||
|
**Purpose**: Ensures host kernel parameters support high numbers of keys (required for some apps).
|
||||||
|
**Parameters**: None
|
||||||
|
**Description**: Checks and optionally updates `kernel.keys.maxkeys` and `kernel.keys.maxbytes`.
|
||||||
|
|
||||||
|
#### `get_current_ip()`
|
||||||
|
**Purpose**: Retrieves the current IP address of the container.
|
||||||
|
**Parameters**: `ctid` (Integer)
|
||||||
|
**Returns**: IP address string.
|
||||||
|
|
||||||
|
#### `update_motd_ip()`
|
||||||
|
**Purpose**: Updates the Message of the Day (MOTD) file with the container's IP.
|
||||||
|
**Parameters**: None
|
||||||
|
|
||||||
## Function Error Handling
|
## Function Error Handling
|
||||||
|
|
||||||
### Validation Functions
|
### Validation Functions
|
||||||
|
|||||||
@@ -60,10 +60,10 @@ export var_gateway="192.168.1.1"
|
|||||||
export var_ip="192.168.1.101"
|
export var_ip="192.168.1.101"
|
||||||
export var_vlan="100"
|
export var_vlan="100"
|
||||||
export var_mtu="9000"
|
export var_mtu="9000"
|
||||||
export var_template_storage="nfs-storage"
|
export var_template_storage="ssd-storage"
|
||||||
export var_container_storage="ssd-storage"
|
export var_container_storage="ssd-storage"
|
||||||
export ENABLE_FUSE="true"
|
export var_fuse="yes"
|
||||||
export ENABLE_TUN="true"
|
export var_tun="yes"
|
||||||
export SSH="true"
|
export SSH="true"
|
||||||
|
|
||||||
# Execute build.func
|
# Execute build.func
|
||||||
|
|||||||
@@ -20,14 +20,19 @@ Complete alphabetical reference of all functions in tools.func with parameters,
|
|||||||
- `setup_nodejs(VERSION)` - Install Node.js and npm
|
- `setup_nodejs(VERSION)` - Install Node.js and npm
|
||||||
- `setup_php(VERSION)` - Install PHP-FPM and CLI
|
- `setup_php(VERSION)` - Install PHP-FPM and CLI
|
||||||
- `setup_python(VERSION)` - Install Python 3 with pip
|
- `setup_python(VERSION)` - Install Python 3 with pip
|
||||||
|
- `setup_uv()` - Install Python uv (modern & fast)
|
||||||
- `setup_ruby(VERSION)` - Install Ruby with gem
|
- `setup_ruby(VERSION)` - Install Ruby with gem
|
||||||
- `setup_golang(VERSION)` - Install Go programming language
|
- `setup_golang(VERSION)` - Install Go programming language
|
||||||
|
- `setup_java(VERSION)` - Install OpenJDK (Adoptium)
|
||||||
|
|
||||||
**Databases**:
|
**Databases**:
|
||||||
- `setup_mariadb()` - Install MariaDB server (distro packages by default)
|
- `setup_mariadb()` - Install MariaDB server
|
||||||
|
- `setup_mariadb_db()` - Create user/db in MariaDB
|
||||||
- `setup_postgresql(VERSION)` - Install PostgreSQL
|
- `setup_postgresql(VERSION)` - Install PostgreSQL
|
||||||
|
- `setup_postgresql_db()` - Create user/db in PostgreSQL
|
||||||
- `setup_mongodb(VERSION)` - Install MongoDB
|
- `setup_mongodb(VERSION)` - Install MongoDB
|
||||||
- `setup_redis(VERSION)` - Install Redis cache
|
- `setup_redis(VERSION)` - Install Redis cache
|
||||||
|
- `setup_meilisearch()` - Install Meilisearch engine
|
||||||
|
|
||||||
**Web Servers**:
|
**Web Servers**:
|
||||||
- `setup_nginx()` - Install Nginx
|
- `setup_nginx()` - Install Nginx
|
||||||
@@ -44,6 +49,7 @@ Complete alphabetical reference of all functions in tools.func with parameters,
|
|||||||
- `setup_docker_compose()` - Install Docker Compose
|
- `setup_docker_compose()` - Install Docker Compose
|
||||||
- `setup_composer()` - Install PHP Composer
|
- `setup_composer()` - Install PHP Composer
|
||||||
- `setup_build_tools()` - Install build-essential
|
- `setup_build_tools()` - Install build-essential
|
||||||
|
- `setup_yq()` - Install mikefarah/yq processor
|
||||||
|
|
||||||
**Monitoring**:
|
**Monitoring**:
|
||||||
- `setup_grafana()` - Install Grafana
|
- `setup_grafana()` - Install Grafana
|
||||||
@@ -60,13 +66,13 @@ Complete alphabetical reference of all functions in tools.func with parameters,
|
|||||||
|
|
||||||
## Core Functions
|
## Core Functions
|
||||||
|
|
||||||
### pkg_install()
|
### install_packages_with_retry()
|
||||||
|
|
||||||
Install one or more packages safely with automatic retry logic and error handling.
|
Install one or more packages safely with automatic retry logic (3 attempts), APT refresh, and lock handling.
|
||||||
|
|
||||||
**Signature**:
|
**Signature**:
|
||||||
```bash
|
```bash
|
||||||
pkg_install PACKAGE1 [PACKAGE2 ...]
|
install_packages_with_retry PACKAGE1 [PACKAGE2 ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters**:
|
**Parameters**:
|
||||||
@@ -74,66 +80,122 @@ pkg_install PACKAGE1 [PACKAGE2 ...]
|
|||||||
|
|
||||||
**Returns**:
|
**Returns**:
|
||||||
- `0` - All packages installed successfully
|
- `0` - All packages installed successfully
|
||||||
- `1` - Installation failed after retries
|
- `1` - Installation failed after all retries
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
- Automatically sets `DEBIAN_FRONTEND=noninteractive`
|
||||||
|
- Handles DPKG lock errors with `dpkg --configure -a`
|
||||||
|
- Retries on transient network or APT failures
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
install_packages_with_retry curl wget git
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### upgrade_packages_with_retry()
|
||||||
|
|
||||||
|
Upgrades installed packages with the same robust retry logic as the installation helper.
|
||||||
|
|
||||||
|
**Signature**:
|
||||||
|
```bash
|
||||||
|
upgrade_packages_with_retry
|
||||||
|
```
|
||||||
|
|
||||||
|
**Returns**:
|
||||||
|
- `0` - Upgrade successful
|
||||||
|
- `1` - Upgrade failed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### fetch_and_deploy_gh_release()
|
||||||
|
|
||||||
|
The primary tool for downloading and installing software from GitHub Releases. Supports binaries, tarballs, and Debian packages.
|
||||||
|
|
||||||
|
**Signature**:
|
||||||
|
```bash
|
||||||
|
fetch_and_deploy_gh_release APPREPO TYPE [VERSION] [DEST] [ASSET_PATTERN]
|
||||||
|
```
|
||||||
|
|
||||||
**Environment Variables**:
|
**Environment Variables**:
|
||||||
- `$STD` - Output suppression (`silent` or empty)
|
- `APPREPO`: GitHub repository (e.g., `owner/repo`)
|
||||||
|
- `TYPE`: Asset type (`binary`, `tarball`, `prebuild`, `singlefile`)
|
||||||
|
- `VERSION`: Specific tag or `latest` (Default: `latest`)
|
||||||
|
- `DEST`: Target directory (Default: `/opt/$APP`)
|
||||||
|
- `ASSET_PATTERN`: Regex or string pattern to match the release asset (Required for `prebuild` and `singlefile`)
|
||||||
|
|
||||||
|
**Supported Operation Modes**:
|
||||||
|
- `tarball`: Downloads and extracts the source tarball.
|
||||||
|
- `binary`: Detects host architecture and installs a `.deb` package using `apt` or `dpkg`.
|
||||||
|
- `prebuild`: Downloads and extracts a pre-built binary archive (supports `.tar.gz`, `.zip`, `.tgz`, `.txz`).
|
||||||
|
- `singlefile`: Downloads a single binary file to the destination.
|
||||||
|
|
||||||
|
**Environment Variables**:
|
||||||
|
- `CLEAN_INSTALL=1`: Removes all contents of the destination directory before extraction.
|
||||||
|
- `DPKG_FORCE_CONFOLD=1`: Forces `dpkg` to keep old config files during package updates.
|
||||||
|
- `SYSTEMD_OFFLINE=1`: Used automatically for `.deb` installs to prevent systemd-tmpfiles failures in unprivileged containers.
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
```bash
|
```bash
|
||||||
pkg_install curl wget git
|
fetch_and_deploy_gh_release "muesli/duf" "binary" "latest" "/opt/duf" "duf_.*_linux_amd64.tar.gz"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### pkg_update()
|
### check_for_gh_release()
|
||||||
|
|
||||||
Update package lists with automatic retry logic for network failures.
|
Checks if a newer version is available on GitHub compared to the installed version.
|
||||||
|
|
||||||
**Signature**:
|
**Signature**:
|
||||||
```bash
|
```bash
|
||||||
pkg_update
|
check_for_gh_release APP REPO
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters**: None
|
|
||||||
|
|
||||||
**Returns**:
|
|
||||||
- `0` - Package lists updated
|
|
||||||
- `1` - Failed after 3 retries
|
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
```bash
|
```bash
|
||||||
pkg_update
|
if check_for_gh_release "nodejs" "nodesource/distributions"; then
|
||||||
|
# update logic
|
||||||
|
fi
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### pkg_remove()
|
### prepare_repository_setup()
|
||||||
|
|
||||||
Remove packages completely including dependencies.
|
Performs safe repository preparation by cleaning up old files, keyrings, and ensuring the APT system is in a working state.
|
||||||
|
|
||||||
**Signature**:
|
**Signature**:
|
||||||
```bash
|
```bash
|
||||||
pkg_remove PACKAGE1 [PACKAGE2 ...]
|
prepare_repository_setup REPO_NAME [REPO_NAME2 ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters**:
|
|
||||||
- `PACKAGE1, PACKAGE2, ...` - Package names to remove
|
|
||||||
|
|
||||||
**Returns**:
|
|
||||||
- `0` - Packages removed
|
|
||||||
- `1` - Removal failed
|
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
```bash
|
```bash
|
||||||
pkg_remove old-package outdated-tool
|
prepare_repository_setup "mariadb" "mysql"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### verify_tool_version()
|
||||||
|
|
||||||
|
Validates if the installed major version matches the expected version.
|
||||||
|
|
||||||
|
**Signature**:
|
||||||
|
```bash
|
||||||
|
verify_tool_version NAME EXPECTED INSTALLED
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
verify_tool_version "nodejs" "22" "$(node -v | grep -oP '^v\K[0-9]+')"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### setup_deb822_repo()
|
### setup_deb822_repo()
|
||||||
|
|
||||||
Add repository in modern deb822 format (recommended over legacy format).
|
Add repository in modern deb822 format.
|
||||||
|
|
||||||
**Signature**:
|
**Signature**:
|
||||||
```bash
|
```bash
|
||||||
@@ -188,12 +250,234 @@ cleanup_repo_metadata
|
|||||||
|
|
||||||
## Tool Installation Functions
|
## Tool Installation Functions
|
||||||
|
|
||||||
### setup_nodejs(VERSION)
|
### setup_nodejs()
|
||||||
|
|
||||||
Install Node.js and npm from official repositories.
|
Install Node.js and npm from official repositories. Handles legacy version cleanup (nvm) automatically.
|
||||||
|
|
||||||
**Signature**:
|
**Signature**:
|
||||||
```bash
|
```bash
|
||||||
|
setup_nodejs
|
||||||
|
```
|
||||||
|
|
||||||
|
**Environment Variables**:
|
||||||
|
- `NODE_VERSION`: Major version to install (e.g. "20", "22", "24"). Default: "24".
|
||||||
|
- `NODE_MODULE`: Optional npm package to install globally during setup (e.g. "pnpm", "yarn").
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
NODE_VERSION="22" NODE_MODULE="pnpm" setup_nodejs
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_php()
|
||||||
|
|
||||||
|
Install PHP with configurable extensions and FPM/Apache integration.
|
||||||
|
|
||||||
|
**Signature**:
|
||||||
|
```bash
|
||||||
|
setup_php
|
||||||
|
```
|
||||||
|
|
||||||
|
**Environment Variables**:
|
||||||
|
- `PHP_VERSION`: Version to install (e.g. "8.3", "8.4"). Default: "8.4".
|
||||||
|
- `PHP_MODULE`: Comma-separated list of additional extensions.
|
||||||
|
- `PHP_FPM`: Set to "YES" to install php-fpm.
|
||||||
|
- `PHP_APACHE`: Set to "YES" to install libapache2-mod-php.
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
PHP_VERSION="8.3" PHP_FPM="YES" PHP_MODULE="mysql,xml,zip" setup_php
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_mariadb_db()
|
||||||
|
|
||||||
|
Creates a new MariaDB database and a dedicated user with all privileges. Automatically generates a password if not provided and saves it to a credentials file.
|
||||||
|
|
||||||
|
**Environment Variables**:
|
||||||
|
- `MARIADB_DB_NAME`: Name of the database (required)
|
||||||
|
- `MARIADB_DB_USER`: Name of the database user (required)
|
||||||
|
- `MARIADB_DB_PASS`: User password (optional, auto-generated if omitted)
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
MARIADB_DB_NAME="myapp" MARIADB_DB_USER="myapp_user" setup_mariadb_db
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_postgresql_db()
|
||||||
|
|
||||||
|
Creates a new PostgreSQL database and a dedicated user/role with all privileges. Automatically generates a password if not provided and saves it to a credentials file.
|
||||||
|
|
||||||
|
**Environment Variables**:
|
||||||
|
- `PG_DB_NAME`: Name of the database (required)
|
||||||
|
- `PG_DB_USER`: Name of the database user (required)
|
||||||
|
- `PG_DB_PASS`: User password (optional, auto-generated if omitted)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_java()
|
||||||
|
|
||||||
|
Installs Temurin JDK.
|
||||||
|
|
||||||
|
**Signature**:
|
||||||
|
```bash
|
||||||
|
JAVA_VERSION="21" setup_java
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
- `JAVA_VERSION` - JDK version (e.g., "17", "21") (default: "21")
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
JAVA_VERSION="17" setup_java
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_uv()
|
||||||
|
|
||||||
|
Installs `uv` (modern Python package manager).
|
||||||
|
|
||||||
|
**Signature**:
|
||||||
|
```bash
|
||||||
|
PYTHON_VERSION="3.13" setup_uv
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
- `PYTHON_VERSION` - Optional Python version to pre-install via uv (e.g., "3.12", "3.13")
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
PYTHON_VERSION="3.13" setup_uv
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_go()
|
||||||
|
|
||||||
|
Installs Go programming language.
|
||||||
|
|
||||||
|
**Signature**:
|
||||||
|
```bash
|
||||||
|
GO_VERSION="1.23" setup_go
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parameters**:
|
||||||
|
- `GO_VERSION` - Go version to install (default: "1.23")
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
GO_VERSION="1.24" setup_go
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_yq()
|
||||||
|
|
||||||
|
Installs `yq` (YAML processor).
|
||||||
|
|
||||||
|
**Signature**:
|
||||||
|
```bash
|
||||||
|
setup_yq
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
setup_yq
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_composer()
|
||||||
|
|
||||||
|
Installs PHP Composer.
|
||||||
|
|
||||||
|
**Signature**:
|
||||||
|
```bash
|
||||||
|
setup_composer
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
setup_composer
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_meilisearch()
|
||||||
|
|
||||||
|
Install and configure Meilisearch search engine.
|
||||||
|
|
||||||
|
**Environment Variables**:
|
||||||
|
- `MEILISEARCH_BIND`: Address and port to bind to (Default: "127.0.0.1:7700")
|
||||||
|
- `MEILISEARCH_ENV`: Environment mode (Default: "production")
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_yq()
|
||||||
|
|
||||||
|
Install the `mikefarah/yq` YAML processor. Removes existing non-compliant versions.
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
setup_yq
|
||||||
|
yq eval '.app.version = "1.0.0"' -i config.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_composer()
|
||||||
|
|
||||||
|
Install or update the PHP Composer package manager. Handles `COMPOSER_ALLOW_SUPERUSER` automatically and performs self-updates if already installed.
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
setup_php
|
||||||
|
setup_composer
|
||||||
|
$STD composer install --no-dev
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_build_tools()
|
||||||
|
|
||||||
|
Install the `build-essential` package suite for compiling software.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_uv()
|
||||||
|
|
||||||
|
Install the modern Python package manager `uv`. Extremely fast replacement for pip/venv.
|
||||||
|
|
||||||
|
**Environment Variables**:
|
||||||
|
- `PYTHON_VERSION`: Major.Minor version to ensure is installed.
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
PYTHON_VERSION="3.12" setup_uv
|
||||||
|
uv sync --locked
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### setup_java()
|
||||||
|
|
||||||
|
Install OpenJDK via the Adoptium repository.
|
||||||
|
|
||||||
|
**Environment Variables**:
|
||||||
|
- `JAVA_VERSION`: Major version to install (e.g. "17", "21"). Default: "21".
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
```bash
|
||||||
|
JAVA_VERSION="21" setup_java
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
```bash
|
||||||
setup_nodejs VERSION
|
setup_nodejs VERSION
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -40,14 +40,15 @@ vm/OsName-vm.sh (host-side)
|
|||||||
|
|
||||||
See `/vm` directory for all VM creation scripts. Examples:
|
See `/vm` directory for all VM creation scripts. Examples:
|
||||||
|
|
||||||
- `ubuntu2404-vm.sh` - Ubuntu 24.04 VM
|
- `ubuntu2504-vm.sh` - Ubuntu 25.04 VM (Latest)
|
||||||
- `ubuntu2204-vm.sh` - Ubuntu 22.04 VM
|
- `ubuntu2404-vm.sh` - Ubuntu 24.04 VM (LTS)
|
||||||
- `debian-vm.sh` - Debian VM
|
- `debian-13-vm.sh` - Debian 13 VM (Trixie)
|
||||||
- `debian-13-vm.sh` - Debian 13 VM
|
- `archlinux-vm.sh` - Arch Linux VM
|
||||||
- `opnsense-vm.sh` - OPNsense firewall
|
|
||||||
- `haos-vm.sh` - Home Assistant OS
|
- `haos-vm.sh` - Home Assistant OS
|
||||||
- `unifi-os-vm.sh` - Unifi Dream Machine
|
- `mikrotik-routeros.sh` - MikroTik RouterOS
|
||||||
- `k3s-vm.sh` - Kubernetes lightweight
|
- `openwrt-vm.sh` - OpenWrt VM
|
||||||
|
- `opnsense-vm.sh` - OPNsense firewall
|
||||||
|
- `umbrel-os-vm.sh` - Umbrel OS VM
|
||||||
- And 10+ more...
|
- And 10+ more...
|
||||||
|
|
||||||
## VM vs Container
|
## VM vs Container
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"generated": "2026-02-04T06:18:03Z",
|
"generated": "2026-02-05T12:12:20Z",
|
||||||
"versions": [
|
"versions": [
|
||||||
{
|
{
|
||||||
"slug": "2fauth",
|
"slug": "2fauth",
|
||||||
@@ -186,9 +186,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "comfyui",
|
"slug": "comfyui",
|
||||||
"repo": "comfyanonymous/ComfyUI",
|
"repo": "comfyanonymous/ComfyUI",
|
||||||
"version": "v0.12.2",
|
"version": "v0.12.3",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-04T06:09:31Z"
|
"date": "2026-02-05T07:04:07Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "commafeed",
|
"slug": "commafeed",
|
||||||
@@ -221,9 +221,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "cronicle",
|
"slug": "cronicle",
|
||||||
"repo": "jhuckaby/Cronicle",
|
"repo": "jhuckaby/Cronicle",
|
||||||
"version": "v0.9.102",
|
"version": "v0.9.103",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2025-12-19T03:45:13Z"
|
"date": "2026-02-05T03:09:04Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "cryptpad",
|
"slug": "cryptpad",
|
||||||
@@ -256,9 +256,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "docmost",
|
"slug": "docmost",
|
||||||
"repo": "docmost/docmost",
|
"repo": "docmost/docmost",
|
||||||
"version": "v0.25.0",
|
"version": "v0.25.1",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-04T00:33:45Z"
|
"date": "2026-02-04T15:19:51Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "domain-locker",
|
"slug": "domain-locker",
|
||||||
@@ -445,9 +445,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "headscale",
|
"slug": "headscale",
|
||||||
"repo": "juanfont/headscale",
|
"repo": "juanfont/headscale",
|
||||||
"version": "v0.27.1",
|
"version": "v0.28.0",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2025-11-11T19:32:29Z"
|
"date": "2026-02-04T20:40:23Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "healthchecks",
|
"slug": "healthchecks",
|
||||||
@@ -494,9 +494,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "homepage",
|
"slug": "homepage",
|
||||||
"repo": "gethomepage/homepage",
|
"repo": "gethomepage/homepage",
|
||||||
"version": "v1.9.0",
|
"version": "v1.10.0",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-19T05:46:09Z"
|
"date": "2026-02-05T06:17:32Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "homer",
|
"slug": "homer",
|
||||||
@@ -515,9 +515,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "huntarr",
|
"slug": "huntarr",
|
||||||
"repo": "plexguide/Huntarr.io",
|
"repo": "plexguide/Huntarr.io",
|
||||||
"version": "9.1.9.1",
|
"version": "9.2.0",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-04T01:08:22Z"
|
"date": "2026-02-05T04:18:08Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "inspircd",
|
"slug": "inspircd",
|
||||||
@@ -536,16 +536,16 @@
|
|||||||
{
|
{
|
||||||
"slug": "invoiceninja",
|
"slug": "invoiceninja",
|
||||||
"repo": "invoiceninja/invoiceninja",
|
"repo": "invoiceninja/invoiceninja",
|
||||||
"version": "v5.12.53",
|
"version": "v5.12.55",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-04T00:52:01Z"
|
"date": "2026-02-05T01:06:15Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "jackett",
|
"slug": "jackett",
|
||||||
"repo": "Jackett/Jackett",
|
"repo": "Jackett/Jackett",
|
||||||
"version": "v0.24.1027",
|
"version": "v0.24.1032",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-04T05:56:22Z"
|
"date": "2026-02-05T05:55:27Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "joplin-server",
|
"slug": "joplin-server",
|
||||||
@@ -746,9 +746,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "mealie",
|
"slug": "mealie",
|
||||||
"repo": "mealie-recipes/mealie",
|
"repo": "mealie-recipes/mealie",
|
||||||
"version": "v3.10.1",
|
"version": "v3.10.2",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-03T01:04:38Z"
|
"date": "2026-02-04T23:32:32Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "mediamanager",
|
"slug": "mediamanager",
|
||||||
@@ -781,9 +781,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "metube",
|
"slug": "metube",
|
||||||
"repo": "alexta69/metube",
|
"repo": "alexta69/metube",
|
||||||
"version": "2026.02.03",
|
"version": "2026.02.04",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-03T21:49:49Z"
|
"date": "2026-02-04T20:01:18Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "miniflux",
|
"slug": "miniflux",
|
||||||
@@ -1096,9 +1096,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "pulse",
|
"slug": "pulse",
|
||||||
"repo": "rcourtman/Pulse",
|
"repo": "rcourtman/Pulse",
|
||||||
"version": "v5.0.17",
|
"version": "v5.1.2",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-20T19:07:30Z"
|
"date": "2026-02-05T00:18:57Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "pve-scripts-local",
|
"slug": "pve-scripts-local",
|
||||||
@@ -1271,9 +1271,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "speedtest-tracker",
|
"slug": "speedtest-tracker",
|
||||||
"repo": "alexjustesen/speedtest-tracker",
|
"repo": "alexjustesen/speedtest-tracker",
|
||||||
"version": "v1.13.6",
|
"version": "v1.13.8",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-02-03T21:20:51Z"
|
"date": "2026-02-04T19:24:23Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "spoolman",
|
"slug": "spoolman",
|
||||||
@@ -1292,9 +1292,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "stirling-pdf",
|
"slug": "stirling-pdf",
|
||||||
"repo": "Stirling-Tools/Stirling-PDF",
|
"repo": "Stirling-Tools/Stirling-PDF",
|
||||||
"version": "v2.4.3",
|
"version": "v2.4.4",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-31T22:19:14Z"
|
"date": "2026-02-05T00:15:53Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "streamlink-webui",
|
"slug": "streamlink-webui",
|
||||||
@@ -1369,9 +1369,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "tianji",
|
"slug": "tianji",
|
||||||
"repo": "msgbyte/tianji",
|
"repo": "msgbyte/tianji",
|
||||||
"version": "v1.31.9",
|
"version": "v1.31.10",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-31T18:22:40Z"
|
"date": "2026-02-04T17:21:04Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "traccar",
|
"slug": "traccar",
|
||||||
@@ -1411,9 +1411,9 @@
|
|||||||
{
|
{
|
||||||
"slug": "trip",
|
"slug": "trip",
|
||||||
"repo": "itskovacs/TRIP",
|
"repo": "itskovacs/TRIP",
|
||||||
"version": "1.38.0",
|
"version": "1.38.1",
|
||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-31T15:56:30Z"
|
"date": "2026-02-04T18:10:15Z"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"slug": "tududi",
|
"slug": "tududi",
|
||||||
@@ -1562,6 +1562,13 @@
|
|||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2026-01-08T09:50:00Z"
|
"date": "2026-01-08T09:50:00Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"slug": "wishlist",
|
||||||
|
"repo": "cmintey/wishlist",
|
||||||
|
"version": "v0.59.0",
|
||||||
|
"pinned": false,
|
||||||
|
"date": "2026-01-19T16:42:14Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"slug": "wizarr",
|
"slug": "wizarr",
|
||||||
"repo": "wizarrrr/wizarr",
|
"repo": "wizarrrr/wizarr",
|
||||||
@@ -1569,6 +1576,13 @@
|
|||||||
"pinned": false,
|
"pinned": false,
|
||||||
"date": "2025-12-09T14:30:23Z"
|
"date": "2025-12-09T14:30:23Z"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"slug": "writefreely",
|
||||||
|
"repo": "writefreely/writefreely",
|
||||||
|
"version": "v0.16.0",
|
||||||
|
"pinned": false,
|
||||||
|
"date": "2025-08-29T19:30:02Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"slug": "yt-dlp-webui",
|
"slug": "yt-dlp-webui",
|
||||||
"repo": "marcopiovanello/yt-dlp-web-ui",
|
"repo": "marcopiovanello/yt-dlp-web-ui",
|
||||||
|
|||||||
44
frontend/public/json/immich-public-proxy.json
Normal file
44
frontend/public/json/immich-public-proxy.json
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "Immich Public Proxy",
|
||||||
|
"slug": "immich-public-proxy",
|
||||||
|
"categories": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"date_created": "2026-02-04",
|
||||||
|
"type": "addon",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 3000,
|
||||||
|
"documentation": "https://github.com/alangrainger/immich-public-proxy/tree/main/docs",
|
||||||
|
"website": "https://github.com/alangrainger/immich-public-proxy",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/immich-public-proxy.webp",
|
||||||
|
"config_path": "/opt/immich-proxy/app/.env",
|
||||||
|
"description": "Share your Immich photos and albums in a safe way without exposing your Immich instance to the public.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "tools/addon/immich-public-proxy.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": null,
|
||||||
|
"ram": null,
|
||||||
|
"hdd": null,
|
||||||
|
"os": null,
|
||||||
|
"version": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
{
|
||||||
|
"text": "Requires Node.js 24+",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Update with: update_immich-public-proxy",
|
||||||
|
"type": "info"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
48
frontend/public/json/nginx-ui.json
Normal file
48
frontend/public/json/nginx-ui.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"name": "Nginx UI",
|
||||||
|
"slug": "nginx-ui",
|
||||||
|
"categories": [
|
||||||
|
21
|
||||||
|
],
|
||||||
|
"date_created": "2026-02-05",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 9000,
|
||||||
|
"documentation": "https://nginxui.com/guide/",
|
||||||
|
"website": "https://nginxui.com",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/nginx-ui.webp",
|
||||||
|
"config_path": "/usr/local/etc/nginx-ui/app.ini",
|
||||||
|
"description": "Nginx UI is a comprehensive web-based interface designed to simplify the management and configuration of Nginx servers. It provides features like online statistics, ChatGPT-powered config assistant, automatic Let's Encrypt certificates, and config file editing with syntax highlighting.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/nginx-ui.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 1,
|
||||||
|
"ram": 512,
|
||||||
|
"hdd": 4,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": "admin",
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
{
|
||||||
|
"text": "Nginx runs on ports 80/443, Nginx UI management interface on port 9000.",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "SSL certificates can be managed automatically with Let's Encrypt integration.",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Initial Login data: `cat ~/nginx-ui.creds`",
|
||||||
|
"type": "info"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
64
frontend/public/json/opencloud.json
Normal file
64
frontend/public/json/opencloud.json
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"name": "OpenCloud",
|
||||||
|
"slug": "opencloud",
|
||||||
|
"categories": [
|
||||||
|
11
|
||||||
|
],
|
||||||
|
"date_created": "2026-02-05",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 443,
|
||||||
|
"documentation": "https://docs.opencloud.eu",
|
||||||
|
"config_path": "/etc/opencloud/opencloud.env, /etc/opencloud/opencloud.yaml, /etc/opencloud/csp.yaml",
|
||||||
|
"website": "https://opencloud.eu",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/opencloud.webp",
|
||||||
|
"description": "OpenCloud is the file sharing and collaboration solution of the Heinlein Group. Through intelligent file management and a strong open source community, files become valuable resources, effectively structured and usable in the long term. With flexible data rooms and intelligent access rights, teams can access and work together on data anytime, anywhere without barriers, but with a lot of productivity.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/opencloud.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 2,
|
||||||
|
"ram": 2048,
|
||||||
|
"hdd": 20,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": "admin",
|
||||||
|
"password": "randomly generated during the installation process"
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
{
|
||||||
|
"text": "Valid TLS certificates and fully-qualified domain names behind a reverse proxy (Caddy) for 3 services - OpenCloud, Collabora, and WOPI are **REQUIRED**",
|
||||||
|
"type": "warning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Forgot your admin password? Check `admin_password` in the 'idm' section in `/etc/opencloud/opencloud.yaml`",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "**Optional External Apps**: extract zip archives from App Store to `/etc/opencloud/assets/apps`",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "**Optional CalDAV and CardDAV**: requires separate Radicale install. Edit and rename `/opt/opencloud/proxy.yaml.bak` and change your Radicale config to use `http_x_remote_user` as the auth method",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "**Optional OpenID**: Authelia and PocketID supported. Uncomment relevant lines in `/opt/opencloud/opencloud.env` and consult OpenCloud GitHub discussions for configuration tips",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "**Optional Full-text Search with Apache Tika**: requires your own Tika LXC. See `https://community-scripts.github.io/ProxmoxVE/scripts?id=apache-tika`",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "**Relevant services**: `opencloud.service`, `opencloud-wopi.service`, `coolwsd.service`",
|
||||||
|
"type": "info"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
52
frontend/public/json/sqlserver2025.json
Normal file
52
frontend/public/json/sqlserver2025.json
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"name": "SQL Server 2025",
|
||||||
|
"slug": "sqlserver2025",
|
||||||
|
"categories": [
|
||||||
|
8
|
||||||
|
],
|
||||||
|
"date_created": "2026-02-05",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": true,
|
||||||
|
"interface_port": 1433,
|
||||||
|
"documentation": "https://learn.microsoft.com/en-us/sql/sql-server/?view=sql-server-ver17",
|
||||||
|
"website": "https://www.microsoft.com/en-us/sql-server/sql-server-2025",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/microsoft-sql-server.webp",
|
||||||
|
"config_path": "",
|
||||||
|
"description": "Script to automatically set up a SQL Server 2025 installation with Ubuntu 24.04 support.",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/sqlserver2025.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 2,
|
||||||
|
"ram": 2048,
|
||||||
|
"hdd": 10,
|
||||||
|
"os": "Ubuntu",
|
||||||
|
"version": "24.04"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
{
|
||||||
|
"text": "If you choose not to run the installation setup, execute: `/opt/mssql/bin/mssql-conf setup` in LXC shell.",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "You can setup the admin account 'SA' during installation",
|
||||||
|
"type": "info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Make sure you disable the SA account if you intend to use this in production!",
|
||||||
|
"type": "warning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "Ubuntu 24.04 support requires SQL Server 2025 CU1 or later",
|
||||||
|
"type": "info"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
35
frontend/public/json/wishlist.json
Normal file
35
frontend/public/json/wishlist.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "Wishlist",
|
||||||
|
"slug": "wishlist",
|
||||||
|
"categories": [
|
||||||
|
12
|
||||||
|
],
|
||||||
|
"date_created": "2026-02-04",
|
||||||
|
"type": "ct",
|
||||||
|
"updateable": true,
|
||||||
|
"privileged": false,
|
||||||
|
"interface_port": 3280,
|
||||||
|
"documentation": "https://github.com/cmintey/wishlist/blob/main/README.md#getting-started",
|
||||||
|
"config_path": "/opt/wishlist/.env",
|
||||||
|
"website": "https://github.com/cmintey/wishlist",
|
||||||
|
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/cmintey-wishlist.webp",
|
||||||
|
"description": "Wishlist is a self-hosted wishlist application that you can share with your friends and family. You no longer have to wonder what to get your family for the holidays, simply check their wishlist and claim any available item!",
|
||||||
|
"install_methods": [
|
||||||
|
{
|
||||||
|
"type": "default",
|
||||||
|
"script": "ct/wishlist.sh",
|
||||||
|
"resources": {
|
||||||
|
"cpu": 2,
|
||||||
|
"ram": 2048,
|
||||||
|
"hdd": 5,
|
||||||
|
"os": "Debian",
|
||||||
|
"version": "13"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"default_credentials": {
|
||||||
|
"username": null,
|
||||||
|
"password": null
|
||||||
|
},
|
||||||
|
"notes": []
|
||||||
|
}
|
||||||
@@ -29,9 +29,10 @@ import { ScriptSchema } from "./_schemas/schemas";
|
|||||||
import Categories from "./_components/categories";
|
import Categories from "./_components/categories";
|
||||||
import Note from "./_components/note";
|
import Note from "./_components/note";
|
||||||
|
|
||||||
import { nord } from "react-syntax-highlighter/dist/esm/styles/hljs";
|
import { githubGist, nord } from "react-syntax-highlighter/dist/esm/styles/hljs";
|
||||||
import SyntaxHighlighter from "react-syntax-highlighter";
|
import SyntaxHighlighter from "react-syntax-highlighter";
|
||||||
import { ScriptItem } from "../scripts/_components/script-item";
|
import { ScriptItem } from "../scripts/_components/script-item";
|
||||||
|
import { useTheme } from "next-themes";
|
||||||
|
|
||||||
const initialScript: Script = {
|
const initialScript: Script = {
|
||||||
name: "",
|
name: "",
|
||||||
@@ -58,6 +59,7 @@ const initialScript: Script = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function JSONGenerator() {
|
export default function JSONGenerator() {
|
||||||
|
const { theme } = useTheme();
|
||||||
const [script, setScript] = useState<Script>(initialScript);
|
const [script, setScript] = useState<Script>(initialScript);
|
||||||
const [isCopied, setIsCopied] = useState(false);
|
const [isCopied, setIsCopied] = useState(false);
|
||||||
const [isValid, setIsValid] = useState(false);
|
const [isValid, setIsValid] = useState(false);
|
||||||
@@ -357,7 +359,7 @@ export default function JSONGenerator() {
|
|||||||
|
|
||||||
<SyntaxHighlighter
|
<SyntaxHighlighter
|
||||||
language="json"
|
language="json"
|
||||||
style={nord}
|
style={theme === "light" ? githubGist : nord}
|
||||||
className="mt-4 p-4 bg-secondary rounded shadow overflow-x-scroll"
|
className="mt-4 p-4 bg-secondary rounded shadow overflow-x-scroll"
|
||||||
>
|
>
|
||||||
{JSON.stringify(script, null, 2)}
|
{JSON.stringify(script, null, 2)}
|
||||||
|
|||||||
@@ -23,6 +23,34 @@ import { Button } from "./ui/button";
|
|||||||
import { Badge } from "./ui/badge";
|
import { Badge } from "./ui/badge";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
|
function search(scripts: Script[], query: string): Script[] {
|
||||||
|
const queryLower = query.toLowerCase().trim();
|
||||||
|
const searchWords = queryLower.split(/\s+/).filter(Boolean);
|
||||||
|
|
||||||
|
return scripts
|
||||||
|
.map(script => {
|
||||||
|
const nameLower = script.name.toLowerCase();
|
||||||
|
const descriptionLower = (script.description || "").toLowerCase();
|
||||||
|
|
||||||
|
let score = 0;
|
||||||
|
|
||||||
|
for (const word of searchWords) {
|
||||||
|
if (nameLower.includes(word)) {
|
||||||
|
score += 10;
|
||||||
|
}
|
||||||
|
if (descriptionLower.includes(word)) {
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { script, score };
|
||||||
|
})
|
||||||
|
.filter(({ score }) => score > 0)
|
||||||
|
.sort((a, b) => b.score - a.score)
|
||||||
|
.slice(0, 20)
|
||||||
|
.map(({ script }) => script);
|
||||||
|
}
|
||||||
|
|
||||||
export function formattedBadge(type: string) {
|
export function formattedBadge(type: string) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "vm":
|
case "vm":
|
||||||
@@ -51,9 +79,11 @@ function getRandomScript(categories: Category[], previouslySelected: Set<string>
|
|||||||
}
|
}
|
||||||
|
|
||||||
function CommandMenu() {
|
function CommandMenu() {
|
||||||
|
const [query, setQuery] = React.useState("");
|
||||||
const [open, setOpen] = React.useState(false);
|
const [open, setOpen] = React.useState(false);
|
||||||
const [links, setLinks] = React.useState<Category[]>([]);
|
const [links, setLinks] = React.useState<Category[]>([]);
|
||||||
const [isLoading, setIsLoading] = React.useState(false);
|
const [isLoading, setIsLoading] = React.useState(false);
|
||||||
|
const [results, setResults] = React.useState<Script[]>([]);
|
||||||
const [selectedScripts, setSelectedScripts] = React.useState<Set<string>>(new Set());
|
const [selectedScripts, setSelectedScripts] = React.useState<Set<string>>(new Set());
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -70,6 +100,27 @@ function CommandMenu() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (query.trim() === "") {
|
||||||
|
fetchSortedCategories();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const scriptMap = new Map<string, Script>();
|
||||||
|
|
||||||
|
for (const category of links) {
|
||||||
|
for (const script of category.scripts || []) {
|
||||||
|
if (!scriptMap.has(script.slug)) {
|
||||||
|
scriptMap.set(script.slug, script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uniqueScripts = Array.from(scriptMap.values());
|
||||||
|
const filteredResults = search(uniqueScripts, query);
|
||||||
|
setResults(filteredResults);
|
||||||
|
}
|
||||||
|
}, [query]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
||||||
@@ -197,20 +248,20 @@ function CommandMenu() {
|
|||||||
|
|
||||||
<CommandDialog
|
<CommandDialog
|
||||||
open={open}
|
open={open}
|
||||||
onOpenChange={setOpen}
|
onOpenChange={(open) => {
|
||||||
filter={(value: string, search: string) => {
|
setOpen(open);
|
||||||
const searchLower = search.toLowerCase().trim();
|
if (open) {
|
||||||
if (!searchLower)
|
setQuery("");
|
||||||
return 1;
|
setResults([]);
|
||||||
const valueLower = value.toLowerCase();
|
}
|
||||||
const searchWords = searchLower.split(/\s+/).filter(Boolean);
|
|
||||||
// All search words must appear somewhere in the value (name + description)
|
|
||||||
const allWordsMatch = searchWords.every((word: string) => valueLower.includes(word));
|
|
||||||
return allWordsMatch ? 1 : 0;
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle className="sr-only">Search scripts</DialogTitle>
|
<DialogTitle className="sr-only">Search scripts</DialogTitle>
|
||||||
<CommandInput placeholder="Search for a script..." />
|
<CommandInput
|
||||||
|
placeholder="Search for a script..."
|
||||||
|
onValueChange={setQuery}
|
||||||
|
value={query}
|
||||||
|
/>
|
||||||
<CommandList>
|
<CommandList>
|
||||||
<CommandEmpty>
|
<CommandEmpty>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
@@ -233,9 +284,10 @@ function CommandMenu() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</CommandEmpty>
|
</CommandEmpty>
|
||||||
{Object.entries(uniqueScriptsByCategory).map(([categoryName, scripts]) => (
|
|
||||||
<CommandGroup key={`category:${categoryName}`} heading={categoryName}>
|
{results.length > 0 ? (
|
||||||
{scripts.map(script => (
|
<CommandGroup heading="Search Results">
|
||||||
|
{results.map(script => (
|
||||||
<CommandItem
|
<CommandItem
|
||||||
key={`script:${script.slug}`}
|
key={`script:${script.slug}`}
|
||||||
value={`${script.name} ${script.type} ${script.description || ""}`}
|
value={`${script.name} ${script.type} ${script.description || ""}`}
|
||||||
@@ -268,7 +320,44 @@ function CommandMenu() {
|
|||||||
</CommandItem>
|
</CommandItem>
|
||||||
))}
|
))}
|
||||||
</CommandGroup>
|
</CommandGroup>
|
||||||
))}
|
) : ( // When no search results, show all scripts grouped by category
|
||||||
|
Object.entries(uniqueScriptsByCategory).map(([categoryName, scripts]) => (
|
||||||
|
<CommandGroup key={`category:${categoryName}`} heading={categoryName}>
|
||||||
|
{scripts.map(script => (
|
||||||
|
<CommandItem
|
||||||
|
key={`script:${script.slug}`}
|
||||||
|
value={`${script.name} ${script.type} ${script.description || ""}`}
|
||||||
|
onSelect={() => {
|
||||||
|
setOpen(false);
|
||||||
|
router.push(`/scripts?id=${script.slug}`);
|
||||||
|
}}
|
||||||
|
tabIndex={0}
|
||||||
|
aria-label={`Open script ${script.name}`}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter" || e.key === " ") {
|
||||||
|
setOpen(false);
|
||||||
|
router.push(`/scripts?id=${script.slug}`);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex gap-2" onClick={() => setOpen(false)}>
|
||||||
|
<Image
|
||||||
|
src={script.logo || `/${basePath}/logo.png`}
|
||||||
|
onError={e => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
|
||||||
|
unoptimized
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
alt=""
|
||||||
|
className="h-5 w-5"
|
||||||
|
/>
|
||||||
|
<span>{script.name}</span>
|
||||||
|
<span>{formattedBadge(script.type)}</span>
|
||||||
|
</div>
|
||||||
|
</CommandItem>
|
||||||
|
))}
|
||||||
|
</CommandGroup>
|
||||||
|
))
|
||||||
|
)}
|
||||||
</CommandList>
|
</CommandList>
|
||||||
</CommandDialog>
|
</CommandDialog>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -13,44 +13,44 @@ setting_up_container
|
|||||||
network_check
|
network_check
|
||||||
update_os
|
update_os
|
||||||
|
|
||||||
echo ""
|
if [ -d /dev/dri ]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "🤖 ${BL}Immich Machine Learning Options${CL}"
|
echo ""
|
||||||
echo "─────────────────────────────────────────"
|
echo -e "🤖 ${BL}Immich Machine Learning Options${CL}"
|
||||||
echo "Please choose your machine-learning type:"
|
echo "─────────────────────────────────────────"
|
||||||
echo ""
|
echo "Please choose your machine-learning type:"
|
||||||
echo " 1) CPU only (default)"
|
echo ""
|
||||||
echo " 2) Intel OpenVINO (requires GPU passthrough)"
|
echo " 1) CPU only (default)"
|
||||||
echo ""
|
echo " 2) Intel OpenVINO (requires GPU passthrough)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
read -r -p "${TAB3}Select machine-learning type [1]: " ML_TYPE
|
read -r -p "${TAB3}Select machine-learning type [1]: " ML_TYPE
|
||||||
ML_TYPE="${ML_TYPE:-1}"
|
ML_TYPE="${ML_TYPE:-1}"
|
||||||
if [[ "$ML_TYPE" == "2" ]]; then
|
if [[ "$ML_TYPE" == "2" ]]; then
|
||||||
msg_info "Installing OpenVINO dependencies"
|
msg_info "Installing OpenVINO dependencies"
|
||||||
touch ~/.openvino
|
touch ~/.openvino
|
||||||
$STD apt install -y --no-install-recommends patchelf
|
$STD apt install -y --no-install-recommends patchelf
|
||||||
tmp_dir=$(mktemp -d)
|
tmp_dir=$(mktemp -d)
|
||||||
$STD pushd "$tmp_dir"
|
$STD pushd "$tmp_dir"
|
||||||
curl -fsSLO https://raw.githubusercontent.com/immich-app/base-images/refs/heads/main/server/Dockerfile
|
curl -fsSLO https://raw.githubusercontent.com/immich-app/base-images/refs/heads/main/server/Dockerfile
|
||||||
readarray -t INTEL_URLS < <(
|
readarray -t INTEL_URLS < <(
|
||||||
sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $2}'
|
sed -n "/intel-[igc|opencl]/p" ./Dockerfile | awk '{print $2}'
|
||||||
sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}'
|
sed -n "/libigdgmm12/p" ./Dockerfile | awk '{print $3}'
|
||||||
)
|
)
|
||||||
for url in "${INTEL_URLS[@]}"; do
|
for url in "${INTEL_URLS[@]}"; do
|
||||||
curl -fsSLO "$url"
|
curl -fsSLO "$url"
|
||||||
done
|
done
|
||||||
$STD apt install -y ./libigdgmm12*.deb
|
$STD apt install -y ./libigdgmm12*.deb
|
||||||
rm ./libigdgmm12*.deb
|
rm ./libigdgmm12*.deb
|
||||||
$STD apt install -y ./*.deb
|
$STD apt install -y ./*.deb
|
||||||
$STD apt-mark hold libigdgmm12
|
$STD apt-mark hold libigdgmm12
|
||||||
$STD popd
|
$STD popd
|
||||||
rm -rf "$tmp_dir"
|
rm -rf "$tmp_dir"
|
||||||
dpkg-query -W -f='${Version}\n' intel-opencl-icd >~/.intel_version
|
dpkg-query -W -f='${Version}\n' intel-opencl-icd >~/.intel_version
|
||||||
msg_ok "Installed OpenVINO dependencies"
|
msg_ok "Installed OpenVINO dependencies"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
setup_uv
|
|
||||||
|
|
||||||
msg_info "Installing dependencies"
|
msg_info "Installing dependencies"
|
||||||
$STD apt install --no-install-recommends -y \
|
$STD apt install --no-install-recommends -y \
|
||||||
git \
|
git \
|
||||||
@@ -144,8 +144,7 @@ msg_info "Installing packages from Debian Testing repo"
|
|||||||
$STD apt install -t testing --no-install-recommends -yqq libmimalloc3 libde265-dev
|
$STD apt install -t testing --no-install-recommends -yqq libmimalloc3 libde265-dev
|
||||||
msg_ok "Installed packages from Debian Testing repo"
|
msg_ok "Installed packages from Debian Testing repo"
|
||||||
|
|
||||||
PNPM_VERSION="$(curl -fsSL "https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/package.json" | jq -r '.packageManager | split("@")[1]')"
|
setup_uv
|
||||||
NODE_VERSION="24" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
|
|
||||||
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
|
PG_VERSION="16" PG_MODULES="pgvector" setup_postgresql
|
||||||
|
|
||||||
VCHORD_RELEASE="0.5.3"
|
VCHORD_RELEASE="0.5.3"
|
||||||
@@ -290,7 +289,9 @@ ML_DIR="${APP_DIR}/machine-learning"
|
|||||||
GEO_DIR="${INSTALL_DIR}/geodata"
|
GEO_DIR="${INSTALL_DIR}/geodata"
|
||||||
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
|
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
|
||||||
|
|
||||||
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.5.2" "$SRC_DIR"
|
fetch_and_deploy_gh_release "immich" "immich-app/immich" "tarball" "v2.5.3" "$SRC_DIR"
|
||||||
|
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1]' ${SRC_DIR}/package.json)"
|
||||||
|
NODE_VERSION="24" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
|
||||||
|
|
||||||
msg_info "Installing Immich (patience)"
|
msg_info "Installing Immich (patience)"
|
||||||
|
|
||||||
|
|||||||
99
install/nginx-ui-install.sh
Normal file
99
install/nginx-ui-install.sh
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#!/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://nginxui.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 \
|
||||||
|
nginx \
|
||||||
|
logrotate
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "nginx-ui" "0xJacky/nginx-ui" "prebuild" "latest" "/opt/nginx-ui" "nginx-ui-linux-64.tar.gz"
|
||||||
|
|
||||||
|
msg_info "Installing Nginx UI"
|
||||||
|
cp /opt/nginx-ui/nginx-ui /usr/local/bin/nginx-ui
|
||||||
|
chmod +x /usr/local/bin/nginx-ui
|
||||||
|
rm -rf /opt/nginx-ui
|
||||||
|
msg_ok "Installed Nginx UI"
|
||||||
|
|
||||||
|
msg_info "Configuring Nginx UI"
|
||||||
|
mkdir -p /usr/local/etc/nginx-ui
|
||||||
|
cat <<EOF >/usr/local/etc/nginx-ui/app.ini
|
||||||
|
[server]
|
||||||
|
HttpHost = 0.0.0.0
|
||||||
|
HttpPort = 9000
|
||||||
|
RunMode = release
|
||||||
|
JwtSecret = $(openssl rand -hex 32)
|
||||||
|
|
||||||
|
[nginx]
|
||||||
|
AccessLogPath = /var/log/nginx/access.log
|
||||||
|
ErrorLogPath = /var/log/nginx/error.log
|
||||||
|
ConfigDir = /etc/nginx
|
||||||
|
PIDPath = /run/nginx.pid
|
||||||
|
TestConfigCmd = nginx -t
|
||||||
|
ReloadCmd = nginx -s reload
|
||||||
|
RestartCmd = systemctl restart nginx
|
||||||
|
|
||||||
|
[app]
|
||||||
|
PageSize = 10
|
||||||
|
|
||||||
|
[cert]
|
||||||
|
Email =
|
||||||
|
CADir =
|
||||||
|
RenewalInterval = 7
|
||||||
|
RecursiveNameservers =
|
||||||
|
EOF
|
||||||
|
msg_ok "Configured Nginx UI"
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/nginx-ui.service
|
||||||
|
[Unit]
|
||||||
|
Description=Another WebUI for Nginx
|
||||||
|
Documentation=https://nginxui.com
|
||||||
|
After=network.target nginx.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/local/bin/nginx-ui --config /usr/local/etc/nginx-ui/app.ini
|
||||||
|
RuntimeDirectory=nginx-ui
|
||||||
|
WorkingDirectory=/var/run/nginx-ui
|
||||||
|
Restart=on-failure
|
||||||
|
TimeoutStopSec=5
|
||||||
|
KillMode=mixed
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
msg_ok "Created Service"
|
||||||
|
|
||||||
|
msg_info "Creating Initial Admin User"
|
||||||
|
systemctl start nginx-ui
|
||||||
|
sleep 3
|
||||||
|
systemctl stop nginx-ui
|
||||||
|
sleep 1
|
||||||
|
/usr/local/bin/nginx-ui reset-password --config /usr/local/etc/nginx-ui/app.ini &>/tmp/nginx-ui-reset.log || true
|
||||||
|
ADMIN_PASS=$(grep -oP 'Password: \K\S+' /tmp/nginx-ui-reset.log || echo "admin")
|
||||||
|
echo -e "Nginx-UI Credentials\nUsername: admin\nPassword: $ADMIN_PASS" >~/nginx-ui.creds
|
||||||
|
rm -f /tmp/nginx-ui-reset.log
|
||||||
|
msg_ok "Created Initial Admin User"
|
||||||
|
|
||||||
|
msg_info "Starting Service"
|
||||||
|
systemctl enable -q --now nginx-ui
|
||||||
|
rm -rf /etc/nginx/sites-enabled/default
|
||||||
|
msg_ok "Started Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
213
install/opencloud-install.sh
Normal file
213
install/opencloud-install.sh
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: vhsdream
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://opencloud.eu
|
||||||
|
|
||||||
|
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||||
|
color
|
||||||
|
verb_ip6
|
||||||
|
catch_errors
|
||||||
|
setting_up_container
|
||||||
|
network_check
|
||||||
|
update_os
|
||||||
|
|
||||||
|
MAX_ATTEMPTS=3
|
||||||
|
servers=("opencloud" "collabora" "wopi")
|
||||||
|
attempt=0
|
||||||
|
for server in "${servers[@]}"; do
|
||||||
|
until ((attempt >= MAX_ATTEMPTS)); do
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
read -rp "${TAB3}Enter the FQDN of your ${server^} server (ATTEMPT $attempt/$MAX_ATTEMPTS) (eg $server.domain.tld): " fqdn
|
||||||
|
if [[ -z "$fqdn" ]]; then
|
||||||
|
msg_warn "Domain cannot be empty!"
|
||||||
|
elif [[ "$fqdn" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
|
||||||
|
msg_warn "IP address not allowed! Please use a FQDN"
|
||||||
|
elif [[ "$fqdn" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$ ]]; then
|
||||||
|
export ${server^^}_FQDN="$fqdn"
|
||||||
|
attempt=0
|
||||||
|
break
|
||||||
|
else
|
||||||
|
msg_warn "Invalid domain format!"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if ((attempt >= MAX_ATTEMPTS)); then
|
||||||
|
msg_error "No more attempts - aborting script!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
msg_info "Installing Collabora Online"
|
||||||
|
curl -fsSL https://collaboraoffice.com/downloads/gpg/collaboraonline-release-keyring.gpg -o /etc/apt/keyrings/collaboraonline-release-keyring.gpg
|
||||||
|
cat <<EOF >/etc/apt/sources.list.d/colloboraonline.sources
|
||||||
|
Types: deb
|
||||||
|
URIs: https://www.collaboraoffice.com/repos/CollaboraOnline/CODE-deb
|
||||||
|
Suites: ./
|
||||||
|
Signed-By: /etc/apt/keyrings/collaboraonline-release-keyring.gpg
|
||||||
|
EOF
|
||||||
|
$STD apt-get update
|
||||||
|
$STD apt-get install -y coolwsd code-brand
|
||||||
|
systemctl stop coolwsd
|
||||||
|
mkdir -p /etc/systemd/system/coolwsd.service.d
|
||||||
|
cat <<EOF >/etc/systemd/system/coolwsd.service.d/override.conf
|
||||||
|
[Unit]
|
||||||
|
Before=opencloud-wopi.service
|
||||||
|
EOF
|
||||||
|
systemctl daemon-reload
|
||||||
|
COOLPASS="$(openssl rand -base64 36)"
|
||||||
|
$STD sudo -u cool coolconfig set-admin-password --user=admin --password="$COOLPASS"
|
||||||
|
echo "$COOLPASS" >~/.coolpass
|
||||||
|
msg_ok "Installed Collabora Online"
|
||||||
|
|
||||||
|
fetch_and_deploy_gh_release "opencloud" "opencloud-eu/opencloud" "singlefile" "v5.0.1" "/usr/bin" "opencloud-*-linux-amd64"
|
||||||
|
|
||||||
|
msg_info "Configuring OpenCloud"
|
||||||
|
DATA_DIR="/var/lib/opencloud/"
|
||||||
|
CONFIG_DIR="/etc/opencloud"
|
||||||
|
ENV_FILE="${CONFIG_DIR}/opencloud.env"
|
||||||
|
mkdir -p "$DATA_DIR" "$CONFIG_DIR"/assets/apps
|
||||||
|
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/opencloud-eu/opencloud-compose/refs/heads/main/config/opencloud/csp.yaml -o "$CONFIG_DIR"/csp.yaml
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/opencloud-eu/opencloud-compose/refs/heads/main/config/opencloud/proxy.yaml -o "$CONFIG_DIR"/proxy.yaml.bak
|
||||||
|
|
||||||
|
cat <<EOF >"$ENV_FILE"
|
||||||
|
OC_URL=https://${OPENCLOUD_FQDN}
|
||||||
|
OC_INSECURE=false
|
||||||
|
IDM_CREATE_DEMO_USERS=false
|
||||||
|
OC_LOG_LEVEL=warning
|
||||||
|
OC_CONFIG_DIR=${CONFIG_DIR}
|
||||||
|
OC_BASE_DATA_PATH=${DATA_DIR}
|
||||||
|
STORAGE_SYSTEM_OC_ROOT=${DATA_DIR}/storage/metadata
|
||||||
|
|
||||||
|
## Web
|
||||||
|
WEB_ASSET_CORE_PATH=${CONFIG_DIR}/web/assets
|
||||||
|
WEB_ASSET_APPS_PATH=${CONFIG_DIR}/web/assets/apps
|
||||||
|
WEB_UI_CONFIG_FILE=${CONFIG_DIR}/web/config.json
|
||||||
|
# WEB_ASSET_THEMES_PATH=${CONFIG_DIR}/web/assets/themes
|
||||||
|
# WEB_UI_THEME_PATH=
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
FRONTEND_DISABLE_RADICALE=true
|
||||||
|
FRONTEND_GROUPWARE_ENABLED=false
|
||||||
|
GRAPH_INCLUDE_OCM_SHAREES=true
|
||||||
|
|
||||||
|
## Proxy
|
||||||
|
PROXY_TLS=false
|
||||||
|
PROXY_CSP_CONFIG_FILE_LOCATION=${CONFIG_DIR}/csp.yaml
|
||||||
|
|
||||||
|
## Collaboration - requires VALID TLS
|
||||||
|
COLLABORA_DOMAIN=${COLLABORA_FQDN}
|
||||||
|
COLLABORATION_APP_NAME="CollaboraOnline"
|
||||||
|
COLLABORATION_APP_PRODUCT="Collabora"
|
||||||
|
COLLABORATION_APP_ADDR=https://${COLLABORA_FQDN}
|
||||||
|
COLLABORATION_APP_INSECURE=false
|
||||||
|
COLLABORATION_HTTP_ADDR=0.0.0.0:9300
|
||||||
|
COLLABORATION_WOPI_SRC=https://${WOPI_FQDN}
|
||||||
|
COLLABORATION_JWT_SECRET=
|
||||||
|
|
||||||
|
## Notifications - Email settings
|
||||||
|
# NOTIFICATIONS_SMTP_HOST=
|
||||||
|
# NOTIFICATIONS_SMTP_PORT=
|
||||||
|
# NOTIFICATIONS_SMTP_SENDER=
|
||||||
|
# NOTIFICATIONS_SMTP_USERNAME=
|
||||||
|
# NOTIFICATIONS_SMTP_PASSWORD=
|
||||||
|
# NOTIFICATIONS_SMTP_AUTHENTICATION=login
|
||||||
|
## Encryption method. Possible values are 'starttls', 'ssltls' and 'none'
|
||||||
|
# NOTIFICATIONS_SMTP_ENCRYPTION=starttls
|
||||||
|
## Allow insecure connections. Defaults to false.
|
||||||
|
# NOTIFICATIONS_SMTP_INSECURE=false
|
||||||
|
|
||||||
|
## Start additional services at runtime
|
||||||
|
## Examples: notifications, antivirus etc.
|
||||||
|
## Do not uncomment unless configured above.
|
||||||
|
# OC_ADD_RUN_SERVICES="notifications"
|
||||||
|
|
||||||
|
## OpenID - via web browser
|
||||||
|
## uncomment for OpenID in general
|
||||||
|
# OC_EXCLUDE_RUN_SERVICES=idp
|
||||||
|
# OC_OIDC_ISSUER=<your auth URL>
|
||||||
|
# IDP_DOMAIN=<your auth URL>
|
||||||
|
# PROXY_OIDC_ACCESS_TOKEN_VERIFY_METHOD=none
|
||||||
|
# PROXY_OIDC_REWRITE_WELLKNOWN=true
|
||||||
|
# PROXY_USER_OIDC_CLAIM=preferred_username
|
||||||
|
# PROXY_USER_CS3_CLAIM=username
|
||||||
|
## automatically create accounts
|
||||||
|
# PROXY_AUTOPROVISION_ACCOUNTS=true
|
||||||
|
# WEB_OIDC_SCOPE=openid profile email groups
|
||||||
|
# GRAPH_ASSIGN_DEFAULT_USER_ROLE=false
|
||||||
|
#
|
||||||
|
## uncomment below if using PocketID
|
||||||
|
# WEB_OIDC_CLIENT_ID=<generated in PocketID>
|
||||||
|
# WEB_OIDC_METADATA_URL=<your auth URL>/.well-known/openid-configuration
|
||||||
|
|
||||||
|
## Full Text Search - Apache Tika
|
||||||
|
## Requires a separate install of Tika - see https://community-scripts.github.io/ProxmoxVE/scripts?id=apache-tika
|
||||||
|
# SEARCH_EXTRACTOR_TYPE=tika
|
||||||
|
# FRONTEND_FULL_TEXT_SEARCH_ENABLED=true
|
||||||
|
# SEARCH_EXTRACTOR_TIKA_TIKA_URL=<your-tika-url>
|
||||||
|
|
||||||
|
## External storage test - Only NFS v4.2+ is supported
|
||||||
|
## User files
|
||||||
|
# STORAGE_USERS_POSIX_ROOT=<path-to-your-bind_mount>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF >/etc/systemd/system/opencloud.service
|
||||||
|
[Unit]
|
||||||
|
Description=OpenCloud server
|
||||||
|
After=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=opencloud
|
||||||
|
Group=opencloud
|
||||||
|
EnvironmentFile=${ENV_FILE}
|
||||||
|
ExecStart=/usr/bin/opencloud server
|
||||||
|
Restart=always
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF >/etc/systemd/system/opencloud-wopi.service
|
||||||
|
[Unit]
|
||||||
|
Description=OpenCloud WOPI Server
|
||||||
|
Wants=coolwsd.service
|
||||||
|
After=opencloud.service coolwsd.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=opencloud
|
||||||
|
Group=opencloud
|
||||||
|
EnvironmentFile=${ENV_FILE}
|
||||||
|
ExecStartPre=/bin/sleep 10
|
||||||
|
ExecStart=/usr/bin/opencloud collaboration server
|
||||||
|
Restart=always
|
||||||
|
KillSignal=SIGKILL
|
||||||
|
KillMode=mixed
|
||||||
|
TimeoutStopSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
$STD sudo -u cool coolconfig set ssl.enable false
|
||||||
|
$STD sudo -u cool coolconfig set ssl.termination true
|
||||||
|
$STD sudo -u cool coolconfig set ssl.ssl_verification true
|
||||||
|
sed -i "s|CSP2\"/>|CSP2\">frame-ancestors https://${OPENCLOUD_FQDN}</content_security_policy>|" /etc/coolwsd/coolwsd.xml
|
||||||
|
useradd -r -M -s /usr/sbin/nologin opencloud
|
||||||
|
chown -R opencloud:opencloud "$CONFIG_DIR" "$DATA_DIR"
|
||||||
|
sudo -u opencloud opencloud init --config-path "$CONFIG_DIR" --insecure no
|
||||||
|
OPENCLOUD_SECRET="$(sed -n '/jwt/p' "$CONFIG_DIR"/opencloud.yaml | awk '{print $2}')"
|
||||||
|
sed -i "s/JWT_SECRET=/&${OPENCLOUD_SECRET//&/\\&}/" "$ENV_FILE"
|
||||||
|
msg_ok "Configured OpenCloud"
|
||||||
|
|
||||||
|
msg_info "Starting services"
|
||||||
|
systemctl enable -q --now coolwsd opencloud
|
||||||
|
sleep 5
|
||||||
|
systemctl enable -q --now opencloud-wopi
|
||||||
|
msg_ok "Started services"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
@@ -23,7 +23,7 @@ msg_ok "Installed Dependencies"
|
|||||||
PG_VERSION=17 setup_postgresql
|
PG_VERSION=17 setup_postgresql
|
||||||
NODE_VERSION="24" setup_nodejs
|
NODE_VERSION="24" setup_nodejs
|
||||||
PG_DB_NAME="scanopy_db" PG_DB_USER="scanopy" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
|
PG_DB_NAME="scanopy_db" PG_DB_USER="scanopy" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db
|
||||||
fetch_and_deploy_gh_release "scanopy" "scanopy/scanopy" "tarball" "latest" "/opt/scanopy"
|
fetch_and_deploy_gh_release "Scanopy" "scanopy/scanopy" "tarball" "latest" "/opt/scanopy"
|
||||||
TOOLCHAIN="$(grep "channel" /opt/scanopy/backend/rust-toolchain.toml | awk -F\" '{print $2}')"
|
TOOLCHAIN="$(grep "channel" /opt/scanopy/backend/rust-toolchain.toml | awk -F\" '{print $2}')"
|
||||||
RUST_TOOLCHAIN=$TOOLCHAIN setup_rust
|
RUST_TOOLCHAIN=$TOOLCHAIN setup_rust
|
||||||
|
|
||||||
@@ -35,11 +35,11 @@ $STD npm ci --no-fund --no-audit
|
|||||||
$STD npm run build
|
$STD npm run build
|
||||||
msg_ok "Created frontend UI"
|
msg_ok "Created frontend UI"
|
||||||
|
|
||||||
msg_info "Building scanopy-server (patience)"
|
msg_info "Building Scanopy Server (patience)"
|
||||||
cd /opt/scanopy/backend
|
cd /opt/scanopy/backend
|
||||||
$STD cargo build --release --bin server
|
$STD cargo build --release --bin server
|
||||||
mv ./target/release/server /usr/bin/scanopy-server
|
mv ./target/release/server /usr/bin/scanopy-server
|
||||||
msg_ok "Built scanopy-server"
|
msg_ok "Built Scanopy Server"
|
||||||
|
|
||||||
msg_info "Configuring server for first-run"
|
msg_info "Configuring server for first-run"
|
||||||
cat <<EOF >/opt/scanopy/.env
|
cat <<EOF >/opt/scanopy/.env
|
||||||
|
|||||||
@@ -14,24 +14,32 @@ network_check
|
|||||||
update_os
|
update_os
|
||||||
|
|
||||||
msg_info "Installing Dependencies"
|
msg_info "Installing Dependencies"
|
||||||
$STD apt install -y \
|
$STD apt install -y coreutils
|
||||||
coreutils
|
|
||||||
msg_ok "Installed Dependencies"
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
msg_info "Setup SQL Server 2022"
|
msg_info "Setting up SQL Server 2022 Repository"
|
||||||
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc >/dev/null
|
setup_deb822_repo \
|
||||||
curl -fsSL https://packages.microsoft.com/config/ubuntu/22.04/mssql-server-2022.list | tee /etc/apt/sources.list.d/mssql-server-2022.list >/dev/null
|
"mssql-server-2022" \
|
||||||
$STD apt-get update -y
|
"https://packages.microsoft.com/keys/microsoft.asc" \
|
||||||
$STD apt-get install -y mssql-server
|
"https://packages.microsoft.com/ubuntu/22.04/mssql-server-2022" \
|
||||||
msg_ok "Setup Server 2022"
|
"./" \
|
||||||
|
""
|
||||||
|
msg_ok "Repository configured"
|
||||||
|
|
||||||
|
msg_info "Installing SQL Server 2022"
|
||||||
|
$STD apt install -y mssql-server
|
||||||
|
msg_ok "Installed SQL Server 2022"
|
||||||
|
|
||||||
msg_info "Installing SQL Server Tools"
|
msg_info "Installing SQL Server Tools"
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
export ACCEPT_EULA=Y
|
export ACCEPT_EULA=Y
|
||||||
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | tee /etc/apt/trusted.gpg.d/microsoft.asc >/dev/null
|
setup_deb822_repo \
|
||||||
curl -fsSL https://packages.microsoft.com/config/ubuntu/22.04/prod.list | tee /etc/apt/sources.list.d/mssql-release.list >/dev/null
|
"mssql-release" \
|
||||||
$STD apt-get update
|
"https://packages.microsoft.com/keys/microsoft.asc" \
|
||||||
$STD apt-get install -y -qq \
|
"https://packages.microsoft.com/ubuntu/22.04/prod" \
|
||||||
|
"jammy" \
|
||||||
|
"main"
|
||||||
|
$STD apt-get install -y \
|
||||||
mssql-tools18 \
|
mssql-tools18 \
|
||||||
unixodbc-dev
|
unixodbc-dev
|
||||||
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >>~/.bash_profile
|
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >>~/.bash_profile
|
||||||
@@ -49,6 +57,11 @@ msg_info "Start Service"
|
|||||||
systemctl enable -q --now mssql-server
|
systemctl enable -q --now mssql-server
|
||||||
msg_ok "Service started"
|
msg_ok "Service started"
|
||||||
|
|
||||||
|
msg_info "Cleaning up"
|
||||||
|
rm -f /etc/profile.d/debuginfod.sh
|
||||||
|
rm -f /etc/profile.d/debuginfod.csh
|
||||||
|
msg_ok "Cleaned up"
|
||||||
|
|
||||||
motd_ssh
|
motd_ssh
|
||||||
customize
|
customize
|
||||||
cleanup_lxc
|
cleanup_lxc
|
||||||
|
|||||||
66
install/sqlserver2025-install.sh
Normal file
66
install/sqlserver2025-install.sh
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#!/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://www.microsoft.com/en-us/sql-server/sql-server-2025
|
||||||
|
|
||||||
|
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 coreutils
|
||||||
|
msg_ok "Installed Dependencies"
|
||||||
|
|
||||||
|
msg_info "Setting up SQL Server 2025 Repository"
|
||||||
|
setup_deb822_repo \
|
||||||
|
"mssql-server-2025" \
|
||||||
|
"https://packages.microsoft.com/keys/microsoft.asc" \
|
||||||
|
"https://packages.microsoft.com/ubuntu/24.04/mssql-server-2025" \
|
||||||
|
"./" \
|
||||||
|
""
|
||||||
|
msg_ok "Repository configured"
|
||||||
|
|
||||||
|
msg_info "Installing SQL Server 2025"
|
||||||
|
$STD apt install -y mssql-server
|
||||||
|
msg_ok "Installed SQL Server 2025"
|
||||||
|
|
||||||
|
msg_info "Installing SQL Server Tools"
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
export ACCEPT_EULA=Y
|
||||||
|
setup_deb822_repo \
|
||||||
|
"mssql-release" \
|
||||||
|
"https://packages.microsoft.com/keys/microsoft.asc" \
|
||||||
|
"https://packages.microsoft.com/ubuntu/24.04/prod" \
|
||||||
|
"noble" \
|
||||||
|
"main"
|
||||||
|
$STD apt-get install -y \
|
||||||
|
mssql-tools18 \
|
||||||
|
unixodbc-dev
|
||||||
|
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >>~/.bash_profile
|
||||||
|
source ~/.bash_profile
|
||||||
|
msg_ok "Installed SQL Server Tools"
|
||||||
|
|
||||||
|
read -r -p "${TAB3}Do you want to run the SQL Server setup now? (Later is also possible) <y/N>" prompt
|
||||||
|
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
/opt/mssql/bin/mssql-conf setup
|
||||||
|
else
|
||||||
|
msg_ok "Skipping SQL Server setup. You can run it later with '/opt/mssql/bin/mssql-conf setup'."
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Starting SQL Server Service"
|
||||||
|
systemctl enable -q --now mssql-server
|
||||||
|
msg_ok "Service started"
|
||||||
|
|
||||||
|
msg_info "Cleaning up"
|
||||||
|
rm -f /etc/profile.d/debuginfod.sh /etc/profile.d/debuginfod.csh
|
||||||
|
msg_ok "Cleaned up"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
66
install/wishlist-install.sh
Normal file
66
install/wishlist-install.sh
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: Dunky13
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/cmintey/wishlist
|
||||||
|
|
||||||
|
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 \
|
||||||
|
openssl \
|
||||||
|
caddy
|
||||||
|
msg_ok "Installed dependencies"
|
||||||
|
|
||||||
|
NODE_VERSION="24" NODE_MODULE="pnpm" setup_nodejs
|
||||||
|
fetch_and_deploy_gh_release "wishlist" "cmintey/wishlist" "tarball"
|
||||||
|
LATEST_APP_VERSION=$(get_latest_github_release "cmintey/wishlist")
|
||||||
|
|
||||||
|
msg_info "Installing Wishlist"
|
||||||
|
cd /opt/wishlist
|
||||||
|
cp .env.example .env
|
||||||
|
sed -i "s|^ORIGIN=.*|ORIGIN=http://${LOCAL_IP}:3280|" /opt/wishlist/.env
|
||||||
|
echo "" >>/opt/wishlist/.env
|
||||||
|
echo "NODE_ENV=production" >>/opt/wishlist/.env
|
||||||
|
$STD pnpm install
|
||||||
|
$STD pnpm svelte-kit sync
|
||||||
|
$STD pnpm prisma generate
|
||||||
|
sed -i 's|/usr/src/app/|/opt/wishlist/|g' $(grep -rl '/usr/src/app/' /opt/wishlist)
|
||||||
|
export VERSION="v${LATEST_APP_VERSION}"
|
||||||
|
export SHA="v${LATEST_APP_VERSION}"
|
||||||
|
$STD pnpm run build
|
||||||
|
$STD pnpm prune --prod
|
||||||
|
chmod +x /opt/wishlist/entrypoint.sh
|
||||||
|
mkdir -p /opt/wishlist/uploads
|
||||||
|
mkdir -p /opt/wishlist/data
|
||||||
|
msg_ok "Installed Wishlist"
|
||||||
|
|
||||||
|
msg_info "Creating Service"
|
||||||
|
cat <<EOF >/etc/systemd/system/wishlist.service
|
||||||
|
[Unit]
|
||||||
|
Description=Wishlist Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
WorkingDirectory=/opt/wishlist
|
||||||
|
EnvironmentFile=/opt/wishlist/.env
|
||||||
|
ExecStart=/usr/bin/env sh -c './entrypoint.sh'
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now wishlist
|
||||||
|
msg_ok "Created Service"
|
||||||
|
|
||||||
|
motd_ssh
|
||||||
|
customize
|
||||||
|
cleanup_lxc
|
||||||
@@ -28,13 +28,210 @@
|
|||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# These can be overridden before sourcing this library
|
# These can be overridden before sourcing this library
|
||||||
|
|
||||||
|
# Disable 'unbound variable' errors for this library (restored at end)
|
||||||
|
_OLD_SET_STATE=$(set +o | grep -E 'set -(e|u|o)')
|
||||||
|
set +u
|
||||||
|
|
||||||
CLOUDINIT_DEFAULT_USER="${CLOUDINIT_DEFAULT_USER:-root}"
|
CLOUDINIT_DEFAULT_USER="${CLOUDINIT_DEFAULT_USER:-root}"
|
||||||
CLOUDINIT_DNS_SERVERS="${CLOUDINIT_DNS_SERVERS:-1.1.1.1 8.8.8.8}"
|
CLOUDINIT_DNS_SERVERS="${CLOUDINIT_DNS_SERVERS:-1.1.1.1 8.8.8.8}"
|
||||||
CLOUDINIT_SEARCH_DOMAIN="${CLOUDINIT_SEARCH_DOMAIN:-local}"
|
CLOUDINIT_SEARCH_DOMAIN="${CLOUDINIT_SEARCH_DOMAIN:-local}"
|
||||||
CLOUDINIT_SSH_KEYS="${CLOUDINIT_SSH_KEYS:-/root/.ssh/authorized_keys}"
|
CLOUDINIT_SSH_KEYS="${CLOUDINIT_SSH_KEYS:-}" # Empty by default - user must explicitly provide keys
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# SECTION 2: HELPER FUNCTIONS
|
# SECTION 2: SSH KEY DISCOVERY AND SELECTION
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# _ci_ssh_extract_keys_from_file - Extracts valid SSH public keys from a file
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
function _ci_ssh_extract_keys_from_file() {
|
||||||
|
local file="$1"
|
||||||
|
[[ -f "$file" && -r "$file" ]] || return 0
|
||||||
|
grep -E '^(ssh-(rsa|ed25519|dss|ecdsa)|ecdsa-sha2-)' "$file" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# _ci_ssh_discover_files - Scans standard paths for SSH keys
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
function _ci_ssh_discover_files() {
|
||||||
|
local -a cand=()
|
||||||
|
shopt -s nullglob
|
||||||
|
cand+=(/root/.ssh/authorized_keys /root/.ssh/authorized_keys2)
|
||||||
|
cand+=(/root/.ssh/*.pub)
|
||||||
|
cand+=(/etc/ssh/authorized_keys /etc/ssh/authorized_keys.d/*)
|
||||||
|
shopt -u nullglob
|
||||||
|
printf '%s\0' "${cand[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# _ci_ssh_build_choices - Builds whiptail checklist from SSH key files
|
||||||
|
#
|
||||||
|
# Sets: CI_SSH_CHOICES (array), CI_SSH_COUNT (int), CI_SSH_MAPFILE (path)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
function _ci_ssh_build_choices() {
|
||||||
|
local -a files=("$@")
|
||||||
|
CI_SSH_CHOICES=()
|
||||||
|
CI_SSH_COUNT=0
|
||||||
|
CI_SSH_MAPFILE="$(mktemp)"
|
||||||
|
local id key typ fp cmt base
|
||||||
|
|
||||||
|
for f in "${files[@]}"; do
|
||||||
|
[[ -f "$f" && -r "$f" ]] || continue
|
||||||
|
base="$(basename -- "$f")"
|
||||||
|
# Skip known_hosts and private keys
|
||||||
|
case "$base" in
|
||||||
|
known_hosts | known_hosts.* | config) continue ;;
|
||||||
|
id_*) [[ "$f" != *.pub ]] && continue ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
while IFS= read -r key; do
|
||||||
|
[[ -n "$key" ]] || continue
|
||||||
|
|
||||||
|
typ=""
|
||||||
|
fp=""
|
||||||
|
cmt=""
|
||||||
|
read -r _typ _b64 _cmt <<<"$key"
|
||||||
|
typ="${_typ:-key}"
|
||||||
|
cmt="${_cmt:-}"
|
||||||
|
|
||||||
|
# Get fingerprint via ssh-keygen if available
|
||||||
|
if command -v ssh-keygen >/dev/null 2>&1; then
|
||||||
|
fp="$(printf '%s\n' "$key" | ssh-keygen -lf - 2>/dev/null | awk '{print $2}')"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Shorten long comments
|
||||||
|
[[ ${#cmt} -gt 40 ]] && cmt="${cmt:0:37}..."
|
||||||
|
|
||||||
|
CI_SSH_COUNT=$((CI_SSH_COUNT + 1))
|
||||||
|
id="K${CI_SSH_COUNT}"
|
||||||
|
echo "${id}|${key}" >>"$CI_SSH_MAPFILE"
|
||||||
|
CI_SSH_CHOICES+=("$id" "[$typ] ${fp:+$fp }${cmt:+$cmt }— ${base}" "OFF")
|
||||||
|
done < <(_ci_ssh_extract_keys_from_file "$f")
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# configure_cloudinit_ssh_keys - Interactive SSH key selection for Cloud-Init
|
||||||
|
#
|
||||||
|
# Usage: configure_cloudinit_ssh_keys
|
||||||
|
# Sets: CLOUDINIT_SSH_KEYS (path to temporary file with selected keys)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
function configure_cloudinit_ssh_keys() {
|
||||||
|
local backtitle="Proxmox VE Helper Scripts"
|
||||||
|
local ssh_key_mode
|
||||||
|
|
||||||
|
# Create temp file for selected keys
|
||||||
|
CLOUDINIT_SSH_KEYS_TEMP="$(mktemp)"
|
||||||
|
: >"$CLOUDINIT_SSH_KEYS_TEMP"
|
||||||
|
|
||||||
|
# Discover keys and build choices
|
||||||
|
IFS=$'\0' read -r -d '' -a _def_files < <(_ci_ssh_discover_files && printf '\0')
|
||||||
|
_ci_ssh_build_choices "${_def_files[@]}"
|
||||||
|
local default_key_count="$CI_SSH_COUNT"
|
||||||
|
|
||||||
|
if [[ "$default_key_count" -gt 0 ]]; then
|
||||||
|
ssh_key_mode=$(whiptail --backtitle "$backtitle" --title "SSH KEY SOURCE" --menu \
|
||||||
|
"Provision SSH keys for Cloud-Init VM:" 14 72 4 \
|
||||||
|
"found" "Select from detected keys (${default_key_count})" \
|
||||||
|
"manual" "Paste a single public key" \
|
||||||
|
"folder" "Scan another folder (path or glob)" \
|
||||||
|
"none" "No SSH keys (password auth only)" 3>&1 1>&2 2>&3) || return 1
|
||||||
|
else
|
||||||
|
ssh_key_mode=$(whiptail --backtitle "$backtitle" --title "SSH KEY SOURCE" --menu \
|
||||||
|
"No host keys detected. Choose:" 12 72 3 \
|
||||||
|
"manual" "Paste a single public key" \
|
||||||
|
"folder" "Scan another folder (path or glob)" \
|
||||||
|
"none" "No SSH keys (password auth only)" 3>&1 1>&2 2>&3) || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$ssh_key_mode" in
|
||||||
|
found)
|
||||||
|
# Show checklist with individual keys
|
||||||
|
local selection
|
||||||
|
selection=$(whiptail --backtitle "$backtitle" --title "SELECT SSH KEYS" \
|
||||||
|
--checklist "Select one or more keys to import:" 20 140 10 "${CI_SSH_CHOICES[@]}" 3>&1 1>&2 2>&3) || return 1
|
||||||
|
|
||||||
|
for tag in $selection; do
|
||||||
|
tag="${tag%\"}"
|
||||||
|
tag="${tag#\"}"
|
||||||
|
local line
|
||||||
|
line=$(grep -E "^${tag}\|" "$CI_SSH_MAPFILE" | head -n1 | cut -d'|' -f2-)
|
||||||
|
[[ -n "$line" ]] && printf '%s\n' "$line" >>"$CLOUDINIT_SSH_KEYS_TEMP"
|
||||||
|
done
|
||||||
|
local imported
|
||||||
|
imported=$(wc -l <"$CLOUDINIT_SSH_KEYS_TEMP")
|
||||||
|
echo -e "${ROOTSSH:- 🔑 }${BOLD}${DGN}SSH Keys: ${BGN}${imported} key(s) selected${CL}"
|
||||||
|
;;
|
||||||
|
manual)
|
||||||
|
local pubkey
|
||||||
|
pubkey=$(whiptail --backtitle "$backtitle" --title "PASTE SSH PUBLIC KEY" \
|
||||||
|
--inputbox "Paste your SSH public key (ssh-rsa, ssh-ed25519, etc.):" 10 76 3>&1 1>&2 2>&3) || return 1
|
||||||
|
if [[ -n "$pubkey" ]]; then
|
||||||
|
echo "$pubkey" >"$CLOUDINIT_SSH_KEYS_TEMP"
|
||||||
|
echo -e "${ROOTSSH:- 🔑 }${BOLD}${DGN}SSH Keys: ${BGN}1 key added manually${CL}"
|
||||||
|
else
|
||||||
|
echo -e "${ROOTSSH:- 🔑 }${BOLD}${DGN}SSH Keys: ${BGN}none (empty input)${CL}"
|
||||||
|
CLOUDINIT_SSH_KEYS=""
|
||||||
|
rm -f "$CLOUDINIT_SSH_KEYS_TEMP" "$CI_SSH_MAPFILE" 2>/dev/null
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
folder)
|
||||||
|
local glob_path
|
||||||
|
glob_path=$(whiptail --backtitle "$backtitle" --title "SCAN FOLDER/GLOB" \
|
||||||
|
--inputbox "Enter a folder or glob to scan (e.g. /root/.ssh/*.pub):" 10 72 3>&1 1>&2 2>&3) || return 1
|
||||||
|
if [[ -n "$glob_path" ]]; then
|
||||||
|
shopt -s nullglob
|
||||||
|
local -a _scan_files=($glob_path)
|
||||||
|
shopt -u nullglob
|
||||||
|
if [[ "${#_scan_files[@]}" -gt 0 ]]; then
|
||||||
|
_ci_ssh_build_choices "${_scan_files[@]}"
|
||||||
|
if [[ "$CI_SSH_COUNT" -gt 0 ]]; then
|
||||||
|
local folder_selection
|
||||||
|
folder_selection=$(whiptail --backtitle "$backtitle" --title "SELECT FOLDER KEYS" \
|
||||||
|
--checklist "Select key(s) to import:" 20 140 10 "${CI_SSH_CHOICES[@]}" 3>&1 1>&2 2>&3) || return 1
|
||||||
|
for tag in $folder_selection; do
|
||||||
|
tag="${tag%\"}"
|
||||||
|
tag="${tag#\"}"
|
||||||
|
local line
|
||||||
|
line=$(grep -E "^${tag}\|" "$CI_SSH_MAPFILE" | head -n1 | cut -d'|' -f2-)
|
||||||
|
[[ -n "$line" ]] && printf '%s\n' "$line" >>"$CLOUDINIT_SSH_KEYS_TEMP"
|
||||||
|
done
|
||||||
|
local imported
|
||||||
|
imported=$(wc -l <"$CLOUDINIT_SSH_KEYS_TEMP")
|
||||||
|
echo -e "${ROOTSSH:- 🔑 }${BOLD}${DGN}SSH Keys: ${BGN}${imported} key(s) from folder${CL}"
|
||||||
|
else
|
||||||
|
whiptail --backtitle "$backtitle" --msgbox "No keys found in: $glob_path" 8 60
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
whiptail --backtitle "$backtitle" --msgbox "Path/glob returned no files." 8 60
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
none | *)
|
||||||
|
echo -e "${ROOTSSH:- 🔑 }${BOLD}${DGN}SSH Keys: ${BGN}none (password auth only)${CL}"
|
||||||
|
CLOUDINIT_SSH_KEYS=""
|
||||||
|
rm -f "$CLOUDINIT_SSH_KEYS_TEMP" "$CI_SSH_MAPFILE" 2>/dev/null
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Cleanup mapfile
|
||||||
|
rm -f "$CI_SSH_MAPFILE" 2>/dev/null
|
||||||
|
|
||||||
|
# Set the variable for setup_cloud_init to use
|
||||||
|
if [[ -s "$CLOUDINIT_SSH_KEYS_TEMP" ]]; then
|
||||||
|
CLOUDINIT_SSH_KEYS="$CLOUDINIT_SSH_KEYS_TEMP"
|
||||||
|
else
|
||||||
|
CLOUDINIT_SSH_KEYS=""
|
||||||
|
rm -f "$CLOUDINIT_SSH_KEYS_TEMP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SECTION 3: HELPER FUNCTIONS
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -144,9 +341,10 @@ function setup_cloud_init() {
|
|||||||
local cipassword=$(openssl rand -base64 16)
|
local cipassword=$(openssl rand -base64 16)
|
||||||
qm set "$vmid" --cipassword "$cipassword" >/dev/null
|
qm set "$vmid" --cipassword "$cipassword" >/dev/null
|
||||||
|
|
||||||
# Add SSH keys if available
|
# Add SSH keys only if explicitly provided (not auto-imported from host)
|
||||||
if [ -f "$CLOUDINIT_SSH_KEYS" ]; then
|
if [ -n "${CLOUDINIT_SSH_KEYS:-}" ] && [ -f "$CLOUDINIT_SSH_KEYS" ]; then
|
||||||
qm set "$vmid" --sshkeys "$CLOUDINIT_SSH_KEYS" >/dev/null 2>&1 || true
|
qm set "$vmid" --sshkeys "$CLOUDINIT_SSH_KEYS" >/dev/null 2>&1 || true
|
||||||
|
_ci_msg_info "SSH keys imported from: $CLOUDINIT_SSH_KEYS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Configure network
|
# Configure network
|
||||||
@@ -459,6 +657,11 @@ export -f wait_for_cloud_init 2>/dev/null || true
|
|||||||
export -f validate_ip_cidr 2>/dev/null || true
|
export -f validate_ip_cidr 2>/dev/null || true
|
||||||
export -f validate_ip 2>/dev/null || true
|
export -f validate_ip 2>/dev/null || true
|
||||||
|
|
||||||
|
# Restore previous shell options if they were saved
|
||||||
|
if [ -n "${_OLD_SET_STATE:-}" ]; then
|
||||||
|
eval "$_OLD_SET_STATE"
|
||||||
|
fi
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# SECTION 7: EXAMPLES & DOCUMENTATION
|
# SECTION 7: EXAMPLES & DOCUMENTATION
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|||||||
620
misc/vm-core.func
Normal file
620
misc/vm-core.func
Normal file
@@ -0,0 +1,620 @@
|
|||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/LICENSE
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
SPINNER_PID=""
|
||||||
|
SPINNER_ACTIVE=0
|
||||||
|
SPINNER_MSG=""
|
||||||
|
declare -A MSG_INFO_SHOWN
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Loads core utility groups once (colors, formatting, icons, defaults).
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[[ -n "${_CORE_FUNC_LOADED:-}" ]] && return
|
||||||
|
_CORE_FUNC_LOADED=1
|
||||||
|
|
||||||
|
load_functions() {
|
||||||
|
[[ -n "${__FUNCTIONS_LOADED:-}" ]] && return
|
||||||
|
__FUNCTIONS_LOADED=1
|
||||||
|
color
|
||||||
|
formatting
|
||||||
|
icons
|
||||||
|
default_vars
|
||||||
|
set_std_mode
|
||||||
|
shell_check
|
||||||
|
get_valid_nextid
|
||||||
|
cleanup_vmid
|
||||||
|
cleanup
|
||||||
|
check_root
|
||||||
|
pve_check
|
||||||
|
arch_check
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to download & save header files
|
||||||
|
get_header() {
|
||||||
|
local app_name=$(echo "${APP,,}" | tr ' ' '-')
|
||||||
|
local app_type=${APP_TYPE:-vm}
|
||||||
|
local header_url="https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/${app_type}/headers/${app_name}"
|
||||||
|
local local_header_path="/usr/local/community-scripts/headers/${app_type}/${app_name}"
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$local_header_path")"
|
||||||
|
|
||||||
|
if [ ! -s "$local_header_path" ]; then
|
||||||
|
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat "$local_header_path" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
header_info() {
|
||||||
|
local app_name=$(echo "${APP,,}" | tr ' ' '-')
|
||||||
|
local header_content
|
||||||
|
|
||||||
|
header_content=$(get_header "$app_name") || header_content=""
|
||||||
|
|
||||||
|
clear
|
||||||
|
local term_width
|
||||||
|
term_width=$(tput cols 2>/dev/null || echo 120)
|
||||||
|
|
||||||
|
if [ -n "$header_content" ]; then
|
||||||
|
echo "$header_content"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Sets ANSI color codes used for styled terminal output.
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
color() {
|
||||||
|
YW=$(echo "\033[33m")
|
||||||
|
YWB=$(echo "\033[93m")
|
||||||
|
BL=$(echo "\033[36m")
|
||||||
|
RD=$(echo "\033[01;31m")
|
||||||
|
BGN=$(echo "\033[4;92m")
|
||||||
|
GN=$(echo "\033[1;92m")
|
||||||
|
DGN=$(echo "\033[32m")
|
||||||
|
CL=$(echo "\033[m")
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Defines formatting helpers like tab, bold, and line reset sequences.
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
formatting() {
|
||||||
|
BFR="\\r\\033[K"
|
||||||
|
BOLD=$(echo "\033[1m")
|
||||||
|
HOLD=" "
|
||||||
|
TAB=" "
|
||||||
|
TAB3=" "
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Sets symbolic icons used throughout user feedback and prompts.
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
icons() {
|
||||||
|
CM="${TAB}✔️${TAB}"
|
||||||
|
CROSS="${TAB}✖️${TAB}"
|
||||||
|
DNSOK="✔️ "
|
||||||
|
DNSFAIL="${TAB}✖️${TAB}"
|
||||||
|
INFO="${TAB}💡${TAB}${CL}"
|
||||||
|
OS="${TAB}🖥️${TAB}${CL}"
|
||||||
|
OSVERSION="${TAB}🌟${TAB}${CL}"
|
||||||
|
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
|
||||||
|
DISKSIZE="${TAB}💾${TAB}${CL}"
|
||||||
|
CPUCORE="${TAB}🧠${TAB}${CL}"
|
||||||
|
RAMSIZE="${TAB}🛠️${TAB}${CL}"
|
||||||
|
SEARCH="${TAB}🔍${TAB}${CL}"
|
||||||
|
VERBOSE_CROPPED="🔍${TAB}"
|
||||||
|
VERIFYPW="${TAB}🔐${TAB}${CL}"
|
||||||
|
CONTAINERID="${TAB}🆔${TAB}${CL}"
|
||||||
|
HOSTNAME="${TAB}🏠${TAB}${CL}"
|
||||||
|
BRIDGE="${TAB}🌉${TAB}${CL}"
|
||||||
|
NETWORK="${TAB}📡${TAB}${CL}"
|
||||||
|
GATEWAY="${TAB}🌐${TAB}${CL}"
|
||||||
|
DISABLEIPV6="${TAB}🚫${TAB}${CL}"
|
||||||
|
ICON_DISABLEIPV6="${TAB}🚫${TAB}${CL}"
|
||||||
|
DEFAULT="${TAB}⚙️${TAB}${CL}"
|
||||||
|
MACADDRESS="${TAB}🔗${TAB}${CL}"
|
||||||
|
VLANTAG="${TAB}🏷️${TAB}${CL}"
|
||||||
|
ROOTSSH="${TAB}🔑${TAB}${CL}"
|
||||||
|
CREATING="${TAB}🚀${TAB}${CL}"
|
||||||
|
ADVANCED="${TAB}🧩${TAB}${CL}"
|
||||||
|
FUSE="${TAB}🗂️${TAB}${CL}"
|
||||||
|
GPU="${TAB}🎮${TAB}${CL}"
|
||||||
|
HOURGLASS="${TAB}⏳${TAB}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Sets default verbose mode for script and os execution.
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
set_std_mode() {
|
||||||
|
if [ "${VERBOSE:-no}" = "yes" ]; then
|
||||||
|
STD=""
|
||||||
|
else
|
||||||
|
STD="silent"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# default_vars()
|
||||||
|
#
|
||||||
|
# - Sets default retry and wait variables used for system actions
|
||||||
|
# - RETRY_NUM: Maximum number of retry attempts (default: 10)
|
||||||
|
# - RETRY_EVERY: Seconds to wait between retries (default: 3)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
default_vars() {
|
||||||
|
RETRY_NUM=10
|
||||||
|
RETRY_EVERY=3
|
||||||
|
i=$RETRY_NUM
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# get_active_logfile()
|
||||||
|
#
|
||||||
|
# - Returns the appropriate log file based on execution context
|
||||||
|
# - BUILD_LOG: Host operations (VM creation)
|
||||||
|
# - Fallback to /tmp/build-<timestamp>.log if not set
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
get_active_logfile() {
|
||||||
|
if [[ -n "${BUILD_LOG:-}" ]]; then
|
||||||
|
echo "$BUILD_LOG"
|
||||||
|
else
|
||||||
|
# Fallback for legacy scripts
|
||||||
|
echo "/tmp/build-$(date +%Y%m%d_%H%M%S).log"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# silent()
|
||||||
|
#
|
||||||
|
# - Executes command with output redirected to active log file
|
||||||
|
# - On error: displays last 10 lines of log and exits with original exit code
|
||||||
|
# - Temporarily disables error trap to capture exit code correctly
|
||||||
|
# - Sources explain_exit_code() for detailed error messages
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
silent() {
|
||||||
|
local cmd="$*"
|
||||||
|
local caller_line="${BASH_LINENO[0]:-unknown}"
|
||||||
|
local logfile="$(get_active_logfile)"
|
||||||
|
|
||||||
|
set +Eeuo pipefail
|
||||||
|
trap - ERR
|
||||||
|
|
||||||
|
"$@" >>"$logfile" 2>&1
|
||||||
|
local rc=$?
|
||||||
|
|
||||||
|
set -Eeuo pipefail
|
||||||
|
trap 'error_handler' ERR
|
||||||
|
|
||||||
|
if [[ $rc -ne 0 ]]; then
|
||||||
|
# Source explain_exit_code if needed
|
||||||
|
if ! declare -f explain_exit_code >/dev/null 2>&1; then
|
||||||
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/misc/error_handler.func) 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
local explanation=""
|
||||||
|
if declare -f explain_exit_code >/dev/null 2>&1; then
|
||||||
|
explanation="$(explain_exit_code "$rc")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "\e[?25h"
|
||||||
|
if [[ -n "$explanation" ]]; then
|
||||||
|
msg_error "in line ${caller_line}: exit code ${rc} (${explanation})"
|
||||||
|
else
|
||||||
|
msg_error "in line ${caller_line}: exit code ${rc}"
|
||||||
|
fi
|
||||||
|
msg_custom "→" "${YWB}" "${cmd}"
|
||||||
|
|
||||||
|
if [[ -s "$logfile" ]]; then
|
||||||
|
local log_lines=$(wc -l <"$logfile")
|
||||||
|
echo "--- Last 10 lines of log ---"
|
||||||
|
tail -n 10 "$logfile"
|
||||||
|
echo "----------------------------"
|
||||||
|
|
||||||
|
# Show how to view full log if there are more lines
|
||||||
|
if [[ $log_lines -gt 10 ]]; then
|
||||||
|
msg_custom "📋" "${YW}" "View full log (${log_lines} lines): ${logfile}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit "$rc"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Performs a curl request with retry logic and inline feedback.
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
run_curl() {
|
||||||
|
if [ "$VERB" = "no" ]; then
|
||||||
|
curl "$@" >/dev/null 2>>/tmp/curl_error.log
|
||||||
|
else
|
||||||
|
curl "$@" 2>>/tmp/curl_error.log
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_handler() {
|
||||||
|
local args=()
|
||||||
|
local url=""
|
||||||
|
local max_retries=0 delay=2 attempt=1
|
||||||
|
local exit_code has_output_file=false
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [[ "$arg" != -* && -z "$url" ]]; then
|
||||||
|
url="$arg"
|
||||||
|
fi
|
||||||
|
[[ "$arg" == "-o" || "$arg" == --output ]] && has_output_file=true
|
||||||
|
args+=("$arg")
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "$url" ]]; then
|
||||||
|
msg_error "no valid url or option entered for curl_handler"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$STD msg_info "Fetching: $url"
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
if $has_output_file; then
|
||||||
|
$STD run_curl "${args[@]}"
|
||||||
|
exit_code=$?
|
||||||
|
else
|
||||||
|
$STD result=$(run_curl "${args[@]}")
|
||||||
|
exit_code=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $exit_code -eq 0 ]]; then
|
||||||
|
stop_spinner
|
||||||
|
msg_ok "Fetched: $url"
|
||||||
|
$has_output_file || printf '%s' "$result"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ((attempt >= max_retries)); then
|
||||||
|
stop_spinner
|
||||||
|
if [ -s /tmp/curl_error.log ]; then
|
||||||
|
local curl_stderr
|
||||||
|
curl_stderr=$(</tmp/curl_error.log)
|
||||||
|
rm -f /tmp/curl_error.log
|
||||||
|
fi
|
||||||
|
__curl_err_handler "$exit_code" "$url" "$curl_stderr"
|
||||||
|
exit 1 # hard exit if exit_code is not 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
$STD printf "\r\033[K${INFO}${YW}Retry $attempt/$max_retries in ${delay}s...${CL}" >&2
|
||||||
|
sleep "$delay"
|
||||||
|
((attempt++))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Handles specific curl error codes and displays descriptive messages.
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
__curl_err_handler() {
|
||||||
|
local exit_code="$1"
|
||||||
|
local target="$2"
|
||||||
|
local curl_msg="$3"
|
||||||
|
|
||||||
|
case $exit_code in
|
||||||
|
1) msg_error "Unsupported protocol: $target" ;;
|
||||||
|
2) msg_error "Curl init failed: $target" ;;
|
||||||
|
3) msg_error "Malformed URL: $target" ;;
|
||||||
|
5) msg_error "Proxy resolution failed: $target" ;;
|
||||||
|
6) msg_error "Host resolution failed: $target" ;;
|
||||||
|
7) msg_error "Connection failed: $target" ;;
|
||||||
|
9) msg_error "Access denied: $target" ;;
|
||||||
|
18) msg_error "Partial file transfer: $target" ;;
|
||||||
|
22) msg_error "HTTP error (e.g. 400/404): $target" ;;
|
||||||
|
23) msg_error "Write error on local system: $target" ;;
|
||||||
|
26) msg_error "Read error from local file: $target" ;;
|
||||||
|
28) msg_error "Timeout: $target" ;;
|
||||||
|
35) msg_error "SSL connect error: $target" ;;
|
||||||
|
47) msg_error "Too many redirects: $target" ;;
|
||||||
|
51) msg_error "SSL cert verify failed: $target" ;;
|
||||||
|
52) msg_error "Empty server response: $target" ;;
|
||||||
|
55) msg_error "Send error: $target" ;;
|
||||||
|
56) msg_error "Receive error: $target" ;;
|
||||||
|
60) msg_error "SSL CA not trusted: $target" ;;
|
||||||
|
67) msg_error "Login denied by server: $target" ;;
|
||||||
|
78) msg_error "Remote file not found (404): $target" ;;
|
||||||
|
*) msg_error "Curl failed with code $exit_code: $target" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[[ -n "$curl_msg" ]] && printf "%s\n" "$curl_msg" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# shell_check()
|
||||||
|
#
|
||||||
|
# - Verifies that the script is running under Bash shell
|
||||||
|
# - Exits with error message if different shell is detected
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
shell_check() {
|
||||||
|
if [[ "$(ps -p $$ -o comm=)" != "bash" ]]; then
|
||||||
|
clear
|
||||||
|
msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell."
|
||||||
|
echo -e "\nExiting..."
|
||||||
|
sleep 2
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# clear_line()
|
||||||
|
#
|
||||||
|
# - Clears current terminal line using tput or ANSI escape codes
|
||||||
|
# - Moves cursor to beginning of line (carriage return)
|
||||||
|
# - Fallback to ANSI codes if tput not available
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
clear_line() {
|
||||||
|
tput cr 2>/dev/null || echo -en "\r"
|
||||||
|
tput el 2>/dev/null || echo -en "\033[K"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# is_verbose_mode()
|
||||||
|
#
|
||||||
|
# - Determines if script should run in verbose mode
|
||||||
|
# - Checks VERBOSE and var_verbose variables
|
||||||
|
# - Also returns true if not running in TTY (pipe/redirect scenario)
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
is_verbose_mode() {
|
||||||
|
local verbose="${VERBOSE:-${var_verbose:-no}}"
|
||||||
|
[[ "$verbose" != "no" || ! -t 2 ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
### dev spinner ###
|
||||||
|
SPINNER_ACTIVE=0
|
||||||
|
SPINNER_PID=""
|
||||||
|
SPINNER_MSG=""
|
||||||
|
declare -A MSG_INFO_SHOWN=()
|
||||||
|
|
||||||
|
# Trap cleanup on various signals
|
||||||
|
trap 'cleanup_spinner' EXIT INT TERM HUP
|
||||||
|
|
||||||
|
# Cleans up spinner process on exit
|
||||||
|
cleanup_spinner() {
|
||||||
|
stop_spinner
|
||||||
|
# Additional cleanup if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
start_spinner() {
|
||||||
|
local msg="${1:-Processing...}"
|
||||||
|
local frames=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
|
||||||
|
local spin_i=0
|
||||||
|
local interval=0.1
|
||||||
|
|
||||||
|
# Set message and clear current line
|
||||||
|
SPINNER_MSG="$msg"
|
||||||
|
printf "\r\e[2K" >&2
|
||||||
|
|
||||||
|
# Stop any existing spinner
|
||||||
|
stop_spinner
|
||||||
|
|
||||||
|
# Set active flag
|
||||||
|
SPINNER_ACTIVE=1
|
||||||
|
|
||||||
|
# Start spinner in background
|
||||||
|
{
|
||||||
|
while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do
|
||||||
|
printf "\r\e[2K%s %b" "${TAB}${frames[spin_i]}${TAB}" "${YW}${SPINNER_MSG}${CL}" >&2
|
||||||
|
spin_i=$(((spin_i + 1) % ${#frames[@]}))
|
||||||
|
sleep "$interval"
|
||||||
|
done
|
||||||
|
} &
|
||||||
|
|
||||||
|
SPINNER_PID=$!
|
||||||
|
|
||||||
|
# Disown to prevent getting "Terminated" messages
|
||||||
|
disown "$SPINNER_PID" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_spinner() {
|
||||||
|
# Check if spinner is active and PID exists
|
||||||
|
if [[ "$SPINNER_ACTIVE" -eq 1 ]] && [[ -n "${SPINNER_PID}" ]]; then
|
||||||
|
SPINNER_ACTIVE=0
|
||||||
|
|
||||||
|
if kill -0 "$SPINNER_PID" 2>/dev/null; then
|
||||||
|
kill "$SPINNER_PID" 2>/dev/null
|
||||||
|
# Give it a moment to terminate
|
||||||
|
sleep 0.1
|
||||||
|
# Force kill if still running
|
||||||
|
if kill -0 "$SPINNER_PID" 2>/dev/null; then
|
||||||
|
kill -9 "$SPINNER_PID" 2>/dev/null
|
||||||
|
fi
|
||||||
|
# Wait for process but ignore errors
|
||||||
|
wait "$SPINNER_PID" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clear spinner line
|
||||||
|
printf "\r\e[2K" >&2
|
||||||
|
SPINNER_PID=""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
spinner_guard() {
|
||||||
|
# Safely stop spinner if it's running
|
||||||
|
if [[ "$SPINNER_ACTIVE" -eq 1 ]] && [[ -n "${SPINNER_PID}" ]]; then
|
||||||
|
stop_spinner
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_info() {
|
||||||
|
local msg="${1:-Information message}"
|
||||||
|
|
||||||
|
# Only show each message once unless reset
|
||||||
|
if [[ -n "${MSG_INFO_SHOWN["$msg"]+x}" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
MSG_INFO_SHOWN["$msg"]=1
|
||||||
|
|
||||||
|
spinner_guard
|
||||||
|
start_spinner "$msg"
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_ok() {
|
||||||
|
local msg="${1:-Operation completed successfully}"
|
||||||
|
stop_spinner
|
||||||
|
printf "\r\e[2K%s %b\n" "${CM}" "${GN}${msg}${CL}" >&2
|
||||||
|
|
||||||
|
# Remove from shown messages to allow it to be shown again
|
||||||
|
local sanitized_msg
|
||||||
|
sanitized_msg=$(printf '%s' "$msg" | sed 's/\x1b\[[0-9;]*m//g; s/[^a-zA-Z0-9_]/_/g')
|
||||||
|
unset 'MSG_INFO_SHOWN['"$sanitized_msg"']' 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_error() {
|
||||||
|
local msg="${1:-An error occurred}"
|
||||||
|
stop_spinner
|
||||||
|
printf "\r\e[2K%s %b\n" "${CROSS}" "${RD}${msg}${CL}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_warn() {
|
||||||
|
stop_spinner
|
||||||
|
local msg="$1"
|
||||||
|
echo -e "${BFR:-}${INFO:-ℹ️} ${YWB}${msg}${CL}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper function to display a message with custom symbol and color
|
||||||
|
msg_custom() {
|
||||||
|
local symbol="${1:-*}"
|
||||||
|
local color="${2:-$CL}"
|
||||||
|
local msg="${3:-Custom message}"
|
||||||
|
[[ -z "$msg" ]] && return
|
||||||
|
stop_spinner
|
||||||
|
printf "\r\e[2K%s %b\n" "$symbol" "${color}${msg}${CL}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# msg_debug()
|
||||||
|
#
|
||||||
|
# - Displays debug message with timestamp when var_full_verbose=1
|
||||||
|
# - Automatically enables var_verbose if not already set
|
||||||
|
# - Uses bright yellow color for debug output
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
msg_debug() {
|
||||||
|
if [[ "${var_full_verbose:-0}" == "1" ]]; then
|
||||||
|
[[ "${var_verbose:-0}" != "1" ]] && var_verbose=1
|
||||||
|
echo -e "${YWB}[$(date '+%F %T')] [DEBUG]${CL} $*"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Displays error message and immediately terminates script
|
||||||
|
fatal() {
|
||||||
|
msg_error "$1"
|
||||||
|
kill -INT $$
|
||||||
|
}
|
||||||
|
|
||||||
|
get_valid_nextid() {
|
||||||
|
local try_id
|
||||||
|
try_id=$(pvesh get /cluster/nextid)
|
||||||
|
while true; do
|
||||||
|
if [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; then
|
||||||
|
try_id=$((try_id + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if lvs --noheadings -o lv_name | grep -qE "(^|[-_])${try_id}($|[-_])"; then
|
||||||
|
try_id=$((try_id + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
break
|
||||||
|
done
|
||||||
|
echo "$try_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_vmid() {
|
||||||
|
if [[ -z "${VMID:-}" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if qm status "$VMID" &>/dev/null; then
|
||||||
|
qm stop "$VMID" &>/dev/null
|
||||||
|
qm destroy "$VMID" &>/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [[ "$(dirs -p | wc -l)" -gt 1 ]]; then
|
||||||
|
popd >/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_root() {
|
||||||
|
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
|
||||||
|
clear
|
||||||
|
msg_error "Please run this script as root."
|
||||||
|
echo -e "\nExiting..."
|
||||||
|
sleep 2
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
pve_check() {
|
||||||
|
if ! pveversion | grep -Eq "pve-manager/(8\.[1-4]|9\.[0-1])(\.[0-9]+)*"; then
|
||||||
|
msg_error "This version of Proxmox Virtual Environment is not supported"
|
||||||
|
echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.4 or 9.0 - 9.1."
|
||||||
|
echo -e "Exiting..."
|
||||||
|
sleep 2
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
arch_check() {
|
||||||
|
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
|
||||||
|
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
|
||||||
|
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
|
||||||
|
echo -e "Exiting..."
|
||||||
|
sleep 2
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
exit_script() {
|
||||||
|
clear
|
||||||
|
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
check_hostname_conflict() {
|
||||||
|
local hostname="$1"
|
||||||
|
if qm list | awk '{print $2}' | grep -qx "$hostname"; then
|
||||||
|
msg_error "Hostname $hostname already in use by another VM."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
set_description() {
|
||||||
|
DESCRIPTION=$(
|
||||||
|
cat <<EOF
|
||||||
|
<div align='center'>
|
||||||
|
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
||||||
|
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<h2 style='font-size: 24px; margin: 20px 0;'>${NSAPP} VM</h2>
|
||||||
|
|
||||||
|
<p style='margin: 16px 0;'>
|
||||||
|
<a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
|
||||||
|
<img src='https://img.shields.io/badge/☕-Buy us a coffee-blue' alt='spend Coffee' />
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<span style='margin: 0 10px;'>
|
||||||
|
<i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
|
||||||
|
<a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
|
||||||
|
</span>
|
||||||
|
<span style='margin: 0 10px;'>
|
||||||
|
<i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
|
||||||
|
<a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
|
||||||
|
</span>
|
||||||
|
<span style='margin: 0 10px;'>
|
||||||
|
<i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
|
||||||
|
<a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
qm set "$VMID" -description "$DESCRIPTION" >/dev/null
|
||||||
|
|
||||||
|
}
|
||||||
264
tools/addon/immich-public-proxy.sh
Normal file
264
tools/addon/immich-public-proxy.sh
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
|
# Author: vhsdream
|
||||||
|
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||||
|
# Source: https://github.com/alangrainger/immich-public-proxy
|
||||||
|
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
|
||||||
|
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func)
|
||||||
|
|
||||||
|
# Enable error handling
|
||||||
|
set -Eeuo pipefail
|
||||||
|
trap 'error_handler' ERR
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# CONFIGURATION
|
||||||
|
# ==============================================================================
|
||||||
|
APP="Immich Public Proxy"
|
||||||
|
APP_TYPE="addon"
|
||||||
|
INSTALL_PATH="/opt/immich-proxy"
|
||||||
|
CONFIG_PATH="/opt/immich-proxy/app"
|
||||||
|
DEFAULT_PORT=3000
|
||||||
|
|
||||||
|
# Initialize all core functions (colors, formatting, icons, STD mode)
|
||||||
|
load_functions
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# HEADER
|
||||||
|
# ==============================================================================
|
||||||
|
function header_info {
|
||||||
|
clear
|
||||||
|
cat <<"EOF"
|
||||||
|
____ _ __ ____
|
||||||
|
/ _/___ ___ ____ ___ (_)____/ /_ / __ \_________ _ ____ __
|
||||||
|
/ // __ `__ \/ __ `__ \/ / ___/ __ \______/ /_/ / ___/ __ \| |/_/ / / /
|
||||||
|
_/ // / / / / / / / / / / / /__/ / / /_____/ ____/ / / /_/ /> </ /_/ /
|
||||||
|
/___/_/ /_/ /_/_/ /_/ /_/_/\___/_/ /_/ /_/ /_/ \____/_/|_|\__, /
|
||||||
|
/____/
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# OS DETECTION
|
||||||
|
# ==============================================================================
|
||||||
|
if [[ -f "/etc/alpine-release" ]]; then
|
||||||
|
msg_error "Alpine is not supported for ${APP}. Use Debian."
|
||||||
|
exit 1
|
||||||
|
elif [[ -f "/etc/debian_version" ]]; then
|
||||||
|
OS="Debian"
|
||||||
|
SERVICE_PATH="/etc/systemd/system/immich-proxy.service"
|
||||||
|
else
|
||||||
|
echo -e "${CROSS} Unsupported OS detected. Exiting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# UNINSTALL
|
||||||
|
# ==============================================================================
|
||||||
|
function uninstall() {
|
||||||
|
msg_info "Uninstalling ${APP}"
|
||||||
|
systemctl disable --now immich-proxy.service &>/dev/null || true
|
||||||
|
rm -f "$SERVICE_PATH"
|
||||||
|
rm -rf "$INSTALL_PATH"
|
||||||
|
rm -f "/usr/local/bin/update_immich-public-proxy"
|
||||||
|
rm -f "$HOME/.immichpublicproxy"
|
||||||
|
msg_ok "${APP} has been uninstalled"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# UPDATE
|
||||||
|
# ==============================================================================
|
||||||
|
function update() {
|
||||||
|
if check_for_gh_release "Immich Public Proxy" "alangrainger/immich-public-proxy"; then
|
||||||
|
msg_info "Stopping service"
|
||||||
|
systemctl stop immich-proxy.service &>/dev/null || true
|
||||||
|
msg_ok "Stopped service"
|
||||||
|
|
||||||
|
msg_info "Backing up configuration"
|
||||||
|
cp "$CONFIG_PATH"/.env /tmp/ipp.env.bak 2>/dev/null || true
|
||||||
|
cp "$CONFIG_PATH"/config.json /tmp/ipp.config.json.bak 2>/dev/null || true
|
||||||
|
msg_ok "Backed up configuration"
|
||||||
|
|
||||||
|
NODE_VERSION="24" setup_nodejs
|
||||||
|
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "Immich Public Proxy" "alangrainger/immich-public-proxy" "tarball" "latest" "$INSTALL_PATH"
|
||||||
|
|
||||||
|
msg_info "Restoring configuration"
|
||||||
|
cp /tmp/ipp.env.bak "$CONFIG_PATH"/.env 2>/dev/null || true
|
||||||
|
cp /tmp/ipp.config.json.bak "$CONFIG_PATH"/config.json 2>/dev/null || true
|
||||||
|
rm -f /tmp/ipp.*.bak
|
||||||
|
msg_ok "Restored configuration"
|
||||||
|
|
||||||
|
msg_info "Installing dependencies"
|
||||||
|
cd "$CONFIG_PATH"
|
||||||
|
$STD npm install
|
||||||
|
msg_ok "Installed dependencies"
|
||||||
|
|
||||||
|
msg_info "Building ${APP}"
|
||||||
|
$STD npm run build
|
||||||
|
msg_ok "Built ${APP}"
|
||||||
|
|
||||||
|
msg_info "Starting service"
|
||||||
|
systemctl start immich-proxy
|
||||||
|
msg_ok "Started service"
|
||||||
|
msg_ok "Updated successfully"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# INSTALL
|
||||||
|
# ==============================================================================
|
||||||
|
function install() {
|
||||||
|
NODE_VERSION="24" setup_nodejs
|
||||||
|
|
||||||
|
# Force fresh download by removing version cache
|
||||||
|
rm -f "$HOME/.immichpublicproxy"
|
||||||
|
fetch_and_deploy_gh_release "Immich Public Proxy" "alangrainger/immich-public-proxy" "tarball" "latest" "$INSTALL_PATH"
|
||||||
|
|
||||||
|
msg_info "Installing dependencies"
|
||||||
|
cd "$CONFIG_PATH"
|
||||||
|
$STD npm install
|
||||||
|
msg_ok "Installed dependencies"
|
||||||
|
|
||||||
|
msg_info "Building ${APP}"
|
||||||
|
$STD npm run build
|
||||||
|
msg_ok "Built ${APP}"
|
||||||
|
|
||||||
|
MAX_ATTEMPTS=3
|
||||||
|
attempt=0
|
||||||
|
while true; do
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
read -rp "${TAB3}Enter your LOCAL Immich IP or domain (ex. 192.168.1.100 or immich.local.lan): " DOMAIN
|
||||||
|
if [[ -z "$DOMAIN" ]]; then
|
||||||
|
if ((attempt >= MAX_ATTEMPTS)); then
|
||||||
|
DOMAIN="${LOCAL_IP:-localhost}"
|
||||||
|
msg_warn "Using fallback: $DOMAIN"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
msg_warn "Domain cannot be empty! (Attempt $attempt/$MAX_ATTEMPTS)"
|
||||||
|
elif [[ "$DOMAIN" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
|
||||||
|
valid_ip=true
|
||||||
|
IFS='.' read -ra octets <<<"$DOMAIN"
|
||||||
|
for octet in "${octets[@]}"; do
|
||||||
|
if ((octet > 255)); then
|
||||||
|
valid_ip=false
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if $valid_ip; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
msg_warn "Invalid IP address!"
|
||||||
|
fi
|
||||||
|
elif [[ "$DOMAIN" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$ || "$DOMAIN" == "localhost" ]]; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
msg_warn "Invalid domain format!"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
msg_info "Creating configuration"
|
||||||
|
cat <<EOF >"$CONFIG_PATH"/.env
|
||||||
|
NODE_ENV=production
|
||||||
|
IMMICH_URL=http://${DOMAIN}:2283
|
||||||
|
EOF
|
||||||
|
chmod 600 "$CONFIG_PATH"/.env
|
||||||
|
msg_ok "Created configuration"
|
||||||
|
|
||||||
|
msg_info "Creating service"
|
||||||
|
cat <<EOF >"$SERVICE_PATH"
|
||||||
|
[Unit]
|
||||||
|
Description=Immich Public Proxy
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=${INSTALL_PATH}
|
||||||
|
EnvironmentFile=${CONFIG_PATH}/.env
|
||||||
|
ExecStart=/usr/bin/node ${INSTALL_PATH}/app/server.js
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
systemctl enable -q --now immich-proxy
|
||||||
|
msg_ok "Created and started service"
|
||||||
|
|
||||||
|
# Create update script (simple wrapper that calls this addon with type=update)
|
||||||
|
msg_info "Creating update script"
|
||||||
|
cat <<'UPDATEEOF' >/usr/local/bin/update_immich-public-proxy
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Immich Public Proxy Update Script
|
||||||
|
type=update bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/immich-public-proxy.sh)"
|
||||||
|
UPDATEEOF
|
||||||
|
chmod +x /usr/local/bin/update_immich-public-proxy
|
||||||
|
msg_ok "Created update script (/usr/local/bin/update_immich-public-proxy)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
msg_ok "${APP} is reachable at: ${BL}http://${LOCAL_IP}:${DEFAULT_PORT}${CL}"
|
||||||
|
echo ""
|
||||||
|
msg_warn "Additional configuration is available at '/opt/immich-proxy/app/config.json'"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# MAIN
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# Handle type=update (called from update script)
|
||||||
|
if [[ "${type:-}" == "update" ]]; then
|
||||||
|
header_info
|
||||||
|
if [[ -d "$INSTALL_PATH" && -f "$SERVICE_PATH" ]]; then
|
||||||
|
update
|
||||||
|
else
|
||||||
|
msg_error "${APP} is not installed. Nothing to update."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
header_info
|
||||||
|
get_lxc_ip
|
||||||
|
|
||||||
|
# Check if already installed
|
||||||
|
if [[ -d "$INSTALL_PATH" && -f "$SERVICE_PATH" ]]; then
|
||||||
|
msg_warn "${APP} is already installed."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo -n "${TAB}Uninstall ${APP}? (y/N): "
|
||||||
|
read -r uninstall_prompt
|
||||||
|
if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
uninstall
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "${TAB}Update ${APP}? (y/N): "
|
||||||
|
read -r update_prompt
|
||||||
|
if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
update
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_warn "No action selected. Exiting."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fresh installation
|
||||||
|
msg_warn "${APP} is not installed."
|
||||||
|
echo ""
|
||||||
|
echo -e "${TAB}${INFO} This will install:"
|
||||||
|
echo -e "${TAB} - Node.js 24"
|
||||||
|
echo -e "${TAB} - Immich Public Proxy"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo -n "${TAB}Install ${APP}? (y/N): "
|
||||||
|
read -r install_prompt
|
||||||
|
if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
|
||||||
|
install
|
||||||
|
else
|
||||||
|
msg_warn "Installation cancelled. Exiting."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
6
tools/headers/immich-public-proxy
Normal file
6
tools/headers/immich-public-proxy
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
____ _ __ ____ __ ___ ____
|
||||||
|
/ _/___ ___ ____ ___ (_)____/ /_ / __ \__ __/ /_ / (_)____ / __ \_________ _ ____ __
|
||||||
|
/ // __ `__ \/ __ `__ \/ / ___/ __ \ / /_/ / / / / __ \/ / / ___/ / /_/ / ___/ __ \| |/_/ / / /
|
||||||
|
_/ // / / / / / / / / / / / /__/ / / / / ____/ /_/ / /_/ / / / /__ / ____/ / / /_/ /> </ /_/ /
|
||||||
|
/___/_/ /_/ /_/_/ /_/ /_/_/\___/_/ /_/ /_/ \__,_/_.___/_/_/\___/ /_/ /_/ \____/_/|_|\__, /
|
||||||
|
/____/
|
||||||
732
vm/docker-vm.sh
732
vm/docker-vm.sh
@@ -1,71 +1,45 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Copyright (c) 2021-2026 community-scripts ORG
|
# Copyright (c) 2021-2026 community-scripts ORG
|
||||||
# Author: thost96 (thost96) | Co-Author: michelroegl-brunner
|
# Author: thost96 (thost96) | michelroegl-brunner | MickLesk
|
||||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
|
||||||
|
|
||||||
source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
|
# ==============================================================================
|
||||||
|
# Docker VM - Creates a Docker-ready Virtual Machine
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
function header_info() {
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/misc/api.func) 2>/dev/null
|
||||||
clear
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/misc/vm-core.func) 2>/dev/null
|
||||||
cat <<"EOF"
|
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main/misc/cloud-init.func) 2>/dev/null || true
|
||||||
____ __ _ ____ ___
|
load_functions
|
||||||
/ __ \____ _____/ /_____ _____ | | / / |/ /
|
|
||||||
/ / / / __ \/ ___/ //_/ _ \/ ___/ | | / / /|_/ /
|
# ==============================================================================
|
||||||
/ /_/ / /_/ / /__/ ,< / __/ / | |/ / / / /
|
# SCRIPT VARIABLES
|
||||||
/_____/\____/\___/_/|_|\___/_/ |___/_/ /_/
|
# ==============================================================================
|
||||||
|
APP="Docker"
|
||||||
|
APP_TYPE="vm"
|
||||||
|
NSAPP="docker-vm"
|
||||||
|
var_os="debian"
|
||||||
|
var_version="13"
|
||||||
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
header_info
|
|
||||||
echo -e "\n Loading..."
|
|
||||||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||||||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||||||
METHOD=""
|
METHOD=""
|
||||||
NSAPP="docker-vm"
|
|
||||||
var_os="debian"
|
|
||||||
var_version="12"
|
|
||||||
DISK_SIZE="10G"
|
DISK_SIZE="10G"
|
||||||
|
USE_CLOUD_INIT="no"
|
||||||
YW=$(echo "\033[33m")
|
OS_TYPE=""
|
||||||
BL=$(echo "\033[36m")
|
OS_VERSION=""
|
||||||
RD=$(echo "\033[01;31m")
|
|
||||||
BGN=$(echo "\033[4;92m")
|
|
||||||
GN=$(echo "\033[1;92m")
|
|
||||||
DGN=$(echo "\033[32m")
|
|
||||||
CL=$(echo "\033[m")
|
|
||||||
|
|
||||||
CL=$(echo "\033[m")
|
|
||||||
BOLD=$(echo "\033[1m")
|
|
||||||
BFR="\\r\\033[K"
|
|
||||||
HOLD=" "
|
|
||||||
TAB=" "
|
|
||||||
|
|
||||||
CM="${TAB}✔️${TAB}${CL}"
|
|
||||||
CROSS="${TAB}✖️${TAB}${CL}"
|
|
||||||
INFO="${TAB}💡${TAB}${CL}"
|
|
||||||
OS="${TAB}🖥️${TAB}${CL}"
|
|
||||||
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
|
|
||||||
DISKSIZE="${TAB}💾${TAB}${CL}"
|
|
||||||
CPUCORE="${TAB}🧠${TAB}${CL}"
|
|
||||||
RAMSIZE="${TAB}🛠️${TAB}${CL}"
|
|
||||||
CONTAINERID="${TAB}🆔${TAB}${CL}"
|
|
||||||
HOSTNAME="${TAB}🏠${TAB}${CL}"
|
|
||||||
BRIDGE="${TAB}🌉${TAB}${CL}"
|
|
||||||
GATEWAY="${TAB}🌐${TAB}${CL}"
|
|
||||||
DEFAULT="${TAB}⚙️${TAB}${CL}"
|
|
||||||
MACADDRESS="${TAB}🔗${TAB}${CL}"
|
|
||||||
VLANTAG="${TAB}🏷️${TAB}${CL}"
|
|
||||||
CREATING="${TAB}🚀${TAB}${CL}"
|
|
||||||
ADVANCED="${TAB}🧩${TAB}${CL}"
|
|
||||||
CLOUD="${TAB}☁️${TAB}${CL}"
|
|
||||||
|
|
||||||
THIN="discard=on,ssd=1,"
|
THIN="discard=on,ssd=1,"
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# ERROR HANDLING & CLEANUP
|
||||||
|
# ==============================================================================
|
||||||
set -e
|
set -e
|
||||||
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT
|
trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT
|
||||||
trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM
|
trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM
|
||||||
|
|
||||||
function error_handler() {
|
function error_handler() {
|
||||||
local exit_code="$?"
|
local exit_code="$?"
|
||||||
local line_number="$1"
|
local line_number="$1"
|
||||||
@@ -76,140 +50,96 @@ function error_handler() {
|
|||||||
cleanup_vmid
|
cleanup_vmid
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_valid_nextid() {
|
# ==============================================================================
|
||||||
local try_id
|
# OS SELECTION FUNCTIONS
|
||||||
try_id=$(pvesh get /cluster/nextid)
|
# ==============================================================================
|
||||||
while true; do
|
function select_os() {
|
||||||
if [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; then
|
if OS_CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SELECT OS" --radiolist \
|
||||||
try_id=$((try_id + 1))
|
"Choose Operating System for Docker VM" 14 68 4 \
|
||||||
continue
|
"debian13" "Debian 13 (Trixie) - Latest" ON \
|
||||||
|
"debian12" "Debian 12 (Bookworm) - Stable" OFF \
|
||||||
|
"ubuntu2404" "Ubuntu 24.04 LTS (Noble)" OFF \
|
||||||
|
"ubuntu2204" "Ubuntu 22.04 LTS (Jammy)" OFF \
|
||||||
|
3>&1 1>&2 2>&3); then
|
||||||
|
case $OS_CHOICE in
|
||||||
|
debian13)
|
||||||
|
OS_TYPE="debian"
|
||||||
|
OS_VERSION="13"
|
||||||
|
OS_CODENAME="trixie"
|
||||||
|
OS_DISPLAY="Debian 13 (Trixie)"
|
||||||
|
;;
|
||||||
|
debian12)
|
||||||
|
OS_TYPE="debian"
|
||||||
|
OS_VERSION="12"
|
||||||
|
OS_CODENAME="bookworm"
|
||||||
|
OS_DISPLAY="Debian 12 (Bookworm)"
|
||||||
|
;;
|
||||||
|
ubuntu2404)
|
||||||
|
OS_TYPE="ubuntu"
|
||||||
|
OS_VERSION="24.04"
|
||||||
|
OS_CODENAME="noble"
|
||||||
|
OS_DISPLAY="Ubuntu 24.04 LTS"
|
||||||
|
;;
|
||||||
|
ubuntu2204)
|
||||||
|
OS_TYPE="ubuntu"
|
||||||
|
OS_VERSION="22.04"
|
||||||
|
OS_CODENAME="jammy"
|
||||||
|
OS_DISPLAY="Ubuntu 22.04 LTS"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo -e "${OS}${BOLD}${DGN}Operating System: ${BGN}${OS_DISPLAY}${CL}"
|
||||||
|
else
|
||||||
|
exit_script
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function select_cloud_init() {
|
||||||
|
if [ "$OS_TYPE" = "ubuntu" ]; then
|
||||||
|
USE_CLOUD_INIT="yes"
|
||||||
|
echo -e "${CLOUD:-${TAB}☁️${TAB}${CL}}${BOLD}${DGN}Cloud-Init: ${BGN}yes (Ubuntu requires Cloud-Init)${CL}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "CLOUD-INIT" \
|
||||||
|
--yesno "Enable Cloud-Init for VM configuration?\n\nCloud-Init allows automatic configuration of:\n- User accounts and passwords\n- SSH keys\n- Network settings (DHCP/Static)\n- DNS configuration\n\nYou can also configure these settings later in Proxmox UI.\n\nNote: Debian without Cloud-Init will use nocloud image with console auto-login." 18 68); then
|
||||||
|
USE_CLOUD_INIT="yes"
|
||||||
|
echo -e "${CLOUD:-${TAB}☁️${TAB}${CL}}${BOLD}${DGN}Cloud-Init: ${BGN}yes${CL}"
|
||||||
|
else
|
||||||
|
USE_CLOUD_INIT="no"
|
||||||
|
echo -e "${CLOUD:-${TAB}☁️${TAB}${CL}}${BOLD}${DGN}Cloud-Init: ${BGN}no${CL}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_image_url() {
|
||||||
|
local arch=$(dpkg --print-architecture)
|
||||||
|
case $OS_TYPE in
|
||||||
|
debian)
|
||||||
|
if [ "$USE_CLOUD_INIT" = "yes" ]; then
|
||||||
|
echo "https://cloud.debian.org/images/cloud/${OS_CODENAME}/latest/debian-${OS_VERSION}-generic-${arch}.qcow2"
|
||||||
|
else
|
||||||
|
echo "https://cloud.debian.org/images/cloud/${OS_CODENAME}/latest/debian-${OS_VERSION}-nocloud-${arch}.qcow2"
|
||||||
fi
|
fi
|
||||||
if lvs --noheadings -o lv_name | grep -qE "(^|[-_])${try_id}($|[-_])"; then
|
;;
|
||||||
try_id=$((try_id + 1))
|
ubuntu)
|
||||||
continue
|
echo "https://cloud-images.ubuntu.com/${OS_CODENAME}/current/${OS_CODENAME}-server-cloudimg-${arch}.img"
|
||||||
fi
|
;;
|
||||||
break
|
esac
|
||||||
done
|
|
||||||
echo "$try_id"
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanup_vmid() {
|
|
||||||
if qm status $VMID &>/dev/null; then
|
|
||||||
qm stop $VMID &>/dev/null
|
|
||||||
qm destroy $VMID &>/dev/null
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanup() {
|
|
||||||
popd >/dev/null
|
|
||||||
post_update_to_api "done" "none"
|
|
||||||
rm -rf $TEMP_DIR
|
|
||||||
}
|
|
||||||
|
|
||||||
TEMP_DIR=$(mktemp -d)
|
|
||||||
pushd $TEMP_DIR >/dev/null
|
|
||||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Docker VM" --yesno "This will create a New Docker VM. Proceed?" 10 58; then
|
|
||||||
:
|
|
||||||
else
|
|
||||||
header_info && echo -e "${CROSS}${RD}User exited script${CL}\n" && exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
function msg_info() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
|
|
||||||
}
|
|
||||||
|
|
||||||
function msg_ok() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${BFR}${CM}${GN}${msg}${CL}"
|
|
||||||
}
|
|
||||||
|
|
||||||
function msg_error() {
|
|
||||||
local msg="$1"
|
|
||||||
echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
|
|
||||||
}
|
|
||||||
|
|
||||||
function check_root() {
|
|
||||||
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
|
|
||||||
clear
|
|
||||||
msg_error "Please run this script as root."
|
|
||||||
echo -e "\nExiting..."
|
|
||||||
sleep 2
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported.
|
|
||||||
# Supported: Proxmox VE 8.0.x – 8.9.x, 9.0 and 9.1
|
|
||||||
pve_check() {
|
|
||||||
local PVE_VER
|
|
||||||
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
|
||||||
|
|
||||||
# Check for Proxmox VE 8.x: allow 8.0–8.9
|
|
||||||
if [[ "$PVE_VER" =~ ^8\.([0-9]+) ]]; then
|
|
||||||
local MINOR="${BASH_REMATCH[1]}"
|
|
||||||
if ((MINOR < 0 || MINOR > 9)); then
|
|
||||||
msg_error "This version of Proxmox VE is not supported."
|
|
||||||
msg_error "Supported: Proxmox VE version 8.0 – 8.9"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check for Proxmox VE 9.x: allow 9.0 and 9.1
|
|
||||||
if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then
|
|
||||||
local MINOR="${BASH_REMATCH[1]}"
|
|
||||||
if ((MINOR < 0 || MINOR > 1)); then
|
|
||||||
msg_error "This version of Proxmox VE is not supported."
|
|
||||||
msg_error "Supported: Proxmox VE version 9.0 – 9.1"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# All other unsupported versions
|
|
||||||
msg_error "This version of Proxmox VE is not supported."
|
|
||||||
msg_error "Supported versions: Proxmox VE 8.0 – 8.x or 9.0 – 9.1"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
function arch_check() {
|
|
||||||
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
|
|
||||||
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
|
|
||||||
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
|
|
||||||
echo -e "Exiting..."
|
|
||||||
sleep 2
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function ssh_check() {
|
|
||||||
if command -v pveversion >/dev/null 2>&1; then
|
|
||||||
if [ -n "${SSH_CLIENT:+x}" ]; then
|
|
||||||
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
|
|
||||||
echo "you've been warned"
|
|
||||||
else
|
|
||||||
clear
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function exit-script() {
|
|
||||||
clear
|
|
||||||
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
|
|
||||||
exit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# SETTINGS FUNCTIONS
|
||||||
|
# ==============================================================================
|
||||||
function default_settings() {
|
function default_settings() {
|
||||||
|
select_os
|
||||||
|
select_cloud_init
|
||||||
|
|
||||||
VMID=$(get_valid_nextid)
|
VMID=$(get_valid_nextid)
|
||||||
FORMAT=",efitype=4m"
|
FORMAT=""
|
||||||
MACHINE=""
|
MACHINE=" -machine q35"
|
||||||
DISK_CACHE=""
|
DISK_CACHE=""
|
||||||
DISK_SIZE="10G"
|
DISK_SIZE="10G"
|
||||||
HN="docker"
|
HN="docker"
|
||||||
CPU_TYPE=""
|
CPU_TYPE=" -cpu host"
|
||||||
CORE_COUNT="2"
|
CORE_COUNT="2"
|
||||||
RAM_SIZE="4096"
|
RAM_SIZE="4096"
|
||||||
BRG="vmbr0"
|
BRG="vmbr0"
|
||||||
@@ -218,12 +148,13 @@ function default_settings() {
|
|||||||
MTU=""
|
MTU=""
|
||||||
START_VM="yes"
|
START_VM="yes"
|
||||||
METHOD="default"
|
METHOD="default"
|
||||||
|
|
||||||
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}${VMID}${CL}"
|
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}${VMID}${CL}"
|
||||||
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}i440fx${CL}"
|
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}Q35 (Modern)${CL}"
|
||||||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE}${CL}"
|
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE}${CL}"
|
||||||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
|
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
|
||||||
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}${HN}${CL}"
|
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}${HN}${CL}"
|
||||||
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
|
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
|
||||||
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
|
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
|
||||||
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE}${CL}"
|
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE}${CL}"
|
||||||
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}${BRG}${CL}"
|
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}${BRG}${CL}"
|
||||||
@@ -231,12 +162,22 @@ function default_settings() {
|
|||||||
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}Default${CL}"
|
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}Default${CL}"
|
||||||
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}Default${CL}"
|
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}Default${CL}"
|
||||||
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
|
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
|
||||||
echo -e "${CREATING}${BOLD}${DGN}Creating a Docker VM using the above default settings${CL}"
|
echo -e "${CREATING}${BOLD}${DGN}Creating a Docker VM using the above settings${CL}"
|
||||||
}
|
}
|
||||||
|
|
||||||
function advanced_settings() {
|
function advanced_settings() {
|
||||||
|
select_os
|
||||||
|
select_cloud_init
|
||||||
|
|
||||||
|
# SSH Key selection for Cloud-Init VMs
|
||||||
|
if [ "$USE_CLOUD_INIT" = "yes" ]; then
|
||||||
|
configure_cloudinit_ssh_keys || true
|
||||||
|
fi
|
||||||
|
|
||||||
METHOD="advanced"
|
METHOD="advanced"
|
||||||
[ -z "${VMID:-}" ] && VMID=$(get_valid_nextid)
|
[ -z "${VMID:-}" ] && VMID=$(get_valid_nextid)
|
||||||
|
|
||||||
|
# VM ID
|
||||||
while true; do
|
while true; do
|
||||||
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 $VMID --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 $VMID --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||||
if [ -z "$VMID" ]; then
|
if [ -z "$VMID" ]; then
|
||||||
@@ -250,27 +191,29 @@ function advanced_settings() {
|
|||||||
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
|
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}$VMID${CL}"
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Machine Type
|
||||||
if MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
|
if MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
|
||||||
"i440fx" "Machine i440fx" ON \
|
"q35" "Q35 (Modern, PCIe)" ON \
|
||||||
"q35" "Machine q35" OFF \
|
"i440fx" "i440fx (Legacy, PCI)" OFF \
|
||||||
3>&1 1>&2 2>&3); then
|
3>&1 1>&2 2>&3); then
|
||||||
if [ $MACH = q35 ]; then
|
if [ $MACH = q35 ]; then
|
||||||
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$MACH${CL}"
|
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}Q35 (Modern)${CL}"
|
||||||
FORMAT=""
|
FORMAT=""
|
||||||
MACHINE=" -machine q35"
|
MACHINE=" -machine q35"
|
||||||
else
|
else
|
||||||
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}$MACH${CL}"
|
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}i440fx (Legacy)${CL}"
|
||||||
FORMAT=",efitype=4m"
|
FORMAT=",efitype=4m"
|
||||||
MACHINE=""
|
MACHINE=""
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Disk Size
|
||||||
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GiB (e.g., 10, 20)" 8 58 "$DISK_SIZE" --title "DISK SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GiB (e.g., 10, 20)" 8 58 "$DISK_SIZE" --title "DISK SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||||
DISK_SIZE=$(echo "$DISK_SIZE" | tr -d ' ')
|
DISK_SIZE=$(echo "$DISK_SIZE" | tr -d ' ')
|
||||||
if [[ "$DISK_SIZE" =~ ^[0-9]+$ ]]; then
|
if [[ "$DISK_SIZE" =~ ^[0-9]+$ ]]; then
|
||||||
@@ -280,12 +223,13 @@ function advanced_settings() {
|
|||||||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
|
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}$DISK_SIZE${CL}"
|
||||||
else
|
else
|
||||||
echo -e "${DISKSIZE}${BOLD}${RD}Invalid Disk Size. Please use a number (e.g., 10 or 10G).${CL}"
|
echo -e "${DISKSIZE}${BOLD}${RD}Invalid Disk Size. Please use a number (e.g., 10 or 10G).${CL}"
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Disk Cache
|
||||||
if DISK_CACHE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
if DISK_CACHE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
||||||
"0" "None (Default)" ON \
|
"0" "None (Default)" ON \
|
||||||
"1" "Write Through" OFF \
|
"1" "Write Through" OFF \
|
||||||
@@ -298,24 +242,25 @@ function advanced_settings() {
|
|||||||
DISK_CACHE=""
|
DISK_CACHE=""
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Hostname
|
||||||
if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 docker --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 docker --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||||
if [ -z $VM_NAME ]; then
|
if [ -z $VM_NAME ]; then
|
||||||
HN="docker"
|
HN="docker"
|
||||||
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
|
|
||||||
else
|
else
|
||||||
HN=$(echo ${VM_NAME,,} | tr -d ' ')
|
HN=$(echo ${VM_NAME,,} | tr -d ' ')
|
||||||
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
|
|
||||||
fi
|
fi
|
||||||
|
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# CPU Model
|
||||||
if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
||||||
"0" "KVM64 (Default)" ON \
|
"1" "Host (Recommended)" ON \
|
||||||
"1" "Host" OFF \
|
"0" "KVM64" OFF \
|
||||||
3>&1 1>&2 2>&3); then
|
3>&1 1>&2 2>&3); then
|
||||||
if [ $CPU_TYPE1 = "1" ]; then
|
if [ $CPU_TYPE1 = "1" ]; then
|
||||||
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
|
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
|
||||||
@@ -325,80 +270,78 @@ function advanced_settings() {
|
|||||||
CPU_TYPE=""
|
CPU_TYPE=""
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# CPU Cores
|
||||||
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 2 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 2 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||||
if [ -z $CORE_COUNT ]; then
|
if [ -z $CORE_COUNT ]; then
|
||||||
CORE_COUNT="2"
|
CORE_COUNT="2"
|
||||||
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
|
|
||||||
else
|
|
||||||
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
|
|
||||||
fi
|
fi
|
||||||
|
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 2048 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
# RAM Size
|
||||||
|
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 4096 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||||
if [ -z $RAM_SIZE ]; then
|
if [ -z $RAM_SIZE ]; then
|
||||||
RAM_SIZE="2048"
|
RAM_SIZE="4096"
|
||||||
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
|
|
||||||
else
|
|
||||||
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
|
|
||||||
fi
|
fi
|
||||||
|
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Bridge
|
||||||
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 vmbr0 --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 vmbr0 --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||||
if [ -z $BRG ]; then
|
if [ -z $BRG ]; then
|
||||||
BRG="vmbr0"
|
BRG="vmbr0"
|
||||||
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
|
|
||||||
else
|
|
||||||
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
|
|
||||||
fi
|
fi
|
||||||
|
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# MAC Address
|
||||||
if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 $GEN_MAC --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 $GEN_MAC --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||||
if [ -z $MAC1 ]; then
|
if [ -z $MAC1 ]; then
|
||||||
MAC="$GEN_MAC"
|
MAC="$GEN_MAC"
|
||||||
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
|
|
||||||
else
|
else
|
||||||
MAC="$MAC1"
|
MAC="$MAC1"
|
||||||
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC1${CL}"
|
|
||||||
fi
|
fi
|
||||||
|
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
# VLAN
|
||||||
|
if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan (leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||||
if [ -z $VLAN1 ]; then
|
if [ -z $VLAN1 ]; then
|
||||||
VLAN1="Default"
|
VLAN1="Default"
|
||||||
VLAN=""
|
VLAN=""
|
||||||
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
|
|
||||||
else
|
else
|
||||||
VLAN=",tag=$VLAN1"
|
VLAN=",tag=$VLAN1"
|
||||||
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
|
|
||||||
fi
|
fi
|
||||||
|
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# MTU
|
||||||
if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||||||
if [ -z $MTU1 ]; then
|
if [ -z $MTU1 ]; then
|
||||||
MTU1="Default"
|
MTU1="Default"
|
||||||
MTU=""
|
MTU=""
|
||||||
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
|
|
||||||
else
|
else
|
||||||
MTU=",mtu=$MTU1"
|
MTU=",mtu=$MTU1"
|
||||||
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
|
|
||||||
fi
|
fi
|
||||||
|
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
|
||||||
else
|
else
|
||||||
exit-script
|
exit_script
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Start VM
|
||||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58); then
|
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58); then
|
||||||
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
|
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
|
||||||
START_VM="yes"
|
START_VM="yes"
|
||||||
@@ -407,6 +350,7 @@ function advanced_settings() {
|
|||||||
START_VM="no"
|
START_VM="no"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Confirm
|
||||||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create a Docker VM?" --no-button Do-Over 10 58); then
|
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create a Docker VM?" --no-button Do-Over 10 58); then
|
||||||
echo -e "${CREATING}${BOLD}${DGN}Creating a Docker VM using the above advanced settings${CL}"
|
echo -e "${CREATING}${BOLD}${DGN}Creating a Docker VM using the above advanced settings${CL}"
|
||||||
else
|
else
|
||||||
@@ -427,13 +371,28 @@ function start_script() {
|
|||||||
advanced_settings
|
advanced_settings
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# MAIN EXECUTION
|
||||||
|
# ==============================================================================
|
||||||
|
header_info
|
||||||
|
|
||||||
check_root
|
check_root
|
||||||
arch_check
|
arch_check
|
||||||
pve_check
|
pve_check
|
||||||
ssh_check
|
|
||||||
|
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Docker VM" --yesno "This will create a New Docker VM. Proceed?" 10 58; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
header_info && echo -e "${CROSS}${RD}User exited script${CL}\n" && exit
|
||||||
|
fi
|
||||||
|
|
||||||
start_script
|
start_script
|
||||||
post_to_api_vm
|
post_to_api_vm
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# STORAGE SELECTION
|
||||||
|
# ==============================================================================
|
||||||
msg_info "Validating Storage"
|
msg_info "Validating Storage"
|
||||||
while read -r line; do
|
while read -r line; do
|
||||||
TAG=$(echo $line | awk '{print $1}')
|
TAG=$(echo $line | awk '{print $1}')
|
||||||
@@ -446,6 +405,7 @@ while read -r line; do
|
|||||||
fi
|
fi
|
||||||
STORAGE_MENU+=("$TAG" "$ITEM" "OFF")
|
STORAGE_MENU+=("$TAG" "$ITEM" "OFF")
|
||||||
done < <(pvesm status -content images | awk 'NR>1')
|
done < <(pvesm status -content images | awk 'NR>1')
|
||||||
|
|
||||||
VALID=$(pvesm status -content images | awk 'NR>1')
|
VALID=$(pvesm status -content images | awk 'NR>1')
|
||||||
if [ -z "$VALID" ]; then
|
if [ -z "$VALID" ]; then
|
||||||
msg_error "Unable to detect a valid storage location."
|
msg_error "Unable to detect a valid storage location."
|
||||||
@@ -453,6 +413,8 @@ if [ -z "$VALID" ]; then
|
|||||||
elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
|
elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
|
||||||
STORAGE=${STORAGE_MENU[0]}
|
STORAGE=${STORAGE_MENU[0]}
|
||||||
else
|
else
|
||||||
|
if [ -n "$SPINNER_PID" ] && ps -p $SPINNER_PID >/dev/null; then kill $SPINNER_PID >/dev/null; fi
|
||||||
|
printf "\e[?25h"
|
||||||
while [ -z "${STORAGE:+x}" ]; do
|
while [ -z "${STORAGE:+x}" ]; do
|
||||||
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
|
STORAGE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
|
||||||
"Which storage pool would you like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
|
"Which storage pool would you like to use for ${HN}?\nTo make a selection, use the Spacebar.\n" \
|
||||||
@@ -462,112 +424,288 @@ else
|
|||||||
fi
|
fi
|
||||||
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
|
msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location."
|
||||||
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
|
msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}."
|
||||||
msg_info "Retrieving the URL for the Debian 12 Qcow2 Disk Image"
|
|
||||||
URL="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-$(dpkg --print-architecture).qcow2"
|
|
||||||
sleep 2
|
|
||||||
msg_ok "${CL}${BL}${URL}${CL}"
|
|
||||||
curl -f#SL -o "$(basename "$URL")" "$URL"
|
|
||||||
echo -en "\e[1A\e[0K"
|
|
||||||
FILE=$(basename $URL)
|
|
||||||
msg_ok "Downloaded ${CL}${BL}${FILE}${CL}"
|
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# PREREQUISITES
|
||||||
|
# ==============================================================================
|
||||||
|
if ! command -v virt-customize &>/dev/null; then
|
||||||
|
msg_info "Installing libguestfs-tools"
|
||||||
|
apt-get -qq update >/dev/null
|
||||||
|
apt-get -qq install libguestfs-tools lsb-release -y >/dev/null
|
||||||
|
apt-get -qq install dhcpcd-base -y >/dev/null 2>&1 || true
|
||||||
|
msg_ok "Installed libguestfs-tools"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# IMAGE DOWNLOAD
|
||||||
|
# ==============================================================================
|
||||||
|
msg_info "Retrieving the URL for the ${OS_DISPLAY} Qcow2 Disk Image"
|
||||||
|
URL=$(get_image_url)
|
||||||
|
CACHE_DIR="/var/lib/vz/template/cache"
|
||||||
|
CACHE_FILE="$CACHE_DIR/$(basename "$URL")"
|
||||||
|
mkdir -p "$CACHE_DIR"
|
||||||
|
msg_ok "${CL}${BL}${URL}${CL}"
|
||||||
|
|
||||||
|
if [[ ! -s "$CACHE_FILE" ]]; then
|
||||||
|
curl -f#SL -o "$CACHE_FILE" "$URL"
|
||||||
|
echo -en "\e[1A\e[0K"
|
||||||
|
msg_ok "Downloaded ${CL}${BL}$(basename "$CACHE_FILE")${CL}"
|
||||||
|
else
|
||||||
|
msg_ok "Using cached image ${CL}${BL}$(basename "$CACHE_FILE")${CL}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# STORAGE TYPE DETECTION
|
||||||
|
# ==============================================================================
|
||||||
STORAGE_TYPE=$(pvesm status -storage "$STORAGE" | awk 'NR>1 {print $2}')
|
STORAGE_TYPE=$(pvesm status -storage "$STORAGE" | awk 'NR>1 {print $2}')
|
||||||
case $STORAGE_TYPE in
|
case $STORAGE_TYPE in
|
||||||
nfs | dir)
|
nfs | dir)
|
||||||
DISK_EXT=".qcow2"
|
DISK_EXT=".qcow2"
|
||||||
DISK_REF="$VMID/"
|
DISK_REF="$VMID/"
|
||||||
DISK_IMPORT="-format qcow2"
|
DISK_IMPORT="--format qcow2"
|
||||||
THIN=""
|
THIN=""
|
||||||
;;
|
;;
|
||||||
btrfs)
|
btrfs)
|
||||||
DISK_EXT=".raw"
|
DISK_EXT=".raw"
|
||||||
DISK_REF="$VMID/"
|
DISK_REF="$VMID/"
|
||||||
DISK_IMPORT="-format raw"
|
DISK_IMPORT="--format raw"
|
||||||
FORMAT=",efitype=4m"
|
FORMAT=",efitype=4m"
|
||||||
THIN=""
|
THIN=""
|
||||||
;;
|
;;
|
||||||
|
*)
|
||||||
|
DISK_EXT=""
|
||||||
|
DISK_REF=""
|
||||||
|
DISK_IMPORT="--format raw"
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
for i in {0,1}; do
|
|
||||||
disk="DISK$i"
|
# ==============================================================================
|
||||||
eval DISK${i}=vm-${VMID}-disk-${i}${DISK_EXT:-}
|
# IMAGE CUSTOMIZATION WITH DOCKER
|
||||||
eval DISK${i}_REF=${STORAGE}:${DISK_REF:-}${!disk}
|
# ==============================================================================
|
||||||
|
msg_info "Preparing ${OS_DISPLAY} image with Docker"
|
||||||
|
|
||||||
|
WORK_FILE=$(mktemp --suffix=.qcow2)
|
||||||
|
cp "$CACHE_FILE" "$WORK_FILE"
|
||||||
|
|
||||||
|
export LIBGUESTFS_BACKEND_SETTINGS=dns=8.8.8.8,1.1.1.1
|
||||||
|
|
||||||
|
DOCKER_PREINSTALLED="no"
|
||||||
|
|
||||||
|
# Install qemu-guest-agent and Docker during image customization
|
||||||
|
msg_info "Installing base packages in image"
|
||||||
|
if virt-customize -a "$WORK_FILE" --install qemu-guest-agent,curl,ca-certificates >/dev/null 2>&1; then
|
||||||
|
msg_ok "Installed base packages"
|
||||||
|
|
||||||
|
msg_info "Installing Docker (this may take 2-5 minutes)"
|
||||||
|
if virt-customize -q -a "$WORK_FILE" --run-command "curl -fsSL https://get.docker.com | sh" >/dev/null 2>&1 &&
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command "systemctl enable docker" >/dev/null 2>&1; then
|
||||||
|
msg_ok "Installed Docker"
|
||||||
|
|
||||||
|
msg_info "Configuring Docker daemon"
|
||||||
|
# Optimize Docker daemon configuration
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command "mkdir -p /etc/docker" >/dev/null 2>&1
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command 'cat > /etc/docker/daemon.json << EOF
|
||||||
|
{
|
||||||
|
"storage-driver": "overlay2",
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF' >/dev/null 2>&1
|
||||||
|
DOCKER_PREINSTALLED="yes"
|
||||||
|
msg_ok "Configured Docker daemon"
|
||||||
|
else
|
||||||
|
msg_ok "Docker will be installed on first boot"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
msg_ok "Packages will be installed on first boot"
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg_info "Finalizing image (hostname, SSH config)"
|
||||||
|
# Set hostname and prepare for unique machine-id
|
||||||
|
virt-customize -q -a "$WORK_FILE" --hostname "${HN}" >/dev/null 2>&1
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command "truncate -s 0 /etc/machine-id" >/dev/null 2>&1
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command "rm -f /var/lib/dbus/machine-id" >/dev/null 2>&1
|
||||||
|
|
||||||
|
# Configure SSH for Cloud-Init
|
||||||
|
if [ "$USE_CLOUD_INIT" = "yes" ]; then
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command "sed -i 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config" >/dev/null 2>&1 || true
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command "sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config" >/dev/null 2>&1 || true
|
||||||
|
else
|
||||||
|
# Configure auto-login for nocloud images (no Cloud-Init)
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command "mkdir -p /etc/systemd/system/serial-getty@ttyS0.service.d" >/dev/null 2>&1 || true
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command 'cat > /etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf << EOF
|
||||||
|
[Service]
|
||||||
|
ExecStart=
|
||||||
|
ExecStart=-/sbin/agetty --autologin root --noclear %I \$TERM
|
||||||
|
EOF' >/dev/null 2>&1 || true
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command "mkdir -p /etc/systemd/system/getty@tty1.service.d" >/dev/null 2>&1 || true
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command 'cat > /etc/systemd/system/getty@tty1.service.d/autologin.conf << EOF
|
||||||
|
[Service]
|
||||||
|
ExecStart=
|
||||||
|
ExecStart=-/sbin/agetty --autologin root --noclear %I \$TERM
|
||||||
|
EOF' >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
msg_ok "Finalized image"
|
||||||
|
|
||||||
|
# Create first-boot Docker install script (fallback if virt-customize failed)
|
||||||
|
if [ "$DOCKER_PREINSTALLED" = "no" ]; then
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command 'cat > /root/install-docker.sh << "DOCKERSCRIPT"
|
||||||
|
#!/bin/bash
|
||||||
|
exec > /var/log/install-docker.log 2>&1
|
||||||
|
echo "[$(date)] Starting Docker installation"
|
||||||
|
|
||||||
|
for i in {1..30}; do
|
||||||
|
ping -c 1 8.8.8.8 >/dev/null 2>&1 && break
|
||||||
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
if ! command -v virt-customize &>/dev/null; then
|
apt-get update
|
||||||
msg_info "Installing Pre-Requisite libguestfs-tools onto Host"
|
apt-get install -y qemu-guest-agent curl ca-certificates
|
||||||
apt-get -qq update >/dev/null
|
curl -fsSL https://get.docker.com | sh
|
||||||
apt-get -qq install libguestfs-tools lsb-release -y >/dev/null
|
systemctl enable docker
|
||||||
# Workaround for Proxmox VE 9.0 libguestfs issue
|
systemctl start docker
|
||||||
apt-get -qq install dhcpcd-base -y >/dev/null 2>&1 || true
|
|
||||||
msg_ok "Installed libguestfs-tools successfully"
|
mkdir -p /etc/docker
|
||||||
|
cat > /etc/docker/daemon.json << DAEMON
|
||||||
|
{
|
||||||
|
"storage-driver": "overlay2",
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": { "max-size": "10m", "max-file": "3" }
|
||||||
|
}
|
||||||
|
DAEMON
|
||||||
|
systemctl restart docker
|
||||||
|
|
||||||
|
touch /root/.docker-installed
|
||||||
|
echo "[$(date)] Docker installation completed"
|
||||||
|
DOCKERSCRIPT
|
||||||
|
chmod +x /root/install-docker.sh' >/dev/null 2>&1
|
||||||
|
|
||||||
|
virt-customize -q -a "$WORK_FILE" --run-command 'cat > /etc/systemd/system/install-docker.service << "DOCKERSERVICE"
|
||||||
|
[Unit]
|
||||||
|
Description=Install Docker on First Boot
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
ConditionPathExists=!/root/.docker-installed
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/root/install-docker.sh
|
||||||
|
RemainAfterExit=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
DOCKERSERVICE
|
||||||
|
systemctl enable install-docker.service' >/dev/null 2>&1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg_info "Adding Docker and Docker Compose Plugin to Debian 12 Qcow2 Disk Image"
|
# Resize disk to target size
|
||||||
virt-customize -q -a "${FILE}" --install qemu-guest-agent,apt-transport-https,ca-certificates,curl,gnupg,software-properties-common,lsb-release >/dev/null &&
|
msg_info "Resizing disk image to ${DISK_SIZE}"
|
||||||
virt-customize -q -a "${FILE}" --run-command "mkdir -p /etc/apt/keyrings && curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg" >/dev/null &&
|
qemu-img resize "$WORK_FILE" "${DISK_SIZE}" >/dev/null 2>&1
|
||||||
virt-customize -q -a "${FILE}" --run-command "echo 'deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable' > /etc/apt/sources.list.d/docker.list" >/dev/null &&
|
msg_ok "Resized disk image"
|
||||||
virt-customize -q -a "${FILE}" --run-command "apt-get update -qq && apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin" >/dev/null &&
|
|
||||||
virt-customize -q -a "${FILE}" --run-command "systemctl enable docker" >/dev/null &&
|
|
||||||
virt-customize -q -a "${FILE}" --hostname "${HN}" >/dev/null &&
|
|
||||||
virt-customize -q -a "${FILE}" --run-command "echo -n > /etc/machine-id" >/dev/null
|
|
||||||
msg_ok "Added Docker and Docker Compose Plugin to Debian 12 Qcow2 Disk Image successfully"
|
|
||||||
|
|
||||||
msg_info "Expanding root partition to use full disk space"
|
# ==============================================================================
|
||||||
qemu-img create -f qcow2 expanded.qcow2 ${DISK_SIZE} >/dev/null 2>&1
|
# VM CREATION
|
||||||
virt-resize --expand /dev/sda1 ${FILE} expanded.qcow2 >/dev/null 2>&1
|
# ==============================================================================
|
||||||
mv expanded.qcow2 ${FILE} >/dev/null 2>&1
|
msg_info "Creating Docker VM shell"
|
||||||
msg_ok "Expanded image to full size"
|
|
||||||
|
|
||||||
msg_info "Creating a Docker VM"
|
|
||||||
qm create $VMID -agent 1${MACHINE} -tablet 0 -localtime 1 -bios ovmf${CPU_TYPE} -cores $CORE_COUNT -memory $RAM_SIZE \
|
qm create $VMID -agent 1${MACHINE} -tablet 0 -localtime 1 -bios ovmf${CPU_TYPE} -cores $CORE_COUNT -memory $RAM_SIZE \
|
||||||
-name $HN -tags community-script -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
|
-name $HN -tags community-script -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci >/dev/null
|
||||||
pvesm alloc $STORAGE $VMID $DISK0 4M 1>&/dev/null
|
|
||||||
qm importdisk $VMID ${FILE} $STORAGE ${DISK_IMPORT:-} 1>&/dev/null
|
msg_ok "Created VM shell"
|
||||||
qm set $VMID \
|
|
||||||
-efidisk0 ${DISK0_REF}${FORMAT} \
|
# ==============================================================================
|
||||||
-scsi0 ${DISK1_REF},${DISK_CACHE}${THIN}size=${DISK_SIZE} \
|
# DISK IMPORT
|
||||||
-boot order=scsi0 \
|
# ==============================================================================
|
||||||
-serial0 socket >/dev/null
|
msg_info "Importing disk into storage ($STORAGE)"
|
||||||
qm resize $VMID scsi0 8G >/dev/null
|
|
||||||
|
if qm disk import --help >/dev/null 2>&1; then
|
||||||
|
IMPORT_CMD=(qm disk import)
|
||||||
|
else
|
||||||
|
IMPORT_CMD=(qm importdisk)
|
||||||
|
fi
|
||||||
|
|
||||||
|
IMPORT_OUT="$("${IMPORT_CMD[@]}" "$VMID" "$WORK_FILE" "$STORAGE" ${DISK_IMPORT:-} 2>&1 || true)"
|
||||||
|
DISK_REF_IMPORTED="$(printf '%s\n' "$IMPORT_OUT" | sed -n "s/.*successfully imported disk '\([^']\+\)'.*/\1/p" | tr -d "\r\"'")"
|
||||||
|
[[ -z "$DISK_REF_IMPORTED" ]] && DISK_REF_IMPORTED="$(pvesm list "$STORAGE" | awk -v id="$VMID" '$5 ~ ("vm-"id"-disk-") {print $1":"$5}' | sort | tail -n1)"
|
||||||
|
[[ -z "$DISK_REF_IMPORTED" ]] && {
|
||||||
|
msg_error "Unable to determine imported disk reference."
|
||||||
|
echo "$IMPORT_OUT"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
msg_ok "Imported disk (${CL}${BL}${DISK_REF_IMPORTED}${CL})"
|
||||||
|
|
||||||
|
# Clean up work file
|
||||||
|
rm -f "$WORK_FILE"
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# VM CONFIGURATION
|
||||||
|
# ==============================================================================
|
||||||
|
msg_info "Attaching EFI and root disk"
|
||||||
|
|
||||||
|
qm set "$VMID" \
|
||||||
|
--efidisk0 "${STORAGE}:0,efitype=4m" \
|
||||||
|
--scsi0 "${DISK_REF_IMPORTED},${DISK_CACHE}${THIN%,}" \
|
||||||
|
--boot order=scsi0 \
|
||||||
|
--serial0 socket >/dev/null
|
||||||
|
|
||||||
qm set $VMID --agent enabled=1 >/dev/null
|
qm set $VMID --agent enabled=1 >/dev/null
|
||||||
|
|
||||||
DESCRIPTION=$(
|
msg_ok "Attached EFI and root disk"
|
||||||
cat <<EOF
|
|
||||||
<div align='center'>
|
|
||||||
<a href='https://Helper-Scripts.com' target='_blank' rel='noopener noreferrer'>
|
|
||||||
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<h2 style='font-size: 24px; margin: 20px 0;'>Docker VM</h2>
|
# Set VM description
|
||||||
|
set_description
|
||||||
|
|
||||||
<p style='margin: 16px 0;'>
|
# Cloud-Init configuration
|
||||||
<a href='https://ko-fi.com/community_scripts' target='_blank' rel='noopener noreferrer'>
|
if [ "$USE_CLOUD_INIT" = "yes" ]; then
|
||||||
<img src='https://img.shields.io/badge/☕-Buy us a coffee-blue' alt='spend Coffee' />
|
msg_info "Configuring Cloud-Init"
|
||||||
</a>
|
setup_cloud_init "$VMID" "$STORAGE" "$HN" "yes"
|
||||||
</p>
|
msg_ok "Cloud-Init configured"
|
||||||
|
fi
|
||||||
|
|
||||||
<span style='margin: 0 10px;'>
|
# Start VM
|
||||||
<i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
|
|
||||||
<a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
|
|
||||||
</span>
|
|
||||||
<span style='margin: 0 10px;'>
|
|
||||||
<i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
|
|
||||||
<a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
|
|
||||||
</span>
|
|
||||||
<span style='margin: 0 10px;'>
|
|
||||||
<i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
|
|
||||||
<a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
qm set $VMID -description "$DESCRIPTION" >/dev/null
|
|
||||||
|
|
||||||
msg_ok "Created a Docker VM ${CL}${BL}(${HN})"
|
|
||||||
if [ "$START_VM" == "yes" ]; then
|
if [ "$START_VM" == "yes" ]; then
|
||||||
msg_info "Starting Docker VM"
|
msg_info "Starting Docker VM"
|
||||||
qm start $VMID
|
qm start $VMID >/dev/null 2>&1
|
||||||
msg_ok "Started Docker VM"
|
msg_ok "Started Docker VM"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ==============================================================================
|
||||||
|
# FINAL OUTPUT
|
||||||
|
# ==============================================================================
|
||||||
|
VM_IP=""
|
||||||
|
if [ "$START_VM" == "yes" ]; then
|
||||||
|
set +e
|
||||||
|
for i in {1..10}; do
|
||||||
|
VM_IP=$(qm guest cmd "$VMID" network-get-interfaces 2>/dev/null |
|
||||||
|
jq -r '.[] | select(.name != "lo") | ."ip-addresses"[]? | select(."ip-address-type" == "ipv4") | ."ip-address"' 2>/dev/null |
|
||||||
|
grep -v "^127\." | head -1) || true
|
||||||
|
[ -n "$VM_IP" ] && break
|
||||||
|
sleep 3
|
||||||
|
done
|
||||||
|
set -e
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\n${INFO}${BOLD}${GN}Docker VM Configuration Summary:${CL}"
|
||||||
|
echo -e "${TAB}${DGN}VM ID: ${BGN}${VMID}${CL}"
|
||||||
|
echo -e "${TAB}${DGN}Hostname: ${BGN}${HN}${CL}"
|
||||||
|
echo -e "${TAB}${DGN}OS: ${BGN}${OS_DISPLAY}${CL}"
|
||||||
|
[ -n "$VM_IP" ] && echo -e "${TAB}${DGN}IP Address: ${BGN}${VM_IP}${CL}"
|
||||||
|
|
||||||
|
if [ "$DOCKER_PREINSTALLED" = "yes" ]; then
|
||||||
|
echo -e "${TAB}${DGN}Docker: ${BGN}Pre-installed (via get.docker.com)${CL}"
|
||||||
|
else
|
||||||
|
echo -e "${TAB}${DGN}Docker: ${BGN}Installing on first boot${CL}"
|
||||||
|
echo -e "${TAB}${YW}⚠️ Wait 2-3 minutes for installation to complete${CL}"
|
||||||
|
echo -e "${TAB}${YW}⚠️ Check progress: ${BL}cat /var/log/install-docker.log${CL}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$USE_CLOUD_INIT" = "yes" ]; then
|
||||||
|
display_cloud_init_info "$VMID" "$HN" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
post_update_to_api "done" "none"
|
post_update_to_api "done" "none"
|
||||||
msg_ok "Completed successfully!\n"
|
msg_ok "Completed successfully!\n"
|
||||||
|
|||||||
6
vm/headers/docker-vm
Normal file
6
vm/headers/docker-vm
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
____ __
|
||||||
|
/ __ \____ _____/ /_____ _____
|
||||||
|
/ / / / __ \/ ___/ //_/ _ \/ ___/
|
||||||
|
/ /_/ / /_/ / /__/ ,< / __/ /
|
||||||
|
/_____/\____/\___/_/|_|\___/_/
|
||||||
|
|
||||||
Reference in New Issue
Block a user