Compare commits

..

11 Commits

Author SHA1 Message Date
MickLesk
82eac757d6 fix: whitespace cleanup and indentation fix in tools.func 2026-03-01 20:22:57 +01:00
MickLesk
31c7a86a4d Merge remote-tracking branch 'origin/main' into refactor/tools-func-stability
# Conflicts:
#	misc/tools.func
2026-03-01 20:18:36 +01:00
CanbiZ
950b32fef8 tools.func: Smarter parallel jobs calculation with load awareness
- get_parallel_jobs: Add memory-based limiting (1.5GB/job), load awareness,
  and container detection for conservative limits
- get_default_php_version: Add future versions (Debian 14, Ubuntu 26.04),
  update defaults to 8.3
- get_default_python_version: Add future versions, update defaults to 3.12
2026-01-05 17:36:51 +01:00
CanbiZ
01ba7356e0 foirmatting 2026-01-05 17:12:54 +01:00
CanbiZ
ef7015e232 Optimize tools.func: intelligent fallbacks, retry logic, caching, DNS pre-check
- curl_with_retry: DNS pre-check + exponential backoff
- download_gpg_key: Auto-detect key format, validation
- ensure_dependencies: Batch dpkg-query check, individual fallback
- install_packages_with_retry: Progressive recovery (dpkg fix, broken deps, individual packages)
- verify_repo_available: Caching with TTL to avoid repeated HTTP requests
- get_fallback_suite: Dynamic HTTP availability check cascade
- ensure_apt_working: APT lock handling, progressive recovery
- safe_service_restart: Wait-for-ready with configurable timeout, retry logic
- get_latest_github_release: Fallback to tags API, prerelease support, rate limit handling
2026-01-05 17:09:16 +01:00
CanbiZ
c118377665 Optimize tools.func: fix typos, duplicate debug_log, Node.js version, PG backup, Intel VPL 2026-01-05 17:05:24 +01:00
CanbiZ
8022525b49 Fix removed features in refactor branch
- Add libmfx-gen1.2 back for Intel Quick Sync Video encoding (Debian 12+13)
- Restore tmpfiles.d configuration for MariaDB /run/mysqld persistence
- Fix MariaDB fallback version from 11.4 to 12.2 (latest GA version)

These changes were incorrectly removed in the refactor commits.
2026-01-05 16:55:26 +01:00
MickLesk
c8dbce6e58 typo 2025-12-28 20:40:02 +01:00
MickLesk
0d821dd704 feat(tools.func): extend retry logic to all major downloads
Added curl_with_retry to all critical download operations:
- Adminer download
- Composer installer
- FFmpeg (binary and source)
- Go tarball
- Ghostscript source
- ImageMagick source
- rbenv and ruby-build
- uv (astral-sh)
- yq binary
- Go version check

Extended timeouts for large downloads:
- CURL_TIMEOUT=300 for FFmpeg, Go (large tarballs)
- CURL_TIMEOUT=180 for Ghostscript, ImageMagick

Remaining without retry (intentional):
- download_with_progress (specialized function)
- Rustup installer (piped to shell)
- Portainer version check (non-critical)

Total curl_with_retry/download_gpg_key usage: 27 locations
2025-12-26 19:03:41 +01:00
MickLesk
52061ea0db feat(tools.func): add retry logic and debug mode for stability
New helper functions:
- curl_with_retry: Robust curl wrapper with retry logic (3 attempts)
- curl_api_with_retry: API calls with HTTP status handling
- download_gpg_key: GPG key download with retry and dearmor support
- debug_log: Conditional debug output when TOOLS_DEBUG=true

Replaced critical curl calls:
- MongoDB GPG key download
- NodeSource GPG key download
- PostgreSQL GPG key download
- PHP (Sury) keyring download
- MySQL GPG key download
- setup_deb822_repo GPG import

Benefits:
- Automatic retry on transient network failures
- Configurable timeouts (CURL_TIMEOUT, CURL_CONNECT_TO)
- Debug mode for troubleshooting (TOOLS_DEBUG=true)
- Consistent error handling across all GPG key imports
2025-12-26 18:50:56 +01:00
MickLesk
5c82757c69 refactor(tools.func): use distro packages by default for stability
- fetch_and_deploy_gh_release: add validation for empty app names
  - Derives app name from repo if not provided
  - Prevents '/root/.: Is a directory' error (fixes #10342)

- setup_hwaccel: fix Intel driver app names for fetch_and_deploy_gh_release
  - Add proper app names: intel-igc-core, intel-igc-opencl, libigdgmm12, intel-opencl-icd

- setup_mariadb: use distro packages by default
  - Default: apt packages (default-mysql-server, mariadb-server)
  - Optional: USE_MARIADB_REPO=true for official MariaDB repo
  - Fixes GPG key/mirror availability issues

- setup_mysql: use distro packages by default
  - Default: apt packages (default-mysql-server, mysql-server)
  - Optional: USE_MYSQL_REPO=true for official MySQL repo
  - Keeps Debian Trixie 8.4 LTS handling when using official repo

- setup_postgresql: use distro packages by default
  - Default: apt packages (postgresql, postgresql-client)
  - Optional: USE_PGDG_REPO=true for official PGDG repo

- setup_docker: use distro packages by default
  - Default: docker.io package
  - Optional: USE_DOCKER_REPO=true for official Docker repo
  - Maintains Portainer support in both modes

This refactoring prioritizes stability by using well-tested distro
packages while maintaining the option to use official repos for
specific version requirements.
2025-12-26 18:42:48 +01:00
188 changed files with 1622 additions and 4342 deletions

View File

@@ -8,7 +8,7 @@ on:
jobs: jobs:
check-new-script: check-new-script:
if: github.repository == 'community-scripts/ProxmoxVE' if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: self-hosted runs-on: coolify-runner
permissions: permissions:
pull-requests: write pull-requests: write
contents: read contents: read

View File

@@ -1,255 +0,0 @@
name: Push JSON changes to PocketBase
on:
push:
branches:
- main
paths:
- "frontend/public/json/**"
jobs:
push-json:
runs-on: self-hosted
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed JSON files with slug
id: changed
run: |
changed=$(git diff --name-only "${{ github.event.before }}" "${{ github.event.after }}" -- frontend/public/json/ | grep '\.json$' || true)
with_slug=""
for f in $changed; do
[[ -f "$f" ]] || continue
jq -e '.slug' "$f" >/dev/null 2>&1 && with_slug="$with_slug $f"
done
with_slug=$(echo $with_slug | xargs -n1)
if [[ -z "$with_slug" ]]; then
echo "No app JSON files changed (or no files with slug)."
echo "count=0" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "$with_slug" > changed_app_jsons.txt
echo "count=$(echo "$with_slug" | wc -w)" >> "$GITHUB_OUTPUT"
- name: Push to PocketBase
if: steps.changed.outputs.count != '0'
env:
POCKETBASE_URL: ${{ secrets.POCKETBASE_URL }}
POCKETBASE_COLLECTION: ${{ secrets.POCKETBASE_COLLECTION }}
POCKETBASE_ADMIN_EMAIL: ${{ secrets.POCKETBASE_ADMIN_EMAIL }}
POCKETBASE_ADMIN_PASSWORD: ${{ secrets.POCKETBASE_ADMIN_PASSWORD }}
run: |
node << 'ENDSCRIPT'
(async function() {
const fs = require('fs');
const https = require('https');
const http = require('http');
const url = require('url');
function request(fullUrl, opts) {
return new Promise(function(resolve, reject) {
const u = url.parse(fullUrl);
const isHttps = u.protocol === 'https:';
const body = opts.body;
const options = {
hostname: u.hostname,
port: u.port || (isHttps ? 443 : 80),
path: u.path,
method: opts.method || 'GET',
headers: opts.headers || {}
};
if (body) options.headers['Content-Length'] = Buffer.byteLength(body);
const lib = isHttps ? https : http;
const req = lib.request(options, function(res) {
let data = '';
res.on('data', function(chunk) { data += chunk; });
res.on('end', function() {
resolve({ ok: res.statusCode >= 200 && res.statusCode < 300, statusCode: res.statusCode, body: data });
});
});
req.on('error', reject);
if (body) req.write(body);
req.end();
});
}
const raw = process.env.POCKETBASE_URL.replace(/\/$/, '');
const apiBase = /\/api$/i.test(raw) ? raw : raw + '/api';
const coll = process.env.POCKETBASE_COLLECTION;
const files = fs.readFileSync('changed_app_jsons.txt', 'utf8').trim().split(/\s+/).filter(Boolean);
const authUrl = apiBase + '/collections/users/auth-with-password';
console.log('Auth URL: ' + authUrl);
const authBody = JSON.stringify({
identity: process.env.POCKETBASE_ADMIN_EMAIL,
password: process.env.POCKETBASE_ADMIN_PASSWORD
});
const authRes = await request(authUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: authBody
});
if (!authRes.ok) {
throw new Error('Auth failed. Tried: ' + authUrl + ' - Verify POST to that URL with body {"identity":"...","password":"..."} works. Response: ' + authRes.body);
}
const token = JSON.parse(authRes.body).token;
const recordsUrl = apiBase + '/collections/' + encodeURIComponent(coll) + '/records';
let categoryIdToName = {};
try {
const metadata = JSON.parse(fs.readFileSync('frontend/public/json/metadata.json', 'utf8'));
(metadata.categories || []).forEach(function(cat) { categoryIdToName[cat.id] = cat.name; });
} catch (e) { console.warn('Could not load metadata.json:', e.message); }
let typeValueToId = {};
let categoryNameToPbId = {};
try {
const typesRes = await request(apiBase + '/collections/z_ref_script_types/records?perPage=500', { headers: { 'Authorization': token } });
if (typesRes.ok) {
const typesData = JSON.parse(typesRes.body);
(typesData.items || []).forEach(function(item) {
if (item.type != null) typeValueToId[item.type] = item.id;
if (item.name != null) typeValueToId[item.name] = item.id;
if (item.value != null) typeValueToId[item.value] = item.id;
});
}
} catch (e) { console.warn('Could not fetch z_ref_script_types:', e.message); }
try {
const catRes = await request(apiBase + '/collections/script_categories/records?perPage=500', { headers: { 'Authorization': token } });
if (catRes.ok) {
const catData = JSON.parse(catRes.body);
(catData.items || []).forEach(function(item) { if (item.name) categoryNameToPbId[item.name] = item.id; });
}
} catch (e) { console.warn('Could not fetch script_categories:', e.message); }
var noteTypeToId = {};
var installMethodTypeToId = {};
var osToId = {};
var osVersionToId = {};
try {
const res = await request(apiBase + '/collections/z_ref_note_types/records?perPage=500', { headers: { 'Authorization': token } });
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.type != null) noteTypeToId[item.type] = item.id; });
} catch (e) { console.warn('z_ref_note_types:', e.message); }
try {
const res = await request(apiBase + '/collections/z_ref_install_method_types/records?perPage=500', { headers: { 'Authorization': token } });
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.type != null) installMethodTypeToId[item.type] = item.id; });
} catch (e) { console.warn('z_ref_install_method_types:', e.message); }
try {
const res = await request(apiBase + '/collections/z_ref_os/records?perPage=500', { headers: { 'Authorization': token } });
if (res.ok) JSON.parse(res.body).items?.forEach(function(item) { if (item.os != null) osToId[item.os] = item.id; });
} catch (e) { console.warn('z_ref_os:', e.message); }
try {
const res = await request(apiBase + '/collections/z_ref_os_version/records?perPage=500&expand=os', { headers: { 'Authorization': token } });
if (res.ok) {
(JSON.parse(res.body).items || []).forEach(function(item) {
var osName = item.expand && item.expand.os && item.expand.os.os != null ? item.expand.os.os : null;
if (osName != null && item.version != null) osVersionToId[osName + '|' + item.version] = item.id;
});
}
} catch (e) { console.warn('z_ref_os_version:', e.message); }
var notesCollUrl = apiBase + '/collections/script_notes/records';
var installMethodsCollUrl = apiBase + '/collections/script_install_methods/records';
for (const file of files) {
if (!fs.existsSync(file)) continue;
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
if (!data.slug) { console.log('Skipping', file, '(no slug)'); continue; }
var payload = {
name: data.name,
slug: data.slug,
script_created: data.date_created || data.script_created,
script_updated: data.date_created || data.script_updated,
updateable: data.updateable,
privileged: data.privileged,
port: data.interface_port != null ? data.interface_port : data.port,
documentation: data.documentation,
website: data.website,
logo: data.logo,
description: data.description,
config_path: data.config_path,
default_user: (data.default_credentials && data.default_credentials.username) || data.default_user,
default_passwd: (data.default_credentials && data.default_credentials.password) || data.default_passwd,
is_dev: false
};
var resolvedType = typeValueToId[data.type];
if (resolvedType == null && data.type === 'ct') resolvedType = typeValueToId['lxc'];
if (resolvedType) payload.type = resolvedType;
var resolvedCats = (data.categories || []).map(function(n) { return categoryNameToPbId[categoryIdToName[n]]; }).filter(Boolean);
if (resolvedCats.length) payload.categories = resolvedCats;
if (data.version !== undefined) payload.version = data.version;
if (data.changelog !== undefined) payload.changelog = data.changelog;
if (data.screenshots !== undefined) payload.screenshots = data.screenshots;
const filter = "(slug='" + data.slug + "')";
const listRes = await request(recordsUrl + '?filter=' + encodeURIComponent(filter) + '&perPage=1', {
headers: { 'Authorization': token }
});
const list = JSON.parse(listRes.body);
const existingId = list.items && list.items[0] && list.items[0].id;
async function resolveNotesAndInstallMethods(scriptId) {
var noteIds = [];
for (var i = 0; i < (data.notes || []).length; i++) {
var note = data.notes[i];
var typeId = noteTypeToId[note.type];
if (typeId == null) continue;
var postRes = await request(notesCollUrl, {
method: 'POST',
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
body: JSON.stringify({ text: note.text || '', type: typeId })
});
if (postRes.ok) noteIds.push(JSON.parse(postRes.body).id);
}
var installMethodIds = [];
for (var j = 0; j < (data.install_methods || []).length; j++) {
var im = data.install_methods[j];
var typeId = installMethodTypeToId[im.type];
var res = im.resources || {};
var osId = osToId[res.os];
var osVersionKey = (res.os != null && res.version != null) ? res.os + '|' + res.version : null;
var osVersionId = osVersionKey ? osVersionToId[osVersionKey] : null;
var imBody = {
script: scriptId,
resources_cpu: res.cpu != null ? res.cpu : 0,
resources_ram: res.ram != null ? res.ram : 0,
resources_hdd: res.hdd != null ? res.hdd : 0
};
if (typeId) imBody.type = typeId;
if (osId) imBody.os = osId;
if (osVersionId) imBody.os_version = osVersionId;
var imPostRes = await request(installMethodsCollUrl, {
method: 'POST',
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
body: JSON.stringify(imBody)
});
if (imPostRes.ok) installMethodIds.push(JSON.parse(imPostRes.body).id);
}
return { noteIds: noteIds, installMethodIds: installMethodIds };
}
if (existingId) {
var resolved = await resolveNotesAndInstallMethods(existingId);
payload.notes = resolved.noteIds;
payload.install_methods = resolved.installMethodIds;
console.log('Updating', file, '(slug=' + data.slug + ')');
const r = await request(recordsUrl + '/' + existingId, {
method: 'PATCH',
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!r.ok) throw new Error('PATCH failed: ' + r.body);
} else {
console.log('Creating', file, '(slug=' + data.slug + ')');
const r = await request(recordsUrl, {
method: 'POST',
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!r.ok) throw new Error('POST failed: ' + r.body);
var scriptId = JSON.parse(r.body).id;
var resolved = await resolveNotesAndInstallMethods(scriptId);
var patchRes = await request(recordsUrl + '/' + scriptId, {
method: 'PATCH',
headers: { 'Authorization': token, 'Content-Type': 'application/json' },
body: JSON.stringify({ install_methods: resolved.installMethodIds, notes: resolved.noteIds })
});
if (!patchRes.ok) throw new Error('PATCH relations failed: ' + patchRes.body);
}
}
console.log('Done.');
})().catch(e => { console.error(e); process.exit(1); });
ENDSCRIPT
shell: bash

View File

