mirror of
https://github.com/community-scripts/ProxmoxVE.git
synced 2026-08-08 00:32:15 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d5e1e04ae | ||
|
|
71da6d96dc |
Generated
+2
-18
@@ -314,17 +314,12 @@ jobs:
|
||||
// ── Allow-lists (mirror the slash bot) ─────────────────────────────
|
||||
const ALLOWED_FIELDS = {
|
||||
name: 'string', description: 'string', logo: 'string', documentation: 'string',
|
||||
website: 'string', project_url: 'string', repository: 'string', config_path: 'string',
|
||||
website: 'string', project_url: 'string', github: 'string', config_path: 'string',
|
||||
tags: 'string', port: 'number', default_user: 'nullable_string', default_passwd: 'nullable_string',
|
||||
unprivileged: 'number', updateable: 'boolean', privileged: 'boolean',
|
||||
architectures: 'select_list', platforms: 'select_list',
|
||||
unprivileged: 'number', updateable: 'boolean', privileged: 'boolean', has_arm: 'boolean',
|
||||
is_dev: 'boolean', is_disabled: 'boolean', disable_message: 'string',
|
||||
is_deleted: 'boolean', deleted_message: 'string'
|
||||
};
|
||||
const SELECT_VALUES = {
|
||||
architectures: ['amd64', 'arm64'],
|
||||
platforms: ['pve', 'incus'],
|
||||
};
|
||||
const FIELD_TO_CT_VAR = { tags: 'var_tags', unprivileged: 'var_unprivileged' };
|
||||
const RESOURCE_KEYS = { cpu: 'number', ram: 'number', hdd: 'number', os: 'string', version: 'string' };
|
||||
const METHOD_KEYS = { config_path: 'string', script: 'string' };
|
||||
@@ -344,17 +339,6 @@ jobs:
|
||||
if (isNaN(n)) return { error: '`' + key + '` must be a number' };
|
||||
return { value: n };
|
||||
}
|
||||
if (type === 'select_list') {
|
||||
// architectures/platforms are multi-selects over a closed set,
|
||||
// so an unknown value is rejected rather than stored. The model
|
||||
// may hand back an array or a comma-separated string.
|
||||
const allowed = SELECT_VALUES[key] || [];
|
||||
const raw = Array.isArray(rawVal) ? rawVal : String(rawVal == null ? '' : rawVal).split(',');
|
||||
const values = raw.map(function (v) { return String(v).trim(); }).filter(Boolean);
|
||||
const bad = values.filter(function (v) { return allowed.indexOf(v) === -1; });
|
||||
if (bad.length > 0) return { error: '`' + key + '` accepts ' + allowed.join(', ') + ' — got: ' + bad.join(', ') };
|
||||
return { value: values };
|
||||
}
|
||||
if (type === 'nullable_string') return { value: rawVal === '' || rawVal == null ? null : String(rawVal) };
|
||||
return { value: String(rawVal) };
|
||||
}
|
||||
|
||||
Generated
+6
-25
@@ -323,10 +323,9 @@ jobs:
|
||||
'/pocketbase <slug> method remove <type>\n' +
|
||||
'```\n' +
|
||||
'Method fields: `cpu` `ram` `hdd` `os` `version` `config_path` `script`\n\n' +
|
||||
'**Editable fields:** `name` `description` `logo` `documentation` `website` `project_url` `repository` ' +
|
||||
'**Editable fields:** `name` `description` `logo` `documentation` `website` `project_url` `github` ' +
|
||||
'`config_path` `port` `default_user` `default_passwd` ' +
|
||||
'`updateable` `privileged` `is_dev` ' +
|
||||
'`architectures` (amd64,arm64) `platforms` (pve,incus) ' +
|
||||
'`updateable` `privileged` `has_arm` `is_dev` ' +
|
||||
'`is_disabled` `disable_message` `is_deleted` `deleted_message`';
|
||||
|
||||
if (!withoutCmd) {
|
||||
@@ -505,8 +504,7 @@ jobs:
|
||||
out.push('- **Port:** ' + (record.port != null ? '`' + record.port + '`' : '—'));
|
||||
out.push('- **Updateable:** ' + (record.updateable ? 'Yes' : 'No'));
|
||||
out.push('- **Privileged:** ' + (record.privileged ? 'Yes' : 'No'));
|
||||
out.push('- **Architectures:** ' + ((record.architectures || []).join(', ') || 'amd64'));
|
||||
out.push('- **Platforms:** ' + ((record.platforms || []).join(', ') || 'pve'));
|
||||
out.push('- **ARM:** ' + (record.has_arm ? 'Yes' : 'No'));
|
||||
if (record.is_dev) out.push('- **Dev:** Yes');
|
||||
if (record.is_disabled) out.push('- **Disabled:** Yes' + (record.disable_message ? ' — ' + record.disable_message : ''));
|
||||
if (record.is_deleted) out.push('- **Deleted:** Yes' + (record.deleted_message ? ' — ' + record.deleted_message : ''));
|
||||
@@ -840,7 +838,7 @@ jobs:
|
||||
const fieldName = setMatch[1].toLowerCase();
|
||||
const SET_ALLOWED = {
|
||||
name: 'string', description: 'string', logo: 'string',
|
||||
documentation: 'string', website: 'string', project_url: 'string', repository: 'string',
|
||||
documentation: 'string', website: 'string', project_url: 'string', github: 'string',
|
||||
config_path: 'string', disable_message: 'string', deleted_message: 'string'
|
||||
};
|
||||
if (!SET_ALLOWED[fieldName]) {
|
||||
@@ -890,7 +888,7 @@ jobs:
|
||||
documentation: 'string',
|
||||
website: 'string',
|
||||
project_url: 'string',
|
||||
repository: 'string',
|
||||
github: 'string',
|
||||
config_path: 'string',
|
||||
tags: 'string',
|
||||
port: 'number',
|
||||
@@ -899,8 +897,7 @@ jobs:
|
||||
unprivileged: 'number',
|
||||
updateable: 'boolean',
|
||||
privileged: 'boolean',
|
||||
architectures: 'select_list',
|
||||
platforms: 'select_list',
|
||||
has_arm: 'boolean',
|
||||
is_dev: 'boolean',
|
||||
is_disabled: 'boolean',
|
||||
disable_message: 'string',
|
||||
@@ -927,10 +924,6 @@ jobs:
|
||||
}
|
||||
|
||||
// Cast values to correct types
|
||||
const SELECT_VALUES = {
|
||||
architectures: ['amd64', 'arm64'],
|
||||
platforms: ['pve', 'incus'],
|
||||
};
|
||||
const payload = {};
|
||||
for (const [key, rawVal] of Object.entries(parsedFields)) {
|
||||
const type = ALLOWED_FIELDS[key];
|
||||
@@ -950,18 +943,6 @@ jobs:
|
||||
process.exit(0);
|
||||
}
|
||||
payload[key] = n;
|
||||
} else if (type === 'select_list') {
|
||||
// architectures/platforms are multi-selects over a closed set,
|
||||
// so an unknown value is rejected rather than stored.
|
||||
const allowed = SELECT_VALUES[key] || [];
|
||||
const values = rawVal.split(',').map(function (v) { return v.trim(); }).filter(Boolean);
|
||||
const bad = values.filter(function (v) { return allowed.indexOf(v) === -1; });
|
||||
if (bad.length > 0) {
|
||||
await addReaction('-1');
|
||||
await postComment('❌ **PocketBase Bot**: `' + key + '` accepts ' + allowed.join(', ') + ' — got: `' + bad.join(', ') + '`');
|
||||
process.exit(0);
|
||||
}
|
||||
payload[key] = values;
|
||||
} else if (type === 'nullable_string') {
|
||||
payload[key] = rawVal === '' ? null : rawVal;
|
||||
} else {
|
||||
|
||||
+1
-13
@@ -179,19 +179,7 @@ jobs:
|
||||
if (resolvedType) payload.type = resolvedType;
|
||||
var resolvedCats = (data.categories || []).map(function(n) { return categoryNameToPbId[categoryIdToName[n]]; }).filter(Boolean);
|
||||
if (resolvedCats.length) payload.categories = resolvedCats;
|
||||
// architectures replaces has_arm: a boolean could say "also ARM" but
|
||||
// not "ARM only" or "amd64 only". A record written before the field
|
||||
// existed is read through the old key so nothing silently drops.
|
||||
if (Array.isArray(data.architectures)) {
|
||||
payload.architectures = data.architectures.filter(function (a) { return a === 'amd64' || a === 'arm64'; });
|
||||
} else if (data.has_arm !== undefined) {
|
||||
payload.architectures = (data.has_arm === true || data.has_arm === 'true') ? ['amd64', 'arm64'] : ['amd64'];
|
||||
}
|
||||
if (Array.isArray(data.platforms)) {
|
||||
payload.platforms = data.platforms.filter(function (p) { return p === 'pve' || p === 'incus'; });
|
||||
}
|
||||
if (Array.isArray(data.app_vars)) payload.app_vars = data.app_vars;
|
||||
if (data.repository !== undefined) payload.repository = data.repository;
|
||||
if (data.has_arm !== undefined) payload.has_arm = data.has_arm === true || data.has_arm === 'true';
|
||||
if (data.version !== undefined) payload.version = data.version;
|
||||
if (data.changelog !== undefined) payload.changelog = data.changelog;
|
||||
if (data.screenshots !== undefined) payload.screenshots = data.screenshots;
|
||||
|
||||
+1
-53
@@ -518,68 +518,16 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
|
||||
|
||||
</details>
|
||||
|
||||
## 2026-08-07
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Docker: report container updates instead of prompting, stop auto-updating Portainer Agent, fix addon detection of legacy Portainer [@MickLesk](https://github.com/MickLesk) ([#16298](https://github.com/community-scripts/ProxmoxVE/pull/16298))
|
||||
- Immich: retry mise install on transient npm download failures [@MickLesk](https://github.com/MickLesk) ([#16301](https://github.com/community-scripts/ProxmoxVE/pull/16301))
|
||||
- changedetection: remove msttcorefonts to fix install hang [@austinpilz](https://github.com/austinpilz) ([#16319](https://github.com/community-scripts/ProxmoxVE/pull/16319))
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- core: extend new vars and pocketbase values [@MickLesk](https://github.com/MickLesk) ([#16313](https://github.com/community-scripts/ProxmoxVE/pull/16313))
|
||||
|
||||
## 2026-08-06
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- paperless: change update abort message (endless spinner) [@MickLesk](https://github.com/MickLesk) ([#16299](https://github.com/community-scripts/ProxmoxVE/pull/16299))
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- Vikunja: remove version pin, v2.5.0 fixes the systemd syscall filter crash [@MickLesk](https://github.com/MickLesk) ([#16300](https://github.com/community-scripts/ProxmoxVE/pull/16300))
|
||||
|
||||
### 💾 Core
|
||||
|
||||
- #### 🔧 Refactor
|
||||
|
||||
- build.func: filter templates by host architecture during search [@MickLesk](https://github.com/MickLesk) ([#16302](https://github.com/community-scripts/ProxmoxVE/pull/16302))
|
||||
|
||||
## 2026-08-05
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### ✨ New Features
|
||||
|
||||
- NextcloudPI: Bump to Debian Trixie & Tweak broken SSH [@MickLesk](https://github.com/MickLesk) ([#15957](https://github.com/community-scripts/ProxmoxVE/pull/15957))
|
||||
|
||||
### 🧰 Tools
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- fix(monitor-all): reduce polling CPU overhead [@jomplox](https://github.com/jomplox) ([#15907](https://github.com/community-scripts/ProxmoxVE/pull/15907))
|
||||
|
||||
## 2026-08-04
|
||||
|
||||
### 🆕 New Scripts
|
||||
|
||||
- Hister ([#16259](https://github.com/community-scripts/ProxmoxVE/pull/16259))
|
||||
- Obsidian-LiveSync ([#16233](https://github.com/community-scripts/ProxmoxVE/pull/16233))
|
||||
- Obsidian-LiveSync ([#16233](https://github.com/community-scripts/ProxmoxVE/pull/16233))
|
||||
|
||||
### 🚀 Updated Scripts
|
||||
|
||||
- #### 🐞 Bug Fixes
|
||||
|
||||
- Actual Budget: allow native module install scripts under npm 11 (Node24) [@MickLesk](https://github.com/MickLesk) ([#16277](https://github.com/community-scripts/ProxmoxVE/pull/16277))
|
||||
- Heimdall-Dashboard: run full composer install on update, force production env [@MickLesk](https://github.com/MickLesk) ([#16278](https://github.com/community-scripts/ProxmoxVE/pull/16278))
|
||||
- xyOps: rebuild xySat satellite during update [@MickLesk](https://github.com/MickLesk) ([#16279](https://github.com/community-scripts/ProxmoxVE/pull/16279))
|
||||
- HAOS: remove non-ASCII dash from CPU model dialog text [@MickLesk](https://github.com/MickLesk) ([#16276](https://github.com/community-scripts/ProxmoxVE/pull/16276))
|
||||
- fix: back up Termix db/data so the update stops destroying encryption keys [@LukeGus](https://github.com/LukeGus) ([#16275](https://github.com/community-scripts/ProxmoxVE/pull/16275))
|
||||
- passwordpusher: dynamically read Ruby version from .ruby-version file [@Copilot](https://github.com/Copilot) ([#16242](https://github.com/community-scripts/ProxmoxVE/pull/16242))
|
||||
- fix(salt): write version cache to ~/.salt, not /~.salt [@TowyTowy](https://github.com/TowyTowy) ([#16265](https://github.com/community-scripts/ProxmoxVE/pull/16265))
|
||||
- AFFiNE: fix version and build type reported by the app itself [@MickLesk](https://github.com/MickLesk) ([#16251](https://github.com/community-scripts/ProxmoxVE/pull/16251))
|
||||
|
||||
@@ -103,55 +103,6 @@ Key rules at a glance:
|
||||
- Quote all variables: `"$VAR"` not `$VAR`
|
||||
- Use lowercase variable names
|
||||
- Do not hardcode credentials or sensitive values
|
||||
- Never prompt without an escape hatch — see below
|
||||
|
||||
### Answering a prompt up front
|
||||
|
||||
An install script that only asks cannot be deployed unattended. Read the
|
||||
variable first and prompt only when it is unset:
|
||||
|
||||
```bash
|
||||
if [[ -z "${var_admin_user:-}" ]]; then
|
||||
read -r -p "${TAB3}Admin username: " var_admin_user
|
||||
fi
|
||||
var_admin_user="${var_admin_user:-admin}"
|
||||
```
|
||||
|
||||
Name them `var_<something>`, the same namespace the container variables use.
|
||||
`install/forgejo-runner-install.sh`, `install/pangolin-install.sh`, and `install/docker-install.sh` all
|
||||
follow this.
|
||||
|
||||
The variable also has to be exported from `ct/<app>.sh`, or it never reaches
|
||||
the container — `lxc-attach` carries the caller's environment, but only for
|
||||
what was actually exported:
|
||||
|
||||
```bash
|
||||
export var_admin_user="${var_admin_user:-}"
|
||||
```
|
||||
|
||||
Declare them on the script's PocketBase record in `app_vars` so the website's
|
||||
generator can offer them as fields:
|
||||
|
||||
```json
|
||||
"app_vars": [
|
||||
{
|
||||
"name": "var_admin_user",
|
||||
"label": "Admin Username",
|
||||
"type": "text",
|
||||
"default": "admin"
|
||||
},
|
||||
{
|
||||
"name": "var_admin_pass",
|
||||
"label": "Admin Password",
|
||||
"type": "password",
|
||||
"secret": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
`type` is one of `text`, `password`, `number`, `boolean` (`yes`/`no`) or
|
||||
`select` (with `options`). Mark anything credential-like `secret` — the
|
||||
generator keeps those out of shareable links and out of the on-screen summary.
|
||||
|
||||
Full standards and examples: **[community-scripts.org/docs/contribution](https://community-scripts.org/docs/contribution)**
|
||||
|
||||
|
||||
@@ -39,9 +39,7 @@ function update_script() {
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
msg_info "Updating Actual Budget to ${RELEASE}"
|
||||
$STD npm config set allow-scripts=bcrypt,better-sqlite3,argon2 --location=global
|
||||
$STD npm update -g @actual-app/sync-server
|
||||
$STD npm rebuild -g
|
||||
echo "${RELEASE}" >~/.actualbudget
|
||||
msg_ok "Updated Actual Budget to ${RELEASE}"
|
||||
|
||||
|
||||
@@ -42,6 +42,20 @@ function update_script() {
|
||||
echo -e "${TAB}${TAB}${GN}bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/portainer.sh)\"${CL}"
|
||||
fi
|
||||
|
||||
if docker ps -a --format '{{.Names}}' | grep -q '^portainer_agent$'; then
|
||||
msg_info "Updating Portainer Agent"
|
||||
$STD docker pull portainer/agent:latest
|
||||
$STD docker stop portainer_agent
|
||||
$STD docker rm portainer_agent
|
||||
$STD docker run -d \
|
||||
-p 9001:9001 \
|
||||
--name=portainer_agent \
|
||||
--restart=always \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
|
||||
portainer/agent
|
||||
msg_ok "Updated Portainer Agent"
|
||||
fi
|
||||
msg_ok "Updated successfully!"
|
||||
exit
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ var_nesting="${var_nesting:-1}"
|
||||
var_keyctl="${var_keyctl:-1}"
|
||||
|
||||
export var_forgejo_instance="${var_forgejo_instance:-}"
|
||||
export var_forgejo_runner_uuid="${var_forgejo_runner_uuid:-}"
|
||||
export var_forgejo_runner_token="${var_forgejo_runner_token:-}"
|
||||
export var_runner_labels="${var_runner_labels:-}"
|
||||
|
||||
@@ -65,10 +64,6 @@ if [[ -n "${mode:-}" ]]; then
|
||||
msg_error "var_forgejo_instance is required for unattended installs."
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "${var_forgejo_runner_uuid:-}" ]]; then
|
||||
msg_error "var_forgejo_runner_uuid is required for unattended installs."
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "${var_forgejo_runner_token:-}" ]]; then
|
||||
msg_error "var_forgejo_runner_token is required for unattended installs."
|
||||
exit 1
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
__ ___ __
|
||||
/ / / (_)____/ /____ _____
|
||||
/ /_/ / / ___/ __/ _ \/ ___/
|
||||
/ __ / (__ ) /_/ __/ /
|
||||
/_/ /_/_/____/\__/\___/_/
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
____ _
|
||||
/ _/___ _____ (_)____
|
||||
/ // __ `/ __ \/ / ___/
|
||||
_/ // /_/ / / / / (__ )
|
||||
/___/\__, /_/ /_/_/____/
|
||||
/____/
|
||||
@@ -46,11 +46,8 @@ function update_script() {
|
||||
|
||||
msg_info "Updating Heimdall-Dashboard"
|
||||
cd /opt/Heimdall
|
||||
sed -i 's/^APP_ENV=.*/APP_ENV=production/' .env
|
||||
rm -f bootstrap/cache/*.php
|
||||
export COMPOSER_ALLOW_SUPERUSER=1
|
||||
$STD composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
|
||||
$STD php artisan optimize:clear
|
||||
$STD composer dump-autoload
|
||||
msg_ok "Updated Heimdall-Dashboard"
|
||||
|
||||
msg_info "Restoring Data"
|
||||
|
||||
@@ -1,55 +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/asciimoo/hister
|
||||
|
||||
APP="Hister"
|
||||
var_tags="${var_tags:-search;browser-history;personal}"
|
||||
var_cpu="${var_cpu:-1}"
|
||||
var_ram="${var_ram:-1024}"
|
||||
var_disk="${var_disk:-20}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -f /usr/local/bin/hister ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "hister" "asciimoo/hister"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop hister
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
fetch_and_deploy_gh_release "hister" "asciimoo/hister" "singlefile" "latest" "/usr/local/bin" "hister_*_linux_$(arch_resolve)"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start hister
|
||||
msg_ok "Started Service"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}http://${IP}:4433${CL}"
|
||||
-79
@@ -1,79 +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/Nystik-gh/ignis
|
||||
|
||||
APP="Ignis"
|
||||
var_tags="${var_tags:-notes;obsidian}"
|
||||
var_cpu="${var_cpu:-2}"
|
||||
var_ram="${var_ram:-4096}"
|
||||
var_disk="${var_disk:-10}"
|
||||
var_os="${var_os:-debian}"
|
||||
var_version="${var_version:-13}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
catch_errors
|
||||
|
||||
function update_script() {
|
||||
header_info
|
||||
check_container_storage
|
||||
check_container_resources
|
||||
|
||||
if [[ ! -d /opt/ignis ]]; then
|
||||
msg_error "No ${APP} Installation Found!"
|
||||
exit
|
||||
fi
|
||||
|
||||
if check_for_gh_release "ignis" "Nystik-gh/ignis"; then
|
||||
msg_info "Stopping Service"
|
||||
systemctl stop ignis
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "ignis" "Nystik-gh/ignis" "tarball"
|
||||
|
||||
msg_info "Building Ignis"
|
||||
cd /opt/ignis
|
||||
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||
export IGNIS_BUILD="$(cat ~/.ignis)"
|
||||
$STD npm ci --ignore-scripts
|
||||
$STD npm run build
|
||||
$STD npm install -g @electron/asar
|
||||
msg_ok "Built Ignis"
|
||||
|
||||
msg_info "Checking Obsidian Web Assets"
|
||||
OBSIDIAN_VERSION=$(grep -oP 'OBSIDIAN_VERSION=\K[0-9.]+' /opt/ignis/apps/ignis-server/Dockerfile | head -n1)
|
||||
[[ -z "$OBSIDIAN_VERSION" ]] && OBSIDIAN_VERSION="$(cat /opt/ignis_data/obsidian.version 2>/dev/null)"
|
||||
if [[ -n "$OBSIDIAN_VERSION" && "$OBSIDIAN_VERSION" != "$(cat /opt/ignis_data/obsidian.version 2>/dev/null)" ]]; then
|
||||
rm -rf /opt/ignis_data/obsidian-app
|
||||
mkdir -p /opt/ignis_data/obsidian-app
|
||||
curl -fsSL -o /tmp/obsidian.asar.gz "https://github.com/obsidianmd/obsidian-releases/releases/download/v${OBSIDIAN_VERSION}/obsidian-${OBSIDIAN_VERSION}.asar.gz"
|
||||
gunzip -f /tmp/obsidian.asar.gz
|
||||
$STD asar extract /tmp/obsidian.asar /opt/ignis_data/obsidian-app
|
||||
rm -f /tmp/obsidian.asar
|
||||
echo "${OBSIDIAN_VERSION}" >/opt/ignis_data/obsidian.version
|
||||
fi
|
||||
msg_ok "Checked Obsidian Web Assets"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start ignis
|
||||
systemctl reload nginx
|
||||
msg_ok "Started Service"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
exit
|
||||
}
|
||||
|
||||
start
|
||||
build_container
|
||||
description
|
||||
|
||||
msg_ok "Completed Successfully!\n"
|
||||
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
|
||||
echo -e "${INFO}${YW}Access it using the following URL:${CL}"
|
||||
echo -e "${GATEWAY}${BGN}https://${IP}${CL}"
|
||||
+1
-10
@@ -214,16 +214,7 @@ EOF
|
||||
cd "$SRC_DIR"
|
||||
export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml
|
||||
export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg
|
||||
mise_ok=0
|
||||
for i in 1 2 3; do
|
||||
$STD mise install && {
|
||||
mise_ok=1
|
||||
break
|
||||
}
|
||||
msg_warn "mise install failed (attempt $i/3) - retrying"
|
||||
sleep 5
|
||||
done
|
||||
[[ "$mise_ok" -eq 1 ]] || exit 1
|
||||
$STD mise install
|
||||
export PATH="$(mise bin-paths 2>/dev/null | tr '\n' ':')$PATH"
|
||||
if ! command -v extism-js >/dev/null 2>&1; then
|
||||
# extism-js ships as a bare gzip-compressed single binary (.gz) that
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ 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_version="${var_version:-12}"
|
||||
var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
|
||||
|
||||
@@ -17,9 +17,6 @@ var_arm64="${var_arm64:-yes}"
|
||||
var_unprivileged="${var_unprivileged:-1}"
|
||||
var_tun="${var_tun:-1}"
|
||||
|
||||
export var_pangolin_url="${var_pangolin_url:-}"
|
||||
export var_pangolin_email="${var_pangolin_email:-}"
|
||||
|
||||
header_info "$APP"
|
||||
variables
|
||||
color
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ function update_script() {
|
||||
read -rp "Do you want to continue with the update? (y/N): " MIGRATE
|
||||
echo
|
||||
if [[ ! "$MIGRATE" =~ ^[Yy]$ ]]; then
|
||||
msg_custom "⚠️" "Update aborted. Decrypt all documents before upgrading to v3."
|
||||
msg_info "Update aborted. Decrypt all documents before upgrading to v3."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
+10
-38
@@ -112,33 +112,14 @@ EOF
|
||||
msg_ok "Stopped Termix"
|
||||
|
||||
msg_info "Migrating Configuration"
|
||||
mkdir -p /opt/termix/db/data
|
||||
|
||||
if [[ -f /opt/termix/data/db.sqlite.encrypted && ! -f /opt/termix/db/data/db.sqlite.encrypted ]]; then
|
||||
cp -a /opt/termix/data/db.sqlite.encrypted /opt/termix/db/data/db.sqlite.encrypted
|
||||
[[ -f /opt/termix/data/db.sqlite.encrypted.meta ]] &&
|
||||
cp -a /opt/termix/data/db.sqlite.encrypted.meta /opt/termix/db/data/db.sqlite.encrypted.meta
|
||||
[[ -f /opt/termix/data/db.sqlite ]] &&
|
||||
cp -a /opt/termix/data/db.sqlite /opt/termix/db/data/db.sqlite
|
||||
fi
|
||||
|
||||
if [[ -f /opt/termix/data/.env && ! -f /opt/termix/db/data/.env ]]; then
|
||||
cp -a /opt/termix/data/.env /opt/termix/db/data/.env
|
||||
fi
|
||||
|
||||
for sub in ssl session_logs session_recordings acme-webroot certbot uploads; do
|
||||
if [[ -d /opt/termix/data/$sub && ! -d /opt/termix/db/data/$sub ]]; then
|
||||
cp -a "/opt/termix/data/$sub" "/opt/termix/db/data/$sub"
|
||||
fi
|
||||
done
|
||||
|
||||
cat <<EOF >/opt/termix/.env
|
||||
if [[ ! -f /opt/termix/.env ]]; then
|
||||
cat <<EOF >/opt/termix/.env
|
||||
NODE_ENV=production
|
||||
DATA_DIR=/opt/termix/db/data
|
||||
DATA_DIR=/opt/termix/data
|
||||
GUACD_HOST=127.0.0.1
|
||||
GUACD_PORT=4822
|
||||
EOF
|
||||
|
||||
fi
|
||||
if ! grep -q "EnvironmentFile" /etc/systemd/system/termix.service 2>/dev/null; then
|
||||
cat <<EOF >/etc/systemd/system/termix.service
|
||||
[Unit]
|
||||
@@ -162,11 +143,7 @@ EOF
|
||||
fi
|
||||
msg_ok "Migrated Configuration"
|
||||
|
||||
create_backup \
|
||||
/opt/termix/db/data \
|
||||
/opt/termix/data \
|
||||
/opt/termix/uploads \
|
||||
/opt/termix/.env
|
||||
create_backup /opt/termix/data /opt/termix/uploads /opt/termix/.env
|
||||
|
||||
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "termix" "Termix-SSH/Termix" "tarball"
|
||||
|
||||
@@ -181,10 +158,10 @@ EOF
|
||||
/opt/termix/db/data
|
||||
msg_ok "Recreated Directories"
|
||||
|
||||
if [[ -f /opt/termix/db/data/db.sqlite.encrypted && ! -f /opt/termix/db/data/.env ]]; then
|
||||
msg_error "Encrypted database restored without its keys (/opt/termix/db/data/.env is missing)"
|
||||
msg_custom "🛟" "Restore the container from a backup and report this at https://github.com/community-scripts/ProxmoxVE/issues"
|
||||
exit 1
|
||||
if [[ -f /opt/termix/data/db.sqlite.encrypted && ! -f /opt/termix/db/data/db.sqlite.encrypted ]]; then
|
||||
msg_info "Migrating Database to new layout"
|
||||
cp -a /opt/termix/data/db.sqlite.encrypted /opt/termix/db/data/db.sqlite.encrypted
|
||||
msg_ok "Migrated Database to new layout"
|
||||
fi
|
||||
|
||||
msg_info "Building Frontend"
|
||||
@@ -260,12 +237,7 @@ EOF
|
||||
fi
|
||||
|
||||
msg_info "Starting Termix"
|
||||
systemctl daemon-reload
|
||||
if ! systemctl start termix; then
|
||||
msg_error "Termix failed to start"
|
||||
journalctl -u termix -n 30 --no-pager || true
|
||||
exit 1
|
||||
fi
|
||||
systemctl start termix
|
||||
msg_ok "Started Termix"
|
||||
msg_ok "Updated successfully!"
|
||||
fi
|
||||
|
||||
+3
-2
@@ -46,7 +46,8 @@ function update_script() {
|
||||
[[ "$CONFIRM2" =~ ^[yY]$ ]] || exit 0
|
||||
fi
|
||||
|
||||
if check_for_gh_release "vikunja" "go-vikunja/vikunja"; then
|
||||
RELEASE="v2.3.0"
|
||||
if check_for_gh_release "vikunja" "go-vikunja/vikunja" "${RELEASE}" "v2.4.0 is killed at startup by the systemd SystemCallFilter shipped in the .deb (upstream go-vikunja/vikunja#3252); pinned until a fixed release is out"; then
|
||||
echo
|
||||
msg_warn "The package update may include config file changes."
|
||||
echo -e "${TAB}${YW}How do you want to handle /etc/vikunja/config.yml?${CL}"
|
||||
@@ -65,7 +66,7 @@ function update_script() {
|
||||
systemctl stop vikunja
|
||||
msg_ok "Stopped Service"
|
||||
|
||||
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
|
||||
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "${RELEASE}" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
|
||||
$STD systemctl daemon-reload
|
||||
|
||||
msg_info "Starting Service"
|
||||
|
||||
@@ -48,13 +48,6 @@ function update_script() {
|
||||
chmod 644 /opt/xyops/node_modules/useragent-ng/lib/regexps.js
|
||||
msg_ok "Rebuilt Application"
|
||||
|
||||
fetch_and_deploy_gh_release "xysat" "pixlcore/xysat" "tarball" "latest" "/opt/xyops/satellite"
|
||||
|
||||
msg_info "Building xySat Satellite"
|
||||
cd /opt/xyops/satellite
|
||||
$STD npm install
|
||||
msg_ok "Built xySat Satellite"
|
||||
|
||||
msg_info "Starting Service"
|
||||
systemctl start xyops
|
||||
msg_ok "Started Service"
|
||||
|
||||
@@ -51,7 +51,6 @@ cat <<EOF >/opt/actualbudget-data/config.json
|
||||
EOF
|
||||
mkdir -p /opt/actualbudget
|
||||
cd /opt/actualbudget
|
||||
$STD npm config set allow-scripts=bcrypt,better-sqlite3,argon2 --location=global
|
||||
$STD npm install --location=global @actual-app/sync-server
|
||||
echo "${RELEASE}" >~/.actualbudget
|
||||
msg_ok "Installed Actual Budget"
|
||||
|
||||
@@ -83,6 +83,7 @@ $STD apt-get install -y \
|
||||
fonts-kacst fonts-liberation \
|
||||
fonts-noto-cjk \
|
||||
fonts-noto-color-emoji \
|
||||
msttcorefonts \
|
||||
fonts-roboto \
|
||||
fonts-thai-tlwg \
|
||||
fonts-wqy-zenhei
|
||||
|
||||
@@ -24,7 +24,6 @@ fetch_and_deploy_gh_release "Heimdall" "linuxserver/Heimdall" "tarball"
|
||||
msg_info "Setting up Heimdall-Dashboard"
|
||||
cd /opt/Heimdall
|
||||
cp .env.example .env
|
||||
sed -i 's/^APP_ENV=.*/APP_ENV=production/' .env
|
||||
$STD php artisan key:generate
|
||||
msg_ok "Setup Heimdall-Dashboard"
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/asciimoo/hister
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
fetch_and_deploy_gh_release "hister" "asciimoo/hister" "singlefile" "latest" "/usr/local/bin" "hister_*_linux_$(arch_resolve)"
|
||||
|
||||
msg_info "Configuring Hister"
|
||||
mkdir -p /opt/hister/data /etc/hister
|
||||
LOCAL_IP=$(hostname -I | awk '{print $1}')
|
||||
cat <<EOF >/etc/hister/config.yaml
|
||||
app:
|
||||
directory: '/opt/hister/data'
|
||||
server:
|
||||
address: '0.0.0.0:4433'
|
||||
base_url: 'http://${LOCAL_IP}:4433'
|
||||
EOF
|
||||
msg_ok "Configured Hister"
|
||||
|
||||
msg_info "Creating Service"
|
||||
cat <<EOF >/etc/systemd/system/hister.service
|
||||
[Unit]
|
||||
Description=Hister Search Engine
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
ExecStart=/usr/local/bin/hister listen --config /etc/hister/config.yaml
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable -q --now hister
|
||||
msg_ok "Created Service"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
@@ -1,113 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2021-2026 community-scripts ORG
|
||||
# Author: MickLesk (CanbiZ)
|
||||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||||
# Source: https://github.com/Nystik-gh/ignis
|
||||
|
||||
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
|
||||
color
|
||||
verb_ip6
|
||||
catch_errors
|
||||
setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
msg_info "Installing Dependencies"
|
||||
$STD apt install -y nginx
|
||||
msg_ok "Installed Dependencies"
|
||||
|
||||
NODE_VERSION="22" setup_nodejs
|
||||
|
||||
fetch_and_deploy_gh_release "ignis" "Nystik-gh/ignis" "tarball"
|
||||
|
||||
msg_info "Building Ignis"
|
||||
cd /opt/ignis
|
||||
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||
export IGNIS_BUILD="$(cat ~/.ignis)"
|
||||
$STD npm ci --ignore-scripts
|
||||
$STD npm run build
|
||||
$STD npm install -g @electron/asar
|
||||
msg_ok "Built Ignis"
|
||||
|
||||
msg_info "Downloading Obsidian Web Assets"
|
||||
mkdir -p /opt/ignis_data/{obsidian-app,vaults,data}
|
||||
OBSIDIAN_VERSION=$(grep -oP 'OBSIDIAN_VERSION=\K[0-9.]+' /opt/ignis/apps/ignis-server/Dockerfile | head -n1)
|
||||
[[ -z "$OBSIDIAN_VERSION" ]] && OBSIDIAN_VERSION="1.12.7"
|
||||
curl -fsSL -o /tmp/obsidian.asar.gz "https://github.com/obsidianmd/obsidian-releases/releases/download/v${OBSIDIAN_VERSION}/obsidian-${OBSIDIAN_VERSION}.asar.gz"
|
||||
gunzip -f /tmp/obsidian.asar.gz
|
||||
$STD asar extract /tmp/obsidian.asar /opt/ignis_data/obsidian-app
|
||||
rm -f /tmp/obsidian.asar
|
||||
echo "${OBSIDIAN_VERSION}" >/opt/ignis_data/obsidian.version
|
||||
msg_ok "Downloaded Obsidian Web Assets"
|
||||
|
||||
msg_info "Creating Service"
|
||||
cat <<EOF >/etc/systemd/system/ignis.service
|
||||
[Unit]
|
||||
Description=Ignis (Obsidian in the browser)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/opt/ignis
|
||||
Environment=NODE_ENV=production
|
||||
Environment=PORT=8080
|
||||
Environment=VAULT_ROOT=/opt/ignis_data/vaults
|
||||
Environment=DATA_ROOT=/opt/ignis_data/data
|
||||
Environment=OBSIDIAN_ASSETS_PATH=/opt/ignis_data/obsidian-app
|
||||
Environment=AUTO_CREATE_DEFAULT=true
|
||||
ExecStart=/usr/bin/node /opt/ignis/apps/ignis-server/server/index.js
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl enable -q --now ignis
|
||||
msg_ok "Created Service"
|
||||
|
||||
msg_info "Generating Self-Signed Certificate"
|
||||
create_self_signed_cert "ignis"
|
||||
msg_ok "Generated Self-Signed Certificate"
|
||||
|
||||
msg_info "Configuring Nginx"
|
||||
cat <<'EOF' >/etc/nginx/sites-available/ignis.conf
|
||||
server {
|
||||
listen 80 default_server;
|
||||
server_name _;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl default_server;
|
||||
http2 on;
|
||||
server_name _;
|
||||
|
||||
ssl_certificate /etc/ssl/ignis/ignis.crt;
|
||||
ssl_certificate_key /etc/ssl/ignis/ignis.key;
|
||||
|
||||
client_max_body_size 1024m;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 3600s;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ln -sf /etc/nginx/sites-available/ignis.conf /etc/nginx/sites-enabled/ignis.conf
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
systemctl restart nginx
|
||||
msg_ok "Configured Nginx"
|
||||
|
||||
motd_ssh
|
||||
customize
|
||||
cleanup_lxc
|
||||
@@ -355,16 +355,7 @@ cp LICENSE "$APP_DIR"
|
||||
cd "$SRC_DIR"
|
||||
export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml
|
||||
export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg
|
||||
mise_ok=0
|
||||
for i in 1 2 3; do
|
||||
$STD mise install && {
|
||||
mise_ok=1
|
||||
break
|
||||
}
|
||||
msg_warn "mise install failed (attempt $i/3) - retrying"
|
||||
sleep 5
|
||||
done
|
||||
[[ "$mise_ok" -eq 1 ]] || exit 1
|
||||
$STD mise install
|
||||
export PATH="$(mise bin-paths 2>/dev/null | tr '\n' ':')$PATH"
|
||||
if ! command -v extism-js >/dev/null 2>&1; then
|
||||
# extism-js is published as a bare gzip-compressed single binary (.gz), which
|
||||
|
||||
@@ -24,16 +24,6 @@ if [[ ! "$CONFIRM" =~ ^([yY][eE][sS]|[yY])$ ]]; then
|
||||
exit 10
|
||||
fi
|
||||
|
||||
msg_info "Making ssh.service reloads behave like restarts"
|
||||
mkdir -p /etc/systemd/system/ssh.service.d
|
||||
cat <<'EOF' >/etc/systemd/system/ssh.service.d/reload-as-restart.conf
|
||||
[Service]
|
||||
ExecReload=
|
||||
ExecReload=/usr/bin/systemd-run --no-block --quiet /bin/systemctl restart ssh.service
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
msg_ok "Made ssh.service reloads behave like restarts"
|
||||
|
||||
msg_info "Installing NextCloudPi (Patience)"
|
||||
$STD bash <(curl -fsSL https://raw.githubusercontent.com/nextcloud/nextcloudpi/master/install.sh)
|
||||
msg_ok "Installed NextCloudPi"
|
||||
|
||||
@@ -27,18 +27,9 @@ fetch_and_deploy_gh_release "pangolin" "fosrl/pangolin" "tarball" "$PANGOLIN_VER
|
||||
fetch_and_deploy_gh_release "gerbil" "fosrl/gerbil" "singlefile" "latest" "/usr/bin" "gerbil_linux_$(arch_resolve)"
|
||||
fetch_and_deploy_gh_release "traefik" "traefik/traefik" "prebuild" "latest" "/usr/bin" "traefik_v*_linux_$(arch_resolve).tar.gz"
|
||||
|
||||
# Read the variable first and prompt only when it is unset, so the install can
|
||||
# be supplied up front. Same convention as install/forgejo-runner-install.sh.
|
||||
pango_url="${var_pangolin_url:-}"
|
||||
if [[ -z "$pango_url" ]]; then
|
||||
read -rp "${TAB3}Enter your Pangolin URL (ex: https://pangolin.example.com): " pango_url
|
||||
fi
|
||||
read -rp "${TAB3}Enter your Pangolin URL (ex: https://pangolin.example.com): " pango_url
|
||||
[[ "$pango_url" != https://* && "$pango_url" != http://* ]] && pango_url="https://${pango_url}"
|
||||
|
||||
pango_email="${var_pangolin_email:-}"
|
||||
if [[ -z "$pango_email" ]]; then
|
||||
read -rp "${TAB3}Enter your email address: " pango_email
|
||||
fi
|
||||
read -rp "${TAB3}Enter your email address: " pango_email
|
||||
|
||||
msg_info "Setup Pangolin"
|
||||
SECRET_KEY=$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 32)
|
||||
|
||||
@@ -125,7 +125,7 @@ EOF
|
||||
|
||||
cat <<EOF >/opt/termix/.env
|
||||
NODE_ENV=production
|
||||
DATA_DIR=/opt/termix/db/data
|
||||
DATA_DIR=/opt/termix/data
|
||||
GUACD_HOST=127.0.0.1
|
||||
GUACD_PORT=4822
|
||||
EOF
|
||||
|
||||
@@ -13,7 +13,8 @@ setting_up_container
|
||||
network_check
|
||||
update_os
|
||||
|
||||
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
|
||||
RELEASE="v2.3.0"
|
||||
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "${RELEASE}" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
|
||||
|
||||
msg_info "Setting up Vikunja"
|
||||
sed -i 's|^# \(service:\)|\1|' /etc/vikunja/config.yml
|
||||
|
||||
+12
-16
@@ -922,10 +922,8 @@ choose_and_set_storage_for_file() {
|
||||
_list_os_versions() {
|
||||
local ostype="${1:-}"
|
||||
[[ -n "$ostype" ]] || return 0
|
||||
local arch
|
||||
arch="$(dpkg --print-architecture 2>/dev/null || echo amd64)"
|
||||
pveam available -section system 2>/dev/null |
|
||||
grep -E "_${arch}\.(tar\.zst|tar\.xz|tar\.gz)([[:space:]]|$)" |
|
||||
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
|
||||
awk '{print $2}' |
|
||||
sed -nE "s/^${ostype}-([0-9]+(\.[0-9]+)?).*/\1/p" |
|
||||
sort -u -V || true
|
||||
@@ -938,10 +936,8 @@ _list_os_versions() {
|
||||
_list_templates() {
|
||||
local search="${1:-}" pattern="${2:-}"
|
||||
[[ -n "$search" ]] || return 0
|
||||
local arch
|
||||
arch="$(dpkg --print-architecture 2>/dev/null || echo amd64)"
|
||||
pveam available -section system 2>/dev/null |
|
||||
grep -E "_${arch}\.(tar\.zst|tar\.xz|tar\.gz)([[:space:]]|$)" |
|
||||
grep -E '\.(tar\.zst|tar\.xz|tar\.gz)$' |
|
||||
awk '{print $2}' |
|
||||
grep -E "^${search}.*${pattern}" |
|
||||
sort -t - -k 2 -V || true
|
||||
@@ -5204,11 +5200,15 @@ EOF
|
||||
# TSTP = Ctrl+Z, TTIN = bg read from tty, TTOU = bg write to tty (tostop)
|
||||
trap '' TSTP TTIN TTOU
|
||||
|
||||
# lxc-attach left us in a background process group - claim the terminal back
|
||||
# before we print anything. Note this does NOT hold: the log collection
|
||||
# below uses pct pull/exec, which take it away again, so every interactive
|
||||
# prompt has to reclaim it again right before its read.
|
||||
reclaim_tty
|
||||
# lxc-attach takes the controlling terminal while the install runs and does
|
||||
# not hand it back, leaving us in a background process group. Reading from
|
||||
# the terminal then returns EIO instead of blocking, because SIGTTIN is
|
||||
# ignored above - so every recovery prompt fails before the user can answer.
|
||||
# Redirecting to /dev/tty does not help: the rule applies to the terminal,
|
||||
# not the file descriptor. Claim the foreground group back; SIGTTOU is
|
||||
# ignored too, so tcsetpgrp() succeeds instead of stopping us. No-op when we
|
||||
# already are in the foreground. perl is a hard dependency of Proxmox VE.
|
||||
perl -e 'use POSIX; open(my $t, "+<", "/dev/tty") or exit 1; POSIX::tcsetpgrp(fileno($t), getpgrp()) or exit 1;' 2>/dev/null || true
|
||||
|
||||
msg_error "Installation failed in container ${CTID} (exit code: ${install_exit_code})"
|
||||
|
||||
@@ -5338,7 +5338,6 @@ EOF
|
||||
pct enter "$CTID"
|
||||
echo ""
|
||||
echo -en "${YW}Container ${CTID} still running. Remove now? (y/N): ${CL}"
|
||||
reclaim_tty
|
||||
if read -r response </dev/tty && [[ "$response" =~ ^[Yy]$ ]]; then
|
||||
pct stop "$CTID" &>/dev/null || true
|
||||
pct destroy "$CTID" &>/dev/null || true
|
||||
@@ -5498,7 +5497,6 @@ EOF
|
||||
|
||||
local response=""
|
||||
local read_rc
|
||||
reclaim_tty
|
||||
read -t 60 -r response </dev/tty
|
||||
read_rc=$?
|
||||
if [[ $read_rc -eq 0 ]]; then
|
||||
@@ -5763,7 +5761,6 @@ destroy_lxc() {
|
||||
trap 'echo; msg_error "Aborted by user (SIGINT/SIGQUIT)"; return 130' INT QUIT
|
||||
|
||||
local prompt
|
||||
reclaim_tty
|
||||
if ! read -rp "Remove this Container? <y/N> " prompt </dev/tty; then
|
||||
# read returns non-zero on Ctrl-D/ESC
|
||||
msg_error "Aborted input (Ctrl-D/ESC)"
|
||||
@@ -6725,8 +6722,7 @@ create_lxc_container() {
|
||||
# Step 1: Check local templates first (instant)
|
||||
mapfile -t LOCAL_TEMPLATES < <(
|
||||
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||
awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" -v arch="${ARCH}" \
|
||||
'$1 ~ search && $1 ~ pattern && $1 ~ ("_" arch "\\.(tar\\.zst|tar\\.xz|tar\\.gz)$") {print $1}' |
|
||||
awk -v search="${TEMPLATE_SEARCH}" -v pattern="${TEMPLATE_PATTERN}" '$1 ~ search && $1 ~ pattern {print $1}' |
|
||||
sed 's|.*/||' | sort -t - -k 2 -V
|
||||
)
|
||||
|
||||
|
||||
@@ -1042,39 +1042,6 @@ ensure_tput() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# reclaim_tty()
|
||||
#
|
||||
# - Reclaims the controlling terminal's foreground process group
|
||||
# - lxc-attach takes the terminal and does not hand it back, leaving us in a
|
||||
# background process group. Reading from the terminal then returns EIO
|
||||
# instead of blocking, because SIGTTIN is ignored during recovery - so the
|
||||
# prompt fails before the user can answer and their keystroke leaks into the
|
||||
# parent shell. Redirecting to /dev/tty does not help: the rule applies to
|
||||
# the terminal, not to the file descriptor.
|
||||
# - pct exec/pull/enter use lxc-attach internally, so the terminal can be taken
|
||||
# away again at any point. Call this immediately before each interactive
|
||||
# read, not once after the install.
|
||||
# - SIGTTOU is ignored inside perl so tcsetpgrp() succeeds instead of stopping
|
||||
# us. No-op when we already are in the foreground or there is no terminal.
|
||||
# perl is a hard dependency of Proxmox VE.
|
||||
# ------------------------------------------------------------------------------
|
||||
reclaim_tty() {
|
||||
command -v perl >/dev/null 2>&1 || return 0
|
||||
[[ -e /dev/tty ]] || return 0
|
||||
|
||||
local pgid
|
||||
pgid=$(ps -o pgid= -p $$ 2>/dev/null | tr -d ' ') || true
|
||||
|
||||
perl -e '
|
||||
use POSIX;
|
||||
$SIG{TTOU} = "IGNORE";
|
||||
my $pgid = $ARGV[0] || POSIX::getpgrp();
|
||||
open(my $t, "+<", "/dev/tty") or exit 1;
|
||||
POSIX::tcsetpgrp(fileno($t), $pgid) or exit 1;
|
||||
' "${pgid:-0}" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# is_alpine()
|
||||
#
|
||||
|
||||
@@ -499,7 +499,6 @@ error_handler() {
|
||||
|
||||
local response=""
|
||||
local read_rc
|
||||
declare -f reclaim_tty >/dev/null 2>&1 && reclaim_tty
|
||||
read -t 60 -r response </dev/tty
|
||||
read_rc=$?
|
||||
if [[ $read_rc -eq 0 ]]; then
|
||||
|
||||
+64
-34
@@ -2576,6 +2576,11 @@ _deploy_unpacked_archive() {
|
||||
local archive="$1" target="$2" workdir="$3"
|
||||
local filename="${archive##*/}"
|
||||
|
||||
mkdir -p "$target"
|
||||
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||
find "${target:?}" -mindepth 1 -delete
|
||||
fi
|
||||
|
||||
if [[ "$filename" == *.zip ]]; then
|
||||
ensure_dependencies unzip
|
||||
unzip -q "$archive" -d "$workdir" || {
|
||||
@@ -2602,44 +2607,38 @@ _deploy_unpacked_archive() {
|
||||
return 65
|
||||
fi
|
||||
|
||||
local top_entries inner_dir source_dir
|
||||
local top_entries inner_dir
|
||||
top_entries=$(find "$workdir" -mindepth 1 -maxdepth 1)
|
||||
if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then
|
||||
inner_dir="$top_entries"
|
||||
source_dir="$inner_dir"
|
||||
else
|
||||
source_dir="$workdir"
|
||||
fi
|
||||
|
||||
shopt -s dotglob nullglob
|
||||
if ! compgen -G "$source_dir/*" >/dev/null; then
|
||||
if [[ -n "$inner_dir" ]]; then
|
||||
shopt -s dotglob nullglob
|
||||
if compgen -G "$inner_dir/*" >/dev/null; then
|
||||
cp -r "$inner_dir"/* "$target/" || {
|
||||
msg_error "Failed to copy contents from $inner_dir to $target"
|
||||
shopt -u dotglob nullglob
|
||||
return 252
|
||||
}
|
||||
else
|
||||
msg_error "Inner directory is empty: $inner_dir"
|
||||
shopt -u dotglob nullglob
|
||||
return 252
|
||||
fi
|
||||
shopt -u dotglob nullglob
|
||||
else
|
||||
shopt -s dotglob nullglob
|
||||
if compgen -G "$workdir/*" >/dev/null; then
|
||||
cp -r "$workdir"/* "$target/" || {
|
||||
msg_error "Failed to copy contents to $target"
|
||||
shopt -u dotglob nullglob
|
||||
return 252
|
||||
}
|
||||
else
|
||||
msg_error "Unpacked archive is empty"
|
||||
shopt -u dotglob nullglob
|
||||
return 252
|
||||
fi
|
||||
shopt -u dotglob nullglob
|
||||
return 252
|
||||
fi
|
||||
|
||||
# <target> is only touched once the payload is known good. Wiping earlier left
|
||||
# CLEAN_INSTALL callers with an empty target directory whenever the download
|
||||
# was truncated, the archive was unreadable, or it unpacked to nothing.
|
||||
mkdir -p "$target"
|
||||
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
|
||||
find "${target:?}" -mindepth 1 -delete
|
||||
fi
|
||||
|
||||
if ! cp -r "$source_dir"/* "$target/"; then
|
||||
if [[ -n "$inner_dir" ]]; then
|
||||
msg_error "Failed to copy contents from $inner_dir to $target"
|
||||
else
|
||||
msg_error "Failed to copy contents to $target"
|
||||
fi
|
||||
shopt -u dotglob nullglob
|
||||
return 252
|
||||
fi
|
||||
shopt -u dotglob nullglob
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -4802,8 +4801,8 @@ EOF
|
||||
|
||||
# Container Update Check
|
||||
# - Skipped entirely when running unattended / non-interactive
|
||||
# - Lists containers with a newer image available and the command to update
|
||||
# them; does not pull/recreate anything itself
|
||||
# - Compose-managed containers: offered via Y/N → docker compose pull + up -d
|
||||
# - Standalone containers: offered via Y/N → image pull only (no stop/rm)
|
||||
if [ "$docker_installed" = true ] && ! _docker_is_noninteractive; then
|
||||
msg_info "Checking for container updates"
|
||||
|
||||
@@ -4841,14 +4840,41 @@ EOF
|
||||
if [[ ${#compose_updates[@]} -eq 0 && ${#standalone_updates[@]} -eq 0 ]]; then
|
||||
msg_ok "All containers are up-to-date"
|
||||
else
|
||||
msg_warn "Updates available (not applied automatically):"
|
||||
local reply
|
||||
for entry in "${compose_updates[@]}"; do
|
||||
IFS='|' read -r name image compose_workdir compose_service <<<"$entry"
|
||||
echo -e "${TAB3}${name} (${image}) — update via: cd ${compose_workdir} && docker compose pull ${compose_service} && docker compose up -d ${compose_service}"
|
||||
reply=""
|
||||
if read -r -t 60 -p "${TAB3}Update ${name} (${image}) via Compose? <y/N> (auto-no in 60s): " reply </dev/tty; then
|
||||
echo ""
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
if [[ "${reply,,}" =~ ^(y|yes)$ ]]; then
|
||||
msg_info "Updating $name"
|
||||
if (cd "$compose_workdir" && $STD docker compose pull "$compose_service" && $STD docker compose up -d "$compose_service"); then
|
||||
msg_ok "Updated $name"
|
||||
else
|
||||
msg_warn "Could not update $name — try manually in $compose_workdir"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
for entry in "${standalone_updates[@]}"; do
|
||||
IFS='|' read -r name image <<<"$entry"
|
||||
echo -e "${TAB3}${name} (${image}) — update via: docker pull ${image} && docker restart ${name}"
|
||||
reply=""
|
||||
if read -r -t 60 -p "${TAB3}Pull new image for ${name} (${image})? <y/N> (auto-no in 60s): " reply </dev/tty; then
|
||||
echo ""
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
if [[ "${reply,,}" =~ ^(y|yes)$ ]]; then
|
||||
msg_info "Pulling new image for $name"
|
||||
if $STD docker pull "$image"; then
|
||||
msg_ok "New image available for $name — recreate the container to apply the update"
|
||||
else
|
||||
msg_warn "Failed to pull image for $name"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
@@ -7706,6 +7732,10 @@ setup_nodejs() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$(npm -v 2>/dev/null | cut -d. -f1)" -ge 11 ]]; then
|
||||
$STD npm config set dangerously-allow-all-scripts true --location=global 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Set a safe default heap limit for Node.js builds if not explicitly provided.
|
||||
# Priority:
|
||||
# 1) NODE_OPTIONS (caller/user override)
|
||||
|
||||
@@ -49,22 +49,6 @@ function uninstall() {
|
||||
msg_ok "${APP} has been uninstalled"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# UPDATE SCRIPT HELPER
|
||||
# ==============================================================================
|
||||
function ensure_update_script() {
|
||||
[[ -f /usr/local/bin/update_portainer ]] && return 0
|
||||
|
||||
msg_info "Creating update script"
|
||||
cat <<'UPDATEEOF' >/usr/local/bin/update_portainer
|
||||
#!/usr/bin/env bash
|
||||
# Portainer Update Script
|
||||
type=update bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/portainer.sh)"
|
||||
UPDATEEOF
|
||||
chmod +x /usr/local/bin/update_portainer
|
||||
msg_ok "Created update script (/usr/local/bin/update_portainer)"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# UPDATE
|
||||
# ==============================================================================
|
||||
@@ -78,8 +62,6 @@ function update() {
|
||||
$STD docker compose up -d --remove-orphans
|
||||
msg_ok "Restarted ${APP}"
|
||||
|
||||
ensure_update_script
|
||||
|
||||
msg_ok "Updated successfully"
|
||||
exit
|
||||
}
|
||||
@@ -133,7 +115,15 @@ function install() {
|
||||
$STD docker compose up -d
|
||||
msg_ok "Started ${APP}"
|
||||
|
||||
ensure_update_script
|
||||
# Create update script
|
||||
msg_info "Creating update script"
|
||||
cat <<'UPDATEEOF' >/usr/local/bin/update_portainer
|
||||
#!/usr/bin/env bash
|
||||
# Portainer Update Script
|
||||
type=update bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/tools/addon/portainer.sh)"
|
||||
UPDATEEOF
|
||||
chmod +x /usr/local/bin/update_portainer
|
||||
msg_ok "Created update script (/usr/local/bin/update_portainer)"
|
||||
|
||||
echo ""
|
||||
msg_ok "${APP} is reachable at: ${BL}https://${LOCAL_IP}:${DEFAULT_PORT}${CL}"
|
||||
@@ -160,9 +150,6 @@ fi
|
||||
header_info
|
||||
get_lxc_ip
|
||||
|
||||
check_docker
|
||||
check_existing_container
|
||||
|
||||
# Check if already installed
|
||||
if [[ -f "$COMPOSE_FILE" ]]; then
|
||||
msg_warn "${APP} is already installed."
|
||||
|
||||
@@ -54,24 +54,18 @@ while true; do
|
||||
continue
|
||||
fi
|
||||
|
||||
# Determine type and read the current config directly from Proxmox's pmxcfs.
|
||||
# Ignore snapshot sections, matching the current config shown by pct/qm config.
|
||||
if [ -r "/etc/pve/lxc/$instance.conf" ]; then
|
||||
# Determine type and set config command
|
||||
if pct status $instance >/dev/null 2>&1; then
|
||||
type="ct"
|
||||
config_file="/etc/pve/lxc/$instance.conf"
|
||||
config_cmd="pct config"
|
||||
else
|
||||
type="vm"
|
||||
config_file="/etc/pve/qemu-server/$instance.conf"
|
||||
config_cmd="qm config"
|
||||
fi
|
||||
config=$(sed '/^\[/,$d' "$config_file")
|
||||
|
||||
# Skip templates and onboot-disabled
|
||||
if grep -q "onboot: 0" <<<"$config" || ! grep -q "onboot" <<<"$config"; then
|
||||
onboot="true"
|
||||
else
|
||||
onboot="false"
|
||||
fi
|
||||
template=$(grep -q "^template:" <<<"$config" && echo "true" || echo "false")
|
||||
onboot=$($config_cmd $instance | grep -q "onboot: 0" || ( ! $config_cmd $instance | grep -q "onboot" ) && echo "true" || echo "false")
|
||||
template=$($config_cmd $instance | grep -q "^template:" && echo "true" || echo "false")
|
||||
|
||||
if [ "$onboot" == "true" ]; then
|
||||
echo "Skipping $instance because it is set not to boot"
|
||||
@@ -82,7 +76,7 @@ while true; do
|
||||
fi
|
||||
|
||||
# Check for mon-restart tag
|
||||
has_tag=$(grep -q "tags:.*mon-restart" <<<"$config" && echo "true" || echo "false")
|
||||
has_tag=$($config_cmd $instance | grep -q "tags:.*mon-restart" && echo "true" || echo "false")
|
||||
if [ "$has_tag" != "true" ]; then
|
||||
echo "Skipping $instance because it does not have 'mon-restart' tag"
|
||||
continue
|
||||
|
||||
@@ -125,6 +125,12 @@ EOF
|
||||
no) msg_error "Selected no to Correcting Proxmox VE Sources" ;;
|
||||
esac
|
||||
|
||||
if [[ "$(dpkg --print-architecture 2>/dev/null)" == "arm64" ]]; then
|
||||
msg_ok "ARM64 detected - skipping Proxmox repository setup"
|
||||
post_routines_common
|
||||
return
|
||||
fi
|
||||
|
||||
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "PVE-ENTERPRISE" --menu "The 'pve-enterprise' repository is only available to users who have purchased a Proxmox VE subscription.\n \nDisable 'pve-enterprise' repository?" 14 58 2 \
|
||||
"yes" " " \
|
||||
"no" " " 3>&2 2>&1 1>&3)
|
||||
@@ -282,6 +288,12 @@ EOF
|
||||
esac
|
||||
fi
|
||||
|
||||
if [[ "$(dpkg --print-architecture 2>/dev/null)" == "arm64" ]]; then
|
||||
msg_ok "ARM64 detected - skipping Proxmox repository setup"
|
||||
post_routines_common
|
||||
return
|
||||
fi
|
||||
|
||||
# ---- PVE-ENTERPRISE ----
|
||||
if component_exists_in_sources "pve-enterprise"; then
|
||||
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
|
||||
|
||||
+1
-1
@@ -402,7 +402,7 @@ function advanced_settings() {
|
||||
fi
|
||||
|
||||
if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose CPU Model" --cancel-button Exit-Script 10 58 2 \
|
||||
"KVM64" "Default - safe for migration/compatibility" ON \
|
||||
"KVM64" "Default – safe for migration/compatibility" ON \
|
||||
"Host" "Use host CPU features (faster, no migration)" OFF \
|
||||
3>&1 1>&2 2>&3); then
|
||||
case "$CPU_TYPE1" in
|
||||
|
||||
Reference in New Issue
Block a user