Compare commits

..

20 Commits

Author SHA1 Message Date
Slaviša Arežina 4bdc876610 Apply suggestion from @tremor021 2026-08-07 19:43:35 +02:00
CanbiZ (MickLesk) bace6db49f Fix source line to always use community scripts URL
Updated the source line to always fetch from the community scripts repository.
2026-08-07 14:24:21 +02:00
push-app-to-main[bot] 347958bd80 Add ignis (ct) 2026-08-07 12:21:58 +00:00
community-scripts-pr-app[bot] 1d94e50601 Update CHANGELOG.md (#16326)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-07 09:44:04 +00:00
CanbiZ (MickLesk) 0092fa8b54 Docker: report container updates instead of prompting, stop auto-updating Portainer Agent, fix addon detection of legacy Portainer (#16298)
* Docker: report container updates instead of prompting, stop auto-updating Portainer Agent, fix addon detection of legacy Portainer

* Update portainer.sh
2026-08-07 19:43:32 +10:00
community-scripts-pr-app[bot] e00d4c6e51 Update CHANGELOG.md (#16322)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-07 08:11:07 +00:00
community-scripts-pr-app[bot] c1d5bfdb83 Update CHANGELOG.md (#16321)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-07 08:10:44 +00:00
CanbiZ (MickLesk) 33de14e45c Immich: retry mise install on transient npm download failures (#16301) 2026-08-07 10:10:35 +02:00
Austin 156f5ae16f changedetection: remove msttcorefonts to fix install hang (#16319) 2026-08-07 10:10:15 +02:00
community-scripts-pr-app[bot] 7100e1679e Update CHANGELOG.md (#16320)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-07 02:50:12 +00:00
CanbiZ (MickLesk) 63e4ea1396 core: extend new vars and pocketbase values (#16313)
* Let docker-install.sh take its three answers up front

The script asked three questions with no way to answer them in advance,
so a Docker container could not be deployed unattended: Portainer, the
Portainer Agent, and whether to expose the TCP socket.

Each now reads a variable and prompts only when it is unset, the same
shape install/forgejo-runner-install.sh already uses:

  var_portainer         yes | no
  var_portainer_agent   yes | no
  var_docker_socket     n | l (127.0.0.1) | a (0.0.0.0)

Interactive behaviour is unchanged — with nothing set, all three still
ask exactly as before.

The matching declaration for the script's PocketBase record, which the
website generator reads to offer these as form fields:

  "app_vars": [
    {"name":"var_portainer","label":"Install Portainer","type":"boolean","default":"no"},
    {"name":"var_portainer_agent","label":"Install Portainer Agent","type":"boolean","default":"no",
     "help":"Only used when Portainer itself is not installed"},
    {"name":"var_docker_socket","label":"Expose Docker TCP socket","type":"select",
     "options":["n","l","a"],"default":"n",
     "help":"l = 127.0.0.1 only, a = all interfaces (insecure)"}
  ]

CONTRIBUTING.md documents the convention so the next script follows it.

* Let docker-install.sh take its three answers up front

The script asked three questions with no way to answer them in advance,
so a Docker container could not be deployed unattended: Portainer, the
Portainer Agent, and whether to expose the TCP socket.

Each now reads a variable and prompts only when it is unset, the same
shape install/forgejo-runner-install.sh already uses:

  var_portainer         yes | no
  var_portainer_agent   yes | no
  var_docker_socket     n | l (127.0.0.1) | a (0.0.0.0)

Interactive behaviour is unchanged — with nothing set, all three still
ask exactly as before.

The matching declaration for the script's PocketBase record, which the
website generator reads to offer these as form fields:

  "app_vars": [
    {"name":"var_portainer","label":"Install Portainer","type":"boolean","default":"no"},
    {"name":"var_portainer_agent","label":"Install Portainer Agent","type":"boolean","default":"no",
     "help":"Only used when Portainer itself is not installed"},
    {"name":"var_docker_socket","label":"Expose Docker TCP socket","type":"select",
     "options":["n","l","a"],"default":"n",
     "help":"l = 127.0.0.1 only, a = all interfaces (insecure)"}
  ]

CONTRIBUTING.md documents the convention so the next script follows it.

* Let forgejo-runner and pangolin take their answers up front

forgejo-runner already exported two of the three values its install
script requires, but not var_forgejo_runner_uuid — so an unattended
install passed the ct-level guard and then stopped at a prompt inside
the container, which is the one place nobody can answer it. The guard
missed it for the same reason.

pangolin asked for its URL and email with no way to supply them. Both
sides are needed: the read in install/ now only fires when the variable
is unset, and ct/ exports it, because lxc-attach carries the caller's
environment but only what was exported.

Reverts the docker change from the previous commit; it is superseded by
work on another branch.

* Teach the PocketBase workflows the capability fields

All three wrote fields the site no longer reads. The slash bot and the
AI bot accepted has_arm=true and github=owner/repo; push-json mapped
has_arm into the payload. After the schema change those writes would
have gone to columns that are not there.

architectures and platforms are multi-selects over a closed set, so
both bots reject an unknown value instead of storing it — the same
guarantee the field type gives in the admin UI.

push-json still reads has_arm when architectures is absent, because
ProxmoxVED's json files carry the old key until they are converted.

* Drop the docker change again

It came back through the merge in 35735dae: the branch was pushed
before the revert, so merging the remote copy restored it. Removing it
forward rather than rewriting history that is already published.
2026-08-07 12:49:45 +10:00
rcourtman 63a91c8d93 fix(tools): stop a failed deploy from wiping the existing install (#16312) 2026-08-06 21:50:12 +02:00
CanbiZ (MickLesk) 590d638094 build.func: fix pveam arch filter for extra whitespace column (#16315) 2026-08-06 21:03:28 +02:00
Sam Heinz fb1d670158 dont skip enterprise repo setup on arm64 (#16307) 2026-08-06 21:02:43 +02:00
community-scripts-pr-app[bot] 5ddc4a2a41 Update CHANGELOG.md (#16309)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-06 12:33:52 +00:00
CanbiZ (MickLesk) 448a080970 build.func: filter templates by host architecture during search (#16302) 2026-08-06 22:33:22 +10:00
community-scripts-pr-app[bot] c45c3f3a6c Update CHANGELOG.md (#16308)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-06 12:29:33 +00:00
CanbiZ (MickLesk) 12f228da1c paperless: change update abort message (endless spinner) (#16299) 2026-08-06 14:28:58 +02:00
community-scripts-pr-app[bot] ecd115c279 Update CHANGELOG.md (#16306)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-06 12:27:06 +00:00
CanbiZ (MickLesk) 288a130fe7 Vikunja: remove version pin, v2.5.0 fixes the systemd syscall filter crash (#16300) 2026-08-06 14:26:40 +02:00
20 changed files with 415 additions and 63 deletions
+18 -2
View File
@@ -314,12 +314,17 @@ jobs:
// ── Allow-lists (mirror the slash bot) ─────────────────────────────
const ALLOWED_FIELDS = {
name: 'string', description: 'string', logo: 'string', documentation: 'string',
website: 'string', project_url: 'string', github: 'string', config_path: 'string',
website: 'string', project_url: 'string', repository: 'string', config_path: 'string',
tags: 'string', port: 'number', default_user: 'nullable_string', default_passwd: 'nullable_string',
unprivileged: 'number', updateable: 'boolean', privileged: 'boolean', has_arm: 'boolean',
unprivileged: 'number', updateable: 'boolean', privileged: 'boolean',
architectures: 'select_list', platforms: 'select_list',
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' };
@@ -339,6 +344,17 @@ 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) };
}
+25 -6
View File
@@ -323,9 +323,10 @@ 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` `github` ' +
'**Editable fields:** `name` `description` `logo` `documentation` `website` `project_url` `repository` ' +
'`config_path` `port` `default_user` `default_passwd` ' +
'`updateable` `privileged` `has_arm` `is_dev` ' +
'`updateable` `privileged` `is_dev` ' +
'`architectures` (amd64,arm64) `platforms` (pve,incus) ' +
'`is_disabled` `disable_message` `is_deleted` `deleted_message`';
if (!withoutCmd) {
@@ -504,7 +505,8 @@ 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('- **ARM:** ' + (record.has_arm ? 'Yes' : 'No'));
out.push('- **Architectures:** ' + ((record.architectures || []).join(', ') || 'amd64'));
out.push('- **Platforms:** ' + ((record.platforms || []).join(', ') || 'pve'));
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 : ''));
@@ -838,7 +840,7 @@ jobs:
const fieldName = setMatch[1].toLowerCase();
const SET_ALLOWED = {
name: 'string', description: 'string', logo: 'string',
documentation: 'string', website: 'string', project_url: 'string', github: 'string',
documentation: 'string', website: 'string', project_url: 'string', repository: 'string',
config_path: 'string', disable_message: 'string', deleted_message: 'string'
};
if (!SET_ALLOWED[fieldName]) {
@@ -888,7 +890,7 @@ jobs:
documentation: 'string',
website: 'string',
project_url: 'string',
github: 'string',
repository: 'string',
config_path: 'string',
tags: 'string',
port: 'number',
@@ -897,7 +899,8 @@ jobs:
unprivileged: 'number',
updateable: 'boolean',
privileged: 'boolean',
has_arm: 'boolean',
architectures: 'select_list',
platforms: 'select_list',
is_dev: 'boolean',
is_disabled: 'boolean',
disable_message: 'string',
@@ -924,6 +927,10 @@ 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];
@@ -943,6 +950,18 @@ 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 {
+13 -1
View File
@@ -179,7 +179,19 @@ 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;
if (data.has_arm !== undefined) payload.has_arm = data.has_arm === true || data.has_arm === 'true';
// 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.version !== undefined) payload.version = data.version;
if (data.changelog !== undefined) payload.changelog = data.changelog;
if (data.screenshots !== undefined) payload.screenshots = data.screenshots;
+32
View File
@@ -518,6 +518,38 @@ 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
+49
View File
@@ -103,6 +103,55 @@ 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)**
+5
View File
@@ -18,6 +18,7 @@ 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:-}"
@@ -64,6 +65,10 @@ 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
+6
View File
@@ -0,0 +1,6 @@
____ _
/ _/___ _____ (_)____
/ // __ `/ __ \/ / ___/
_/ // /_/ / / / / (__ )
/___/\__, /_/ /_/_/____/
/____/
+79
View File
@@ -0,0 +1,79 @@
#!/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}"
+10 -1
View File
@@ -214,7 +214,16 @@ EOF
cd "$SRC_DIR"
export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml
export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg
$STD mise install
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
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
+3
View File
@@ -17,6 +17,9 @@ 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
View File
@@ -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_info "Update aborted. Decrypt all documents before upgrading to v3."
msg_custom "⚠️" "Update aborted. Decrypt all documents before upgrading to v3."
exit 0
fi
fi
+2 -3
View File
@@ -46,8 +46,7 @@ function update_script() {
[[ "$CONFIRM2" =~ ^[yY]$ ]] || exit 0
fi
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
if check_for_gh_release "vikunja" "go-vikunja/vikunja"; 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}"
@@ -66,7 +65,7 @@ function update_script() {
systemctl stop vikunja
msg_ok "Stopped Service"
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "${RELEASE}" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
$STD systemctl daemon-reload
msg_info "Starting Service"
-1
View File
@@ -83,7 +83,6 @@ $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
+113
View File
@@ -0,0 +1,113 @@
#!/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
+10 -1
View File
@@ -355,7 +355,16 @@ cp LICENSE "$APP_DIR"
cd "$SRC_DIR"
export MISE_TRUSTED_CONFIG_PATHS="$SRC_DIR"/mise.toml
export MISE_DISABLE_TOOLS=github:jellyfin/jellyfin-ffmpeg
$STD mise install
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
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
+11 -2
View File
@@ -27,9 +27,18 @@ 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 -rp "${TAB3}Enter your Pangolin URL (ex: https://pangolin.example.com): " pango_url
# 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
[[ "$pango_url" != https://* && "$pango_url" != http://* ]] && pango_url="https://${pango_url}"
read -rp "${TAB3}Enter your email address: " pango_email
pango_email="${var_pangolin_email:-}"
if [[ -z "$pango_email" ]]; then
read -rp "${TAB3}Enter your email address: " pango_email
fi
msg_info "Setup Pangolin"
SECRET_KEY=$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 32)
+1 -2
View File
@@ -13,8 +13,7 @@ setting_up_container
network_check
update_os
RELEASE="v2.3.0"
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "${RELEASE}" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
fetch_and_deploy_gh_release "vikunja" "go-vikunja/vikunja" "binary" "latest" "" "vikunja-*-$(arch_resolve "x86_64" "aarch64").deb"
msg_info "Setting up Vikunja"
sed -i 's|^# \(service:\)|\1|' /etc/vikunja/config.yml
+8 -3
View File
@@ -922,8 +922,10 @@ 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 '\.(tar\.zst|tar\.xz|tar\.gz)$' |
grep -E "_${arch}\.(tar\.zst|tar\.xz|tar\.gz)([[:space:]]|$)" |
awk '{print $2}' |
sed -nE "s/^${ostype}-([0-9]+(\.[0-9]+)?).*/\1/p" |
sort -u -V || true
@@ -936,8 +938,10 @@ _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 '\.(tar\.zst|tar\.xz|tar\.gz)$' |
grep -E "_${arch}\.(tar\.zst|tar\.xz|tar\.gz)([[:space:]]|$)" |
awk '{print $2}' |
grep -E "^${search}.*${pattern}" |
sort -t - -k 2 -V || true
@@ -6721,7 +6725,8 @@ 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}" '$1 ~ search && $1 ~ pattern {print $1}' |
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}' |
sed 's|.*/||' | sort -t - -k 2 -V
)
+29 -28
View File
@@ -2576,11 +2576,6 @@ _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" || {
@@ -2607,38 +2602,44 @@ _deploy_unpacked_archive() {
return 65
fi
local top_entries inner_dir
local top_entries inner_dir source_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"
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
source_dir="$inner_dir"
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
}
source_dir="$workdir"
fi
shopt -s dotglob nullglob
if ! compgen -G "$source_dir/*" >/dev/null; then
if [[ -n "$inner_dir" ]]; then
msg_error "Inner directory is empty: $inner_dir"
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
}
-12
View File
@@ -125,12 +125,6 @@ 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)
@@ -288,12 +282,6 @@ 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" \