@@ -410,171 +410,8 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-03-07
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix(immich): fix update script failing to add Debian testing repo when preferences file already exists [@Copilot](https://github.com/Copilot) ([#12631](https://github.com/community-scripts/ProxmoxVE/pull/12631))
## 2026-03-06
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- RustDesk Server: Fix update script [@tremor021](https://github.com/tremor021) ([#12625](https://github.com/community-scripts/ProxmoxVE/pull/12625))
- [Node-RED] Restart service after update [@Aurelien30000](https://github.com/Aurelien30000) ([#12621](https://github.com/community-scripts/ProxmoxVE/pull/12621))
- wealthfolio: update cors [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12617](https://github.com/community-scripts/ProxmoxVE/pull/12617))
- CryptPad: Better update handling [@tremor021](https://github.com/tremor021) ([#12611](https://github.com/community-scripts/ProxmoxVE/pull/12611))
- #### ✨ New Features
- RustDesk Server: Switch to updated repository [@tremor021](https://github.com/tremor021) ([#12083](https://github.com/community-scripts/ProxmoxVE/pull/12083))
- #### 💥 Breaking Changes
- Semaphore: Move from BoltDB to SQLite [@tremor021](https://github.com/tremor021) ([#12624](https://github.com/community-scripts/ProxmoxVE/pull/12624))
## 2026-03-05
### 🆕 New Scripts
- ddclient ([#12587](https://github.com/community-scripts/ProxmoxVE/pull/12587))
- Netbird ([#12585](https://github.com/community-scripts/ProxmoxVE/pull/12585))
- Papra ([#12577](https://github.com/community-scripts/ProxmoxVE/pull/12577))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fluid-calendar: add build-essential to install and update dependencies [@Copilot](https://github.com/Copilot) ([#12602](https://github.com/community-scripts/ProxmoxVE/pull/12602))
- Refactor: BentoPDF [@vhsdream](https://github.com/vhsdream) ([#12597](https://github.com/community-scripts/ProxmoxVE/pull/12597))
- Tianji: Fix the bug introduced by the refactor [@tremor021](https://github.com/tremor021) ([#12564](https://github.com/community-scripts/ProxmoxVE/pull/12564))
- PowerDNS: use 'launch=' instead of 'launch+=' for gsqlite3 backend [@MickLesk](https://github.com/MickLesk) ([#12579](https://github.com/community-scripts/ProxmoxVE/pull/12579))
### 🗑️ Deleted Scripts
- Suwayomi-Server: remove due to inactivity and very low usage [@MickLesk](https://github.com/MickLesk) ([#12596](https://github.com/community-scripts/ProxmoxVE/pull/12596))
### 💾 Core
- #### 🔧 Refactor
- core: add var_os / var_version to whitelist for app.vars [@MickLesk](https://github.com/MickLesk) ([#12576](https://github.com/community-scripts/ProxmoxVE/pull/12576))
## 2026-03-04
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- fix: gitea-mirror [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12549](https://github.com/community-scripts/ProxmoxVE/pull/12549))
- fix(immich): correct LibRaw clone URL to official upstream [@DenislavDenev](https://github.com/DenislavDenev) ([#12526](https://github.com/community-scripts/ProxmoxVE/pull/12526))
- update: stirling-pdf: java 25 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#12552](https://github.com/community-scripts/ProxmoxVE/pull/12552))
- Docmost: register NoopAuditService globally when EE submodule is missing [@MickLesk](https://github.com/MickLesk) ([#12551](https://github.com/community-scripts/ProxmoxVE/pull/12551))
- jellyseer/overseer migration corrupting /usr/bin/update [@MickLesk](https://github.com/MickLesk) ([#12539](https://github.com/community-scripts/ProxmoxVE/pull/12539))
- PowerDNS: use gsqlite3 backend instead of BIND [@MickLesk](https://github.com/MickLesk) ([#12538](https://github.com/community-scripts/ProxmoxVE/pull/12538))
- addon migrations: /usr/bin/update replacement to prevent syntax error [@MickLesk](https://github.com/MickLesk) ([#12540](https://github.com/community-scripts/ProxmoxVE/pull/12540))
- #### 🔧 Refactor
- Fluid-Calendar: NodeJS bump [@tremor021](https://github.com/tremor021) ([#12558](https://github.com/community-scripts/ProxmoxVE/pull/12558))
- Refactor: LiteLLM [@tremor021](https://github.com/tremor021) ([#12550](https://github.com/community-scripts/ProxmoxVE/pull/12550))
### 💾 Core
- #### 🐞 Bug Fixes
- tools: fall back to distro packages for psql [@MickLesk](https://github.com/MickLesk) ([#12542](https://github.com/community-scripts/ProxmoxVE/pull/12542))
- fix: whitelist var_searchdomain and fix the handling of var_ns and va… [@tommoyer](https://github.com/tommoyer) ([#12521](https://github.com/community-scripts/ProxmoxVE/pull/12521))
## 2026-03-03
### 🆕 New Scripts
- Tinyauth: v5 Support & add Debian Version [@MickLesk](https://github.com/MickLesk) ([#12501](https://github.com/community-scripts/ProxmoxVE/pull/12501))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- cross-seed: install build-essential to resolve missing `make` error [@Copilot](https://github.com/Copilot) ([#12522](https://github.com/community-scripts/ProxmoxVE/pull/12522))
- meshcentral: increased disk space to 4GB [@MickLesk](https://github.com/MickLesk) ([#12509](https://github.com/community-scripts/ProxmoxVE/pull/12509))
- #### 🔧 Refactor
- opnsense-vm: harden temp dir, bridge detection and network selection [@MickLesk](https://github.com/MickLesk) ([#12513](https://github.com/community-scripts/ProxmoxVE/pull/12513))
### 🗑️ Deleted Scripts
- Remove Unifi Network Server scripts (dead APT repo) [@Copilot](https://github.com/Copilot) ([#12500](https://github.com/community-scripts/ProxmoxVE/pull/12500))
### 💾 Core
- #### ✨ New Features
- core: recovery - add ENOSPC disk-full detection with auto-retry using * 2 hdd [@MickLesk](https://github.com/MickLesk) ([#12511](https://github.com/community-scripts/ProxmoxVE/pull/12511))
### 📚 Documentation
- Fix config_path casing in reactive-resume.json [@ScubyG](https://github.com/ScubyG) ([#12525](https://github.com/community-scripts/ProxmoxVE/pull/12525))
### 🌐 Website
- #### 🐞 Bug Fixes
- Revert #11534 PR that messed up search [@BramSuurdje](https://github.com/BramSuurdje) ([#12492](https://github.com/community-scripts/ProxmoxVE/pull/12492))
## 2026-03-02
### 🆕 New Scripts
- PowerDNS ([#12481](https://github.com/community-scripts/ProxmoxVE/pull/12481))
- Profilarr ([#12441](https://github.com/community-scripts/ProxmoxVE/pull/12441))
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Tracearr: prepare for imminent v1.4.19 release [@durzo](https://github.com/durzo) ([#12413](https://github.com/community-scripts/ProxmoxVE/pull/12413))
- #### ✨ New Features
- Frigate: Bump to v0.17 [@MickLesk](https://github.com/MickLesk) ([#12474](https://github.com/community-scripts/ProxmoxVE/pull/12474))
- #### 💥 Breaking Changes
- Migrate: DokPloy, Komodo, Coolify, Dockge, Runtipi to Addons [@MickLesk](https://github.com/MickLesk) ([#12275](https://github.com/community-scripts/ProxmoxVE/pull/12275))
- #### 🔧 Refactor
- ref: replace generic exit 1 with specific exit codes in ct & install [@MickLesk](https://github.com/MickLesk) ([#12475](https://github.com/community-scripts/ProxmoxVE/pull/12475))
### 💾 Core
- #### ✨ New Features
- tools.func: Improve stability with retry logic, caching, and debug mode [@MickLesk](https://github.com/MickLesk) ([#10351](https://github.com/community-scripts/ProxmoxVE/pull/10351))
- #### 🔧 Refactor
- core: standardize exit codes and add mappings [@MickLesk](https://github.com/MickLesk) ([#12467](https://github.com/community-scripts/ProxmoxVE/pull/12467))
### 🌐 Website
- frontend: improve detail view badges, addon texts, and HTML title [@MickLesk](https://github.com/MickLesk) ([#12461](https://github.com/community-scripts/ProxmoxVE/pull/12461))
## 2026-03-01 ## 2026-03-01
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Sparkyfitness: use pnpm [@tomfrenzel](https://github.com/tomfrenzel) ([#12445](https://github.com/community-scripts/ProxmoxVE/pull/12445))
- OpenArchiver: Fix installation [@tremor021](https://github.com/tremor021) ([#12447](https://github.com/community-scripts/ProxmoxVE/pull/12447))
## 2026-02-28 ## 2026-02-28
### 🚀 Updated Scripts ### 🚀 Updated Scripts

View File

@@ -19,48 +19,44 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh"
function update_script() { function update_script() {
if [[ ! -d /opt/komodo ]]; then [[ -d /opt/komodo ]] || {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi }
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_info "Updating ${APP}"
echo "" COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1)
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" if [[ -z "$COMPOSE_FILE" ]]; then
echo -e "${TAB}${TAB}${GN}update_komodo${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" msg_error "No valid compose file found in /opt/komodo!"
echo "" exit
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM fi
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then COMPOSE_BASENAME=$(basename "$COMPOSE_FILE")
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)" if [[ "$COMPOSE_BASENAME" == "sqlite.compose.yaml" || "$COMPOSE_BASENAME" == "postgres.compose.yaml" ]]; then
COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1) msg_error "❌ Detected outdated Komodo setup using SQLite or PostgreSQL (FerretDB v1)."
if [[ -z "$COMPOSE_FILE" ]]; then echo -e "${YW}This configuration is no longer supported since Komodo v1.18.0.${CL}"
msg_error "No valid compose file found in /opt/komodo!" echo -e "${YW}Please follow the migration guide:${CL}"
exit 252 echo -e "${BGN}https://github.com/community-scripts/ProxmoxVE/discussions/5689${CL}\n"
fi
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
msg_ok "Updated ${APP}"
exit exit
fi fi
msg_info "Migrating update function" BACKUP_FILE="/opt/komodo/${COMPOSE_BASENAME}.bak_$(date +%Y%m%d_%H%M%S)"
TMP_UPDATE=$(mktemp) cp "$COMPOSE_FILE" "$BACKUP_FILE" || {
cat <<'MIGRATION_EOF' >"$TMP_UPDATE" msg_error "Failed to create backup of ${COMPOSE_BASENAME}!"
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh)" exit
MIGRATION_EOF }
mv "$TMP_UPDATE" /usr/bin/update GITHUB_URL="https://raw.githubusercontent.com/moghtech/komodo/main/compose/${COMPOSE_BASENAME}"
chmod +x /usr/bin/update if ! curl -fsSL "$GITHUB_URL" -o "$COMPOSE_FILE"; then
msg_error "Failed to download ${COMPOSE_BASENAME} from GitHub!"
ln -sf /usr/bin/update /usr/bin/update_komodo 2>/dev/null || true mv "$BACKUP_FILE" "$COMPOSE_FILE"
msg_ok "Migration complete" exit
fi
msg_info "Running addon update" $STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
type=update bash <(curl -fsSL "${ADDON_SCRIPT}") $STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
exit msg_ok "Updated Alpine-Komodo"
msg_ok "Updated successfully!"
exit 0
} }
start start

View File

@@ -31,10 +31,6 @@ function update_script() {
msg_info "Updating Node-RED" msg_info "Updating Node-RED"
$STD npm install -g --unsafe-perm node-red $STD npm install -g --unsafe-perm node-red
msg_ok "Updated Node-RED" msg_ok "Updated Node-RED"
msg_info "Restarting Node-RED"
$STD rc-service nodered restart
msg_ok "Restarted Node-RED"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit 0 exit 0
} }

View File

@@ -27,21 +27,21 @@ function update_script() {
fi fi
APIRELEASE=$(curl -s https://api.github.com/repos/lejianwen/rustdesk-api/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }') APIRELEASE=$(curl -s https://api.github.com/repos/lejianwen/rustdesk-api/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
RELEASE=$(curl -s https://api.github.com/repos/lejianwen/rustdesk-server/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') RELEASE=$(curl -s https://api.github.com/repos/rustdesk/rustdesk-server/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
if [ "${RELEASE}" != "$(cat ~/.rustdesk-server 2>/dev/null)" ] || [ ! -f ~/.rustdesk-server ]; then if [ "${RELEASE}" != "$(cat ~/.rustdesk-server 2>/dev/null)" ] || [ ! -f ~/.rustdesk-server ]; then
msg_info "Updating RustDesk Server to v${RELEASE}" msg_info "Updating RustDesk Server to v${RELEASE}"
$STD apk -U upgrade $STD apk -U upgrade
$STD service rustdesk-server-hbbs stop $STD service rustdesk-server-hbbs stop
$STD service rustdesk-server-hbbr stop $STD service rustdesk-server-hbbr stop
temp_file1=$(mktemp) temp_file1=$(mktemp)
curl -fsSL "https://github.com/lejianwen/rustdesk-server/releases/download/${RELEASE}/rustdesk-server-linux-amd64.zip" -o "$temp_file1" curl -fsSL "https://github.com/rustdesk/rustdesk-server/releases/download/${RELEASE}/rustdesk-server-linux-amd64.zip" -o "$temp_file1"
$STD unzip "$temp_file1" $STD unzip "$temp_file1"
cp -r amd64/* /opt/rustdesk-server/ cp -r amd64/* /opt/rustdesk-server/
echo "${RELEASE}" >~/.rustdesk-server echo "${RELEASE}" >~/.rustdesk-server
$STD service rustdesk-server-hbbs start $STD service rustdesk-server-hbbs start
$STD service rustdesk-server-hbbr start $STD service rustdesk-server-hbbr start
rm -rf amd64 rm -rf amd64
rm -f "$temp_file1" rm -f $temp_file1
msg_ok "Updated RustDesk Server" msg_ok "Updated RustDesk Server"
else else
msg_ok "No update required. ${APP} is already at v${RELEASE}" msg_ok "No update required. ${APP} is already at v${RELEASE}"
@@ -56,7 +56,7 @@ function update_script() {
echo "${APIRELEASE}" >~/.rustdesk-api echo "${APIRELEASE}" >~/.rustdesk-api
$STD service rustdesk-api start $STD service rustdesk-api start
rm -rf release rm -rf release
rm -f "$temp_file2" rm -f $temp_file2
msg_ok "Updated RustDesk API" msg_ok "Updated RustDesk API"
else else
msg_ok "No update required. RustDesk API is already at v${APIRELEASE}" msg_ok "No update required. RustDesk API is already at v${APIRELEASE}"

View File

@@ -35,20 +35,6 @@ function update_script() {
$STD service tinyauth stop $STD service tinyauth stop
msg_ok "Service Stopped" msg_ok "Service Stopped"
if [[ -f /opt/tinyauth/.env ]] && ! grep -q "^TINYAUTH_" /opt/tinyauth/.env; then
msg_info "Migrating .env to v5 format"
sed -i \
-e 's/^DATABASE_PATH=/TINYAUTH_DATABASE_PATH=/' \
-e 's/^USERS=/TINYAUTH_AUTH_USERS=/' \
-e "s/^USERS='/TINYAUTH_AUTH_USERS='/" \
-e 's/^APP_URL=/TINYAUTH_APPURL=/' \
-e 's/^SECRET=/TINYAUTH_AUTH_SECRET=/' \
-e 's/^PORT=/TINYAUTH_SERVER_PORT=/' \
-e 's/^ADDRESS=/TINYAUTH_SERVER_ADDRESS=/' \
/opt/tinyauth/.env
msg_ok "Migrated .env to v5 format"
fi
msg_info "Updating Tinyauth" msg_info "Updating Tinyauth"
rm -f /opt/tinyauth/tinyauth rm -f /opt/tinyauth/tinyauth
curl -fsSL "https://github.com/steveiliop56/tinyauth/releases/download/v${RELEASE}/tinyauth-amd64" -o /opt/tinyauth/tinyauth curl -fsSL "https://github.com/steveiliop56/tinyauth/releases/download/v${RELEASE}/tinyauth-amd64" -o /opt/tinyauth/tinyauth

View File

@@ -7,7 +7,7 @@ source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxV
APP="BentoPDF" APP="BentoPDF"
var_tags="${var_tags:-pdf-editor}" var_tags="${var_tags:-pdf-editor}"
var_cpu="${var_cpu:-2}" var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-4096}" var_ram="${var_ram:-4096}"
var_disk="${var_disk:-4}" var_disk="${var_disk:-4}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
@@ -35,32 +35,16 @@ function update_script() {
systemctl stop bentopdf systemctl stop bentopdf
msg_ok "Stopped Service" msg_ok "Stopped Service"
[[ -f /opt/bentopdf/.env.production ]] && cp /opt/bentopdf/.env.production /opt/production.env
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bentopdf" "alam00000/bentopdf" "tarball" "latest" "/opt/bentopdf" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "bentopdf" "alam00000/bentopdf" "tarball" "latest" "/opt/bentopdf"
msg_info "Updating BentoPDF" msg_info "Updating BentoPDF"
cd /opt/bentopdf cd /opt/bentopdf
$STD npm ci --no-audit --no-fund $STD npm ci --no-audit --no-fund
$STD npm install http-server -g
if [[ -f /opt/production.env ]]; then
mv /opt/production.env ./.env.production
else
cp ./.env.example ./.env.production
fi
export NODE_OPTIONS="--max-old-space-size=3072"
export SIMPLE_MODE=true export SIMPLE_MODE=true
export VITE_USE_CDN=true $STD npm run build -- --mode production
$STD npm run build:all
msg_ok "Updated BentoPDF" msg_ok "Updated BentoPDF"
msg_info "Starting Service" msg_info "Starting Service"
if grep -q '8080' /etc/systemd/system/bentopdf.service; then
sed -i -e 's|/bentopdf|/bentopdf/dist|' \
-e 's|npx.*|npx http-server -g -b -d false -r --no-dotfiles|' \
/etc/systemd/system/bentopdf.service
systemctl daemon-reload
fi
systemctl start bentopdf systemctl start bentopdf
msg_ok "Started Service" msg_ok "Started Service"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"

View File

@@ -19,8 +19,6 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coolify.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
@@ -31,33 +29,10 @@ function update_script() {
exit exit
fi fi
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_info "Updating Coolify"
echo "" $STD bash <(curl -fsSL https://cdn.coollabs.io/coolify/install.sh)
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" msg_ok "Updated Coolify"
echo -e "${TAB}${TAB}${GN}update_coolify${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" msg_ok "Updated successfully!"
echo ""
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)"
$STD bash <(curl -fsSL https://cdn.coollabs.io/coolify/install.sh)
msg_ok "Updated ${APP}"
exit
fi
msg_info "Migrating update function"
TMP_UPDATE=$(mktemp)
cat <<'MIGRATION_EOF' >"$TMP_UPDATE"
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coolify.sh)"
MIGRATION_EOF
mv "$TMP_UPDATE" /usr/bin/update
chmod +x /usr/bin/update
ln -sf /usr/bin/update /usr/bin/update_coolify 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

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

View File

@@ -33,23 +33,17 @@ function update_script() {
systemctl stop cryptpad systemctl stop cryptpad
msg_info "Stopped Service" msg_info "Stopped Service"
msg_info "Creating backup" msg_info "Backing up configuration"
[ -f /opt/cryptpad/config/config.js ] && mv /opt/cryptpad/config/config.js /opt/ [ -f /opt/cryptpad/config/config.js ] && mv /opt/cryptpad/config/config.js /opt/
for dir in blob block customize data datastore www/common/onlyoffice/dist onlyoffice-conf; do msg_ok "Backed up configuration"
[ -d "/opt/cryptpad/${dir}" ] && mv "/opt/cryptpad/${dir}" "/tmp/cryptpad_${dir//\//_}"
done
msg_ok "Created backup"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "cryptpad" "cryptpad/cryptpad" "tarball" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "cryptpad" "cryptpad/cryptpad" "tarball"
msg_info "Restoring backup" msg_info "Restoring configuration"
mv /opt/config.js /opt/cryptpad/config/ mv /opt/config.js /opt/cryptpad/config/
for dir in blob block customize data datastore www/common/onlyoffice/dist onlyoffice-conf; do msg_ok "Configuration restored"
[ -d "/tmp/cryptpad_${dir//\//_}" ] && mv "/tmp/cryptpad_${dir//\//_}" "/opt/cryptpad/${dir}"
done
msg_ok "Restored backup"
msg_info "Updating CryptPad" msg_info "Updating CryptaPad"
cd /opt/cryptpad cd /opt/cryptpad
$STD npm ci $STD npm ci
$STD npm run install:components $STD npm run install:components

View File

@@ -1,46 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: mitchscobell
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://ddclient.net/
APP="ddclient"
var_tags="${var_tags:-network}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}"
var_disk="${var_disk:-2}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -f /etc/ddclient.conf ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating ddclient"
$STD apt update
$STD apt install --only-upgrade -y ddclient
$STD systemctl restart ddclient
msg_ok "Updated ddclient"
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}"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck # Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster) | Migration: MickLesk (CanbiZ) # Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://dockge.kuma.pet/ # Source: https://dockge.kuma.pet/
@@ -19,47 +19,26 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dockge.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/dockge ]]; then if [[ ! -d /opt/dockge ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_info "Updating base system"
echo "" $STD apt update
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" $STD apt upgrade -y
echo -e "${TAB}${TAB}${GN}update_dockge${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" msg_ok "Base system updated"
echo ""
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)"
cd /opt/dockge
$STD docker compose pull
$STD docker compose up -d
msg_ok "Updated ${APP}"
exit
fi
msg_info "Migrating update function" msg_info "Updating Dockge"
TMP_UPDATE=$(mktemp) cd /opt/dockge
cat <<'MIGRATION_EOF' >"$TMP_UPDATE" $STD docker compose pull
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dockge.sh)" $STD docker compose up -d
MIGRATION_EOF msg_ok "Updated Dockge"
mv "$TMP_UPDATE" /usr/bin/update msg_ok "Updated successfully!"
chmod +x /usr/bin/update
ln -sf /usr/bin/update /usr/bin/update_dockge 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

@@ -48,17 +48,6 @@ function update_script() {
cd /opt/docmost cd /opt/docmost
mv /opt/.env /opt/docmost/.env mv /opt/.env /opt/docmost/.env
mv /opt/data /opt/docmost/data mv /opt/data /opt/docmost/data
# Fix: Docmost EE (audit logs etc.) lives in a git submodule that is NOT
# included in GitHub tarballs. The community NoopAuditService exists but
# is only exported by CoreModule child modules such as UserModule cannot
# resolve it. Making CoreModule @Global() exposes the token app-wide.
if [[ ! -f /opt/docmost/apps/server/src/ee/ee.module.ts ]] \
&& ! grep -q '@Global()' /opt/docmost/apps/server/src/core/core.module.ts 2>/dev/null; then
sed -i '/^ Module,$/a\ Global,' /opt/docmost/apps/server/src/core/core.module.ts
sed -i '/^@Module({$/i @Global()' /opt/docmost/apps/server/src/core/core.module.ts
fi
$STD pnpm install --force $STD pnpm install --force
$STD pnpm build $STD pnpm build
msg_ok "Updated ${APP}" msg_ok "Updated ${APP}"

View File

@@ -19,8 +19,6 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dokploy.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
@@ -31,33 +29,10 @@ function update_script() {
exit exit
fi fi
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_info "Updating Dokploy"
echo "" curl -sSL https://dokploy.com/install.sh | $STD bash -s update
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" msg_ok "Updated Dokploy"
echo -e "${TAB}${TAB}${GN}update_dokploy${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" msg_ok "Updated successfully!"
echo ""
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)"
curl -sSL https://dokploy.com/install.sh | $STD bash -s update
msg_ok "Updated ${APP}"
exit
fi
msg_info "Migrating update function"
TMP_UPDATE=$(mktemp)
cat <<'MIGRATION_EOF' >"$TMP_UPDATE"
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dokploy.sh)"
MIGRATION_EOF
mv "$TMP_UPDATE" /usr/bin/update
chmod +x /usr/bin/update
ln -sf /usr/bin/update /usr/bin/update_dokploy 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

@@ -26,7 +26,7 @@ function update_script() {
if [[ ! -d /opt/endurain ]]; then if [[ ! -d /opt/endurain ]]; then
msg_error "No ${APP} installation found!" msg_error "No ${APP} installation found!"
exit 233 exit 1
fi fi
if check_for_gh_release "endurain" "endurain-project/endurain"; then if check_for_gh_release "endurain" "endurain-project/endurain"; then
msg_info "Stopping Service" msg_info "Stopping Service"

View File

@@ -25,7 +25,7 @@ function update_script() {
check_container_resources check_container_resources
if ! command -v evcc >/dev/null 2>&1; then if ! command -v evcc >/dev/null 2>&1; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit 233 exit 1
fi fi
if [[ -f /etc/apt/sources.list.d/evcc-stable.list ]]; then if [[ -f /etc/apt/sources.list.d/evcc-stable.list ]]; then

View File

@@ -28,10 +28,6 @@ function update_script() {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
ensure_dependencies build-essential
NODE_VERSION="24" setup_nodejs
if check_for_gh_release "fluid-calendar" "dotnetfactory/fluid-calendar"; then if check_for_gh_release "fluid-calendar" "dotnetfactory/fluid-calendar"; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop fluid-calendar systemctl stop fluid-calendar
@@ -49,7 +45,7 @@ function update_script() {
$STD npx prisma migrate deploy $STD npx prisma migrate deploy
$STD npm run build:os $STD npm run build:os
msg_ok "Updated Fluid Calendar" msg_ok "Updated Fluid Calendar"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start fluid-calendar systemctl start fluid-calendar
msg_ok "Started Service" msg_ok "Started Service"

View File

@@ -87,8 +87,6 @@ EOF
msg_ok "Old Enviroment fixed" msg_ok "Old Enviroment fixed"
fi fi
ensure_dependencies git
if check_for_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror"; then if check_for_gh_release "gitea-mirror" "RayLabsHQ/gitea-mirror"; then
msg_info "Stopping Services" msg_info "Stopping Services"
systemctl stop gitea-mirror systemctl stop gitea-mirror
@@ -96,7 +94,7 @@ EOF
msg_info "Backup Data" msg_info "Backup Data"
mkdir -p /opt/gitea-mirror-backup/data mkdir -p /opt/gitea-mirror-backup/data
cp -r /opt/gitea-mirror/data/* /opt/gitea-mirror-backup/data/ cp /opt/gitea-mirror/data/* /opt/gitea-mirror-backup/data/
msg_ok "Backup Data" msg_ok "Backup Data"
msg_info "Installing Bun" msg_info "Installing Bun"
@@ -113,11 +111,12 @@ EOF
$STD bun run setup $STD bun run setup
$STD bun run build $STD bun run build
APP_VERSION=$(grep -o '"version": *"[^"]*"' package.json | cut -d'"' -f4) APP_VERSION=$(grep -o '"version": *"[^"]*"' package.json | cut -d'"' -f4)
sed -i.bak "s|^npm_package_version=.*|npm_package_version=${APP_VERSION}|" /opt/gitea-mirror.env
sudo sed -i.bak "s|^npm_package_version=.*|npm_package_version=${APP_VERSION}|" /opt/gitea-mirror.env
msg_ok "Updated and rebuilt ${APP}" msg_ok "Updated and rebuilt ${APP}"
msg_info "Restoring Data" msg_info "Restoring Data"
cp -r /opt/gitea-mirror-backup/data/* /opt/gitea-mirror/data cp /opt/gitea-mirror-backup/data/* /opt/gitea-mirror/data
msg_ok "Restored Data" msg_ok "Restored Data"
msg_info "Starting Service" msg_info "Starting Service"

View File

@@ -26,7 +26,7 @@ function update_script() {
if ! dpkg -s grafana >/dev/null 2>&1; then if ! dpkg -s grafana >/dev/null 2>&1; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit 233 exit 1
fi fi
if [[ -f /etc/apt/sources.list.d/grafana.list ]] || [[ ! -f /etc/apt/sources.list.d/grafana.sources ]]; then if [[ -f /etc/apt/sources.list.d/grafana.list ]] || [[ ! -f /etc/apt/sources.list.d/grafana.sources ]]; then

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

6
ct/headers/unifi Normal file
View File

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

View File

@@ -36,13 +36,9 @@ function update_script() {
exit exit
fi fi
if ! grep -qE '(^|[[:space:]])testing([[:space:]]|$)' /etc/apt/sources.list.d/debian.sources 2>/dev/null; then if [[ ! -f /etc/apt/preferences.d/preferences ]]; then
msg_info "Adding Debian Testing repo" msg_info "Adding Debian Testing repo"
if grep -q "trixie-updates" /etc/apt/sources.list.d/debian.sources 2>/dev/null; then 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
else
sed -i '/^[[:space:]]*Suites:.*trixie/ s/$/ testing/' /etc/apt/sources.list.d/debian.sources
fi
cat <<EOF >/etc/apt/preferences.d/preferences cat <<EOF >/etc/apt/preferences.d/preferences
Package: * Package: *
Pin: release a=unstable Pin: release a=unstable
@@ -341,7 +337,7 @@ function compile_libraw() {
if [[ "$LIBRAW_REVISION" != "$(grep 'libraw' ~/.immich_library_revisions | awk '{print $2}')" ]]; then if [[ "$LIBRAW_REVISION" != "$(grep 'libraw' ~/.immich_library_revisions | awk '{print $2}')" ]]; then
msg_info "Recompiling libraw" msg_info "Recompiling libraw"
[[ -d "$SOURCE" ]] && rm -rf "$SOURCE" [[ -d "$SOURCE" ]] && rm -rf "$SOURCE"
$STD git clone https://github.com/LibRaw/LibRaw.git "$SOURCE" $STD git clone https://github.com/libraw/libraw.git "$SOURCE"
cd "$SOURCE" cd "$SOURCE"
$STD git reset --hard "$LIBRAW_REVISION" $STD git reset --hard "$LIBRAW_REVISION"
$STD autoreconf --install $STD autoreconf --install

View File

@@ -26,7 +26,7 @@ function update_script() {
if [[ ! -f /etc/itsm-ng/config_db.php ]]; then if [[ ! -f /etc/itsm-ng/config_db.php ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit 233 exit 1
fi fi
setup_mariadb setup_mariadb

View File

@@ -45,15 +45,14 @@ function update_script() {
fi fi
msg_info "Switching update script to Seerr" msg_info "Switching update script to Seerr"
TMP_UPDATE=$(mktemp) cat <<'EOF' >/usr/bin/update
cat <<'EOF' >"$TMP_UPDATE" #!/usr/bin/env bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/seerr.sh)" bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/seerr.sh)"
EOF EOF
mv "$TMP_UPDATE" /usr/bin/update
chmod +x /usr/bin/update chmod +x /usr/bin/update
msg_ok "Switched update script to Seerr" msg_ok "Switched update script to Seerr"
msg_warn "Please type 'update' again to complete the migration" msg_warn "Please type 'update' again to complete the migration"
exit 0 exit
fi fi
msg_info "Updating Jellyseerr" msg_info "Updating Jellyseerr"

View File

@@ -45,7 +45,7 @@ function update_script() {
if [[ -z "$KASM_URL" ]] || [[ -z "$KASM_VERSION" ]]; then if [[ -z "$KASM_URL" ]] || [[ -z "$KASM_VERSION" ]]; then
msg_error "Unable to detect latest Kasm release URL." msg_error "Unable to detect latest Kasm release URL."
exit 250 exit 1
fi fi
msg_info "Checked for new version" msg_info "Checked for new version"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG # Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ) # Author: MickLesk
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://komo.do/ # Source: https://komo.do/
@@ -19,51 +19,49 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/komodo ]]; then [[ -d /opt/komodo ]] || {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit 1
}
msg_info "Updating Komodo"
COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1)
if [[ -z "$COMPOSE_FILE" ]]; then
msg_error "No valid compose file found in /opt/komodo!"
exit 1
fi
COMPOSE_BASENAME=$(basename "$COMPOSE_FILE")
if [[ "$COMPOSE_BASENAME" == "sqlite.compose.yaml" || "$COMPOSE_BASENAME" == "postgres.compose.yaml" ]]; then
msg_error "❌ Detected outdated Komodo setup using SQLite or PostgreSQL (FerretDB v1)."
echo -e "${YW}This configuration is no longer supported since Komodo v1.18.0.${CL}"
echo -e "${YW}Please follow the migration guide:${CL}"
echo -e "${BGN}https://github.com/community-scripts/ProxmoxVE/discussions/5689${CL}\n"
exit 1
fi fi
msg_warn "⚠️ ${APP} has been migrated to an addon script." BACKUP_FILE="/opt/komodo/${COMPOSE_BASENAME}.bak_$(date +%Y%m%d_%H%M%S)"
echo "" cp "$COMPOSE_FILE" "$BACKUP_FILE" || {
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:" msg_error "Failed to create backup of ${COMPOSE_BASENAME}!"
echo -e "${TAB}${TAB}${GN}update_komodo${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}" exit 1
echo "" }
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM GITHUB_URL="https://raw.githubusercontent.com/moghtech/komodo/main/compose/${COMPOSE_BASENAME}"
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then if ! curl -fsSL "$GITHUB_URL" -o "$COMPOSE_FILE"; then
msg_warn "Migration skipped. The old update will continue to work for now." msg_error "Failed to download ${COMPOSE_BASENAME} from GitHub!"
msg_info "Updating ${APP} (legacy)" mv "$BACKUP_FILE" "$COMPOSE_FILE"
COMPOSE_FILE=$(find /opt/komodo -maxdepth 1 -type f -name '*.compose.yaml' ! -name 'compose.env' | head -n1) exit 1
if [[ -z "$COMPOSE_FILE" ]]; then
msg_error "No valid compose file found in /opt/komodo!"
exit 252
fi
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
$STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
msg_ok "Updated ${APP}"
exit
fi fi
if ! grep -qxF 'COMPOSE_KOMODO_BACKUPS_PATH=/etc/komodo/backups' /opt/komodo/compose.env; then
msg_info "Migrating update function" sed -i '/^COMPOSE_KOMODO_IMAGE_TAG=latest$/a COMPOSE_KOMODO_BACKUPS_PATH=/etc/komodo/backups' /opt/komodo/compose.env
TMP_UPDATE=$(mktemp) fi
cat <<'MIGRATION_EOF' >"$TMP_UPDATE" $STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env pull
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh)" $STD docker compose -p komodo -f "$COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
MIGRATION_EOF msg_ok "Updated Komodo"
mv "$TMP_UPDATE" /usr/bin/update
chmod +x /usr/bin/update
ln -sf /usr/bin/update /usr/bin/update_komodo 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

@@ -34,7 +34,7 @@ function update_script() {
msg_ok "Stopped Service" msg_ok "Stopped Service"
VENV_PATH="/opt/litellm/.venv" VENV_PATH="/opt/litellm/.venv"
PYTHON_VERSION="3.13" USE_UVX="YES" setup_uv PYTHON_VERSION="3.13" setup_uv
msg_info "Updating LiteLLM" msg_info "Updating LiteLLM"
$STD "$VENV_PATH/bin/python" -m pip install --upgrade litellm[proxy] prisma $STD "$VENV_PATH/bin/python" -m pip install --upgrade litellm[proxy] prisma

View File

@@ -26,7 +26,7 @@ function update_script() {
if ! dpkg -s loki >/dev/null 2>&1; then if ! dpkg -s loki >/dev/null 2>&1; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit 233 exit 1
fi fi
CHOICE=$(msg_menu "Loki Update Options" \ CHOICE=$(msg_menu "Loki Update Options" \

View File

@@ -9,7 +9,7 @@ APP="MeshCentral"
var_tags="${var_tags:-remote-management}" var_tags="${var_tags:-remote-management}"
var_cpu="${var_cpu:-1}" var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-512}"
var_disk="${var_disk:-4}" var_disk="${var_disk:-2}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-13}" var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"

View File

@@ -44,11 +44,10 @@ function update_script() {
fi fi
msg_info "Switching update script to Seerr" msg_info "Switching update script to Seerr"
TMP_UPDATE=$(mktemp) cat <<'EOF' >/usr/bin/update
cat <<'EOF' >"$TMP_UPDATE" #!/usr/bin/env bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/seerr.sh)" bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/seerr.sh)"
EOF EOF
mv "$TMP_UPDATE" /usr/bin/update
chmod +x /usr/bin/update chmod +x /usr/bin/update
msg_ok "Switched update script to Seerr" msg_ok "Switched update script to Seerr"
msg_warn "Please type 'update' again to complete the migration" msg_warn "Please type 'update' again to complete the migration"

View File

@@ -44,7 +44,7 @@ function update_script() {
echo -e "${TAB}${GATEWAY}${BGN}https://github.com/community-scripts/ProxmoxVE/discussions/9223${CL}" echo -e "${TAB}${GATEWAY}${BGN}https://github.com/community-scripts/ProxmoxVE/discussions/9223${CL}"
echo -e "" echo -e ""
msg_custom "⚠️" "Update aborted. Please migrate your data first." msg_custom "⚠️" "Update aborted. Please migrate your data first."
exit 253 exit 1
fi fi
fi fi

View File

@@ -1,68 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/papra-hq/papra
APP="Papra"
var_tags="${var_tags:-document-management}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-10}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/papra ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "papra" "papra-hq/papra"; then
msg_info "Stopping Service"
systemctl stop papra
msg_ok "Stopped Service"
msg_info "Backing up Configuration"
cp /opt/papra/apps/papra-server/.env /opt/papra_env.bak
msg_ok "Backed up Configuration"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "papra" "papra-hq/papra" "tarball"
msg_info "Building Application"
cd /opt/papra
cp /opt/papra_env.bak /opt/papra/apps/papra-server/.env
$STD pnpm install --frozen-lockfile
$STD pnpm --filter "@papra/app-client..." run build
$STD pnpm --filter "@papra/app-server..." run build
ln -sf /opt/papra/apps/papra-client/dist /opt/papra/apps/papra-server/public
rm -f /opt/papra_env.bak
msg_ok "Built Application"
msg_info "Starting Service"
systemctl start papra
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}:1221${CL}"

View File

@@ -1,71 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://www.powerdns.com/
APP="PowerDNS"
var_tags="${var_tags:-dns}"
var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-1024}"
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 [[ ! -d /opt/poweradmin ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Updating PowerDNS"
$STD apt update
$STD apt install -y --only-upgrade pdns-server pdns-backend-sqlite3
msg_ok "Updated PowerDNS"
if check_for_gh_release "poweradmin" "poweradmin/poweradmin"; then
msg_info "Backing up Configuration"
cp /opt/poweradmin/config/settings.php /opt/poweradmin_settings.php.bak
cp /opt/poweradmin/powerdns.db /opt/poweradmin_powerdns.db.bak
msg_ok "Backed up Configuration"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "poweradmin" "poweradmin/poweradmin" "tarball"
msg_info "Updating Poweradmin"
cp /opt/poweradmin_settings.php.bak /opt/poweradmin/config/settings.php
cp /opt/poweradmin_powerdns.db.bak /opt/poweradmin/powerdns.db
rm -rf /opt/poweradmin/install
rm -f /opt/poweradmin_settings.php.bak /opt/poweradmin_powerdns.db.bak
chown -R www-data:pdns /opt/poweradmin
chmod 775 /opt/poweradmin
chown pdns:pdns /opt/poweradmin/powerdns.db
chmod 664 /opt/poweradmin/powerdns.db
msg_ok "Updated Poweradmin"
msg_info "Restarting Services"
systemctl restart pdns apache2
msg_ok "Restarted Services"
msg_ok "Updated successfully!"
fi
exit
}
start
build_container
description
msg_ok "Completed Successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}${CL}"

View File

@@ -1,85 +0,0 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: michelroegl-brunner
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/Dictionarry-Hub/profilarr
APP="Profilarr"
var_tags="${var_tags:-arr;radarr;sonarr;config}"
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/profilarr ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "profilarr" "Dictionarry-Hub/profilarr"; then
msg_info "Stopping Service"
systemctl stop profilarr
msg_ok "Stopped Service"
msg_info "Backing up Data"
if [[ -d /config ]]; then
cp -r /config /opt/profilarr_config_backup
fi
msg_ok "Backed up Data"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "profilarr" "Dictionarry-Hub/profilarr" "tarball"
msg_info "Installing Python Dependencies"
cd /opt/profilarr/backend
$STD uv venv /opt/profilarr/backend/.venv
sed 's/==/>=/g' requirements.txt >requirements-relaxed.txt
$STD uv pip install --python /opt/profilarr/backend/.venv/bin/python -r requirements-relaxed.txt
rm -f requirements-relaxed.txt
msg_ok "Installed Python Dependencies"
msg_info "Building Frontend"
if [[ -d /opt/profilarr/frontend ]]; then
cd /opt/profilarr/frontend
$STD npm install
$STD npm run build
cp -r dist /opt/profilarr/backend/app/static
fi
msg_ok "Built Frontend"
msg_info "Restoring Data"
if [[ -d /opt/profilarr_config_backup ]]; then
mkdir -p /config
cp -r /opt/profilarr_config_backup/. /config/
rm -rf /opt/profilarr_config_backup
fi
msg_ok "Restored Data"
msg_info "Starting Service"
systemctl start profilarr
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}:6868${CL}"

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 tteck # Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster) | Migration: MickLesk (CanbiZ) # Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://runtipi.io/ # Source: https://runtipi.io/
@@ -19,45 +19,16 @@ variables
color color
catch_errors catch_errors
ADDON_SCRIPT="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/runtipi.sh"
function update_script() { function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/runtipi ]]; then if [[ ! -d /opt/runtipi ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
cd /opt/runtipi && ./runtipi-cli update latest
msg_warn "⚠️ ${APP} has been migrated to an addon script." msg_ok "Updated successfully!"
echo ""
msg_info "This is a one-time migration. After this, you can update ${APP} anytime with:"
echo -e "${TAB}${TAB}${GN}update_runtipi${CL} or ${GN}bash <(curl -fsSL ${ADDON_SCRIPT})${CL}"
echo ""
read -r -p "${TAB}Migrate update function now? [y/N]: " CONFIRM
if [[ ! "${CONFIRM,,}" =~ ^(y|yes)$ ]]; then
msg_warn "Migration skipped. The old update will continue to work for now."
msg_info "Updating ${APP} (legacy)"
cd /opt/runtipi && ./runtipi-cli update latest
msg_ok "Updated ${APP}"
exit
fi
msg_info "Migrating update function"
TMP_UPDATE=$(mktemp)
cat <<'MIGRATION_EOF' >"$TMP_UPDATE"
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/runtipi.sh)"
MIGRATION_EOF
mv "$TMP_UPDATE" /usr/bin/update
chmod +x /usr/bin/update
ln -sf /usr/bin/update /usr/bin/update_runtipi 2>/dev/null || true
msg_ok "Migration complete"
msg_info "Running addon update"
type=update bash <(curl -fsSL "${ADDON_SCRIPT}")
exit exit
} }

View File

@@ -29,7 +29,9 @@ function update_script() {
exit exit
fi fi
if check_for_gh_release "rustdesk-api"; then RELEASE=$(curl -fsSL https://api.github.com/repos/rustdesk/rustdesk-server/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
APIRELEASE=$(curl -fsSL https://api.github.com/repos/lejianwen/rustdesk-api/releases/latest | grep "tag_name" | awk '{print substr($2, 3, length($2)-4) }')
if [[ "${RELEASE}" != "$(cat ~/.rustdesk-hbbr)" ]] || [[ "${APIRELEASE}" != "$(cat ~/.rustdesk-api)" ]] || [[ ! -f ~/.rustdesk-hbbr ]] || [[ ! -f ~/.rustdesk-api ]]; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop rustdesk-hbbr systemctl stop rustdesk-hbbr
systemctl stop rustdesk-hbbs systemctl stop rustdesk-hbbs
@@ -38,13 +40,13 @@ function update_script() {
fi fi
msg_info "Stopped Service" msg_info "Stopped Service"
fetch_and_deploy_gh_release "rustdesk-hbbr" "lejianwen/rustdesk-server" "binary" "latest" "/opt/rustdesk" "rustdesk-server-hbbr*amd64.deb" fetch_and_deploy_gh_release "rustdesk-hbbr" "rustdesk/rustdesk-server" "binary" "latest" "/opt/rustdesk" "rustdesk-server-hbbr*amd64.deb"
fetch_and_deploy_gh_release "rustdesk-hbbs" "lejianwen/rustdesk-server" "binary" "latest" "/opt/rustdesk" "rustdesk-server-hbbs*amd64.deb" fetch_and_deploy_gh_release "rustdesk-hbbs" "rustdesk/rustdesk-server" "binary" "latest" "/opt/rustdesk" "rustdesk-server-hbbs*amd64.deb"
fetch_and_deploy_gh_release "rustdesk-utils" "lejianwen/rustdesk-server" "binary" "latest" "/opt/rustdesk" "rustdesk-server-utils*amd64.deb" fetch_and_deploy_gh_release "rustdesk-utils" "rustdesk/rustdesk-server" "binary" "latest" "/opt/rustdesk" "rustdesk-server-utils*amd64.deb"
fetch_and_deploy_gh_release "rustdesk-api" "lejianwen/rustdesk-api" "binary" "latest" "/opt/rustdesk" "rustdesk-api-server*amd64.deb" fetch_and_deploy_gh_release "rustdesk-api" "lejianwen/rustdesk-api" "binary" "latest" "/opt/rustdesk" "rustdesk-api-server*amd64.deb"
msg_info "Starting services" msg_info "Starting services"
systemctl start -q rustdesk-* systemctl start -q rustdesk-* --all
msg_ok "Services started" msg_ok "Services started"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"

View File

@@ -28,34 +28,6 @@ function update_script() {
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
if [[ -f /opt/semaphore/semaphore_db.bolt ]]; then
msg_warn "WARNING: Due to bugs with BoltDB database, update script will move your application"
msg_warn "to use SQLite database instead. Unfortunately, this will reset your application and make it a fresh"
msg_warn "installation. All your data will be lost!"
echo ""
read -r -p "${TAB3}Do you want to continue? (y/N): " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
exit 0
else
msg_info "Moving from BoltDB to SQLite"
systemctl stop semaphore
rm -rf /opt/semaphore/semaphore_db.bolt
sed -i \
-e 's|"bolt": {|"sqlite": {|' \
-e 's|/semaphore_db.bolt"|/database.sqlite"|' \
-e '/semaphore_db.bolt/d' \
-e '/"dialect"/d' \
-e '/^ },$/a\ "dialect": "sqlite",' \
/opt/semaphore/config.json
SEM_PW=$(cat ~/semaphore.creds)
systemctl start semaphore
$STD semaphore user add --admin --login admin --email admin@helper-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
msg_ok "Moved from BoltDB to SQLite"
fi
fi
if check_for_gh_release "semaphore" "semaphoreui/semaphore"; then if check_for_gh_release "semaphore" "semaphoreui/semaphore"; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop semaphore systemctl stop semaphore

View File

@@ -29,6 +29,8 @@ function update_script() {
exit exit
fi fi
NODE_VERSION="25" setup_nodejs
if check_for_gh_release "sparkyfitness" "CodeWithCJ/SparkyFitness"; then if check_for_gh_release "sparkyfitness" "CodeWithCJ/SparkyFitness"; then
msg_info "Stopping Services" msg_info "Stopping Services"
systemctl stop sparkyfitness-server nginx systemctl stop sparkyfitness-server nginx
@@ -46,9 +48,6 @@ function update_script() {
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "sparkyfitness" "CodeWithCJ/SparkyFitness" "tarball" CLEAN_INSTALL=1 fetch_and_deploy_gh_release "sparkyfitness" "CodeWithCJ/SparkyFitness" "tarball"
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1]' /opt/sparkyfitness/package.json)"
NODE_VERSION="25" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
msg_info "Updating Sparky Fitness Backend" msg_info "Updating Sparky Fitness Backend"
cd /opt/sparkyfitness/SparkyFitnessServer cd /opt/sparkyfitness/SparkyFitnessServer
$STD npm install $STD npm install
@@ -56,8 +55,8 @@ function update_script() {
msg_info "Updating Sparky Fitness Frontend (Patience)" msg_info "Updating Sparky Fitness Frontend (Patience)"
cd /opt/sparkyfitness/SparkyFitnessFrontend cd /opt/sparkyfitness/SparkyFitnessFrontend
$STD pnpm install $STD npm install
$STD pnpm run build $STD npm run build
cp -a /opt/sparkyfitness/SparkyFitnessFrontend/dist/. /var/www/sparkyfitness/ cp -a /opt/sparkyfitness/SparkyFitnessFrontend/dist/. /var/www/sparkyfitness/
msg_ok "Updated Sparky Fitness Frontend" msg_ok "Updated Sparky Fitness Frontend"

View File

@@ -35,7 +35,7 @@ function update_script() {
fi fi
PYTHON_VERSION="3.12" setup_uv PYTHON_VERSION="3.12" setup_uv
JAVA_VERSION="25" setup_java JAVA_VERSION="21" setup_java
msg_info "Stopping Services" msg_info "Stopping Services"
systemctl stop stirlingpdf libreoffice-listener unoserver systemctl stop stirlingpdf libreoffice-listener unoserver

View File

@@ -1,14 +1,14 @@
#!/usr/bin/env bash #!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG # Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ) # Author: Slaviša Arežina (tremor021)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/steveiliop56/tinyauth # Source: https://github.com/Suwayomi/Suwayomi-Server
APP="Tinyauth" APP="SuwayomiServer"
var_tags="${var_tags:-auth}" var_tags="${var_tags:-media;manga}"
var_cpu="${var_cpu:-1}" var_cpu="${var_cpu:-1}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-1024}"
var_disk="${var_disk:-4}" var_disk="${var_disk:-4}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-13}" var_version="${var_version:-13}"
@@ -23,20 +23,23 @@ function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /opt/tinyauth ]]; then
if [[ ! -f /usr/bin/suwayomi-server ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
if check_for_gh_release "tinyauth" "steveiliop56/tinyauth"; then if check_for_gh_release "suwayomi-server" "Suwayomi/Suwayomi-Server"; then
msg_info "Stopping Service" JAVA_VERSION=21 setup_java
systemctl stop tinyauth
msg_ok "Stopped Service"
fetch_and_deploy_gh_release "tinyauth" "steveiliop56/tinyauth" "singlefile" "latest" "/opt/tinyauth" "tinyauth-amd64" msg_info "Stopping Service"
systemctl stop suwayomi-server
msg_info "Stopped Service"
fetch_and_deploy_gh_release "suwayomi-server" "Suwayomi/Suwayomi-Server" "binary"
msg_info "Starting Service" msg_info "Starting Service"
systemctl start tinyauth systemctl start suwayomi-server
msg_ok "Started Service" msg_ok "Started Service"
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
fi fi
@@ -50,4 +53,4 @@ description
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}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}" echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:4567${CL}"

View File

@@ -75,31 +75,10 @@ if [ -f \$pg_config_file ]; then
fi fi
fi fi
systemctl restart postgresql systemctl restart postgresql
sudo -u postgres psql -c "ALTER USER tracearr WITH SUPERUSER;"
EOF EOF
chmod +x /data/tracearr/prestart.sh chmod +x /data/tracearr/prestart.sh
msg_ok "Updated prestart script" msg_ok "Updated prestart script"
# check if tailscale is installed
if command -v tailscale >/dev/null 2>&1; then
# Tracearr runs tailscaled in user mode, disable the service.
$STD systemctl disable --now tailscaled
$STD systemctl stop tailscaled
msg_ok "Tailscale already installed"
else
msg_info "Installing tailscale"
setup_deb822_repo \
"tailscale" \
"https://pkgs.tailscale.com/stable/$(get_os_info id)/$(get_os_info codename).noarmor.gpg" \
"https://pkgs.tailscale.com/stable/$(get_os_info id)/" \
"$(get_os_info codename)"
$STD apt install -y tailscale
# Tracearr runs tailscaled in user mode, disable the service.
$STD systemctl disable --now tailscaled
$STD systemctl stop tailscaled
msg_ok "Installed tailscale"
fi
if check_for_gh_release "tracearr" "connorgallopo/Tracearr"; then if check_for_gh_release "tracearr" "connorgallopo/Tracearr"; then
msg_info "Stopping Services" msg_info "Stopping Services"
systemctl stop tracearr postgresql redis systemctl stop tracearr postgresql redis
@@ -143,8 +122,6 @@ EOF
sed -i "s/^APP_VERSION=.*/APP_VERSION=$(cat /root/.tracearr)/" /data/tracearr/.env sed -i "s/^APP_VERSION=.*/APP_VERSION=$(cat /root/.tracearr)/" /data/tracearr/.env
chmod 600 /data/tracearr/.env chmod 600 /data/tracearr/.env
chown -R tracearr:tracearr /data/tracearr chown -R tracearr:tracearr /data/tracearr
mkdir -p /data/backup
chown -R tracearr:tracearr /data/backup
msg_ok "Configured Tracearr" msg_ok "Configured Tracearr"
msg_info "Starting services" msg_info "Starting services"

View File

@@ -1,19 +1,18 @@
#!/usr/bin/env bash #!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func) source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG # Copyright (c) 2021-2026 tteck
# Author: TechHutTV # Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://netbird.io/ # Source: https://ui.com/download/unifi
APP="NetBird" APP="Unifi"
var_tags="${var_tags:-network;vpn}" var_tags="${var_tags:-network;unifi}"
var_cpu="${var_cpu:-1}" var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-512}" var_ram="${var_ram:-2048}"
var_disk="${var_disk:-4}" var_disk="${var_disk:-8}"
var_os="${var_os:-debian}" var_os="${var_os:-debian}"
var_version="${var_version:-13}" var_version="${var_version:-12}"
var_unprivileged="${var_unprivileged:-1}" var_unprivileged="${var_unprivileged:-1}"
var_tun="${var_tun:-yes}"
header_info "$APP" header_info "$APP"
variables variables
@@ -24,15 +23,16 @@ function update_script() {
header_info header_info
check_container_storage check_container_storage
check_container_resources check_container_resources
if [[ ! -d /usr/lib/unifi ]]; then
if [[ ! -f /etc/netbird/config.json ]]; then
msg_error "No ${APP} Installation Found!" msg_error "No ${APP} Installation Found!"
exit exit
fi fi
msg_info "Updating Netbird" JAVA_VERSION="21" setup_java
$STD apt update
$STD apt upgrade -y msg_info "Updating ${APP}"
$STD apt update --allow-releaseinfo-change
ensure_dependencies unifi
msg_ok "Updated successfully!" msg_ok "Updated successfully!"
exit exit
} }
@@ -43,5 +43,5 @@ description
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 NetBird by entering the container and running:${CL}" echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}netbird up${CL}" echo -e "${TAB}${GATEWAY}${BGN}https://${IP}:8443${CL}"

View File

@@ -34,14 +34,14 @@ function update_script() {
msg_warn "This requires MANUAL config changes in /etc/vikunja/config.yml." msg_warn "This requires MANUAL config changes in /etc/vikunja/config.yml."
msg_warn "See: https://vikunja.io/changelog/whats-new-in-vikunja-1.0.0/#config-changes" msg_warn "See: https://vikunja.io/changelog/whats-new-in-vikunja-1.0.0/#config-changes"
read -rp "Continue with update? (y to proceed): " -t 30 CONFIRM1 || exit 254 read -rp "Continue with update? (y to proceed): " -t 30 CONFIRM1 || exit 1
[[ "$CONFIRM1" =~ ^[yY]$ ]] || exit 0 [[ "$CONFIRM1" =~ ^[yY]$ ]] || exit 0
echo echo
msg_warn "Vikunja may not start after the update until you manually adjust the config." msg_warn "Vikunja may not start after the update until you manually adjust the config."
msg_warn "Details: https://vikunja.io/changelog/whats-new-in-vikunja-1.0.0/#config-changes" msg_warn "Details: https://vikunja.io/changelog/whats-new-in-vikunja-1.0.0/#config-changes"
read -rp "Acknowledge and continue? (y): " -t 30 CONFIRM2 || exit 254 read -rp "Acknowledge and continue? (y): " -t 30 CONFIRM2 || exit 1
[[ "$CONFIRM2" =~ ^[yY]$ ]] || exit 0 [[ "$CONFIRM2" =~ ^[yY]$ ]] || exit 0
fi fi

View File

@@ -29,10 +29,6 @@ function update_script() {
exit exit
fi fi
if grep -q '^WF_CORS_ALLOW_ORIGINS=\*$' /opt/wealthfolio/.env; then
sed -i "s|^WF_CORS_ALLOW_ORIGINS=\*$|WF_CORS_ALLOW_ORIGINS=http://${LOCAL_IP}:8080|" /opt/wealthfolio/.env
fi
if check_for_gh_release "wealthfolio" "afadil/wealthfolio"; then if check_for_gh_release "wealthfolio" "afadil/wealthfolio"; then
msg_info "Stopping Service" msg_info "Stopping Service"
systemctl stop wealthfolio systemctl stop wealthfolio

View File

@@ -1,10 +1,10 @@
{ {
"name": "Tinyauth", "name": "Alpine-Tinyauth",
"slug": "tinyauth", "slug": "alpine-tinyauth",
"categories": [ "categories": [
6 6
], ],
"date_created": "2026-03-03", "date_created": "2025-05-06",
"type": "ct", "type": "ct",
"updateable": true, "updateable": true,
"privileged": false, "privileged": false,
@@ -17,13 +17,13 @@
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "ct/tinyauth.sh", "script": "ct/alpine-tinyauth.sh",
"resources": { "resources": {
"cpu": 1, "cpu": 1,
"ram": 512, "ram": 256,
"hdd": 4, "hdd": 2,
"os": "debian", "os": "alpine",
"version": "13" "version": "3.23"
} }
}, },
{ {

View File

@@ -19,7 +19,7 @@
"type": "default", "type": "default",
"script": "ct/bentopdf.sh", "script": "ct/bentopdf.sh",
"resources": { "resources": {
"cpu": 2, "cpu": 1,
"ram": 4096, "ram": 4096,
"hdd": 4, "hdd": 4,
"os": "debian", "os": "debian",

View File

@@ -1,56 +1,52 @@
{ {
"name": "Coolify", "name": "Coolify",
"slug": "coolify", "slug": "coolify",
"categories": [ "categories": [
3 3
], ],
"date_created": "2025-12-09", "date_created": "2025-12-09",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": false, "privileged": false,
"interface_port": 8000, "interface_port": 8000,
"documentation": "https://coolify.io/docs", "documentation": "https://coolify.io/docs",
"website": "https://coolify.io/", "config_path": "/data/coolify",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/coolify.webp", "website": "https://coolify.io/",
"config_path": "/data/coolify", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/coolify.webp",
"description": "Coolify is an open-source & self-hostable alternative to Heroku, Netlify, and Vercel. It helps you manage your servers, applications, and databases on your own hardware with Docker. Deploy any application from Git repositories, Docker images, or use pre-built templates.", "description": "Coolify is an open-source & self-hostable alternative to Heroku, Netlify, and Vercel. It helps you manage your servers, applications, and databases on your own hardware with Docker. Deploy any application from Git repositories, Docker images, or use pre-built templates.",
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/coolify.sh", "script": "ct/coolify.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 4096,
"hdd": null, "hdd": 30,
"os": null, "os": "Debian",
"version": null "version": "13"
} }
} }
], ],
"default_credentials": { "default_credentials": {
"username": null, "username": null,
"password": null "password": null
},
"notes": [
{
"text": "This is an addon script intended to be used on top of an existing Docker container.",
"type": "info"
}, },
{ "notes": [
"text": "Execute within an existing LXC console (Debian / Ubuntu / Alpine supported)", {
"type": "info" "text": "Initial setup will be done via the web interface on first access.",
}, "type": "info"
{ },
"text": "Initial setup will be done via the web interface on first access.", {
"type": "info" "text": "Coolify has built-in auto-updates. You can configure update frequency in Settings.",
}, "type": "info"
{ },
"text": "Coolify has built-in auto-updates. You can configure update frequency in Settings.", {
"type": "info" "text": "Coolify requires SSH access to manage deployments. SSH is enabled automatically.",
}, "type": "info"
{ },
"text": "To update via CLI, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/coolify.sh)", {
"type": "info" "text": "This container uses Docker-in-Docker (nesting) for application deployments.",
} "type": "warning"
] }
]
} }

View File

@@ -1,44 +0,0 @@
{
"name": "ddclient",
"slug": "ddclient",
"categories": [
4
],
"date_created": "2026-03-05",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://ddclient.net/",
"website": "https://ddclient.net/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/ddclient.webp",
"config_path": "/etc/ddclient.conf",
"description": "ddclient is a Perl client used to update dynamic DNS entries for accounts on a wide range of dynamic DNS service providers. It supports multiple protocols and providers, allowing automatic IP address updates for your domain names.",
"install_methods": [
{
"type": "default",
"script": "ct/ddclient.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 2,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"type": "info",
"text": "After installation, edit `/etc/ddclient.conf` with your dynamic DNS provider credentials"
},
{
"type": "info",
"text": "Sample configuration is created for Namecheap but can be modified for other providers"
}
]
}

View File

@@ -5,25 +5,25 @@
3 3
], ],
"date_created": "2024-05-02", "date_created": "2024-05-02",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": false, "privileged": false,
"interface_port": 5001, "interface_port": 5001,
"documentation": null, "documentation": null,
"website": "https://github.com/louislam/dockge", "website": "https://github.com/louislam/dockge",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/dockge.webp", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/dockge.webp",
"config_path": "/opt/dockge/compose.yaml", "config_path": "",
"description": "Dockge is a fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.", "description": "Dockge is a fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.",
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/dockge.sh", "script": "ct/dockge.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 2048,
"hdd": null, "hdd": 18,
"os": null, "os": "debian",
"version": null "version": "13"
} }
} }
], ],
@@ -33,16 +33,12 @@
}, },
"notes": [ "notes": [
{ {
"text": "This is an addon script intended to be used on top of an existing Docker container.", "text": "Options to add Immich and/or Home Assistant",
"type": "info" "type": "info"
}, },
{ {
"text": "Execute within an existing LXC console (Debian / Ubuntu / Alpine supported)", "text": "If the LXC is created Privileged, the script will automatically set up USB passthrough.",
"type": "info" "type": "warning"
},
{
"text": "To update, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dockge.sh)",
"type": "info"
} }
] ]
} }

View File

@@ -1,56 +1,48 @@
{ {
"name": "Dokploy", "name": "Dokploy",
"slug": "dokploy", "slug": "dokploy",
"categories": [ "categories": [
3 3
], ],
"date_created": "2025-12-09", "date_created": "2025-12-09",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": true, "privileged": true,
"interface_port": 3000, "interface_port": 3000,
"documentation": "https://docs.dokploy.com/", "documentation": "https://docs.dokploy.com/",
"website": "https://dokploy.com/", "config_path": "/etc/dokploy",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/png/dokploy.png", "website": "https://dokploy.com/",
"config_path": "/etc/dokploy", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons/png/dokploy.png",
"description": "Dokploy is a free, self-hostable Platform as a Service (PaaS) that simplifies the deployment and management of applications and databases. Built with Docker and Traefik, it offers features like automatic SSL, Docker Compose support, database backups, and a real-time monitoring dashboard.", "description": "Dokploy is a free, self-hostable Platform as a Service (PaaS) that simplifies the deployment and management of applications and databases. Built with Docker and Traefik, it offers features like automatic SSL, Docker Compose support, database backups, and a real-time monitoring dashboard.",
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/dokploy.sh", "script": "ct/dokploy.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 2048,
"hdd": null, "hdd": 10,
"os": null, "os": "Debian",
"version": null "version": "13"
} }
} }
], ],
"default_credentials": { "default_credentials": {
"username": null, "username": null,
"password": null "password": null
},
"notes": [
{
"text": "This is an addon script intended to be used on top of an existing Docker container.",
"type": "info"
}, },
{ "notes": [
"text": "Execute within an existing LXC console (Debian / Ubuntu / Alpine supported)", {
"type": "info" "text": "Initial setup will be done via the web interface on first access.",
}, "type": "info"
{ },
"text": "Initial setup will be done via the web interface on first access.", {
"type": "info" "text": "Dokploy has built-in auto-updates via the web interface.",
}, "type": "info"
{ },
"text": "Dokploy has built-in auto-updates via the web interface.", {
"type": "info" "text": "This container uses Docker-in-Docker (nesting) for application deployments.",
}, "type": "warning"
{ }
"text": "To update via CLI, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/dokploy.sh)", ]
"type": "info"
}
]
} }

View File

@@ -1,5 +1,5 @@
{ {
"generated": "2026-03-07T12:08:02Z", "generated": "2026-03-01T18:07:06Z",
"versions": [ "versions": [
{ {
"slug": "2fauth", "slug": "2fauth",
@@ -39,9 +39,9 @@
{ {
"slug": "ampache", "slug": "ampache",
"repo": "ampache/ampache", "repo": "ampache/ampache",
"version": "7.9.2", "version": "7.9.1",
"pinned": false, "pinned": false,
"date": "2026-03-05T03:54:03Z" "date": "2026-02-25T08:52:58Z"
}, },
{ {
"slug": "argus", "slug": "argus",
@@ -116,9 +116,9 @@
{ {
"slug": "bentopdf", "slug": "bentopdf",
"repo": "alam00000/bentopdf", "repo": "alam00000/bentopdf",
"version": "v2.4.1", "version": "v2.4.0",
"pinned": false, "pinned": false,
"date": "2026-03-07T09:14:39Z" "date": "2026-03-01T14:25:43Z"
}, },
{ {
"slug": "beszel", "slug": "beszel",
@@ -151,9 +151,9 @@
{ {
"slug": "booklore", "slug": "booklore",
"repo": "booklore-app/BookLore", "repo": "booklore-app/BookLore",
"version": "v2.0.6", "version": "v2.0.5",
"pinned": false, "pinned": false,
"date": "2026-03-06T19:16:29Z" "date": "2026-03-01T16:13:13Z"
}, },
{ {
"slug": "bookstack", "slug": "bookstack",
@@ -193,16 +193,16 @@
{ {
"slug": "checkmate", "slug": "checkmate",
"repo": "bluewave-labs/Checkmate", "repo": "bluewave-labs/Checkmate",
"version": "v3.5.1", "version": "v3.4.0",
"pinned": false, "pinned": false,
"date": "2026-03-06T21:18:36Z" "date": "2026-02-20T21:08:55Z"
}, },
{ {
"slug": "cleanuparr", "slug": "cleanuparr",
"repo": "Cleanuparr/Cleanuparr", "repo": "Cleanuparr/Cleanuparr",
"version": "v2.7.7", "version": "v2.7.6",
"pinned": false, "pinned": false,
"date": "2026-03-02T13:08:32Z" "date": "2026-02-27T19:32:02Z"
}, },
{ {
"slug": "cloudreve", "slug": "cloudreve",
@@ -214,9 +214,9 @@
{ {
"slug": "comfyui", "slug": "comfyui",
"repo": "comfyanonymous/ComfyUI", "repo": "comfyanonymous/ComfyUI",
"version": "v0.16.3", "version": "v0.15.1",
"pinned": false, "pinned": false,
"date": "2026-03-05T23:18:25Z" "date": "2026-02-26T22:01:35Z"
}, },
{ {
"slug": "commafeed", "slug": "commafeed",
@@ -242,9 +242,9 @@
{ {
"slug": "cosmos", "slug": "cosmos",
"repo": "azukaar/Cosmos-Server", "repo": "azukaar/Cosmos-Server",
"version": "v0.21.7", "version": "v0.21.6",
"pinned": false, "pinned": false,
"date": "2026-03-03T18:15:29Z" "date": "2026-02-28T22:00:49Z"
}, },
{ {
"slug": "cronicle", "slug": "cronicle",
@@ -270,9 +270,9 @@
{ {
"slug": "databasus", "slug": "databasus",
"repo": "databasus/databasus", "repo": "databasus/databasus",
"version": "v3.17.0", "version": "v3.16.4",
"pinned": false, "pinned": false,
"date": "2026-03-06T07:07:22Z" "date": "2026-03-01T08:20:17Z"
}, },
{ {
"slug": "dawarich", "slug": "dawarich",
@@ -284,23 +284,23 @@
{ {
"slug": "discopanel", "slug": "discopanel",
"repo": "nickheyer/discopanel", "repo": "nickheyer/discopanel",
"version": "v2.0.1", "version": "v1.0.37",
"pinned": false, "pinned": false,
"date": "2026-03-07T02:43:33Z" "date": "2026-02-18T08:53:43Z"
}, },
{ {
"slug": "dispatcharr", "slug": "dispatcharr",
"repo": "Dispatcharr/Dispatcharr", "repo": "Dispatcharr/Dispatcharr",
"version": "v0.20.2", "version": "v0.20.1",
"pinned": false, "pinned": false,
"date": "2026-03-03T01:40:33Z" "date": "2026-02-26T21:38:19Z"
}, },
{ {
"slug": "docmost", "slug": "docmost",
"repo": "docmost/docmost", "repo": "docmost/docmost",
"version": "v0.70.1", "version": "v0.25.3",
"pinned": false, "pinned": false,
"date": "2026-03-04T12:54:49Z" "date": "2026-02-10T02:58:23Z"
}, },
{ {
"slug": "domain-locker", "slug": "domain-locker",
@@ -312,9 +312,9 @@
{ {
"slug": "domain-monitor", "slug": "domain-monitor",
"repo": "Hosteroid/domain-monitor", "repo": "Hosteroid/domain-monitor",
"version": "v1.1.4", "version": "v1.1.3",
"pinned": false, "pinned": false,
"date": "2026-03-02T09:25:01Z" "date": "2026-02-11T15:48:18Z"
}, },
{ {
"slug": "donetick", "slug": "donetick",
@@ -326,9 +326,9 @@
{ {
"slug": "drawio", "slug": "drawio",
"repo": "jgraph/drawio", "repo": "jgraph/drawio",
"version": "v29.6.1", "version": "v29.5.2",
"pinned": false, "pinned": false,
"date": "2026-03-06T09:14:17Z" "date": "2026-02-22T10:36:14Z"
}, },
{ {
"slug": "duplicati", "slug": "duplicati",
@@ -382,9 +382,9 @@
{ {
"slug": "firefly", "slug": "firefly",
"repo": "firefly-iii/firefly-iii", "repo": "firefly-iii/firefly-iii",
"version": "v6.5.4", "version": "v6.5.1",
"pinned": false, "pinned": false,
"date": "2026-03-06T09:07:56Z" "date": "2026-02-27T20:55:55Z"
}, },
{ {
"slug": "fladder", "slug": "fladder",
@@ -424,9 +424,9 @@
{ {
"slug": "frigate", "slug": "frigate",
"repo": "blakeblackshear/frigate", "repo": "blakeblackshear/frigate",
"version": "v0.17.0", "version": "v0.16.4",
"pinned": true, "pinned": true,
"date": "2026-02-27T03:03:01Z" "date": "2026-01-29T00:42:14Z"
}, },
{ {
"slug": "gatus", "slug": "gatus",
@@ -438,9 +438,9 @@
{ {
"slug": "ghostfolio", "slug": "ghostfolio",
"repo": "ghostfolio/ghostfolio", "repo": "ghostfolio/ghostfolio",
"version": "2.247.0", "version": "2.245.0",
"pinned": false, "pinned": false,
"date": "2026-03-04T07:48:00Z" "date": "2026-03-01T09:09:57Z"
}, },
{ {
"slug": "gitea", "slug": "gitea",
@@ -452,9 +452,9 @@
{ {
"slug": "gitea-mirror", "slug": "gitea-mirror",
"repo": "RayLabsHQ/gitea-mirror", "repo": "RayLabsHQ/gitea-mirror",
"version": "v3.12.5", "version": "v3.10.1",
"pinned": false, "pinned": false,
"date": "2026-03-07T01:30:40Z" "date": "2026-03-01T03:08:07Z"
}, },
{ {
"slug": "glance", "slug": "glance",
@@ -473,9 +473,9 @@
{ {
"slug": "gokapi", "slug": "gokapi",
"repo": "Forceu/Gokapi", "repo": "Forceu/Gokapi",
"version": "v2.2.3", "version": "v2.2.2",
"pinned": false, "pinned": false,
"date": "2026-03-04T21:29:16Z" "date": "2026-01-31T21:11:27Z"
}, },
{ {
"slug": "gotify", "slug": "gotify",
@@ -501,9 +501,9 @@
{ {
"slug": "grocy", "slug": "grocy",
"repo": "grocy/grocy", "repo": "grocy/grocy",
"version": "v4.6.0", "version": "v4.5.0",
"pinned": false, "pinned": false,
"date": "2026-03-06T17:35:19Z" "date": "2025-03-28T19:02:22Z"
}, },
{ {
"slug": "guardian", "slug": "guardian",
@@ -550,16 +550,16 @@
{ {
"slug": "homarr", "slug": "homarr",
"repo": "homarr-labs/homarr", "repo": "homarr-labs/homarr",
"version": "v1.55.0", "version": "v1.54.0",
"pinned": false, "pinned": false,
"date": "2026-03-06T19:40:16Z" "date": "2026-02-27T19:38:50Z"
}, },
{ {
"slug": "homebox", "slug": "homebox",
"repo": "sysadminsmedia/homebox", "repo": "sysadminsmedia/homebox",
"version": "v0.24.0", "version": "v0.23.1",
"pinned": false, "pinned": false,
"date": "2026-03-03T16:09:55Z" "date": "2026-02-01T22:53:32Z"
}, },
{ {
"slug": "homepage", "slug": "homepage",
@@ -585,9 +585,9 @@
{ {
"slug": "immich-public-proxy", "slug": "immich-public-proxy",
"repo": "alangrainger/immich-public-proxy", "repo": "alangrainger/immich-public-proxy",
"version": "v1.15.4", "version": "v1.15.3",
"pinned": false, "pinned": false,
"date": "2026-03-02T21:28:06Z" "date": "2026-02-16T22:54:27Z"
}, },
{ {
"slug": "inspircd", "slug": "inspircd",
@@ -606,16 +606,16 @@
{ {
"slug": "invoiceninja", "slug": "invoiceninja",
"repo": "invoiceninja/invoiceninja", "repo": "invoiceninja/invoiceninja",
"version": "v5.12.70", "version": "v5.12.69",
"pinned": false, "pinned": false,
"date": "2026-03-06T01:53:38Z" "date": "2026-02-26T22:23:32Z"
}, },
{ {
"slug": "jackett", "slug": "jackett",
"repo": "Jackett/Jackett", "repo": "Jackett/Jackett",
"version": "v0.24.1307", "version": "v0.24.1234",
"pinned": false, "pinned": false,
"date": "2026-03-07T05:55:30Z" "date": "2026-03-01T05:55:44Z"
}, },
{ {
"slug": "jellystat", "slug": "jellystat",
@@ -634,16 +634,16 @@
{ {
"slug": "jotty", "slug": "jotty",
"repo": "fccview/jotty", "repo": "fccview/jotty",
"version": "1.21.0", "version": "1.20.0",
"pinned": false, "pinned": false,
"date": "2026-03-02T11:08:54Z" "date": "2026-02-12T09:23:30Z"
}, },
{ {
"slug": "kapowarr", "slug": "kapowarr",
"repo": "Casvt/Kapowarr", "repo": "Casvt/Kapowarr",
"version": "V1.3.0", "version": "V1.2.0",
"pinned": false, "pinned": false,
"date": "2026-03-06T16:38:21Z" "date": "2025-04-16T14:55:28Z"
}, },
{ {
"slug": "karakeep", "slug": "karakeep",
@@ -662,16 +662,16 @@
{ {
"slug": "keycloak", "slug": "keycloak",
"repo": "keycloak/keycloak", "repo": "keycloak/keycloak",
"version": "26.5.5", "version": "26.5.4",
"pinned": false, "pinned": false,
"date": "2026-03-05T15:40:30Z" "date": "2026-02-20T09:19:45Z"
}, },
{ {
"slug": "kima-hub", "slug": "kima-hub",
"repo": "Chevron7Locked/kima-hub", "repo": "Chevron7Locked/kima-hub",
"version": "v1.6.2", "version": "v1.6.0-rc.1",
"pinned": false, "pinned": false,
"date": "2026-03-05T05:38:02Z" "date": "2026-03-01T05:38:32Z"
}, },
{ {
"slug": "kimai", "slug": "kimai",
@@ -690,9 +690,9 @@
{ {
"slug": "koel", "slug": "koel",
"repo": "koel/koel", "repo": "koel/koel",
"version": "v8.3.1", "version": "v8.3.0",
"pinned": false, "pinned": false,
"date": "2026-03-04T08:22:06Z" "date": "2026-01-08T21:32:58Z"
}, },
{ {
"slug": "koillection", "slug": "koillection",
@@ -753,9 +753,9 @@
{ {
"slug": "libretranslate", "slug": "libretranslate",
"repo": "LibreTranslate/LibreTranslate", "repo": "LibreTranslate/LibreTranslate",
"version": "v1.9.5", "version": "v1.9.4",
"pinned": false, "pinned": false,
"date": "2026-03-03T18:25:04Z" "date": "2026-02-24T17:06:05Z"
}, },
{ {
"slug": "lidarr", "slug": "lidarr",
@@ -872,9 +872,9 @@
{ {
"slug": "metube", "slug": "metube",
"repo": "alexta69/metube", "repo": "alexta69/metube",
"version": "2026.03.06", "version": "2026.02.27",
"pinned": false, "pinned": false,
"date": "2026-03-06T13:52:56Z" "date": "2026-02-27T11:47:02Z"
}, },
{ {
"slug": "miniflux", "slug": "miniflux",
@@ -921,9 +921,9 @@
{ {
"slug": "netbox", "slug": "netbox",
"repo": "netbox-community/netbox", "repo": "netbox-community/netbox",
"version": "v4.5.4", "version": "v4.5.3",
"pinned": false, "pinned": false,
"date": "2026-03-03T20:32:16Z" "date": "2026-02-17T15:39:18Z"
}, },
{ {
"slug": "nextcloud-exporter", "slug": "nextcloud-exporter",
@@ -942,9 +942,9 @@
{ {
"slug": "nightscout", "slug": "nightscout",
"repo": "nightscout/cgm-remote-monitor", "repo": "nightscout/cgm-remote-monitor",
"version": "v15.0.6", "version": "15.0.4",
"pinned": false, "pinned": false,
"date": "2026-03-03T23:04:35Z" "date": "2026-02-28T17:07:02Z"
}, },
{ {
"slug": "nocodb", "slug": "nocodb",
@@ -956,9 +956,9 @@
{ {
"slug": "nodebb", "slug": "nodebb",
"repo": "NodeBB/NodeBB", "repo": "NodeBB/NodeBB",
"version": "v4.9.1", "version": "v4.9.0",
"pinned": false, "pinned": false,
"date": "2026-03-01T20:52:43Z" "date": "2026-02-27T19:20:51Z"
}, },
{ {
"slug": "nodecast-tv", "slug": "nodecast-tv",
@@ -1061,9 +1061,9 @@
{ {
"slug": "paperless-ngx", "slug": "paperless-ngx",
"repo": "paperless-ngx/paperless-ngx", "repo": "paperless-ngx/paperless-ngx",
"version": "v2.20.10", "version": "v2.20.9",
"pinned": false, "pinned": false,
"date": "2026-03-04T19:20:57Z" "date": "2026-02-28T10:17:35Z"
}, },
{ {
"slug": "patchmon", "slug": "patchmon",
@@ -1110,9 +1110,9 @@
{ {
"slug": "photoprism", "slug": "photoprism",
"repo": "photoprism/photoprism", "repo": "photoprism/photoprism",
"version": "260305-fad9d5395", "version": "251130-b3068414c",
"pinned": false, "pinned": false,
"date": "2026-03-05T20:25:12Z" "date": "2025-12-01T05:07:31Z"
}, },
{ {
"slug": "pihole-exporter", "slug": "pihole-exporter",
@@ -1138,9 +1138,9 @@
{ {
"slug": "pocketbase", "slug": "pocketbase",
"repo": "pocketbase/pocketbase", "repo": "pocketbase/pocketbase",
"version": "v0.36.6", "version": "v0.36.5",
"pinned": false, "pinned": false,
"date": "2026-03-06T08:07:09Z" "date": "2026-02-21T11:45:32Z"
}, },
{ {
"slug": "pocketid", "slug": "pocketid",
@@ -1149,13 +1149,6 @@
"pinned": false, "pinned": false,
"date": "2026-02-23T19:50:48Z" "date": "2026-02-23T19:50:48Z"
}, },
{
"slug": "powerdns",
"repo": "poweradmin/poweradmin",
"version": "v4.0.7",
"pinned": false,
"date": "2026-02-15T20:09:48Z"
},
{ {
"slug": "privatebin", "slug": "privatebin",
"repo": "PrivateBin/PrivateBin", "repo": "PrivateBin/PrivateBin",
@@ -1163,13 +1156,6 @@
"pinned": false, "pinned": false,
"date": "2025-11-12T07:10:14Z" "date": "2025-11-12T07:10:14Z"
}, },
{
"slug": "profilarr",
"repo": "Dictionarry-Hub/profilarr",
"version": "v1.1.4",
"pinned": false,
"date": "2026-01-29T14:57:25Z"
},
{ {
"slug": "projectsend", "slug": "projectsend",
"repo": "projectsend/projectsend", "repo": "projectsend/projectsend",
@@ -1229,9 +1215,9 @@
{ {
"slug": "pulse", "slug": "pulse",
"repo": "rcourtman/Pulse", "repo": "rcourtman/Pulse",
"version": "v5.1.21", "version": "v5.1.15",
"pinned": false, "pinned": false,
"date": "2026-03-06T12:13:08Z" "date": "2026-02-27T15:17:24Z"
}, },
{ {
"slug": "pve-scripts-local", "slug": "pve-scripts-local",
@@ -1285,16 +1271,16 @@
{ {
"slug": "rclone", "slug": "rclone",
"repo": "rclone/rclone", "repo": "rclone/rclone",
"version": "v1.73.2", "version": "v1.73.1",
"pinned": false, "pinned": false,
"date": "2026-03-06T20:42:26Z" "date": "2026-02-17T18:27:21Z"
}, },
{ {
"slug": "rdtclient", "slug": "rdtclient",
"repo": "rogerfar/rdt-client", "repo": "rogerfar/rdt-client",
"version": "v2.0.125", "version": "v2.0.124",
"pinned": false, "pinned": false,
"date": "2026-03-01T18:29:10Z" "date": "2026-02-24T03:18:03Z"
}, },
{ {
"slug": "reactive-resume", "slug": "reactive-resume",
@@ -1306,9 +1292,9 @@
{ {
"slug": "recyclarr", "slug": "recyclarr",
"repo": "recyclarr/recyclarr", "repo": "recyclarr/recyclarr",
"version": "v8.4.0", "version": "v8.3.2",
"pinned": false, "pinned": false,
"date": "2026-03-06T01:25:59Z" "date": "2026-02-25T22:39:51Z"
}, },
{ {
"slug": "reitti", "slug": "reitti",
@@ -1333,10 +1319,10 @@
}, },
{ {
"slug": "rustdeskserver", "slug": "rustdeskserver",
"repo": "lejianwen/rustdesk-server", "repo": "rustdesk/rustdesk-server",
"version": "v0.1.2", "version": "1.1.15",
"pinned": false, "pinned": false,
"date": "2025-09-01T02:52:30Z" "date": "2026-01-12T05:38:30Z"
}, },
{ {
"slug": "rustypaste", "slug": "rustypaste",
@@ -1355,9 +1341,9 @@
{ {
"slug": "scanopy", "slug": "scanopy",
"repo": "scanopy/scanopy", "repo": "scanopy/scanopy",
"version": "v0.14.15", "version": "v0.14.10",
"pinned": false, "pinned": false,
"date": "2026-03-06T23:06:01Z" "date": "2026-02-28T21:05:12Z"
}, },
{ {
"slug": "scraparr", "slug": "scraparr",
@@ -1369,9 +1355,9 @@
{ {
"slug": "seaweedfs", "slug": "seaweedfs",
"repo": "seaweedfs/seaweedfs", "repo": "seaweedfs/seaweedfs",
"version": "4.15", "version": "4.13",
"pinned": false, "pinned": false,
"date": "2026-03-05T06:30:30Z" "date": "2026-02-17T01:09:45Z"
}, },
{ {
"slug": "seelf", "slug": "seelf",
@@ -1390,9 +1376,9 @@
{ {
"slug": "semaphore", "slug": "semaphore",
"repo": "semaphoreui/semaphore", "repo": "semaphoreui/semaphore",
"version": "v2.17.16", "version": "v2.17.15",
"pinned": false, "pinned": false,
"date": "2026-03-05T12:39:05Z" "date": "2026-02-28T09:04:40Z"
}, },
{ {
"slug": "shelfmark", "slug": "shelfmark",
@@ -1411,9 +1397,9 @@
{ {
"slug": "silverbullet", "slug": "silverbullet",
"repo": "silverbulletmd/silverbullet", "repo": "silverbulletmd/silverbullet",
"version": "2.5.2", "version": "2.4.1",
"pinned": false, "pinned": false,
"date": "2026-03-06T12:20:58Z" "date": "2026-01-16T12:08:28Z"
}, },
{ {
"slug": "slskd", "slug": "slskd",
@@ -1432,9 +1418,9 @@
{ {
"slug": "snowshare", "slug": "snowshare",
"repo": "TuroYT/snowshare", "repo": "TuroYT/snowshare",
"version": "v1.3.8", "version": "v1.3.7",
"pinned": false, "pinned": false,
"date": "2026-03-02T07:43:42Z" "date": "2026-02-23T15:51:39Z"
}, },
{ {
"slug": "sonarr", "slug": "sonarr",
@@ -1446,9 +1432,9 @@
{ {
"slug": "sonobarr", "slug": "sonobarr",
"repo": "Dodelidoo-Labs/sonobarr", "repo": "Dodelidoo-Labs/sonobarr",
"version": "0.12.1", "version": "0.11.0",
"pinned": false, "pinned": false,
"date": "2026-03-03T13:43:02Z" "date": "2026-01-21T19:07:21Z"
}, },
{ {
"slug": "speedtest-tracker", "slug": "speedtest-tracker",
@@ -1467,16 +1453,16 @@
{ {
"slug": "sportarr", "slug": "sportarr",
"repo": "Sportarr/Sportarr", "repo": "Sportarr/Sportarr",
"version": "v4.0.987.1062", "version": "v4.0.983.1057",
"pinned": false, "pinned": false,
"date": "2026-03-07T05:01:48Z" "date": "2026-01-26T18:54:50Z"
}, },
{ {
"slug": "stirling-pdf", "slug": "stirling-pdf",
"repo": "Stirling-Tools/Stirling-PDF", "repo": "Stirling-Tools/Stirling-PDF",
"version": "v2.7.0", "version": "v2.5.3",
"pinned": false, "pinned": false,
"date": "2026-03-06T11:21:47Z" "date": "2026-02-23T23:23:39Z"
}, },
{ {
"slug": "streamlink-webui", "slug": "streamlink-webui",
@@ -1562,13 +1548,6 @@
"pinned": false, "pinned": false,
"date": "2026-02-13T16:30:09Z" "date": "2026-02-13T16:30:09Z"
}, },
{
"slug": "tinyauth",
"repo": "steveiliop56/tinyauth",
"version": "v5.0.1",
"pinned": false,
"date": "2026-03-04T21:05:05Z"
},
{ {
"slug": "traccar", "slug": "traccar",
"repo": "traccar/traccar", "repo": "traccar/traccar",
@@ -1579,9 +1558,9 @@
{ {
"slug": "tracearr", "slug": "tracearr",
"repo": "connorgallopo/Tracearr", "repo": "connorgallopo/Tracearr",
"version": "v1.4.21", "version": "v1.4.19",
"pinned": false, "pinned": false,
"date": "2026-03-03T18:43:20Z" "date": "2026-02-28T21:25:47Z"
}, },
{ {
"slug": "tracktor", "slug": "tracktor",
@@ -1593,23 +1572,23 @@
{ {
"slug": "traefik", "slug": "traefik",
"repo": "traefik/traefik", "repo": "traefik/traefik",
"version": "v3.6.10", "version": "v3.6.9",
"pinned": false, "pinned": false,
"date": "2026-03-06T15:08:35Z" "date": "2026-02-23T17:21:17Z"
}, },
{ {
"slug": "trilium", "slug": "trilium",
"repo": "TriliumNext/Trilium", "repo": "TriliumNext/Trilium",
"version": "v0.102.0", "version": "v0.101.3",
"pinned": false, "pinned": false,
"date": "2026-03-01T20:37:40Z" "date": "2026-01-08T18:05:22Z"
}, },
{ {
"slug": "trip", "slug": "trip",
"repo": "itskovacs/TRIP", "repo": "itskovacs/TRIP",
"version": "1.41.1", "version": "1.41.0",
"pinned": false, "pinned": false,
"date": "2026-03-04T07:25:35Z" "date": "2026-02-23T17:57:31Z"
}, },
{ {
"slug": "tududi", "slug": "tududi",
@@ -1649,9 +1628,9 @@
{ {
"slug": "upgopher", "slug": "upgopher",
"repo": "wanetty/upgopher", "repo": "wanetty/upgopher",
"version": "v1.15.2", "version": "v1.14.0",
"pinned": false, "pinned": false,
"date": "2026-03-03T13:40:45Z" "date": "2026-02-24T22:43:34Z"
}, },
{ {
"slug": "upsnap", "slug": "upsnap",
@@ -1663,9 +1642,9 @@
{ {
"slug": "uptimekuma", "slug": "uptimekuma",
"repo": "louislam/uptime-kuma", "repo": "louislam/uptime-kuma",
"version": "2.2.0", "version": "2.1.3",
"pinned": false, "pinned": false,
"date": "2026-03-05T02:08:14Z" "date": "2026-02-19T05:37:30Z"
}, },
{ {
"slug": "vaultwarden", "slug": "vaultwarden",
@@ -1677,9 +1656,9 @@
{ {
"slug": "victoriametrics", "slug": "victoriametrics",
"repo": "VictoriaMetrics/VictoriaMetrics", "repo": "VictoriaMetrics/VictoriaMetrics",
"version": "v1.137.0", "version": "v1.136.0",
"pinned": false, "pinned": false,
"date": "2026-03-02T10:09:29Z" "date": "2026-02-16T13:17:50Z"
}, },
{ {
"slug": "vikunja", "slug": "vikunja",
@@ -1698,16 +1677,16 @@
{ {
"slug": "wallos", "slug": "wallos",
"repo": "ellite/Wallos", "repo": "ellite/Wallos",
"version": "v4.6.2", "version": "v4.6.1",
"pinned": false, "pinned": false,
"date": "2026-03-05T22:18:06Z" "date": "2026-02-10T21:06:46Z"
}, },
{ {
"slug": "wanderer", "slug": "wanderer",
"repo": "meilisearch/meilisearch", "repo": "meilisearch/meilisearch",
"version": "v1.37.0", "version": "v1.36.0",
"pinned": false, "pinned": false,
"date": "2026-03-02T09:16:36Z" "date": "2026-02-23T08:13:32Z"
}, },
{ {
"slug": "warracker", "slug": "warracker",
@@ -1719,9 +1698,9 @@
{ {
"slug": "watcharr", "slug": "watcharr",
"repo": "sbondCo/Watcharr", "repo": "sbondCo/Watcharr",
"version": "v3.0.0", "version": "v2.1.1",
"pinned": false, "pinned": false,
"date": "2026-03-04T09:29:14Z" "date": "2025-07-15T22:38:01Z"
}, },
{ {
"slug": "watchyourlan", "slug": "watchyourlan",
@@ -1740,9 +1719,9 @@
{ {
"slug": "wealthfolio", "slug": "wealthfolio",
"repo": "afadil/wealthfolio", "repo": "afadil/wealthfolio",
"version": "v3.0.3", "version": "v3.0.0",
"pinned": true, "pinned": false,
"date": "2026-03-03T21:47:55Z" "date": "2026-02-24T22:37:05Z"
}, },
{ {
"slug": "web-check", "slug": "web-check",
@@ -1796,9 +1775,9 @@
{ {
"slug": "yubal", "slug": "yubal",
"repo": "guillevc/yubal", "repo": "guillevc/yubal",
"version": "v0.6.3", "version": "v0.6.2",
"pinned": false, "pinned": false,
"date": "2026-03-07T03:24:05Z" "date": "2026-02-24T15:15:46Z"
}, },
{ {
"slug": "zerobyte", "slug": "zerobyte",
@@ -1810,9 +1789,9 @@
{ {
"slug": "zigbee2mqtt", "slug": "zigbee2mqtt",
"repo": "Koenkk/zigbee2mqtt", "repo": "Koenkk/zigbee2mqtt",
"version": "2.9.1", "version": "2.9.0",
"pinned": false, "pinned": false,
"date": "2026-03-02T11:16:46Z" "date": "2026-03-01T13:58:14Z"
}, },
{ {
"slug": "zipline", "slug": "zipline",
@@ -1824,9 +1803,9 @@
{ {
"slug": "zitadel", "slug": "zitadel",
"repo": "zitadel/zitadel", "repo": "zitadel/zitadel",
"version": "v4.12.1", "version": "v4.11.1",
"pinned": false, "pinned": false,
"date": "2026-03-04T12:40:17Z" "date": "2026-02-25T06:13:13Z"
}, },
{ {
"slug": "zoraxy", "slug": "zoraxy",
@@ -1838,9 +1817,9 @@
{ {
"slug": "zwave-js-ui", "slug": "zwave-js-ui",
"repo": "zwave-js/zwave-js-ui", "repo": "zwave-js/zwave-js-ui",
"version": "v11.14.0", "version": "v11.12.0",
"pinned": false, "pinned": false,
"date": "2026-03-06T09:34:32Z" "date": "2026-02-19T10:14:19Z"
} }
] ]
} }

View File

@@ -5,7 +5,7 @@
3 3
], ],
"date_created": "2025-01-01", "date_created": "2025-01-01",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": false, "privileged": false,
"interface_port": 9120, "interface_port": 9120,
@@ -17,13 +17,24 @@
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/komodo.sh", "script": "ct/komodo.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 2048,
"hdd": null, "hdd": 10,
"os": null, "os": "debian",
"version": null "version": "13"
}
},
{
"type": "alpine",
"script": "ct/alpine-komodo.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 10,
"os": "alpine",
"version": "3.23"
} }
} }
], ],
@@ -33,19 +44,7 @@
}, },
"notes": [ "notes": [
{ {
"text": "This is an addon script intended to be used on top of an existing Docker container.", "text": "For admin username and password type `cat ~/komodo.creds` inside LXC.",
"type": "info"
},
{
"text": "Execute within an existing LXC console (Debian / Ubuntu / Alpine supported)",
"type": "info"
},
{
"text": "For admin username and password, run: cat ~/komodo.creds",
"type": "info"
},
{
"text": "To update, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/komodo.sh)",
"type": "info" "type": "info"
} }
] ]

View File

@@ -21,7 +21,7 @@
"resources": { "resources": {
"cpu": 1, "cpu": 1,
"ram": 512, "ram": 512,
"hdd": 4, "hdd": 2,
"os": "debian", "os": "debian",
"version": "13" "version": "13"
} }

View File

@@ -1,50 +0,0 @@
{
"name": "NetBird",
"slug": "netbird",
"categories": [4],
"date_created": "2026-03-05",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": null,
"documentation": "https://docs.netbird.io/",
"website": "https://netbird.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/netbird.webp",
"config_path": "/etc/netbird/config.json",
"description": "NetBird is an open source VPN management platform that creates secure peer-to-peer networks using WireGuard. It enables secure connectivity between devices anywhere in the world without complex firewall configurations or port forwarding. NetBird offers features like zero-configuration networking, SSO integration, access control policies, and a centralized management dashboard. It's designed to be simple to deploy and manage, making it ideal for connecting remote teams, securing IoT devices, or building secure infrastructure networks.",
"install_methods": [
{
"type": "default",
"script": "ct/netbird.sh",
"resources": {
"cpu": 1,
"ram": 512,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "The NetBird client (agent) allows a peer to join a pre-existing NetBird deployment. If a NetBird deployment is not yet available, there are both managed and self-hosted options available.",
"type": "info"
},
{
"text": "After installation, enter the container and run `netbird` to view the commands.",
"type": "info"
},
{
"text": "Use a Setup Key from your NetBird dashboard or SSO login to authenticate during setup or in the container.",
"type": "info"
},
{
"text": "Check connection status with `netbird status`.",
"type": "info"
}
]
}

View File

@@ -1,56 +0,0 @@
{
"name": "Papra",
"slug": "papra",
"categories": [
12
],
"date_created": "2026-03-05",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 1221,
"documentation": "https://github.com/CorentinTh/papra",
"website": "https://github.com/CorentinTh/papra",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/papra.webp",
"config_path": "/opt/papra/.env",
"description": "Papra is a modern, self-hosted document management system with full-text search, OCR support, and automatic document processing. Built with Node.js and featuring a clean web interface for organizing and managing your documents.",
"install_methods": [
{
"type": "default",
"script": "ct/papra.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 10,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "First visit will prompt you to create an account",
"type": "info"
},
{
"text": "Tesseract OCR is pre-installed for all languages",
"type": "info"
},
{
"text": "Documents are stored in /opt/papra/app-data/documents",
"type": "info"
},
{
"text": "Ingestion folder available at /opt/papra/ingestion for automatic document import",
"type": "info"
},
{
"text": "Email functionality runs in dry-run mode by default",
"type": "warning"
}
]
}

View File

@@ -1,40 +0,0 @@
{
"name": "PowerDNS",
"slug": "powerdns",
"categories": [
5
],
"date_created": "2026-03-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 80,
"documentation": "https://doc.powerdns.com/index.html",
"config_path": "/opt/poweradmin/config/settings.php",
"website": "https://www.powerdns.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/powerdns.webp",
"description": "The PowerDNS Authoritative Server is a versatile nameserver which supports a large number of backends. These backends can either be plain zone files or be more dynamic in nature. PowerDNS has the concepts of backends. A backend is a datastore that the server will consult that contains DNS records (and some metadata). The backends range from database backends (MySQL, PostgreSQL) and BIND zone files to co-processes and JSON APIs.",
"install_methods": [
{
"type": "default",
"script": "ct/powerdns.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 4,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "For administrator credentials type: `cat ~/poweradmin.creds` inside LXC.",
"type": "info"
}
]
}

View File

@@ -1,35 +0,0 @@
{
"name": "Profilarr",
"slug": "profilarr",
"categories": [
14
],
"date_created": "2026-03-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 6868,
"documentation": "https://github.com/Dictionarry-Hub/profilarr#readme",
"website": "https://github.com/Dictionarry-Hub/profilarr",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/profilarr.webp",
"config_path": "/config",
"description": "Profilarr is a configuration management platform for Radarr and Sonarr that simplifies importing, syncing, and managing quality profiles, custom formats, and release profiles.",
"install_methods": [
{
"type": "default",
"script": "ct/profilarr.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "Debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": []
}

View File

@@ -12,7 +12,7 @@
"documentation": "https://docs.rxresume.org/", "documentation": "https://docs.rxresume.org/",
"website": "https://rxresume.org", "website": "https://rxresume.org",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/reactive-resume.webp", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/reactive-resume.webp",
"config_path": "/opt/Reactive-Resume/.env", "config_path": "/opt/reactive-resume/.env",
"description": "A one-of-a-kind resume builder that keeps your privacy in mind. Completely secure, customizable, portable, open-source and free forever.", "description": "A one-of-a-kind resume builder that keeps your privacy in mind. Completely secure, customizable, portable, open-source and free forever.",
"install_methods": [ "install_methods": [
{ {

View File

@@ -5,25 +5,25 @@
2 2
], ],
"date_created": "2024-05-02", "date_created": "2024-05-02",
"type": "addon", "type": "ct",
"updateable": true, "updateable": true,
"privileged": false, "privileged": false,
"interface_port": 80, "interface_port": 80,
"documentation": "https://runtipi.io/docs/introduction", "documentation": "https://runtipi.io/docs/introduction",
"website": "https://runtipi.io/", "website": "https://runtipi.io/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/runtipi.webp", "logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/runtipi.webp",
"config_path": "/opt/runtipi/state/settings.json", "config_path": "opt/runtipi/state/settings.json",
"description": "Runtipi lets you install all your favorite self-hosted apps without the hassle of configuring and managing each service. One-click installs and updates for more than 180 popular apps.", "description": "Runtipi lets you install all your favorite self-hosted apps without the hassle of configuring and managing each service. One-click installs and updates for more than 180 popular apps.",
"install_methods": [ "install_methods": [
{ {
"type": "default", "type": "default",
"script": "tools/addon/runtipi.sh", "script": "ct/runtipi.sh",
"resources": { "resources": {
"cpu": null, "cpu": 2,
"ram": null, "ram": 2048,
"hdd": null, "hdd": 8,
"os": null, "os": "debian",
"version": null "version": "13"
} }
} }
], ],
@@ -32,21 +32,9 @@
"password": null "password": null
}, },
"notes": [ "notes": [
{
"text": "This is an addon script intended to be used on top of an existing Docker container.",
"type": "info"
},
{
"text": "Execute within an existing LXC console (Debian / Ubuntu only)",
"type": "info"
},
{ {
"text": "WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.", "text": "WARNING: Installation sources scripts outside of Community Scripts repo. Please check the source before installing.",
"type": "warning" "type": "warning"
},
{
"text": "To update via CLI, run the addon script again and select Update, or use: bash <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/runtipi.sh)",
"type": "info"
} }
] ]
} }

View File

@@ -54,10 +54,6 @@
{ {
"text": "To see admin password on Alpine, type `cat ~/rustdesk.creds` inside LXC.", "text": "To see admin password on Alpine, type `cat ~/rustdesk.creds` inside LXC.",
"type": "info" "type": "info"
},
{
"text": "This script uses hbbs/hbbr builds from `lejianwen/rustdesk-server` (instead of the official repo) for full compatibility with the RustDesk API (SSO/OAuth). See `https://github.com/community-scripts/ProxmoxVE/issues/12079`.",
"type": "info"
} }
] ]
} }

View File

@@ -33,7 +33,7 @@
}, },
"notes": [ "notes": [
{ {
"text": "This instance uses SQLite", "text": "This instance uses BoltDB",
"type": "info" "type": "info"
}, },
{ {

View File

@@ -0,0 +1,40 @@
{
"name": "Suwayomi-Server",
"slug": "suwayomi-server",
"categories": [
13
],
"date_created": "2025-08-01",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 4567,
"documentation": "https://github.com/Suwayomi/Suwayomi-Server/wiki",
"website": "https://github.com/Suwayomi/Suwayomi-Server",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/suwayomi.webp",
"config_path": "",
"description": "A free and open source manga reader server that runs extensions built for Mihon (Tachiyomi).",
"install_methods": [
{
"type": "default",
"script": "ct/suwayomiserver.sh",
"resources": {
"cpu": 1,
"ram": 1024,
"hdd": 4,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "This application can be conflicting with Kaspersky products. You maybe need to disable Kaspersky in order to use this application.",
"type": "info"
}
]
}

View File

@@ -0,0 +1,42 @@
{
"name": "UniFi Network Server",
"slug": "unifi",
"categories": [
4
],
"date_created": "2024-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8443,
"documentation": "https://help.ui.com/hc/en-us/articles/360012282453-Self-Hosting-a-UniFi-Network-Server",
"website": "https://www.ui.com/",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/ubiquiti-unifi.webp",
"config_path": "",
"description": "UniFi Network Server is a software that helps manage and monitor UniFi networks (Wi-Fi, Ethernet, etc.) by providing an intuitive user interface and advanced features. It allows network administrators to configure, monitor, and upgrade network devices, as well as view network statistics, client devices, and historical events. The aim of the application is to make the management of UniFi networks easier and more efficient.",
"disable": true,
"disable_description": "This script is disabled because UniFi no longer delivers APT packages for Debian systems. The installation relies on APT repositories that are no longer maintained or available. For more details, see: https://github.com/community-scripts/ProxmoxVE/issues/11876",
"install_methods": [
{
"type": "default",
"script": "ct/unifi.sh",
"resources": {
"cpu": 2,
"ram": 2048,
"hdd": 8,
"os": "debian",
"version": "12"
}
}
],
"default_credentials": {
"username": null,
"password": null
},
"notes": [
{
"text": "For non-AVX CPUs, MongoDB 4.4 is installed. Please note this is a legacy solution that may present security risks and could become unsupported in future updates.",
"type": "warning"
}
]
}

View File

@@ -2,68 +2,42 @@
import type { z } from "zod"; import type { z } from "zod";
import { githubGist, nord } from "react-syntax-highlighter/dist/esm/styles/hljs";
import { CalendarIcon, Check, Clipboard, Download } from "lucide-react"; import { CalendarIcon, Check, Clipboard, Download } from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useState } from "react";
import SyntaxHighlighter from "react-syntax-highlighter";
import { useTheme } from "next-themes";
import { format } from "date-fns"; import { format } from "date-fns";
import { toast } from "sonner"; import { toast } from "sonner";
import Image from "next/image";
import type { Category } from "@/lib/types"; import type { Category } from "@/lib/types";
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Calendar } from "@/components/ui/calendar"; import { Calendar } from "@/components/ui/calendar";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import { basePath } from "@/config/site-config";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { fetchCategories } from "@/lib/data"; import { fetchCategories } from "@/lib/data";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import type { Script } from "./_schemas/schemas"; import type { Script } from "./_schemas/schemas";
import { ScriptItem } from "../scripts/_components/script-item";
import InstallMethod from "./_components/install-method"; import InstallMethod from "./_components/install-method";
import { ScriptSchema } from "./_schemas/schemas"; 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";
function search(scripts: Script[], query: string): Script[] { import { githubGist, nord } from "react-syntax-highlighter/dist/esm/styles/hljs";
const queryLower = query.toLowerCase().trim(); import SyntaxHighlighter from "react-syntax-highlighter";
const searchWords = queryLower.split(/\s+/).filter(Boolean); import { ScriptItem } from "../scripts/_components/script-item";
import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
return scripts import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
.map((script) => { import { search } from "@/components/command-menu";
const nameLower = script.name.toLowerCase(); import { basePath } from "@/config/site-config";
const descriptionLower = (script.description || "").toLowerCase(); import Image from "next/image";
import { useTheme } from "next-themes";
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);
}
const initialScript: Script = { const initialScript: Script = {
name: "", name: "",
@@ -103,32 +77,32 @@ export default function JSONGenerator() {
const selectedCategoryObj = useMemo( const selectedCategoryObj = useMemo(
() => categories.find(cat => cat.id.toString() === selectedCategory), () => categories.find(cat => cat.id.toString() === selectedCategory),
[categories, selectedCategory], [categories, selectedCategory]
); );
const allScripts = useMemo( const allScripts = useMemo(
() => categories.flatMap(cat => cat.scripts || []), () => categories.flatMap(cat => cat.scripts || []),
[categories], [categories]
); );
const scripts = useMemo(() => { const scripts = useMemo(() => {
const query = searchQuery.trim(); const query = searchQuery.trim()
if (query) { if (query) {
return search(allScripts, query); return search(allScripts, query)
} }
if (selectedCategoryObj) { if (selectedCategoryObj) {
return selectedCategoryObj.scripts || []; return selectedCategoryObj.scripts || []
} }
return []; return []
}, [allScripts, selectedCategoryObj, searchQuery]); }, [allScripts, selectedCategoryObj, searchQuery]);
useEffect(() => { useEffect(() => {
fetchCategories() fetchCategories()
.then(setCategories) .then(setCategories)
.catch(error => console.error("Error fetching categories:", error)); .catch((error) => console.error("Error fetching categories:", error));
}, []); }, []);
useEffect(() => { useEffect(() => {
@@ -148,14 +122,11 @@ export default function JSONGenerator() {
if (updated.type === "pve") { if (updated.type === "pve") {
scriptPath = `tools/pve/${updated.slug}.sh`; scriptPath = `tools/pve/${updated.slug}.sh`;
} } else if (updated.type === "addon") {
else if (updated.type === "addon") {
scriptPath = `tools/addon/${updated.slug}.sh`; scriptPath = `tools/addon/${updated.slug}.sh`;
} } else if (method.type === "alpine") {
else if (method.type === "alpine") {
scriptPath = `${updated.type}/alpine-${updated.slug}.sh`; scriptPath = `${updated.type}/alpine-${updated.slug}.sh`;
} } else {
else {
scriptPath = `${updated.type}/${updated.slug}.sh`; scriptPath = `${updated.type}/${updated.slug}.sh`;
} }
@@ -174,13 +145,11 @@ export default function JSONGenerator() {
}, []); }, []);
const handleCopy = useCallback(() => { const handleCopy = useCallback(() => {
if (!isValid) if (!isValid) toast.warning("JSON schema is invalid. Copying anyway.");
toast.warning("JSON schema is invalid. Copying anyway.");
navigator.clipboard.writeText(JSON.stringify(script, null, 2)); navigator.clipboard.writeText(JSON.stringify(script, null, 2));
setIsCopied(true); setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000); setTimeout(() => setIsCopied(false), 2000);
if (isValid) if (isValid) toast.success("Copied metadata to clipboard");
toast.success("Copied metadata to clipboard");
}, [script]); }, [script]);
const importScript = (script: Script) => { const importScript = (script: Script) => {
@@ -197,11 +166,11 @@ export default function JSONGenerator() {
setIsValid(true); setIsValid(true);
setZodErrors(null); setZodErrors(null);
toast.success("Imported JSON successfully"); toast.success("Imported JSON successfully");
} } catch (error) {
catch (error) {
toast.error("Failed to read or parse the JSON file."); toast.error("Failed to read or parse the JSON file.");
} }
};
}
const handleFileImport = useCallback(() => { const handleFileImport = useCallback(() => {
const input = document.createElement("input"); const input = document.createElement("input");
@@ -211,8 +180,7 @@ export default function JSONGenerator() {
input.onchange = (e: Event) => { input.onchange = (e: Event) => {
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
const file = target.files?.[0]; const file = target.files?.[0];
if (!file) if (!file) return;
return;
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (event) => { reader.onload = (event) => {
@@ -221,8 +189,7 @@ export default function JSONGenerator() {
const parsed = JSON.parse(content); const parsed = JSON.parse(content);
importScript(parsed); importScript(parsed);
toast.success("Imported JSON successfully"); toast.success("Imported JSON successfully");
} } catch (error) {
catch (error) {
toast.error("Failed to read the JSON file."); toast.error("Failed to read the JSON file.");
} }
}; };
@@ -276,10 +243,7 @@ export default function JSONGenerator() {
<div className="mt-2 space-y-1"> <div className="mt-2 space-y-1">
{zodErrors.issues.map((error, index) => ( {zodErrors.issues.map((error, index) => (
<AlertDescription key={index} className="p-1 text-red-500"> <AlertDescription key={index} className="p-1 text-red-500">
{error.path.join(".")} {error.path.join(".")} -{error.message}
{" "}
-
{error.message}
</AlertDescription> </AlertDescription>
))} ))}
</div> </div>
@@ -306,7 +270,7 @@ export default function JSONGenerator() {
onOpenChange={setIsImportDialogOpen} onOpenChange={setIsImportDialogOpen}
> >
<DialogTrigger asChild> <DialogTrigger asChild>
<DropdownMenuItem onSelect={e => e.preventDefault()}> <DropdownMenuItem onSelect={(e) => e.preventDefault()}>
Import existing script Import existing script
</DropdownMenuItem> </DropdownMenuItem>
</DialogTrigger> </DialogTrigger>
@@ -328,7 +292,7 @@ export default function JSONGenerator() {
<SelectValue placeholder="Category" /> <SelectValue placeholder="Category" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
{categories.map(category => ( {categories.map((category) => (
<SelectItem key={category.id} value={category.id.toString()}> <SelectItem key={category.id} value={category.id.toString()}>
{category.name} {category.name}
</SelectItem> </SelectItem>
@@ -338,44 +302,40 @@ export default function JSONGenerator() {
<Input <Input
placeholder="Search for a script..." placeholder="Search for a script..."
value={searchQuery} value={searchQuery}
onChange={e => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
/> />
{!selectedCategory && !searchQuery {!selectedCategory && !searchQuery ? (
? ( <p className="text-muted-foreground text-sm text-center">
<p className="text-muted-foreground text-sm text-center"> Select a category or search for a script
Select a category or search for a script </p>
</p> ) : scripts.length === 0 ? (
) <p className="text-muted-foreground text-sm text-center">
: scripts.length === 0 No scripts found
? ( </p>
<p className="text-muted-foreground text-sm text-center"> ) : (
No scripts found <div className="grid grid-cols-3 auto-rows-min h-64 overflow-y-auto gap-4">
</p> {scripts.map(script => (
) <div
: ( key={script.slug}
<div className="grid grid-cols-3 auto-rows-min h-64 overflow-y-auto gap-4"> className="p-2 border rounded cursor-pointer hover:bg-accent hover:text-accent-foreground"
{scripts.map(script => ( onClick={() => {
<div importScript(script);
key={script.slug} setIsImportDialogOpen(false);
className="p-2 border rounded cursor-pointer hover:bg-accent hover:text-accent-foreground" }}
onClick={() => { >
importScript(script); <Image
setIsImportDialogOpen(false); src={script.logo || `/${basePath}/logo.png`}
}} alt={script.name}
> className="w-full h-12 object-contain mb-2"
<Image width={16}
src={script.logo || `/${basePath}/logo.png`} height={16}
alt={script.name} unoptimized
className="w-full h-12 object-contain mb-2" />
width={16} <p className="text-sm text-center">{script.name}</p>
height={16} </div>
unoptimized ))}
/> </div>
<p className="text-sm text-center">{script.name}</p> )}
</div>
))}
</div>
)}
</div> </div>
</div> </div>
</DialogContent> </DialogContent>
@@ -388,19 +348,15 @@ export default function JSONGenerator() {
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<div> <div>
<Label> <Label>
Name Name <span className="text-red-500">*</span>
{" "}
<span className="text-red-500">*</span>
</Label> </Label>
<Input placeholder="Example" value={script.name} onChange={e => updateScript("name", e.target.value)} /> <Input placeholder="Example" value={script.name} onChange={(e) => updateScript("name", e.target.value)} />
</div> </div>
<div> <div>
<Label> <Label>
Slug Slug <span className="text-red-500">*</span>
{" "}
<span className="text-red-500">*</span>
</Label> </Label>
<Input placeholder="example" value={script.slug} onChange={e => updateScript("slug", e.target.value)} /> <Input placeholder="example" value={script.slug} onChange={(e) => updateScript("slug", e.target.value)} />
</div> </div>
</div> </div>
<div> <div>
@@ -410,7 +366,7 @@ export default function JSONGenerator() {
<Input <Input
placeholder="Full logo URL" placeholder="Full logo URL"
value={script.logo || ""} value={script.logo || ""}
onChange={e => updateScript("logo", e.target.value || null)} onChange={(e) => updateScript("logo", e.target.value || null)}
/> />
</div> </div>
<div> <div>
@@ -418,28 +374,24 @@ export default function JSONGenerator() {
<Input <Input
placeholder="Path to config file" placeholder="Path to config file"
value={script.config_path || ""} value={script.config_path || ""}
onChange={e => updateScript("config_path", e.target.value || "")} onChange={(e) => updateScript("config_path", e.target.value || "")}
/> />
</div> </div>
<div> <div>
<Label> <Label>
Description Description <span className="text-red-500">*</span>
{" "}
<span className="text-red-500">*</span>
</Label> </Label>
<Textarea <Textarea
placeholder="Example" placeholder="Example"
value={script.description} value={script.description}
onChange={e => updateScript("description", e.target.value)} onChange={(e) => updateScript("description", e.target.value)}
/> />
</div> </div>
<Categories script={script} setScript={setScript} categories={categories} /> <Categories script={script} setScript={setScript} categories={categories} />
<div className="flex gap-2"> <div className="flex gap-2">
<div className="flex flex-col gap-2 w-full"> <div className="flex flex-col gap-2 w-full">
<Label> <Label>
Date Created Date Created <span className="text-red-500">*</span>
{" "}
<span className="text-red-500">*</span>
</Label> </Label>
<Popover> <Popover>
<PopoverTrigger asChild className="flex-1"> <PopoverTrigger asChild className="flex-1">
@@ -463,7 +415,7 @@ export default function JSONGenerator() {
</div> </div>
<div className="flex flex-col gap-2 w-full"> <div className="flex flex-col gap-2 w-full">
<Label>Type</Label> <Label>Type</Label>
<Select value={script.type} onValueChange={value => updateScript("type", value)}> <Select value={script.type} onValueChange={(value) => updateScript("type", value)}>
<SelectTrigger className="flex-1"> <SelectTrigger className="flex-1">
<SelectValue placeholder="Type" /> <SelectValue placeholder="Type" />
</SelectTrigger> </SelectTrigger>
@@ -478,17 +430,17 @@ export default function JSONGenerator() {
</div> </div>
<div className="w-full flex gap-5"> <div className="w-full flex gap-5">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Switch checked={script.updateable} onCheckedChange={checked => updateScript("updateable", checked)} /> <Switch checked={script.updateable} onCheckedChange={(checked) => updateScript("updateable", checked)} />
<label>Updateable</label> <label>Updateable</label>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Switch checked={script.privileged} onCheckedChange={checked => updateScript("privileged", checked)} /> <Switch checked={script.privileged} onCheckedChange={(checked) => updateScript("privileged", checked)} />
<label>Privileged</label> <label>Privileged</label>
</div> </div>
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Switch <Switch
checked={script.disable || false} checked={script.disable || false}
onCheckedChange={checked => updateScript("disable", checked)} onCheckedChange={(checked) => updateScript("disable", checked)}
/> />
<label>Disabled</label> <label>Disabled</label>
</div> </div>
@@ -496,14 +448,12 @@ export default function JSONGenerator() {
{script.disable && ( {script.disable && (
<div> <div>
<Label> <Label>
Disable Description Disable Description <span className="text-red-500">*</span>
{" "}
<span className="text-red-500">*</span>
</Label> </Label>
<Textarea <Textarea
placeholder="Explain why this script is disabled..." placeholder="Explain why this script is disabled..."
value={script.disable_description || ""} value={script.disable_description || ""}
onChange={e => updateScript("disable_description", e.target.value)} onChange={(e) => updateScript("disable_description", e.target.value)}
/> />
</div> </div>
)} )}
@@ -511,18 +461,18 @@ export default function JSONGenerator() {
placeholder="Interface Port" placeholder="Interface Port"
type="number" type="number"
value={script.interface_port || ""} value={script.interface_port || ""}
onChange={e => updateScript("interface_port", e.target.value ? Number(e.target.value) : null)} onChange={(e) => updateScript("interface_port", e.target.value ? Number(e.target.value) : null)}
/> />
<div className="flex gap-2"> <div className="flex gap-2">
<Input <Input
placeholder="Website URL" placeholder="Website URL"
value={script.website || ""} value={script.website || ""}
onChange={e => updateScript("website", e.target.value || null)} onChange={(e) => updateScript("website", e.target.value || null)}
/> />
<Input <Input
placeholder="Documentation URL" placeholder="Documentation URL"
value={script.documentation || ""} value={script.documentation || ""}
onChange={e => updateScript("documentation", e.target.value || null)} onChange={(e) => updateScript("documentation", e.target.value || null)}
/> />
</div> </div>
<InstallMethod script={script} setScript={setScript} setIsValid={setIsValid} setZodErrors={setZodErrors} /> <InstallMethod script={script} setScript={setScript} setIsValid={setIsValid} setZodErrors={setZodErrors} />
@@ -530,20 +480,22 @@ export default function JSONGenerator() {
<Input <Input
placeholder="Username" placeholder="Username"
value={script.default_credentials.username || ""} value={script.default_credentials.username || ""}
onChange={e => onChange={(e) =>
updateScript("default_credentials", { updateScript("default_credentials", {
...script.default_credentials, ...script.default_credentials,
username: e.target.value || null, username: e.target.value || null,
})} })
}
/> />
<Input <Input
placeholder="Password" placeholder="Password"
value={script.default_credentials.password || ""} value={script.default_credentials.password || ""}
onChange={e => onChange={(e) =>
updateScript("default_credentials", { updateScript("default_credentials", {
...script.default_credentials, ...script.default_credentials,
password: e.target.value || null, password: e.target.value || null,
})} })
}
/> />
<Note script={script} setScript={setScript} setIsValid={setIsValid} setZodErrors={setZodErrors} /> <Note script={script} setScript={setScript} setIsValid={setIsValid} setZodErrors={setZodErrors} />
</form> </form>
@@ -552,7 +504,7 @@ export default function JSONGenerator() {
<Tabs <Tabs
defaultValue="json" defaultValue="json"
className="w-full" className="w-full"
onValueChange={value => setCurrentTab(value as "json" | "preview")} onValueChange={(value) => setCurrentTab(value as "json" | "preview")}
value={currentTab} value={currentTab}
> >
<TabsList className="grid w-full grid-cols-2"> <TabsList className="grid w-full grid-cols-2">

View File

@@ -19,9 +19,8 @@ export function getDisplayValueFromType(type: string) {
case "vm": case "vm":
return "VM"; return "VM";
case "pve": case "pve":
return "PVE";
case "addon": case "addon":
return "ADDON"; return "";
default: default:
return ""; return "";
} }
@@ -37,9 +36,10 @@ export function LatestScripts({
onPageChange: (page: number) => void; onPageChange: (page: number) => void;
}) { }) {
const latestScripts = useMemo(() => { const latestScripts = useMemo(() => {
if (!items) return []; if (!items)
return [];
const scripts = items.flatMap((category) => category.scripts || []); const scripts = items.flatMap(category => category.scripts || []);
// Filter out duplicates by slug // Filter out duplicates by slug
const uniqueScriptsMap = new Map<string, Script>(); const uniqueScriptsMap = new Map<string, Script>();
@@ -97,7 +97,7 @@ export function LatestScripts({
</div> </div>
)} )}
<div className="min-w flex w-full flex-row flex-wrap gap-4"> <div className="min-w flex w-full flex-row flex-wrap gap-4">
{latestScripts.slice(startIndex, endIndex).map((script) => ( {latestScripts.slice(startIndex, endIndex).map(script => (
<Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30"> <Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30">
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-3"> <CardTitle className="flex items-center gap-3">
@@ -108,13 +108,15 @@ export function LatestScripts({
height={64} height={64}
width={64} width={64}
alt="" alt=""
onError={(e) => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)} onError={e => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
className="h-11 w-11 object-contain" className="h-11 w-11 object-contain"
/> />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<p className="text-lg line-clamp-1"> <p className="text-lg line-clamp-1">
{script.name} {getDisplayValueFromType(script.type)} {script.name}
{" "}
{getDisplayValueFromType(script.type)}
</p> </p>
<p className="text-sm text-muted-foreground flex items-center gap-1"> <p className="text-sm text-muted-foreground flex items-center gap-1">
<CalendarPlus className="h-4 w-4" /> <CalendarPlus className="h-4 w-4" />
@@ -147,7 +149,7 @@ export function LatestScripts({
export function MostViewedScripts({ items }: { items: Category[] }) { export function MostViewedScripts({ items }: { items: Category[] }) {
const mostViewedScripts = items.reduce((acc: Script[], category) => { const mostViewedScripts = items.reduce((acc: Script[], category) => {
const foundScripts = category.scripts.filter((script) => mostPopularScripts.includes(script.slug)); const foundScripts = category.scripts.filter(script => mostPopularScripts.includes(script.slug));
return acc.concat(foundScripts); return acc.concat(foundScripts);
}, []); }, []);
@@ -159,7 +161,7 @@ export function MostViewedScripts({ items }: { items: Category[] }) {
</> </>
)} )}
<div className="min-w flex w-full flex-row flex-wrap gap-4"> <div className="min-w flex w-full flex-row flex-wrap gap-4">
{mostViewedScripts.map((script) => ( {mostViewedScripts.map(script => (
<Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30"> <Card key={script.slug} className="min-w-[250px] flex-1 flex-grow bg-accent/30">
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-3"> <CardTitle className="flex items-center gap-3">
@@ -170,13 +172,15 @@ export function MostViewedScripts({ items }: { items: Category[] }) {
height={64} height={64}
width={64} width={64}
alt="" alt=""
onError={(e) => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)} onError={e => ((e.currentTarget as HTMLImageElement).src = `/${basePath}/logo.png`)}
className="h-11 w-11 object-contain" className="h-11 w-11 object-contain"
/> />
</div> </div>
<div className="flex flex-col"> <div className="flex flex-col">
<p className="line-clamp-1 text-lg"> <p className="line-clamp-1 text-lg">
{script.name} {getDisplayValueFromType(script.type)} {script.name}
{" "}
{getDisplayValueFromType(script.type)}
</p> </p>
<p className="flex items-center gap-1 text-sm text-muted-foreground"> <p className="flex items-center gap-1 text-sm text-muted-foreground">
<CalendarPlus className="h-4 w-4" /> <CalendarPlus className="h-4 w-4" />

View File

@@ -14,7 +14,6 @@ import { basePath } from "@/config/site-config";
import { extractDate } from "@/lib/time"; import { extractDate } from "@/lib/time";
import DisableDescription from "./script-items/disable-description"; import DisableDescription from "./script-items/disable-description";
import { formattedBadge } from "@/components/command-menu";
import { getDisplayValueFromType } from "./script-info-blocks"; import { getDisplayValueFromType } from "./script-info-blocks";
import DefaultPassword from "./script-items/default-password"; import DefaultPassword from "./script-items/default-password";
import InstallCommand from "./script-items/install-command"; import InstallCommand from "./script-items/install-command";
@@ -32,7 +31,7 @@ type ScriptItemProps = {
function ScriptHeader({ item }: { item: Script }) { function ScriptHeader({ item }: { item: Script }) {
const defaultInstallMethod = item.install_methods?.[0]; const defaultInstallMethod = item.install_methods?.[0];
const os = defaultInstallMethod?.resources?.os || (item.type === "addon" ? "Existing LXC or Proxmox Node" : "Proxmox Node"); const os = defaultInstallMethod?.resources?.os || "Proxmox Node";
const version = defaultInstallMethod?.resources?.version || ""; const version = defaultInstallMethod?.resources?.version || "";
return ( return (
@@ -56,7 +55,9 @@ function ScriptHeader({ item }: { item: Script }) {
<h1 className="text-2xl font-semibold tracking-tight flex items-center gap-2"> <h1 className="text-2xl font-semibold tracking-tight flex items-center gap-2">
{item.name} {item.name}
<VersionInfo item={item} /> <VersionInfo item={item} />
{formattedBadge(item.type)} <span className="inline-flex items-center rounded-md bg-accent/30 px-2 py-1 text-sm">
{getDisplayValueFromType(item.type)}
</span>
</h1> </h1>
<div className="mt-1 flex items-center gap-3 text-sm text-muted-foreground"> <div className="mt-1 flex items-center gap-3 text-sm text-muted-foreground">
<span> <span>

View File

@@ -36,24 +36,17 @@ const TooltipBadge: React.FC<TooltipProps> = ({ variant, label, content }) => (
export default function Tooltips({ item }: { item: Script }) { export default function Tooltips({ item }: { item: Script }) {
return ( return (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{item.privileged && item.type !== "addon" && ( {item.privileged && (
<TooltipBadge variant="warning" label="Privileged" content="This script will be run in a privileged LXC" /> <TooltipBadge variant="warning" label="Privileged" content="This script will be run in a privileged LXC" />
)} )}
{item.updateable && item.type !== "pve" && item.type !== "addon" && ( {item.updateable && item.type !== "pve" && (
<TooltipBadge <TooltipBadge
variant="success" variant="success"
label="Updateable" label="Updateable"
content={`To Update ${item.name}, run the command below (or type update) in the LXC Console.`} content={`To Update ${item.name}, run the command below (or type update) in the LXC Console.`}
/> />
)} )}
{item.updateable && item.type === "addon" && ( {!item.updateable && item.type !== "pve" && <TooltipBadge variant="failure" label="Not Updateable" />}
<TooltipBadge
variant="success"
label="Updateable"
content={`Run update_${item.slug} to update or use the bash command inside the LXC.`}
/>
)}
{!item.updateable && item.type !== "pve" && item.type !== "addon" && <TooltipBadge variant="failure" label="Not Updateable" />}
</div> </div>
); );
} }

View File

@@ -32,11 +32,6 @@ function ScriptContent() {
.flat() .flat()
.find(script => script.slug === selectedScript); .find(script => script.slug === selectedScript);
setItem(script); setItem(script);
if (script) {
document.title = `${script.name} | Proxmox VE Helper-Scripts`;
}
} else {
document.title = "Proxmox VE Helper-Scripts";
} }
}, [selectedScript, links]); }, [selectedScript, links]);

View File

@@ -1,7 +1,6 @@
import { ArrowRightIcon, Sparkles } from "lucide-react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { ArrowRightIcon, Sparkles } from "lucide-react";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link";
import React from "react"; import React from "react";
import type { Category, Script } from "@/lib/types"; import type { Category, Script } from "@/lib/types";
@@ -22,6 +21,35 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/t
import { DialogTitle } from "./ui/dialog"; import { DialogTitle } from "./ui/dialog";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
import { Badge } from "./ui/badge"; import { Badge } from "./ui/badge";
import Link from "next/link";
export 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) {
@@ -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,49 +248,46 @@ 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 ? (
? ( "Searching..."
"Searching..." ) : (
) <div className="flex flex-col items-center justify-center py-6 text-center">
: ( <p className="text-sm text-muted-foreground">No scripts match your search.</p>
<div className="flex flex-col items-center justify-center py-6 text-center"> <div className="mt-4">
<p className="text-sm text-muted-foreground">No scripts match your search.</p> <p className="text-xs text-muted-foreground mb-2">Want to add a new script?</p>
<div className="mt-4"> <Button variant="outline" size="sm" asChild>
<p className="text-xs text-muted-foreground mb-2">Want to add a new script?</p> <Link
<Button variant="outline" size="sm" asChild> href={`https://github.com/community-scripts/${basePath}/tree/main/docs/contribution/GUIDE.md`}
<Link target="_blank"
href={`https://github.com/community-scripts/${basePath}/tree/main/docs/contribution/GUIDE.md`} rel="noopener noreferrer"
target="_blank" >
rel="noopener noreferrer" Documentation <ArrowRightIcon className="ml-2 h-4 w-4" />
> </Link>
Documentation </Button>
{" "} </div>
<ArrowRightIcon className="ml-2 h-4 w-4" /> </div>
</Link> )}
</Button>
</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 || ""}`}
@@ -272,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>
</> </>

View File

@@ -0,0 +1,75 @@
#!/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://komo.do/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apk add --no-cache ca-certificates openssl
msg_ok "Installed Dependencies"
msg_info "Setup Docker Repository"
$STD apk add --no-cache docker docker-cli docker-compose openrc
msg_ok "Setup Docker Repository"
msg_info "Enabling Docker Service"
$STD rc-update add docker boot
$STD service docker start
msg_ok "Enabled Docker Service"
echo "${TAB3}Choose the database for Komodo installation:"
echo "${TAB3}1) MongoDB (recommended)"
echo "${TAB3}2) FerretDB"
read -rp "${TAB3}Enter your choice (default: 1): " DB_CHOICE
DB_CHOICE=${DB_CHOICE:-1}
case $DB_CHOICE in
1)
DB_COMPOSE_FILE="mongo.compose.yaml"
;;
2)
DB_COMPOSE_FILE="ferretdb.compose.yaml"
;;
*)
echo "Invalid choice. Defaulting to MongoDB."
DB_COMPOSE_FILE="mongo.compose.yaml"
;;
esac
mkdir -p /opt/komodo
cd /opt/komodo
curl -fsSL "https://raw.githubusercontent.com/moghtech/komodo/main/compose/$DB_COMPOSE_FILE" -o "$(basename "$DB_COMPOSE_FILE")"
msg_info "Setup Komodo Environment"
curl -fsSL "https://raw.githubusercontent.com/moghtech/komodo/main/compose/compose.env" -o "/opt/komodo/compose.env"
DB_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=')
PASSKEY=$(openssl rand -base64 24 | tr -d '/+=')
WEBHOOK_SECRET=$(openssl rand -base64 24 | tr -d '/+=')
JWT_SECRET=$(openssl rand -base64 24 | tr -d '/+=')
sed -i "s/^KOMODO_DB_USERNAME=.*/KOMODO_DB_USERNAME=komodo_admin/" /opt/komodo/compose.env
sed -i "s/^KOMODO_DB_PASSWORD=.*/KOMODO_DB_PASSWORD=${DB_PASSWORD}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_PASSKEY=.*/KOMODO_PASSKEY=${PASSKEY}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_WEBHOOK_SECRET=.*/KOMODO_WEBHOOK_SECRET=${WEBHOOK_SECRET}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_JWT_SECRET=.*/KOMODO_JWT_SECRET=${JWT_SECRET}/" /opt/komodo/compose.env
msg_ok "Setup Komodo Environment"
msg_info "Initialize Komodo"
$STD docker compose -p komodo -f "/opt/komodo/$DB_COMPOSE_FILE" --env-file /opt/komodo/compose.env up -d
msg_ok "Initialized Komodo"
motd_ssh
customize
msg_info "Cleaning up"
$STD apk cache clean
msg_ok "Cleaned"

View File

@@ -14,7 +14,7 @@ network_check
update_os update_os
read -r -p "${TAB3}Enter PostgreSQL version (15/16/17): " ver read -r -p "${TAB3}Enter PostgreSQL version (15/16/17): " ver
[[ $ver =~ ^(15|16|17)$ ]] || { echo "Invalid version"; exit 64; } [[ $ver =~ ^(15|16|17)$ ]] || { echo "Invalid version"; exit 1; }
msg_info "Installing PostgreSQL ${ver}" msg_info "Installing PostgreSQL ${ver}"
$STD apk add --no-cache postgresql${ver} postgresql${ver}-contrib postgresql${ver}-openrc sudo $STD apk add --no-cache postgresql${ver} postgresql${ver}-contrib postgresql${ver}-openrc sudo

View File

@@ -13,17 +13,17 @@ setting_up_container
network_check network_check
update_os update_os
RELEASE=$(curl -s https://api.github.com/repos/lejianwen/rustdesk-server/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }') RELEASE=$(curl -s https://api.github.com/repos/rustdesk/rustdesk-server/releases/latest | grep "tag_name" | awk '{print substr($2, 2, length($2)-3) }')
msg_info "Installing RustDesk Server v${RELEASE}" msg_info "Installing RustDesk Server v${RELEASE}"
temp_file1=$(mktemp) temp_file1=$(mktemp)
curl -fsSL "https://github.com/lejianwen/rustdesk-server/releases/download/${RELEASE}/rustdesk-server-linux-amd64.zip" -o "$temp_file1" curl -fsSL "https://github.com/rustdesk/rustdesk-server/releases/download/${RELEASE}/rustdesk-server-linux-amd64.zip" -o "$temp_file1"
$STD unzip "$temp_file1" $STD unzip "$temp_file1"
mv amd64 /opt/rustdesk-server mv amd64 /opt/rustdesk-server
mkdir -p /root/.config/rustdesk mkdir -p /root/.config/rustdesk
cd /opt/rustdesk-server cd /opt/rustdesk-server
./rustdesk-utils genkeypair >/tmp/rustdesk_keys.txt ./rustdesk-utils genkeypair > /tmp/rustdesk_keys.txt
grep "Public Key" /tmp/rustdesk_keys.txt | awk '{print $3}' >/root/.config/rustdesk/id_ed25519.pub grep "Public Key" /tmp/rustdesk_keys.txt | awk '{print $3}' > /root/.config/rustdesk/id_ed25519.pub
grep "Secret Key" /tmp/rustdesk_keys.txt | awk '{print $3}' >/root/.config/rustdesk/id_ed25519 grep "Secret Key" /tmp/rustdesk_keys.txt | awk '{print $3}' > /root/.config/rustdesk/id_ed25519
chmod 600 /root/.config/rustdesk/id_ed25519 chmod 600 /root/.config/rustdesk/id_ed25519
chmod 644 /root/.config/rustdesk/id_ed25519.pub chmod 644 /root/.config/rustdesk/id_ed25519.pub
rm /tmp/rustdesk_keys.txt rm /tmp/rustdesk_keys.txt

View File

@@ -36,9 +36,9 @@ msg_ok "Installed Tinyauth"
read -r -p "${TAB3}Enter your Tinyauth subdomain (e.g. https://tinyauth.example.com): " app_url read -r -p "${TAB3}Enter your Tinyauth subdomain (e.g. https://tinyauth.example.com): " app_url
cat <<EOF >/opt/tinyauth/.env cat <<EOF >/opt/tinyauth/.env
TINYAUTH_DATABASE_PATH=/opt/tinyauth/database.db DATABASE_PATH=/opt/tinyauth/database.db
TINYAUTH_AUTH_USERS='${USER}' USERS='${USER}'
TINYAUTH_APPURL=${app_url} APP_URL=${app_url}
EOF EOF
msg_info "Creating Service" msg_info "Creating Service"

View File

@@ -25,7 +25,7 @@ case $version in
;; ;;
*) *)
msg_error "Invalid JDK version selected. Please enter 8, 11, 17 or 21." msg_error "Invalid JDK version selected. Please enter 8, 11, 17 or 21."
exit 64 exit 1
;; ;;
esac esac
;; ;;
@@ -39,7 +39,7 @@ case $version in
;; ;;
*) *)
msg_error "Invalid JDK version selected. Please enter 11, 17 or 21." msg_error "Invalid JDK version selected. Please enter 11, 17 or 21."
exit 64 exit 1
;; ;;
esac esac
;; ;;
@@ -53,13 +53,13 @@ case $version in
;; ;;
*) *)
msg_error "Invalid JDK version selected. Please enter 17 or 21." msg_error "Invalid JDK version selected. Please enter 17 or 21."
exit 64 exit 1
;; ;;
esac esac
;; ;;
*) *)
msg_error "Invalid Tomcat version selected. Please enter 9, 10.1 or 11." msg_error "Invalid Tomcat version selected. Please enter 9, 10.1 or 11."
exit 64 exit 1
;; ;;
esac esac

View File

@@ -19,12 +19,8 @@ fetch_and_deploy_gh_release "bentopdf" "alam00000/bentopdf" "tarball" "latest" "
msg_info "Setup BentoPDF" msg_info "Setup BentoPDF"
cd /opt/bentopdf cd /opt/bentopdf
$STD npm ci --no-audit --no-fund $STD npm ci --no-audit --no-fund
$STD npm install http-server -g
cp ./.env.example ./.env.production
export NODE_OPTIONS="--max-old-space-size=3072"
export SIMPLE_MODE=true export SIMPLE_MODE=true
export VITE_USE_CDN=true $STD npm run build -- --mode production
$STD npm run build:all
msg_ok "Setup BentoPDF" msg_ok "Setup BentoPDF"
msg_info "Creating Service" msg_info "Creating Service"
@@ -35,8 +31,8 @@ After=network.target
[Service] [Service]
Type=simple Type=simple
WorkingDirectory=/opt/bentopdf/dist WorkingDirectory=/opt/bentopdf
ExecStart=/usr/bin/npx http-server -g -b -d false -r --no-dotfiles ExecStart=/usr/bin/npx serve dist -p 8080
Restart=always Restart=always
RestartSec=10 RestartSec=10

View File

@@ -59,7 +59,7 @@ mkdir -p /opt/booklore/dist
JAR_PATH=$(find /opt/booklore/booklore-api/build/libs -maxdepth 1 -type f -name "booklore-api-*.jar" ! -name "*plain*" | head -n1) JAR_PATH=$(find /opt/booklore/booklore-api/build/libs -maxdepth 1 -type f -name "booklore-api-*.jar" ! -name "*plain*" | head -n1)
if [[ -z "$JAR_PATH" ]]; then if [[ -z "$JAR_PATH" ]]; then
msg_error "Backend JAR not found" msg_error "Backend JAR not found"
exit 153 exit 1
fi fi
cp "$JAR_PATH" /opt/booklore/dist/app.jar cp "$JAR_PATH" /opt/booklore/dist/app.jar
msg_ok "Built Backend" msg_ok "Built Backend"

View File

@@ -0,0 +1,39 @@
#!/bin/bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://coolify.io/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y \
git \
openssl
msg_ok "Installed Dependencies"
msg_warn "WARNING: This script will run an external installer from a third-party source (https://coolify.io/)."
msg_warn "The following code is NOT maintained or audited by our repository."
msg_warn "If you have any doubts or concerns, please review the installer code before proceeding:"
msg_custom "${TAB3}${GATEWAY}${BGN}${CL}" "\e[1;34m" "→ https://cdn.coollabs.io/coolify/install.sh"
echo
read -r -p "${TAB3}Do you want to continue? [y/N]: " CONFIRM
if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
msg_error "Aborted by user. No changes have been made."
exit 10
fi
msg_info "Installing Coolify (Patience - this installs Docker and pulls containers)"
$STD bash <(curl -fsSL https://cdn.coollabs.io/coolify/install.sh)
msg_ok "Installed Coolify"
motd_ssh
customize
cleanup_lxc

View File

@@ -13,10 +13,6 @@ setting_up_container
network_check network_check
update_os update_os
msg_info "Installing Dependencies"
$STD apt install -y build-essential
msg_ok "Installed Dependencies"
NODE_VERSION="24" setup_nodejs NODE_VERSION="24" setup_nodejs
msg_info "Setup Cross-Seed" msg_info "Setup Cross-Seed"

View File

@@ -33,7 +33,7 @@ done
# Install MongoDB Database Tools via direct .deb (no APT repo for Debian 13) # Install MongoDB Database Tools via direct .deb (no APT repo for Debian 13)
[[ "$(get_os_info id)" == "ubuntu" ]] && MONGO_DIST="ubuntu2204" || MONGO_DIST="debian12" [[ "$(get_os_info id)" == "ubuntu" ]] && MONGO_DIST="ubuntu2204" || MONGO_DIST="debian12"
MONGO_VERSION=$(get_latest_gh_tag "mongodb/mongo-tools" "100." || echo "100.14.1") MONGO_VERSION=$(get_latest_gh_tag "mongodb/mongo-tools" "100." || echo "100.14.1")
fetch_and_deploy_from_url "https://fastdl.mongodb.org/tools/db/mongodb-database-tools-${MONGO_DIST}-x86_64-${MONGO_VERSION}.deb" "" fetch_and_deploy_from_url "https://fastdl.mongodb.org/tools/db/mongodb-database-tools-${MONGO_DIST}-x86_64-${MONGO_VERSION}.deb"
mkdir -p /usr/local/mongodb-database-tools/bin mkdir -p /usr/local/mongodb-database-tools/bin
[[ -f /usr/bin/mongodump ]] && ln -sf /usr/bin/mongodump /usr/local/mongodb-database-tools/bin/mongodump [[ -f /usr/bin/mongodump ]] && ln -sf /usr/bin/mongodump /usr/local/mongodb-database-tools/bin/mongodump
[[ -f /usr/bin/mongorestore ]] && ln -sf /usr/bin/mongorestore /usr/local/mongodb-database-tools/bin/mongorestore [[ -f /usr/bin/mongorestore ]] && ln -sf /usr/bin/mongorestore /usr/local/mongodb-database-tools/bin/mongorestore

View File

@@ -1,37 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 mitchscobell
# Author: mitchscobell
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://ddclient.net/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing ddclient"
DEBIAN_FRONTEND=noninteractive $STD apt -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install -y ddclient
msg_ok "Installed ddclient"
msg_info "Creating ddclient service"
cat << EOF >/etc/ddclient.conf
protocol=namecheap
use=web, web=dynamicdns.park-your-domain.com/getip
protocol=namecheap
use=web, web=dynamicdns.park-your-domain.com/getip
server=dynamicdns.park-your-domain.com
login=yourdomain.com
password='your-ddns-password'
@,www
EOF
chmod 600 /etc/ddclient.conf
systemctl enable -q --now ddclient
msg_ok "Created ddclient service"
motd_ssh
customize
cleanup_lxc

View File

@@ -86,7 +86,7 @@ EOF
msg_ok "Docker TCP socket available on $socket" msg_ok "Docker TCP socket available on $socket"
else else
msg_error "Docker failed to restart. Check journalctl -xeu docker.service" msg_error "Docker failed to restart. Check journalctl -xeu docker.service"
exit 150 exit 1
fi fi
fi fi

64
install/dockge-install.sh Normal file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 tteck
# Author: tteck (tteckster)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://dockge.kuma.pet/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
DOCKER_LATEST_VERSION=$(get_latest_github_release "moby/moby")
msg_info "Installing Docker $DOCKER_LATEST_VERSION (with Compose, Buildx)"
DOCKER_CONFIG_PATH='/etc/docker/daemon.json'
mkdir -p $(dirname $DOCKER_CONFIG_PATH)
echo -e '{\n "log-driver": "journald"\n}' >/etc/docker/daemon.json
$STD sh <(curl -fsSL https://get.docker.com)
msg_ok "Installed Docker $DOCKER_LATEST_VERSION"
msg_info "Installing Dockge"
mkdir -p /opt/{dockge,stacks}
curl -fsSL "https://raw.githubusercontent.com/louislam/dockge/master/compose.yaml" -o "/opt/dockge/compose.yaml"
cd /opt/dockge
$STD docker compose up -d
msg_ok "Installed Dockge"
read -r -p "${TAB3}Would you like to add Immich? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
msg_info "Adding Immich compose.yaml"
mkdir -p /opt/stacks/immich
curl -fsSL "https://github.com/immich-app/immich/releases/latest/download/docker-compose.yml" -o "/opt/stacks/immich/compose.yaml"
curl -fsSL "https://github.com/immich-app/immich/releases/latest/download/example.env" -o "/opt/stacks/immich/.env"
msg_ok "Added Immich compose.yaml"
fi
read -r -p "${TAB3}Would you like to add Home Assistant? <y/N> " prompt
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
msg_info "Adding Home Assistant compose.yaml"
mkdir -p /opt/stacks/homeassistant
cat <<EOF >/opt/stacks/homeassistant/compose.yaml
version: "3"
services:
homeassistant:
container_name: homeassistant
image: ghcr.io/home-assistant/home-assistant:stable
volumes:
- ./config:/config
- /etc/localtime:/etc/localtime:ro
- /run/dbus:/run/dbus:ro
restart: unless-stopped
privileged: true
network_mode: host
EOF
msg_ok "Added Home Assistant compose.yaml"
fi
motd_ssh
customize
cleanup_lxc

View File

@@ -26,17 +26,6 @@ fetch_and_deploy_gh_release "docmost" "docmost/docmost" "tarball"
msg_info "Configuring Docmost (Patience)" msg_info "Configuring Docmost (Patience)"
cd /opt/docmost cd /opt/docmost
# Fix: Docmost EE (audit logs etc.) lives in a git submodule that is NOT
# included in GitHub tarballs. The community NoopAuditService exists but
# is only exported by CoreModule child modules such as UserModule cannot
# resolve it. Making CoreModule @Global() exposes the token app-wide.
if [[ ! -f /opt/docmost/apps/server/src/ee/ee.module.ts ]] \
&& ! grep -q '@Global()' /opt/docmost/apps/server/src/core/core.module.ts 2>/dev/null; then
sed -i '/^ Module,$/a\ Global,' /opt/docmost/apps/server/src/core/core.module.ts
sed -i '/^@Module({$/i @Global()' /opt/docmost/apps/server/src/core/core.module.ts
fi
mv .env.example .env mv .env.example .env
mkdir data mkdir data
sed -i -e "s|APP_SECRET=.*|APP_SECRET=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | cut -c1-32)|" \ sed -i -e "s|APP_SECRET=.*|APP_SECRET=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | cut -c1-32)|" \

View File

@@ -0,0 +1,40 @@
#!/bin/bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://dokploy.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 \
git \
openssl \
redis
msg_ok "Installed Dependencies"
msg_warn "WARNING: This script will run an external installer from a third-party source (https://dokploy.com/)."
msg_warn "The following code is NOT maintained or audited by our repository."
msg_warn "If you have any doubts or concerns, please review the installer code before proceeding:"
msg_custom "${TAB3}${GATEWAY}${BGN}${CL}" "\e[1;34m" "→ https://dokploy.com/install.sh"
echo
read -r -p "${TAB3}Do you want to continue? [y/N]: " CONFIRM
if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
msg_error "Aborted by user. No changes have been made."
exit 10
fi
msg_info "Installing Dokploy (Patience - this installs Docker and pulls containers)"
$STD bash <(curl -sSL https://dokploy.com/install.sh)
msg_ok "Installed Dokploy"
motd_ssh
customize
cleanup_lxc

View File

@@ -21,7 +21,7 @@ msg_info "Fetching latest EMQX Enterprise version"
LATEST_VERSION=$(curl -fsSL https://www.emqx.com/en/downloads/enterprise | grep -oP '/en/downloads/enterprise/v\K[0-9]+\.[0-9]+\.[0-9]+' | sort -V | tail -n1) LATEST_VERSION=$(curl -fsSL https://www.emqx.com/en/downloads/enterprise | grep -oP '/en/downloads/enterprise/v\K[0-9]+\.[0-9]+\.[0-9]+' | sort -V | tail -n1)
if [[ -z "$LATEST_VERSION" ]]; then if [[ -z "$LATEST_VERSION" ]]; then
msg_error "Failed to determine latest EMQX version" msg_error "Failed to determine latest EMQX version"
exit 250 exit 1
fi fi
msg_ok "Latest version: v$LATEST_VERSION" msg_ok "Latest version: v$LATEST_VERSION"

View File

@@ -14,14 +14,12 @@ network_check
update_os update_os
msg_info "Installing Dependencies" msg_info "Installing Dependencies"
$STD apt install -y \ $STD apt install -y zip
build-essential \
zip
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PG_VERSION="17" setup_postgresql PG_VERSION="17" setup_postgresql
PG_DB_NAME="fluiddb" PG_DB_USER="fluiduser" setup_postgresql_db PG_DB_NAME="fluiddb" PG_DB_USER="fluiduser" setup_postgresql_db
NODE_VERSION="24" setup_nodejs NODE_VERSION="20" setup_nodejs
fetch_and_deploy_gh_release "fluid-calendar" "dotnetfactory/fluid-calendar" "tarball" fetch_and_deploy_gh_release "fluid-calendar" "dotnetfactory/fluid-calendar" "tarball"
msg_info "Configuring fluid-calendar" msg_info "Configuring fluid-calendar"

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG # Copyright (c) 2021-2026 community-scripts ORG
# Authors: MickLesk (CanbiZ) | Co-Authors: remz1337 # Authors: MickLesk (CanbiZ)
# Co-Authors: remz1337
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE # License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://frigate.video/ | Github: https://github.com/blakeblackshear/frigate # Source: https://frigate.video/ | Github: https://github.com/blakeblackshear/frigate
@@ -16,7 +17,7 @@ update_os
source /etc/os-release source /etc/os-release
if [[ "$VERSION_ID" != "12" ]]; then if [[ "$VERSION_ID" != "12" ]]; then
msg_error "Frigate requires Debian 12 (Bookworm) due to Python 3.11 dependencies" msg_error "Frigate requires Debian 12 (Bookworm) due to Python 3.11 dependencies"
exit 238 exit 1
fi fi
msg_info "Converting APT sources to DEB822 format" msg_info "Converting APT sources to DEB822 format"
@@ -84,7 +85,6 @@ $STD apt install -y \
tclsh \ tclsh \
libopenblas-dev \ libopenblas-dev \
liblapack-dev \ liblapack-dev \
libgomp1 \
make \ make \
moreutils moreutils
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
@@ -101,16 +101,9 @@ export NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
export TOKENIZERS_PARALLELISM=true export TOKENIZERS_PARALLELISM=true
export TRANSFORMERS_NO_ADVISORY_WARNINGS=1 export TRANSFORMERS_NO_ADVISORY_WARNINGS=1
export OPENCV_FFMPEG_LOGLEVEL=8 export OPENCV_FFMPEG_LOGLEVEL=8
export PYTHONWARNINGS="ignore:::numpy.core.getlimits"
export HAILORT_LOGGER_PATH=NONE export HAILORT_LOGGER_PATH=NONE
export TF_CPP_MIN_LOG_LEVEL=3
export TF_CPP_MIN_VLOG_LEVEL=3
export TF_ENABLE_ONEDNN_OPTS=0
export AUTOGRAPH_VERBOSITY=0
export GLOG_minloglevel=3
export GLOG_logtostderr=0
fetch_and_deploy_gh_release "frigate" "blakeblackshear/frigate" "tarball" "v0.17.0" "/opt/frigate" fetch_and_deploy_gh_release "frigate" "blakeblackshear/frigate" "tarball" "v0.16.4" "/opt/frigate"
msg_info "Building Nginx" msg_info "Building Nginx"
$STD bash /opt/frigate/docker/main/build_nginx.sh $STD bash /opt/frigate/docker/main/build_nginx.sh
@@ -145,19 +138,13 @@ install -c -m 644 libusb-1.0.pc /usr/local/lib/pkgconfig
ldconfig ldconfig
msg_ok "Built libUSB" msg_ok "Built libUSB"
msg_info "Bootstrapping pip"
wget -q https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py
sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' /tmp/get-pip.py
$STD python3 /tmp/get-pip.py "pip"
rm -f /tmp/get-pip.py
msg_ok "Bootstrapped pip"
msg_info "Installing Python Dependencies" msg_info "Installing Python Dependencies"
$STD pip3 install -r /opt/frigate/docker/main/requirements.txt $STD pip3 install -r /opt/frigate/docker/main/requirements.txt
msg_ok "Installed Python Dependencies" msg_ok "Installed Python Dependencies"
msg_info "Building Python Wheels (Patience)" msg_info "Building Python Wheels (Patience)"
mkdir -p /wheels mkdir -p /wheels
sed -i 's|^SQLITE3_VERSION=.*|SQLITE3_VERSION="version-3.46.0"|g' /opt/frigate/docker/main/build_pysqlite3.sh
$STD bash /opt/frigate/docker/main/build_pysqlite3.sh $STD bash /opt/frigate/docker/main/build_pysqlite3.sh
for i in {1..3}; do for i in {1..3}; do
$STD pip3 wheel --wheel-dir=/wheels -r /opt/frigate/docker/main/requirements-wheels.txt --default-timeout=300 --retries=3 && break $STD pip3 wheel --wheel-dir=/wheels -r /opt/frigate/docker/main/requirements-wheels.txt --default-timeout=300 --retries=3 && break
@@ -165,7 +152,7 @@ for i in {1..3}; do
done done
msg_ok "Built Python Wheels" msg_ok "Built Python Wheels"
NODE_VERSION="20" setup_nodejs NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs
msg_info "Downloading Inference Models" msg_info "Downloading Inference Models"
mkdir -p /models /openvino-model mkdir -p /models /openvino-model
@@ -196,10 +183,6 @@ $STD pip3 install -U /wheels/*.whl
ldconfig ldconfig
msg_ok "Installed HailoRT Runtime" msg_ok "Installed HailoRT Runtime"
msg_info "Installing MemryX Runtime"
$STD bash /opt/frigate/docker/main/install_memryx.sh
msg_ok "Installed MemryX Runtime"
msg_info "Installing OpenVino" msg_info "Installing OpenVino"
$STD pip3 install -r /opt/frigate/docker/main/requirements-ov.txt $STD pip3 install -r /opt/frigate/docker/main/requirements-ov.txt
msg_ok "Installed OpenVino" msg_ok "Installed OpenVino"
@@ -226,8 +209,6 @@ $STD make version
cd /opt/frigate/web cd /opt/frigate/web
$STD npm install $STD npm install
$STD npm run build $STD npm run build
mv /opt/frigate/web/dist/BASE_PATH/monacoeditorwork/* /opt/frigate/web/dist/assets/
rm -rf /opt/frigate/web/dist/BASE_PATH
cp -r /opt/frigate/web/dist/* /opt/frigate/web/ cp -r /opt/frigate/web/dist/* /opt/frigate/web/
sed -i '/^s6-svc -O \.$/s/^/#/' /opt/frigate/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/run sed -i '/^s6-svc -O \.$/s/^/#/' /opt/frigate/docker/main/rootfs/etc/s6-overlay/s6-rc.d/frigate/run
msg_ok "Built Frigate Application" msg_ok "Built Frigate Application"
@@ -243,19 +224,6 @@ echo "tmpfs /tmp/cache tmpfs defaults 0 0" >>/etc/fstab
cat <<EOF >/etc/frigate.env cat <<EOF >/etc/frigate.env
DEFAULT_FFMPEG_VERSION="7.0" DEFAULT_FFMPEG_VERSION="7.0"
INCLUDED_FFMPEG_VERSIONS="7.0:5.0" INCLUDED_FFMPEG_VERSIONS="7.0:5.0"
NVIDIA_VISIBLE_DEVICES=all
NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
TOKENIZERS_PARALLELISM=true
TRANSFORMERS_NO_ADVISORY_WARNINGS=1
OPENCV_FFMPEG_LOGLEVEL=8
PYTHONWARNINGS="ignore:::numpy.core.getlimits"
HAILORT_LOGGER_PATH=NONE
TF_CPP_MIN_LOG_LEVEL=3
TF_CPP_MIN_VLOG_LEVEL=3
TF_ENABLE_ONEDNN_OPTS=0
AUTOGRAPH_VERBOSITY=0
GLOG_minloglevel=3
GLOG_logtostderr=0
EOF EOF
cat <<EOF >/config/config.yml cat <<EOF >/config/config.yml
@@ -269,6 +237,7 @@ cameras:
input_args: -re -stream_loop -1 -fflags +genpts input_args: -re -stream_loop -1 -fflags +genpts
roles: roles:
- detect - detect
- rtmp
detect: detect:
height: 1080 height: 1080
width: 1920 width: 1920
@@ -286,7 +255,6 @@ ffmpeg:
detectors: detectors:
detector01: detector01:
type: openvino type: openvino
device: AUTO
model: model:
width: 300 width: 300
height: 300 height: 300

View File

@@ -18,8 +18,7 @@ $STD apt install -y \
build-essential \ build-essential \
openssl \ openssl \
sqlite3 \ sqlite3 \
unzip \ unzip
git
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
msg_info "Installing Bun" msg_info "Installing Bun"

View File

@@ -232,7 +232,7 @@ msg_ok "(2/5) Compiled libheif"
msg_info "(3/5) Compiling libraw" msg_info "(3/5) Compiling libraw"
SOURCE=${SOURCE_DIR}/libraw SOURCE=${SOURCE_DIR}/libraw
: "${LIBRAW_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libraw.json)}" : "${LIBRAW_REVISION:=$(jq -cr '.revision' $BASE_DIR/server/sources/libraw.json)}"
$STD git clone https://github.com/LibRaw/LibRaw.git "$SOURCE" $STD git clone https://github.com/libraw/libraw.git "$SOURCE"
cd "$SOURCE" cd "$SOURCE"
$STD git reset --hard "$LIBRAW_REVISION" $STD git reset --hard "$LIBRAW_REVISION"
$STD autoreconf --install $STD autoreconf --install

View File

@@ -31,7 +31,7 @@ fi
if [[ -z "$KASM_URL" ]] || [[ -z "$KASM_VERSION" ]]; then if [[ -z "$KASM_URL" ]] || [[ -z "$KASM_VERSION" ]]; then
msg_error "Unable to detect latest Kasm release URL." msg_error "Unable to detect latest Kasm release URL."
exit 250 exit 1
fi fi
msg_ok "Detected Kasm Workspaces version $KASM_VERSION" msg_ok "Detected Kasm Workspaces version $KASM_VERSION"

85
install/komodo-install.sh Normal file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://komo.do/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Setup Docker Repository"
setup_deb822_repo \
"docker" \
"https://download.docker.com/linux/$(get_os_info id)/gpg" \
"https://download.docker.com/linux/$(get_os_info id)" \
"$(get_os_info codename)" \
"stable" \
"$(dpkg --print-architecture)"
msg_ok "Setup Docker Repository"
msg_info "Installing Docker"
$STD apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
msg_ok "Installed Docker"
echo "${TAB3}Choose the database for Komodo installation:"
echo "${TAB3}1) MongoDB (recommended)"
echo "${TAB3}2) FerretDB"
read -rp "${TAB3}Enter your choice (default: 1): " DB_CHOICE
DB_CHOICE=${DB_CHOICE:-1}
case $DB_CHOICE in
1)
DB_COMPOSE_FILE="mongo.compose.yaml"
;;
2)
DB_COMPOSE_FILE="ferretdb.compose.yaml"
;;
*)
echo "Invalid choice. Defaulting to MongoDB."
DB_COMPOSE_FILE="mongo.compose.yaml"
;;
esac
mkdir -p /opt/komodo
cd /opt/komodo
curl -fsSL "https://raw.githubusercontent.com/moghtech/komodo/main/compose/$DB_COMPOSE_FILE" -o "/opt/komodo/$DB_COMPOSE_FILE"
msg_info "Setup Komodo Environment"
curl -fsSL "https://raw.githubusercontent.com/moghtech/komodo/main/compose/compose.env" -o "/opt/komodo/compose.env"
DB_PASSWORD=$(openssl rand -base64 16 | tr -d '/+=')
ADMIN_PASSWORD=$(openssl rand -base64 8 | tr -d '/+=')
PASSKEY=$(openssl rand -base64 24 | tr -d '/+=')
WEBHOOK_SECRET=$(openssl rand -base64 24 | tr -d '/+=')
JWT_SECRET=$(openssl rand -base64 24 | tr -d '/+=')
sed -i "s/^KOMODO_DB_USERNAME=.*/KOMODO_DB_USERNAME=komodo_admin/" /opt/komodo/compose.env
sed -i "s/^KOMODO_DB_PASSWORD=.*/KOMODO_DB_PASSWORD=${DB_PASSWORD}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_INIT_ADMIN_PASSWORD=changeme/KOMODO_INIT_ADMIN_PASSWORD=${ADMIN_PASSWORD}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_PASSKEY=.*/KOMODO_PASSKEY=${PASSKEY}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_WEBHOOK_SECRET=.*/KOMODO_WEBHOOK_SECRET=${WEBHOOK_SECRET}/" /opt/komodo/compose.env
sed -i "s/^KOMODO_JWT_SECRET=.*/KOMODO_JWT_SECRET=${JWT_SECRET}/" /opt/komodo/compose.env
{
echo "Komodo Credentials"
echo ""
echo "Admin User : admin"
echo "Admin Password: $ADMIN_PASSWORD"
} >>~/komodo.creds
msg_ok "Setup Komodo Environment"
msg_info "Initialize Komodo"
$STD docker compose -p komodo -f /opt/komodo/$DB_COMPOSE_FILE --env-file /opt/komodo/compose.env up -d
msg_ok "Initialized Komodo"
motd_ssh
customize
cleanup_lxc

View File

@@ -20,8 +20,24 @@ $STD apt install -y \
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PG_VERSION="17" setup_postgresql PG_VERSION="17" setup_postgresql
PG_DB_NAME="litellm_db" PG_DB_USER="litellm" setup_postgresql_db PYTHON_VERSION="3.13" setup_uv
PYTHON_VERSION="3.13" USE_UVX="YES" setup_uv
msg_info "Setting up PostgreSQL"
DB_NAME="litellm_db"
DB_USER="litellm"
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 $DB_NAME WITH OWNER $DB_USER ENCODING 'UTF8' TEMPLATE template0;"
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET client_encoding TO 'utf8';"
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET default_transaction_isolation TO 'read committed';"
$STD sudo -u postgres psql -c "ALTER ROLE $DB_USER SET timezone TO 'UTC';"
{
echo "${APPLICATION} Credentials"
echo "Database Name: $DB_NAME"
echo "Database User: $DB_USER"
echo "Database Password: $DB_PASS"
} >>~/litellm.creds
msg_ok "Set up PostgreSQL"
msg_info "Setting up Virtual Environment" msg_info "Setting up Virtual Environment"
mkdir -p /opt/litellm mkdir -p /opt/litellm
@@ -37,9 +53,10 @@ mkdir -p /opt
cat <<EOF >/opt/litellm/litellm.yaml cat <<EOF >/opt/litellm/litellm.yaml
general_settings: general_settings:
master_key: sk-1234 master_key: sk-1234
database_url: postgresql://$PG_DB_USER:$PG_DB_PASS@127.0.0.1:5432/$PG_DB_NAME database_url: postgresql://$DB_USER:$DB_PASS@127.0.0.1:5432/$DB_NAME
store_model_in_db: true store_model_in_db: true
EOF EOF
uv --directory=/opt/litellm run litellm --config /opt/litellm/litellm.yaml --use_prisma_db_push --skip_server_startup uv --directory=/opt/litellm run litellm --config /opt/litellm/litellm.yaml --use_prisma_db_push --skip_server_startup
msg_ok "Configured LiteLLM" msg_ok "Configured LiteLLM"
@@ -56,6 +73,7 @@ Restart=always
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
EOF EOF
systemctl enable -q --now litellm systemctl enable -q --now litellm
msg_ok "Created Service" msg_ok "Created Service"

View File

@@ -28,7 +28,7 @@ $STD apt install -y \
msg_ok "Installed Dependencies" msg_ok "Installed Dependencies"
PYTHON_VERSION="3.12" setup_uv PYTHON_VERSION="3.12" setup_uv
PG_VERSION="16" setup_postgresql POSTGRES_VERSION="16" setup_postgresql
NODE_MODULE="yarn" NODE_VERSION="24" setup_nodejs NODE_MODULE="yarn" NODE_VERSION="24" setup_nodejs
fetch_and_deploy_gh_release "mealie" "mealie-recipes/mealie" "tarball" "latest" "/opt/mealie" fetch_and_deploy_gh_release "mealie" "mealie-recipes/mealie" "tarball" "latest" "/opt/mealie"
PG_DB_NAME="mealie_db" PG_DB_USER="mealie_user" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db PG_DB_NAME="mealie_db" PG_DB_USER="mealie_user" PG_DB_GRANT_SUPERUSER="true" setup_postgresql_db

Some files were not shown because too many files have changed in this diff Show More