Compare commits

...
Author SHA1 Message Date
CanbiZ (MickLesk) 422fec4b0c arm64 unknown 2026-11-07 21:04:23 +01:00
push-app-to-main[bot] b0154bca84 Add pixelfed (ct) 2026-11-07 19:58:08 +00:00
community-scripts-pr-app[bot]andgithub-actions[bot] fbbbc55699 Update CHANGELOG.md (#18518)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-07 19:54:21 +00:00
community-scripts-pr-app[bot]andgithub-actions[bot] 6ad67ca11e Update CHANGELOG.md (#18517)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-07 19:53:59 +00:00
Tobias 68c1309517 fix: gotenberg: update to v9 (#18491) 2026-11-07 20:53:53 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] 53c32f293b Update CHANGELOG.md (#18508)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-07 20:53:36 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] 1d5fdefc4e Update CHANGELOG.md (#18509)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-07 00:40:43 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] 6a0c9b002d Update CHANGELOG.md (#18507)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-06 22:51:59 +00:00
CanbiZ (MickLesk) 81d218adc2 fix(umbrel-os-vm): report runs as ProxmoxVE, not DevScripts (#18497)
The script kept the DevScripts base URL from the refactor in #17505, so every production run was filed under DevScripts in telemetry.
2026-11-06 23:51:57 +01:00
CanbiZ (MickLesk) 125c2c44a7 ci: reject DevScripts URLs in scripts (#18498)
openwrt-vm and umbrel-os-vm kept the DevScripts base URL when they moved over, and telemetry filed their production runs under DevScripts. The check fails a pull request that adds such a URL to ct, install, vm or tools.
2026-11-06 23:51:35 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] d63c98936b Update CHANGELOG.md (#18506)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-06 22:50:56 +00:00
CanbiZ (MickLesk) df10e1d2dd Technitium DNS: read the version from its GitHub releases (#18425)
The version came from scraping technitium.com, which failed for some hosts ("Command substitution exited with status 1", 6 runs on 4 hosts in three days) and has no rate-limit fallback. The GitHub release carries the same version and goes through the engine's release lookup.
2026-11-06 23:50:54 +01:00
CanbiZ (MickLesk) 50c5b786e4 Caddy: skip the xCaddy test build below 2 GB RAM (#18472)
* fix(caddy): skip the xCaddy test build below 2 GB RAM

The container defaults to 512 MB (256 MB on Alpine), and Go's linker was
killed in xcaddy build: 14 runs on 6 hosts in a week. The build only
produced an unused binary, so below 2 GB xCaddy is installed without it
and a warning says why; install and update alike.

* Change directory to /opt before building xCaddy
2026-11-06 23:50:49 +01:00
CanbiZ (MickLesk) 3c0e693c2d fix(thingsboard): keep the package defaults in thingsboard.conf (#18499)
The install replaced the file, which dropped JAVA_OPTS with install.data_dir, so creating a tenant failed. The DB settings are now appended, and an update restores the defaults on existing containers. The package upgrade keeps the edited file. Fixes #18483.
2026-11-06 23:50:29 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] d8f3874f42 Update CHANGELOG.md (#18505)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-06 22:47:00 +00:00
CanbiZ (MickLesk) 1a2bbb06bb fix(nexterm): keep the extracted app out of the /tmp cleanup (#18501)
The server unpacks its frontend into /tmp/nexterm-sea-*. systemd-tmpfiles removes it after 10 days while the process keeps running, and every page returns 404. Fixes #18488.
2026-11-06 23:46:31 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] 996900f145 Update CHANGELOG.md (#18504)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-06 22:42:46 +00:00
CanbiZ (MickLesk) bc348949c4 fix(planka): run the service with node instead of nodemon (#18503)
npm 12 rejects --prod, and --production still starts PLANKA through nodemon. Starting node app.js directly needs HOME: Sails 1.5.18 only looks for the project's .sailsrc when HOME is set, and systemd sets none without User=, so the app lifted with the wrong paths and returned 503. The unit now sets NODE_ENV and HOME, and an update repairs existing units even without a new release. Follow-up to #18477.
2026-11-06 23:42:25 +01:00
CanbiZ (MickLesk) 5720358d1b MeTube/Yubal: install Deno without its shell setup (#18406)
* MeTube: install Deno without its shell setup

With -y, deno's install.sh also fetches jsr:@deno/installer-shell-setup to edit the shell profile, and when jsr.io did not answer the install stopped ("JSR package manifest ... failed to load"). Deno goes to /usr/local/bin, which is on PATH, so the shell setup is not needed; CI=1 keeps the installer from asking for it on a terminal.

* Modify Deno installation command

Update Deno installation command to include CI environment variable.
2026-11-06 23:42:22 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] ebf9cf656e Update CHANGELOG.md (#18502)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-06 18:32:26 +00:00
CanbiZ (MickLesk) c5c406b392 OPNsense VM: size the temp space check to the unpacked image | say why the EFI disk could not be allocated (#18404)
* OPNsense VM: size the temp space check to the unpacked image

The script refused to run unless TEMP_DIR had 20 GB free, a figure left
over from when the download went there too. The download now goes to the
image cache and only the unpacked FreeBSD image (2.5 GB) lands in
TEMP_DIR, so hosts with 8 to 16 GB free in /tmp stopped with exit 214.
Check the size xz reports for the image instead.

* OPNsense VM: say why the EFI disk could not be allocated

pvesm's error went to stderr only, so the two exit 220 runs in telemetry
carry no reason. As msg_error it reaches the log and the trace, e.g.
"disk image '.../vm-969-disk-0.qcow2' already exists" after an earlier
run left its disk on a storage that qm destroy does not clean.

* Clean up comments in opnsense-vm.sh

Removed comments about image cache and size calculation.
2026-11-06 19:31:58 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] 745043bd9a Update CHANGELOG.md (#18490)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-06 07:58:59 +00:00
community-scripts-pr-app[bot]andgithub-actions[bot] c0df6c9870 Update CHANGELOG.md (#18486)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-05 20:22:30 +00:00
CanbiZ (MickLesk) 5e5e840458 fix(openwrt-vm): leave the NIC untagged on a bridge without a port (#18473)
Advanced mode prefills the LAN VLAN with 999. On a bridge with no
physical port that is not VLAN-aware (an internal vmbr1, the usual LAN
choice) pve-bridge cannot tag the tap, and qm start failed with "no
physical interface on bridge 'vmbr1'". The tag is dropped there with a
warning, for LAN and WAN alike.

The scripts base still pointed at DevScripts, where this script was
removed on 10-09, so every run was reported as a DevScripts run.
2026-11-05 21:21:58 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] 4adef93eb9 Update CHANGELOG.md (#18485)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-05 20:21:25 +00:00
CanbiZ (MickLesk) 94aa8e7ab0 fix(podman): skip Portainer where Podman has no Quadlet (#18469)
Portainer and the agent are written as Quadlet .container units, which
need Podman 4.4. Debian 12 ships 4.3.1, so systemctl start portainer
failed with "Unit portainer.service not found". Without Quadlet both
prompts are skipped with a warning.
2026-11-05 21:20:55 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] eb7d180f9f Update CHANGELOG.md (#18484)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-05 20:18:12 +00:00
CanbiZ (MickLesk) 6e6ca04f24 truenas-VM: let a failed ISO lookup reach its own error (#18476)
* fix(truenas-vm): let a failed ISO lookup reach its own error

When download.truenas.com did not answer, the lookup handed an empty
path to an associative array (bad array subscript) and the pipeline
failed under pipefail, so the run ended with exit 1 at the SELECTED_ISO
line instead of the "Could not find a stable ISO" message. The index
fetch now fails on HTTP errors and retries, empty lines are skipped, and
the assignment no longer aborts on an empty result.

* fix(truenas-vm): use the engine's retry flags for the ISO index
2026-11-05 21:17:45 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] ce04c99aa2 Update CHANGELOG.md (#18482)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-05 16:23:05 +00:00
CanbiZ (MickLesk) df705aefc4 proxmox-mail-gateway: take the repo suite from the container (#18475)
* fix(proxmox-mail-gateway): take the repo suite from the container

The install hardcoded trixie, so a Debian 12 container got the PMG 9
repository and pmg-api could not resolve its trixie dependencies (held
broken packages). Suite and key now follow the container's codename;
bookworm still has PMG 8 with proxmox-mailgateway-container.

* fix(proxmox-mail-gateway): read the codename inline
2026-11-05 17:22:36 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] 4fd7aa7edb Update CHANGELOG.md (#18481)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-05 15:32:06 +00:00
CanbiZ (MickLesk) c55556144a Immich: Bump to 3.3.6 and minor improvement (#18474)
* fix(immich): take the watchfiles wheel and retry GeoNames longer

The v3.3.5 lock pins watchfiles 0.21.0, which has no wheel for the
Python 3.13 machine-learning venv, so every ML install downloaded a Rust
toolchain and compiled it. Where static.rust-lang.org reset the
connection, uv sync failed three times. --upgrade-package watchfiles
takes 1.3.0, an abi3 wheel; only uvicorn's reload mode uses it.

download.geonames.org dropped connections on 11-03/04 and the first file
failed after three 10 s connects; those four calls now retry six times
with a 30 s connect timeout.

* Immich: bump release version to v3.3.6

v3.3.6 disables onnxruntime's telemetry in immich_ml, which runs from
source here, so nothing else changes. The lock still pins watchfiles
0.21.0, so the wheel upgrade stays.
2026-11-05 16:31:37 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] 43481c25fd Update CHANGELOG.md (#18480)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-05 14:25:17 +00:00
CerberusStyle d2970719e4 Change npm start argument to --production (#18478)
* Change npm start argument to --production

* update service with --production

* Reload systemd daemon after updating service file
2026-11-05 15:24:44 +01:00
community-scripts-pr-app[bot]andgithub-actions[bot] 215f9be228 Update CHANGELOG.md (#18468)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-05 10:57:03 +00:00
CanbiZ (MickLesk) 3e7fcf1350 Arcane: write both env names, stop shipping the unused .env (#18466)
The compose file from main now uses ARCANE_ENCRYPTION_KEY and
ARCANE_PROJECTS_DIRECTORY, which the latest image (2.17.3) does not read,
so it panicked on a missing ENCRYPTION_KEY. Arcane 3 in turn refuses to
start when only the old names are set. Install and update now keep both
names in compose.yaml, which also carries existing installs over to 3.

The .env was never referenced by the compose file, but compose parses it,
and the unanchored ENCRYPTION_KEY sed turned the renamed line into
ARCANE_#ENCRYPTION_KEY and broke every install. New installs no longer
download it; update repairs the broken line.
2026-11-05 11:56:39 +01:00
CanbiZ (MickLesk) 8ba3582919 OPNsense VM: wait for the FreeBSD login prompt instead of 180 seconds (#18467)
The FreeBSD image boots in under a minute when both NICs get DHCP, but
dhclient waits 60 seconds on each NIC without a DHCP server, which is the
normal case for a firewall's LAN before setup. On vx-pve an isolated LAN
took 110 seconds; the reporter of #18464 measured 210. The keys then went
into the boot output. The image prints its login prompt on the serial
console as well, so the script now reads serial0 and continues when it
appears, up to 15 minutes, or waits the old 3 minutes if the console
cannot be read.
2026-11-05 11:56:32 +01:00
CanbiZ (MickLesk) 37e4a33615 Tududi: run 2.0 on PostgreSQL, keep SQLite installs on 1.15.0 (#18465)
Tududi 2.0.0 dropped SQLite and refuses to start next to a populated 1.x
database. New installs set up PostgreSQL and let start.sh create the
schema; db:init would sync the tables without SequelizeMeta and make
db-prepare treat the database as an old 1.x one. Installs without
DATABASE_URL stay on 1.15.0, the final SQLite release, which also brings
back installs that already updated to 2.0.0.

Uploads lived in backend/uploads, which CLEAN_INSTALL wiped on every
update; they move to /opt/tududi-uploads.
2026-11-05 11:56:29 +01:00
30 changed files with 615 additions and 118 deletions

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
name: Check Script Repo URL
on:
pull_request:
branches: ["main"]
paths:
- "ct/**"
- "install/**"
- "vm/**"
- "tools/**"
permissions:
contents: read
jobs:
check:
if: github.repository == 'community-scripts/ProxmoxVE'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Reject DevScripts URLs
run: |
if grep -rnE 'community-scripts/(ProxmoxVED|DevScripts)/' ct install vm tools; then
echo "::error::These lines point at DevScripts, so telemetry files the runs there. Use community-scripts/ProxmoxVE."
exit 1
fi
+64
View File
@@ -571,6 +571,70 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-11-07
### 🚀 Updated Scripts
- #### 💥 Breaking Changes
- fix: gotenberg: update to v9 [@CrazyWolf13](https://github.com/CrazyWolf13) ([#18491](https://github.com/community-scripts/ProxmoxVE/pull/18491))
## 2026-11-06
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- UmbrelOS-VM: report runs as ProxmoxVE, not DevScripts [@MickLesk](https://github.com/MickLesk) ([#18497](https://github.com/community-scripts/ProxmoxVE/pull/18497))
- Caddy: skip the xCaddy test build below 2 GB RAM [@MickLesk](https://github.com/MickLesk) ([#18472](https://github.com/community-scripts/ProxmoxVE/pull/18472))
- Thingsboard: keep the package defaults in thingsboard.conf [@MickLesk](https://github.com/MickLesk) ([#18499](https://github.com/community-scripts/ProxmoxVE/pull/18499))
- Nexterm: keep the extracted app out of the /tmp cleanup [@MickLesk](https://github.com/MickLesk) ([#18501](https://github.com/community-scripts/ProxmoxVE/pull/18501))
- PLANKA: run the service with node instead of nodemon [@MickLesk](https://github.com/MickLesk) ([#18503](https://github.com/community-scripts/ProxmoxVE/pull/18503))
- MeTube/Yubal: install Deno without its shell setup [@MickLesk](https://github.com/MickLesk) ([#18406](https://github.com/community-scripts/ProxmoxVE/pull/18406))
- OPNsense VM: size the temp space check to the unpacked image | say why the EFI disk could not be allocated [@MickLesk](https://github.com/MickLesk) ([#18404](https://github.com/community-scripts/ProxmoxVE/pull/18404))
- #### 🔧 Refactor
- Technitium DNS: read the version from its GitHub releases [@MickLesk](https://github.com/MickLesk) ([#18425](https://github.com/community-scripts/ProxmoxVE/pull/18425))
### 💾 Core
- fix: spot same-filesystem bind mounts on Alpine [@rcourtman](https://github.com/rcourtman) ([core#212](https://github.com/community-scripts/core/pull/212))
- fix: report a container that went down during setup, keep finished installs [@MickLesk](https://github.com/MickLesk) ([core#211](https://github.com/community-scripts/core/pull/211))
### 📚 Documentation
- ci: reject DevScripts URLs in scripts [@MickLesk](https://github.com/MickLesk) ([#18498](https://github.com/community-scripts/ProxmoxVE/pull/18498))
## 2026-11-05
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- OpenWRT-VM: leave the NIC untagged on a bridge without a port [@MickLesk](https://github.com/MickLesk) ([#18473](https://github.com/community-scripts/ProxmoxVE/pull/18473))
- Podman: skip Portainer where Podman has no Quadlet [@MickLesk](https://github.com/MickLesk) ([#18469](https://github.com/community-scripts/ProxmoxVE/pull/18469))
- Planka: change npm start argument to --production [@CerberusStyle](https://github.com/CerberusStyle) ([#18478](https://github.com/community-scripts/ProxmoxVE/pull/18478))
- OPNsense VM: wait for the FreeBSD login prompt instead of 180 seconds [@MickLesk](https://github.com/MickLesk) ([#18467](https://github.com/community-scripts/ProxmoxVE/pull/18467))
- #### 🔧 Refactor
- truenas-VM: let a failed ISO lookup reach its own error [@MickLesk](https://github.com/MickLesk) ([#18476](https://github.com/community-scripts/ProxmoxVE/pull/18476))
- proxmox-mail-gateway: take the repo suite from the container [@MickLesk](https://github.com/MickLesk) ([#18475](https://github.com/community-scripts/ProxmoxVE/pull/18475))
- Immich: Bump to 3.3.6 and minor improvement [@MickLesk](https://github.com/MickLesk) ([#18474](https://github.com/community-scripts/ProxmoxVE/pull/18474))
- Tududi: run 2.0 on PostgreSQL, keep SQLite installs on 1.15.0 [@MickLesk](https://github.com/MickLesk) ([#18465](https://github.com/community-scripts/ProxmoxVE/pull/18465))
### 💾 Core
- fix: keep the existing install until the new archive has extracted [@rcourtman](https://github.com/rcourtman) ([core#201](https://github.com/community-scripts/core/pull/201))
- fix: keep the install when a clone or an Alpine extract fails [@rcourtman](https://github.com/rcourtman) ([core#210](https://github.com/community-scripts/core/pull/210))
### 🧰 Tools
- #### 🐞 Bug Fixes
- Arcane: write both env names, stop shipping the unused .env [@MickLesk](https://github.com/MickLesk) ([#18466](https://github.com/community-scripts/ProxmoxVE/pull/18466))
## 2026-11-04
### 🚀 Updated Scripts
+7 -3
View File
@@ -55,9 +55,13 @@ update_deb_based() {
setup_go
fetch_and_deploy_gh_release "xcaddy" "caddyserver/xcaddy" "binary"
msg_info "Updating xCaddy"
$STD xcaddy build
msg_ok "Updated xCaddy"
if (($(awk '/^MemTotal:/ {print int($2 / 1024)}' /proc/meminfo) < 1900)); then
msg_warn "xCaddy updated; its test build was skipped because linking Caddy needs about 2 GB RAM"
else
msg_info "Updating xCaddy"
$STD xcaddy build
msg_ok "Updated xCaddy"
fi
fi
fi
msg_ok "Updated successfully!"
+23 -6
View File
@@ -45,15 +45,32 @@ function update_script() {
export CGO_ENABLED=0
$STD go mod download
$STD go build -o /usr/local/bin/gotenberg \
-ldflags "-s -w -X 'github.com/gotenberg/gotenberg/v8/cmd.Version=$(cat ~/.gotenberg)'" \
-ldflags "-s -w -X 'github.com/gotenberg/gotenberg/v9/cmd.Version=$(cat ~/.gotenberg)'" \
cmd/gotenberg/main.go
msg_ok "Built gotenberg"
msg_info "Updating unoconverter"
UNOCONVERTER_VERSION=$(get_latest_github_release "gotenberg/unoconverter" "false")
download_file "https://raw.githubusercontent.com/gotenberg/unoconverter/${UNOCONVERTER_VERSION}/unoconv" /usr/local/bin/unoconverter
chmod +x /usr/local/bin/unoconverter
msg_ok "Updated unoconverter"
LOK_VERSION="$(awk -F= '/^ARG LOK_VERSION=/{print $2}' /opt/gotenberg/build/Dockerfile)"
fetch_and_deploy_gh_release "lok" "gotenberg/lok" "prebuild" "$LOK_VERSION" "/usr/local/bin" "lok_${LOK_VERSION#v}_linux_$(arch_resolve "amd64" "arm64").tar.gz"
msg_info "Migrating to Gotenberg 9"
CODENAME=$(get_os_info codename)
setup_deb822_repo \
"debian-backports" \
"file:///usr/share/keyrings/debian-archive-keyring.gpg" \
"http://deb.debian.org/debian" \
"${CODENAME}-backports" \
"main"
$STD apt install -y fonts-urw-base35
$STD apt install -y -t "${CODENAME}-backports" \
libreoffice-writer libreoffice-calc libreoffice-impress libreoffice-draw libreoffice-math
$STD apt purge -y python3-uno python-is-python3 pdftk-java qpdf libimage-exiftool-perl
$STD apt autoremove -y
rm -rf /usr/local/bin/unoconverter /usr/local/bin/pdfcpu /opt/pdfcpu
sed -i '/^Environment=\(UNOCONVERTER\|PDFTK\|QPDF\|EXIFTOOL\|PDFCPU\)_BIN_PATH=/d' /etc/systemd/system/gotenberg.service
grep -q '^Environment=LOK_BIN_PATH=' /etc/systemd/system/gotenberg.service ||
sed -i '/^Environment=LIBREOFFICE_BIN_PATH=/a Environment=LOK_BIN_PATH=/usr/local/bin/lok' /etc/systemd/system/gotenberg.service
systemctl daemon-reload
msg_ok "Migrated to Gotenberg 9"
msg_info "Starting Service"
systemctl start gotenberg
+3 -3
View File
@@ -75,7 +75,7 @@ EOF
BASE_DIR=${STAGING_DIR}/base-images
SOURCE_DIR=${STAGING_DIR}/image-source
cd /tmp
RELEASE="v3.3.5"
RELEASE="v3.3.6"
if [[ -f ~/.intel_version ]]; then
INTEL_SRC="https://raw.githubusercontent.com/immich-app/immich/${RELEASE}/machine-learning"
curl -fsSL "${INTEL_SRC}/scripts/install-intel-runtime.sh" -o ./intel-runtime 2>/dev/null ||
@@ -292,7 +292,7 @@ EOF
msg_ok "Pre-installed Python ${ML_PYTHON}"
msg_info "Updating Intel OpenVINO machine-learning"
for attempt in $(seq 1 3); do
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT,UV_CONCURRENT_DOWNLOADS,UV_CONCURRENT_BUILDS,UV_CONCURRENT_INSTALLS -Pnu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT,UV_CONCURRENT_DOWNLOADS,UV_CONCURRENT_BUILDS,UV_CONCURRENT_INSTALLS -Pnu immich uv sync --extra openvino --no-dev --upgrade-package watchfiles --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
[[ $attempt -eq 3 ]] && { ML_FAILED=1; break; }
# Parallel fetches can trip DNS rate limits (AdGuard, Pi-hole); retry one at a time.
export UV_CONCURRENT_DOWNLOADS=1 UV_CONCURRENT_BUILDS=1 UV_CONCURRENT_INSTALLS=1
@@ -310,7 +310,7 @@ EOF
msg_ok "Pre-installed Python ${ML_PYTHON}"
msg_info "Updating machine-learning"
for attempt in $(seq 1 3); do
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT,UV_CONCURRENT_DOWNLOADS,UV_CONCURRENT_BUILDS,UV_CONCURRENT_INSTALLS -Pnu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT,UV_CONCURRENT_DOWNLOADS,UV_CONCURRENT_BUILDS,UV_CONCURRENT_INSTALLS -Pnu immich uv sync --extra cpu --no-dev --upgrade-package watchfiles --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
[[ $attempt -eq 3 ]] && { ML_FAILED=1; break; }
# Parallel fetches can trip DNS rate limits (AdGuard, Pi-hole); retry one at a time.
export UV_CONCURRENT_DOWNLOADS=1 UV_CONCURRENT_BUILDS=1 UV_CONCURRENT_INSTALLS=1
+1 -1
View File
@@ -36,7 +36,7 @@ function update_script() {
source ~/.bashrc
if ! command -v deno &>/dev/null; then
export DENO_INSTALL="/usr/local"
curl -fsSL https://deno.land/install.sh | $STD sh -s -- -y
curl -fsSL https://deno.land/install.sh | CI=1 $STD sh -s
else
$STD deno upgrade
fi
+3
View File
@@ -31,6 +31,8 @@ function update_script() {
exit
fi
echo "x /tmp/nexterm-sea-*" >/etc/tmpfiles.d/nexterm.conf
if check_for_gh_release "nexterm-engine" "gnmyt/Nexterm"; then
msg_info "Stopping nexterm-engine"
systemctl stop nexterm-engine
@@ -46,6 +48,7 @@ function update_script() {
if check_for_gh_release "nexterm-server" "gnmyt/Nexterm"; then
msg_info "Stopping nexterm-server"
systemctl stop nexterm-server
rm -rf /tmp/nexterm-sea-*
msg_ok "Stopped nexterm-server"
fetch_and_deploy_gh_release "nexterm-server" "gnmyt/Nexterm" "singlefile" "latest" "/opt/nexterm/server" "nexterm-server-linux-$(arch_resolve "x64" "arm64")"
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
_cs_boot="${COMMUNITY_SCRIPTS_CORE_DIR:-$(dirname "${BASH_SOURCE[0]}")/../../core}/core/build.func"
source "$_cs_boot" 2>/dev/null || source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/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://pixelfed.org/
APP="Pixelfed"
var_tags="${var_tags:-fediverse;social}"
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_arm64="${var_arm64:-no}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -d /opt/pixelfed ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
if check_for_gh_release "pixelfed" "pixelfed/pixelfed"; then
msg_info "Stopping Services"
systemctl stop pixelfed-horizon pixelfed-scheduler.timer
msg_ok "Services stopped"
create_backup /opt/pixelfed/.env \
/opt/pixelfed/storage
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "pixelfed" "pixelfed/pixelfed" "tarball" "latest" "/opt/pixelfed"
restore_backup
msg_info "Updating Pixelfed"
cd /opt/pixelfed
chmod -R 755 /opt/pixelfed
chmod -R 775 /opt/pixelfed/storage /opt/pixelfed/bootstrap/cache
export COMPOSER_ALLOW_SUPERUSER=1
$STD composer install --no-dev --no-ansi --no-interaction --optimize-autoloader
chown -R pixelfed:pixelfed /opt/pixelfed
$STD sudo -u pixelfed php artisan storage:link
$STD sudo -u pixelfed php artisan migrate --force
$STD sudo -u pixelfed php artisan route:cache
$STD sudo -u pixelfed php artisan view:cache
$STD sudo -u pixelfed php artisan config:cache
$STD sudo -u pixelfed php artisan horizon:publish
msg_ok "Updated Pixelfed"
msg_info "Starting Services"
systemctl start pixelfed-horizon pixelfed-scheduler.timer
msg_ok "Services started"
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}${CL}"
echo -e "${INFO}${YW} Create an admin account with:${CL}"
echo -e "${TAB}cd /opt/pixelfed && sudo -u pixelfed php artisan user:create"
+9
View File
@@ -30,6 +30,15 @@ function update_script() {
msg_error "No ${APP} Installation Found!"
exit
fi
if ! grep -q "^Environment=HOME=" /etc/systemd/system/planka.service; then
msg_info "Updating Service"
sed -i -e '/^Environment=NODE_ENV=/d' -e 's|^ExecStart=.*|Environment=NODE_ENV=production\nEnvironment=HOME=/root\nExecStart=/usr/bin/node app.js --prod|' /etc/systemd/system/planka.service
systemctl daemon-reload
systemctl restart planka
msg_ok "Updated Service"
fi
if check_for_gh_release "planka" "plankanban/planka"; then
msg_info "Stopping Service"
systemctl stop planka
+1 -1
View File
@@ -47,7 +47,7 @@ function update_script() {
$STD apt install -y aspnetcore-runtime-10.0
fi
RELEASE=$(curl -fsSL https://technitium.com/dns/ | grep -oP 'Version \K[\d.]+')
RELEASE=$(get_latest_github_release "TechnitiumSoftware/DnsServer")
if [[ ! -f ~/.technitium || ${RELEASE} != "$(cat ~/.technitium 2>/dev/null)" ]]; then
fetch_and_deploy_from_url "https://download.technitium.com/dns/DnsServerPortable.tar.gz" /opt/technitium/dns
echo "${RELEASE}" >~/.technitium
+19 -1
View File
@@ -31,12 +31,30 @@ function update_script() {
fi
JAVA_VERSION="25" setup_java
if ! grep -q "install.data_dir" /etc/thingsboard/conf/thingsboard.conf; then
msg_info "Restoring Package Defaults"
cat <<'EOF' >>/etc/thingsboard/conf/thingsboard.conf
export JAVA_OPTS="$JAVA_OPTS -Dplatform=deb -Dinstall.data_dir=/usr/share/thingsboard/data"
export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/thingsboard/gc.log:time,uptime,level,tags:filecount=10,filesize=10M"
export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError"
export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark"
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10"
export LOG_FILENAME=thingsboard.out
export LOADER_PATH=/usr/share/thingsboard/conf,/usr/share/thingsboard/extensions
export SQL_DATA_FOLDER=/usr/share/thingsboard/data/sql
EOF
systemctl restart thingsboard
msg_ok "Restored Package Defaults"
fi
if check_for_gh_release "thingsboard" "thingsboard/thingsboard"; then
msg_info "Stopping Service"
systemctl stop thingsboard
msg_ok "Stopped Service"
fetch_and_deploy_gh_release "thingsboard" "thingsboard/thingsboard" "binary" "latest" "/tmp" "thingsboard-*.deb"
DPKG_FORCE_CONFOLD=1 fetch_and_deploy_gh_release "thingsboard" "thingsboard/thingsboard" "binary" "latest" "/tmp" "thingsboard-*.deb"
msg_info "Running Database Upgrade"
$STD /usr/share/thingsboard/bin/install/upgrade.sh
+14 -2
View File
@@ -32,7 +32,14 @@ function update_script() {
NODE_VERSION="22" setup_nodejs
if check_for_gh_release "tududi" "chrisvel/tududi"; then
RELEASE=""
if ! grep -qs '^DATABASE_URL=' /opt/tududi/backend/.env; then
RELEASE="v1.15.0"
msg_warn "Tududi 2.0 runs on PostgreSQL only, so this SQLite install stays on 1.15.0"
msg_warn "To move to 2.0, export in Settings > Backups and import into a new Tududi LXC"
fi
if check_for_gh_release "tududi" "chrisvel/tududi" "${RELEASE}" "2.0 needs PostgreSQL"; then
msg_info "Stopping Service"
systemctl stop tududi
msg_ok "Stopped Service"
@@ -43,9 +50,14 @@ function update_script() {
else
cp /opt/tududi/.env /opt/tududi.env
fi
if ! grep -q '^TUDUDI_UPLOAD_PATH=' /opt/tududi.env; then
mkdir -p /opt/tududi-uploads
[[ -d /opt/tududi/backend/uploads ]] && cp -a /opt/tududi/backend/uploads/. /opt/tududi-uploads/
echo "TUDUDI_UPLOAD_PATH=/opt/tududi-uploads" >>/opt/tududi.env
fi
msg_ok "Backed up env file"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "tududi" "chrisvel/tududi" "tarball" "latest" "/opt/tududi"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "tududi" "chrisvel/tududi" "tarball" "${CHECK_UPDATE_RELEASE}" "/opt/tududi"
msg_info "Updating Tududi"
cd /opt/tududi
+16 -7
View File
@@ -23,10 +23,15 @@ setup_deb_based() {
setup_go
fetch_and_deploy_gh_release "xcaddy" "caddyserver/xcaddy" "binary"
msg_info "Setup xCaddy"
$STD apt install -y git
$STD xcaddy build
msg_ok "Setup xCaddy"
if (($(awk '/^MemTotal:/ {print int($2 / 1024)}' /proc/meminfo) < 1900)); then
msg_warn "xCaddy is installed; its test build was skipped because linking Caddy needs about 2 GB RAM"
else
msg_info "Setup xCaddy"
cd /opt
$STD xcaddy build
msg_ok "Setup xCaddy"
fi
fi
}
@@ -69,10 +74,14 @@ EOF
GO_VERSION="$(curl -fsSL https://go.dev/VERSION?m=text | head -1 | cut -c3-)" setup_go
fetch_and_deploy_gh_release "xcaddy" "caddyserver/xcaddy" "prebuild" "latest" "/opt/xcaddy" "xcaddy_*_linux_$(arch_resolve).tar.gz"
ln -sf /opt/xcaddy/xcaddy /usr/local/bin/xcaddy
msg_info "Setup xCaddy"
cd /opt
$STD xcaddy build
msg_ok "Setup xCaddy"
if (($(awk '/^MemTotal:/ {print int($2 / 1024)}' /proc/meminfo) < 1900)); then
msg_warn "xCaddy is installed; its test build was skipped because linking Caddy needs about 2 GB RAM"
else
msg_info "Setup xCaddy"
cd /opt
$STD xcaddy build
msg_ok "Setup xCaddy"
fi
fi
msg_info "Enabling Caddy Service"
+21 -26
View File
@@ -14,18 +14,15 @@ network_check
update_os
msg_info "Installing Dependencies"
CODENAME=$(get_os_info codename)
setup_deb822_repo \
"debian-backports" \
"file:///usr/share/keyrings/debian-archive-keyring.gpg" \
"http://deb.debian.org/debian" \
"${CODENAME}-backports" \
"main"
$STD apt install -y \
chromium \
libreoffice-writer \
libreoffice-calc \
libreoffice-impress \
libreoffice-draw \
libreoffice-math \
python3-uno \
python-is-python3 \
pdftk-java \
qpdf \
libimage-exiftool-perl \
fonts-crosextra-carlito \
fonts-crosextra-caladea \
fonts-liberation \
@@ -33,28 +30,30 @@ $STD apt install -y \
fonts-dejavu \
fonts-noto-cjk \
fonts-noto-color-emoji \
fonts-noto-core
fonts-noto-core \
fonts-urw-base35
# lok is built against the LibreOffice from backports
$STD apt install -y -t "${CODENAME}-backports" \
libreoffice-writer \
libreoffice-calc \
libreoffice-impress \
libreoffice-draw \
libreoffice-math
msg_ok "Installed Dependencies"
fetch_and_deploy_gh_release "pdfcpu" "pdfcpu/pdfcpu" "prebuild" "latest" "/opt/pdfcpu" "pdfcpu_*_Linux_$(arch_resolve "x86_64" "arm64").tar.xz"
ln -sf "$(find /opt/pdfcpu -type f -name pdfcpu | head -n1)" /usr/local/bin/pdfcpu
msg_info "Installing unoconverter"
UNOCONVERTER_VERSION=$(get_latest_github_release "gotenberg/unoconverter" "false")
download_file "https://raw.githubusercontent.com/gotenberg/unoconverter/${UNOCONVERTER_VERSION}/unoconv" /usr/local/bin/unoconverter
chmod +x /usr/local/bin/unoconverter
msg_ok "Installed unoconverter"
fetch_and_deploy_gh_release "gotenberg" "gotenberg/gotenberg" "tarball" "latest" "/opt/gotenberg"
GO_VERSION="$(awk '$1=="go"{print $2}' /opt/gotenberg/go.mod | cut -d. -f1,2)" setup_go
LOK_VERSION="$(awk -F= '/^ARG LOK_VERSION=/{print $2}' /opt/gotenberg/build/Dockerfile)"
fetch_and_deploy_gh_release "lok" "gotenberg/lok" "prebuild" "$LOK_VERSION" "/usr/local/bin" "lok_${LOK_VERSION#v}_linux_$(arch_resolve "amd64" "arm64").tar.gz"
msg_info "Building Gotenberg (Patience)"
cd /opt/gotenberg
export CGO_ENABLED=0
$STD go mod download
$STD go build -o /usr/local/bin/gotenberg \
-ldflags "-s -w -X 'github.com/gotenberg/gotenberg/v8/cmd.Version=$(cat ~/.gotenberg)'" \
-ldflags "-s -w -X 'github.com/gotenberg/gotenberg/v9/cmd.Version=$(cat ~/.gotenberg)'" \
cmd/gotenberg/main.go
msg_ok "Built Gotenberg"
@@ -70,14 +69,10 @@ Type=simple
User=root
Environment=LANG=C.UTF-8
Environment=LC_ALL=C.UTF-8
Environment=PDFTK_BIN_PATH=/usr/bin/pdftk
Environment=QPDF_BIN_PATH=/usr/bin/qpdf
Environment=EXIFTOOL_BIN_PATH=/usr/bin/exiftool
Environment=PDFCPU_BIN_PATH=/usr/local/bin/pdfcpu
Environment=CHROMIUM_BIN_PATH=/usr/bin/chromium
Environment=CHROMIUM_HYPHEN_DATA_DIR_PATH=/opt/gotenberg/build/chromium-hyphen-data
Environment=LIBREOFFICE_BIN_PATH=/usr/lib/libreoffice/program/soffice.bin
Environment=UNOCONVERTER_BIN_PATH=/usr/local/bin/unoconverter
Environment=LOK_BIN_PATH=/usr/local/bin/lok
Environment=OTEL_TRACES_EXPORTER=none
Environment=OTEL_METRICS_EXPORTER=none
Environment=OTEL_LOGS_EXPORTER=none
+7 -7
View File
@@ -23,7 +23,7 @@ if [[ "$(arch_resolve)" == "amd64" ]] && ! grep -qm1 sse4_2 /proc/cpuinfo; then
exit 236
fi
RELEASE="v3.3.5"
RELEASE="v3.3.6"
if lscpu | grep -q 'GenuineIntel'; then
echo ""
echo ""
@@ -146,10 +146,10 @@ mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
msg_info "Installing GeoNames data"
cd "$GEO_DIR"
curl_with_retry "https://download.geonames.org/export/dump/admin1CodesASCII.txt" "admin1CodesASCII.txt"
curl_with_retry "https://download.geonames.org/export/dump/admin2Codes.txt" "admin2Codes.txt"
curl_with_retry "https://download.geonames.org/export/dump/countryInfo.txt" "countryInfo.txt"
curl_with_retry "https://download.geonames.org/export/dump/cities500.zip" "cities500.zip"
CURL_RETRIES=6 CURL_CONNECT_TO=30 curl_with_retry "https://download.geonames.org/export/dump/admin1CodesASCII.txt" "admin1CodesASCII.txt"
CURL_RETRIES=6 CURL_CONNECT_TO=30 curl_with_retry "https://download.geonames.org/export/dump/admin2Codes.txt" "admin2Codes.txt"
CURL_RETRIES=6 CURL_CONNECT_TO=30 curl_with_retry "https://download.geonames.org/export/dump/countryInfo.txt" "countryInfo.txt"
CURL_RETRIES=6 CURL_CONNECT_TO=30 curl_with_retry "https://download.geonames.org/export/dump/cities500.zip" "cities500.zip"
curl_with_retry "https://raw.githubusercontent.com/nvkelso/natural-earth-vector/v5.1.2/geojson/ne_10m_admin_0_countries.geojson" "ne_10m_admin_0_countries.geojson"
unzip -q cities500.zip
date --iso-8601=seconds | tr -d "\n" >geodata-date.txt
@@ -463,7 +463,7 @@ if [[ -f ~/.openvino ]]; then
msg_ok "Pre-installed Python ${ML_PYTHON}"
msg_info "Installing Intel OpenVINO machine-learning"
for attempt in $(seq 1 3); do
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT,UV_CONCURRENT_DOWNLOADS,UV_CONCURRENT_BUILDS,UV_CONCURRENT_INSTALLS -Pnu immich uv sync --extra openvino --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT,UV_CONCURRENT_DOWNLOADS,UV_CONCURRENT_BUILDS,UV_CONCURRENT_INSTALLS -Pnu immich uv sync --extra openvino --no-dev --upgrade-package watchfiles --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
[[ $attempt -eq 3 ]] && { msg_error "uv sync failed three times, the machine-learning environment was not built"; exit 1; }
# Parallel fetches can trip DNS rate limits (AdGuard, Pi-hole); retry one at a time.
export UV_CONCURRENT_DOWNLOADS=1 UV_CONCURRENT_BUILDS=1 UV_CONCURRENT_INSTALLS=1
@@ -481,7 +481,7 @@ else
msg_ok "Pre-installed Python ${ML_PYTHON}"
msg_info "Installing machine-learning"
for attempt in $(seq 1 3); do
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT,UV_CONCURRENT_DOWNLOADS,UV_CONCURRENT_BUILDS,UV_CONCURRENT_INSTALLS -Pnu immich uv sync --extra cpu --no-dev --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
$STD sudo --preserve-env=VIRTUAL_ENV,UV_HTTP_TIMEOUT,UV_CONCURRENT_DOWNLOADS,UV_CONCURRENT_BUILDS,UV_CONCURRENT_INSTALLS -Pnu immich uv sync --extra cpu --no-dev --upgrade-package watchfiles --active --link-mode copy -n -p "${ML_PYTHON}" --managed-python && break
[[ $attempt -eq 3 ]] && { msg_error "uv sync failed three times, the machine-learning environment was not built"; exit 1; }
# Parallel fetches can trip DNS rate limits (AdGuard, Pi-hole); retry one at a time.
export UV_CONCURRENT_DOWNLOADS=1 UV_CONCURRENT_BUILDS=1 UV_CONCURRENT_INSTALLS=1
+1 -1
View File
@@ -26,7 +26,7 @@ NODE_VERSION="24" NODE_MODULE="corepack,pnpm" setup_nodejs
msg_info "Installing Deno"
export DENO_INSTALL="/usr/local"
curl -fsSL https://deno.land/install.sh | $STD sh -s -- -y
curl -fsSL https://deno.land/install.sh | CI=1 $STD sh -s
[[ ":$PATH:" != *":/usr/local/bin:"* ]] &&
echo -e "\nexport PATH=\"/usr/local/bin:\$PATH\"" >>~/.bashrc &&
source ~/.bashrc
+1
View File
@@ -33,6 +33,7 @@ LOCAL_ENGINE_TOKEN=${LOCAL_ENGINE_TOKEN}
ENCRYPTION_KEY=${ENCRYPTION_KEY}
EOF
chmod 0640 /etc/nexterm-engine/config.yaml /etc/nexterm-server/server.env
echo "x /tmp/nexterm-sea-*" >/etc/tmpfiles.d/nexterm.conf
msg_ok "Configured Nexterm"
msg_info "Creating Services"
+236
View File
@@ -0,0 +1,236 @@
#!/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://pixelfed.org/
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 \
redis-server \
ffmpeg \
jpegoptim \
optipng \
pngquant \
gifsicle \
libvips42
msg_ok "Installed Dependencies"
msg_info "Creating Pixelfed User"
useradd -rU -s /bin/bash pixelfed
usermod -aG redis pixelfed
msg_ok "Created Pixelfed User"
PG_VERSION="17" setup_postgresql
PG_DB_NAME="pixelfed" PG_DB_USER="pixelfed" setup_postgresql_db
PHP_VERSION="8.4" PHP_FPM="YES" PHP_MODULE="bcmath,ctype,curl,exif,gd,imagick,intl,mbstring,pgsql,redis,xml,zip" PHP_UPLOAD_MAX_FILESIZE="500M" PHP_POST_MAX_SIZE="500M" PHP_MAX_EXECUTION_TIME="600" setup_php
setup_composer
msg_info "Configuring Redis"
REDIS_PASS=$(openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c13)
sed -i "s/^# requirepass foobared/requirepass $REDIS_PASS/" /etc/redis/redis.conf
sed -i "s/^requirepass .*/requirepass $REDIS_PASS/" /etc/redis/redis.conf
systemctl restart redis-server
msg_ok "Configured Redis"
msg_info "Configuring PHP-FPM Pool"
cp /etc/php/8.4/fpm/pool.d/www.conf /etc/php/8.4/fpm/pool.d/pixelfed.conf
sed -i 's/\[www\]/[pixelfed]/' /etc/php/8.4/fpm/pool.d/pixelfed.conf
sed -i 's/^user = www-data/user = pixelfed/' /etc/php/8.4/fpm/pool.d/pixelfed.conf
sed -i 's/^group = www-data/group = pixelfed/' /etc/php/8.4/fpm/pool.d/pixelfed.conf
sed -i 's|^listen = .*|listen = /run/php/php8.4-fpm-pixelfed.sock|' /etc/php/8.4/fpm/pool.d/pixelfed.conf
sed -i 's/^listen.owner = .*/listen.owner = www-data/' /etc/php/8.4/fpm/pool.d/pixelfed.conf
sed -i 's/^listen.group = .*/listen.group = www-data/' /etc/php/8.4/fpm/pool.d/pixelfed.conf
systemctl restart php8.4-fpm
msg_ok "Configured PHP-FPM Pool"
fetch_and_deploy_gh_release "pixelfed" "pixelfed/pixelfed" "tarball" "latest" "/opt/pixelfed"
msg_info "Installing Pixelfed (Patience)"
cd /opt/pixelfed
cat <<EOF >/opt/pixelfed/.env
APP_NAME="Pixelfed"
APP_ENV="production"
APP_KEY=
APP_DEBUG="false"
APP_URL=http://${LOCAL_IP}
APP_DOMAIN=${LOCAL_IP}
ADMIN_DOMAIN=${LOCAL_IP}
SESSION_DOMAIN=${LOCAL_IP}
TRUST_PROXIES="*"
FORCE_HTTPS_URLS="false"
OPEN_REGISTRATION="false"
ENFORCE_EMAIL_VERIFICATION="false"
PF_MAX_USERS="1000"
OAUTH_ENABLED="true"
ENABLE_CONFIG_CACHE="true"
INSTANCE_DISCOVER_PUBLIC="true"
PF_OPTIMIZE_IMAGES="true"
IMAGE_QUALITY="80"
MAX_PHOTO_SIZE="15000"
MAX_CAPTION_LENGTH="500"
MAX_ALBUM_LENGTH="4"
DB_CONNECTION="pgsql"
DB_HOST="127.0.0.1"
DB_PORT="5432"
DB_DATABASE="${PG_DB_NAME}"
DB_USERNAME="${PG_DB_USER}"
DB_PASSWORD="${PG_DB_PASS}"
REDIS_CLIENT="predis"
REDIS_SCHEME="tcp"
REDIS_HOST="127.0.0.1"
REDIS_PASSWORD="${REDIS_PASS}"
REDIS_PORT="6379"
SESSION_DRIVER="database"
CACHE_DRIVER="redis"
QUEUE_DRIVER="redis"
BROADCAST_DRIVER="log"
LOG_CHANNEL="stack"
HORIZON_PREFIX="horizon-"
ACTIVITY_PUB="true"
AP_REMOTE_FOLLOW="true"
AP_INBOX="true"
AP_OUTBOX="true"
AP_SHAREDINBOX="true"
EXP_EMC="true"
MAIL_DRIVER="log"
MAIL_HOST="smtp.mailtrap.io"
MAIL_PORT="2525"
MAIL_USERNAME="null"
MAIL_PASSWORD="null"
MAIL_ENCRYPTION="null"
MAIL_FROM_ADDRESS="pixelfed@example.com"
MAIL_FROM_NAME="Pixelfed"
PF_ENABLE_CLOUD="false"
FILESYSTEM_CLOUD="s3"
SESSION_SECURE_COOKIE="false"
HTTPS="false"
EOF
chmod -R 755 /opt/pixelfed
chmod -R 775 /opt/pixelfed/storage /opt/pixelfed/bootstrap/cache
export COMPOSER_ALLOW_SUPERUSER=1
$STD composer install --no-dev --no-ansi --no-interaction --optimize-autoloader
$STD php artisan key:generate --force
$STD php artisan storage:link
$STD php artisan migrate --force
$STD php artisan import:cities
$STD php artisan passport:keys
$STD php artisan route:cache
$STD php artisan view:cache
$STD php artisan config:cache
$STD php artisan instance:actor
$STD php artisan horizon:install
chown -R pixelfed:pixelfed /opt/pixelfed
msg_ok "Installed Pixelfed"
msg_info "Configuring Nginx"
cat <<'EOF' >/etc/nginx/sites-available/pixelfed
server {
listen 80;
server_name _;
root /opt/pixelfed/public;
index index.php;
charset utf-8;
client_max_body_size 100M;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php8.4-fpm-pixelfed.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
EOF
ln -sf /etc/nginx/sites-available/pixelfed /etc/nginx/sites-enabled/pixelfed
rm -f /etc/nginx/sites-enabled/default
$STD nginx -t
systemctl reload nginx
msg_ok "Configured Nginx"
msg_info "Creating Services"
cat <<'EOF' >/etc/systemd/system/pixelfed-horizon.service
[Unit]
Description=Pixelfed Horizon Queue Worker
After=network.target redis-server.service postgresql.service
Requires=redis-server.service
[Service]
Type=simple
User=pixelfed
WorkingDirectory=/opt/pixelfed
ExecStart=/usr/bin/php /opt/pixelfed/artisan horizon
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
cat <<'EOF' >/etc/systemd/system/pixelfed-scheduler.service
[Unit]
Description=Pixelfed Task Scheduler
After=network.target
[Service]
Type=oneshot
User=pixelfed
WorkingDirectory=/opt/pixelfed
ExecStart=/usr/bin/php /opt/pixelfed/artisan schedule:run
EOF
cat <<'EOF' >/etc/systemd/system/pixelfed-scheduler.timer
[Unit]
Description=Run Pixelfed Scheduler every minute
[Timer]
OnCalendar=*-*-* *:*:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl enable -q --now pixelfed-horizon pixelfed-scheduler.timer
msg_ok "Created Services"
motd_ssh
customize
cleanup_lxc
+3 -1
View File
@@ -70,7 +70,9 @@ After=network.target
[Service]
WorkingDirectory=/opt/planka
ExecStart=/usr/bin/npm start --prod
Environment=NODE_ENV=production
Environment=HOME=/root
ExecStart=/usr/bin/node app.js --prod
Restart=always
[Install]
+4
View File
@@ -48,6 +48,10 @@ msg_ok "Installed Podman"
mkdir -p /etc/containers/systemd
if [[ ! -x /usr/libexec/podman/quadlet ]]; then
msg_warn "Portainer runs as a Quadlet unit, which needs Podman 4.4 or newer (Debian 13); skipping it"
var_podman_portainer="n" var_podman_portainer_agent="n"
fi
prompt="${var_podman_portainer:-}"
[[ -n "$prompt" ]] || read -r -p "${TAB3}Would you like to add Portainer? <y/N> " prompt || true
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
+2 -2
View File
@@ -16,9 +16,9 @@ update_os
msg_info "Installing Proxmox Mail Gateway"
setup_deb822_repo \
"pmg" \
"https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg" \
"https://enterprise.proxmox.com/debian/proxmox-release-$(get_os_info codename).gpg" \
"http://download.proxmox.com/debian/pmg" \
"trixie" \
"$(get_os_info codename)" \
"pmg-no-subscription"
$STD apt install -y proxmox-mailgateway-container
msg_ok "Installed Proxmox Mail Gateway"
+1 -1
View File
@@ -23,7 +23,7 @@ setup_deb822_repo \
$STD apt install -y aspnetcore-runtime-10.0
msg_ok "Installed Dependencies"
RELEASE=$(curl -fsSL https://technitium.com/dns/ | grep -oP 'Version \K[\d.]+')
RELEASE=$(get_latest_github_release "TechnitiumSoftware/DnsServer")
fetch_and_deploy_from_url "https://download.technitium.com/dns/DnsServerPortable.tar.gz" /opt/technitium/dns
echo "${RELEASE}" >~/.technitium
+2 -1
View File
@@ -26,7 +26,8 @@ PG_DB_NAME="thingsboard_db" PG_DB_USER="thingsboard" setup_postgresql_db
fetch_and_deploy_gh_release "thingsboard" "thingsboard/thingsboard" "binary" "latest" "/tmp" "thingsboard-*.deb"
msg_info "Configuring ThingsBoard"
cat <<EOF >/etc/thingsboard/conf/thingsboard.conf
cat <<EOF >>/etc/thingsboard/conf/thingsboard.conf
# DB Configuration
export DATABASE_TS_TYPE=sql
export SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/${PG_DB_NAME}
+9 -21
View File
@@ -13,13 +13,9 @@ setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y \
sqlite3 \
yq
msg_ok "Installed Dependencies"
NODE_VERSION="22" setup_nodejs
PG_VERSION="17" setup_postgresql
PG_DB_NAME="tududi" PG_DB_USER="tududi" setup_postgresql_db
fetch_and_deploy_gh_release "tududi" "chrisvel/tududi" "tarball" "latest" "/opt/tududi"
msg_info "Configuring Tududi"
@@ -30,30 +26,22 @@ $STD npm run frontend:build
mv ./dist ./backend
msg_ok "Configured Tududi"
msg_info "Creating env and database"
DB_LOCATION="/opt/tududi-db"
UPLOAD_DIR="/opt/tududi-uploads"
mkdir -p {"$DB_LOCATION","$UPLOAD_DIR"}
msg_info "Creating env"
mkdir -p /opt/tududi-uploads
SECRET="$(openssl rand -hex 64)"
sed -e '/^NODE_ENV=/s/=.*$/=production/' \
-e 's/^TUDUDI_USER/# TUDUDI_USER/g' \
-e "/_SECRET=/s/=.*$/=${SECRET}/" \
-e '/^# DB_FILE=/s/^# //' \
-e "s|^DB_FILE=.*|DB_FILE=${DB_LOCATION}/production.sqlite3|" \
-e "/^# TUDUDI_ALLOWED/s/^# //; \
\|_ORIGINS=|s|=.*$|=<your tududi IP or FDQN>|" \
-e "/^# TUDUDI_UPLOAD/s/^# //; \
\|UPLOAD_PATH=|s|=.*$|=${UPLOAD_DIR}|" \
-e "s/^TUDUDI_SESSION_SECRET=.*/TUDUDI_SESSION_SECRET=${SECRET}/" \
-e "s|^DATABASE_URL=.*|DATABASE_URL=postgres://tududi:${PG_DB_PASS}@localhost:5432/tududi|" \
/opt/tududi/backend/.env.example >/opt/tududi/backend/.env
export DB_FILE="${DB_LOCATION}/production.sqlite3"
$STD npm run db:init
msg_ok "Created env and database"
echo "TUDUDI_UPLOAD_PATH=/opt/tududi-uploads" >>/opt/tududi/backend/.env
msg_ok "Created env"
msg_info "Creating service"
cat <<EOF >/etc/systemd/system/tududi.service
[Unit]
Description=Tududi Service
After=network.target
After=network.target postgresql.service
[Service]
Type=simple
+1 -1
View File
@@ -31,7 +31,7 @@ ln -sf /opt/bun/bin/bunx /usr/local/bin/bunx
msg_ok "Installed Bun"
msg_info "Installing Deno"
$STD sh -c "curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh -s -- -y"
curl -fsSL https://deno.land/install.sh | CI=1 $STD sh -s
msg_ok "Installed Deno"
msg_info "Creating directories"
+17 -13
View File
@@ -58,8 +58,21 @@ function uninstall() {
# ==============================================================================
# UPDATE
# ==============================================================================
# Arcane 3 needs the ARCANE_* names, the current latest image reads only the old ones.
function sync_env_names() {
local key
for key in ENCRYPTION_KEY PROJECTS_DIRECTORY; do
grep -q "^[[:space:]]*- ARCANE_${key}=" "$COMPOSE_FILE" || sed -i "/^[[:space:]]*- ${key}=/{p;s/- ${key}=/- ARCANE_${key}=/;}" "$COMPOSE_FILE"
grep -q "^[[:space:]]*- ${key}=" "$COMPOSE_FILE" || sed -i "/^[[:space:]]*- ARCANE_${key}=/{p;s/- ARCANE_${key}=/- ${key}=/;}" "$COMPOSE_FILE"
done
if [[ -f "$ENV_FILE" ]]; then
sed -i 's/^ARCANE_#/#ARCANE_/' "$ENV_FILE"
fi
}
function update() {
chown -R 65532:65532 /etc/arcane/projects /etc/arcane/builds 2>/dev/null || true
sync_env_names
msg_info "Pulling latest ${APP} image"
cd "$INSTALL_PATH"
@@ -85,9 +98,8 @@ function install() {
msg_ok "Created ${INSTALL_PATH}"
# Generate secrets and config values
local ENCRYPTION_KEY JWT_SECRET PROJ_DIR BUILDS_DIR
local ENCRYPTION_KEY PROJ_DIR BUILDS_DIR
ENCRYPTION_KEY=$(random_password 32)
JWT_SECRET=$(random_password 32)
PROJ_DIR="/etc/arcane/projects"
BUILDS_DIR="/etc/arcane/builds"
@@ -108,20 +120,12 @@ function install() {
curl -fsSL "https://raw.githubusercontent.com/getarcaneapp/arcane/refs/heads/main/docker/examples/compose.basic.yaml" -o "$COMPOSE_FILE"
msg_ok "Downloaded Docker Compose file"
msg_info "Downloading .env file"
curl -fsSL "https://raw.githubusercontent.com/getarcaneapp/arcane/refs/heads/main/.env.example" -o "$ENV_FILE"
chmod 600 "$ENV_FILE"
msg_ok "Downloaded .env file"
msg_info "Configuring compose and env files"
msg_info "Configuring compose file"
sed -i '/^[[:space:]]*#/!s|/host/path/to/projects|'"$PROJ_DIR"'|g' "$COMPOSE_FILE"
sed -i '/^[[:space:]]*#/!s|/host/path/to/builds|'"$BUILDS_DIR"'|g' "$COMPOSE_FILE"
sed -i '/^[[:space:]]*#/!s|ENCRYPTION_KEY=.*|ENCRYPTION_KEY='"$ENCRYPTION_KEY"'|g' "$COMPOSE_FILE"
sed -i '/^[[:space:]]*#/!s|JWT_SECRET=.*|JWT_SECRET='"$JWT_SECRET"'|g' "$COMPOSE_FILE"
sed -i '/^[[:space:]]*#/!s|APP_URL=.*|APP_URL=http://localhost:'"$DEFAULT_PORT"'|g' "$ENV_FILE"
sed -i '/^[[:space:]]*#/!s|ENCRYPTION_KEY=.*|#&|g' "$ENV_FILE"
sed -i '/^[[:space:]]*#/!s|JWT_SECRET=.*|#&|g' "$ENV_FILE"
msg_ok "Configured compose and env files"
sync_env_names
msg_ok "Configured compose file"
msg_info "Starting ${APP}"
cd "$INSTALL_PATH"
+13 -1
View File
@@ -4,7 +4,7 @@
# License: MIT
# https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
COMMUNITY_SCRIPTS_URL="${COMMUNITY_SCRIPTS_URL:-https://raw.githubusercontent.com/community-scripts/DevScripts/main}"
COMMUNITY_SCRIPTS_URL="${COMMUNITY_SCRIPTS_URL:-https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main}"
source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/pve/vm-core.func")
load_functions
@@ -341,6 +341,18 @@ if [[ "$VM_STATE" != *stopped* ]]; then
fi
msg_ok "OpenWrt has shut down"
# pve-bridge tags a NIC on a port of the bridge; a bridge without one only takes tags when VLAN-aware
if [[ -n "$LAN_VLAN" && -d "/sys/class/net/${LAN_BRG}/bridge" && "$(cat "/sys/class/net/${LAN_BRG}/bridge/vlan_filtering" 2>/dev/null)" != "1" ]] &&
! ls "/sys/class/net/${LAN_BRG}/brif" 2>/dev/null | grep -qE '^((eth|bond)[0-9]+|en[^.]+)(\.[0-9]+)?$'; then
msg_warn "LAN bridge ${LAN_BRG} has no physical port and is not VLAN-aware; the LAN NIC stays untagged"
LAN_VLAN=""
fi
if [[ -n "$VLAN" && -d "/sys/class/net/${BRG}/bridge" && "$(cat "/sys/class/net/${BRG}/bridge/vlan_filtering" 2>/dev/null)" != "1" ]] &&
! ls "/sys/class/net/${BRG}/brif" 2>/dev/null | grep -qE '^((eth|bond)[0-9]+|en[^.]+)(\.[0-9]+)?$'; then
msg_warn "WAN bridge ${BRG} has no physical port and is not VLAN-aware; the WAN NIC stays untagged"
VLAN=""
fi
msg_info "Adding bridge interfaces on Proxmox side"
qm set $VMID \
-net0 virtio,bridge=${LAN_BRG},macaddr=${LAN_MAC}${LAN_VLAN}${MTU} \
+27 -16
View File
@@ -47,7 +47,7 @@ function check_disk_space() {
}
TEMP_DIR=$(mktemp -d)
if ! check_disk_space "$TEMP_DIR" 20 && [ -d "/var/tmp" ] && check_disk_space "/var/tmp" 20; then
if ! check_disk_space "$TEMP_DIR" 4 && [ -d "/var/tmp" ] && check_disk_space "/var/tmp" 4; then
rm -rf "$TEMP_DIR"
TEMP_DIR=$(mktemp -d /var/tmp/opnsense-vm.XXXXXX)
fi
@@ -364,15 +364,6 @@ FREEBSD_VER="$VM_INDEX_LATEST"
URL="$VM_INDEX_URL"
msg_ok "Download URL: ${CL}${BL}${URL}${CL}"
# Check available disk space (require at least 20GB for safety)
if ! check_disk_space "$TEMP_DIR" 20; then
AVAILABLE_GB=$(df -h "$TEMP_DIR" | awk 'NR==2 {print $4}')
msg_error "Insufficient disk space in temporary directory ($TEMP_DIR)."
msg_error "Available: ${AVAILABLE_GB}, Required: ~20GB for FreeBSD image decompression."
msg_error "Please free up space or ensure /tmp has sufficient storage."
exit 214
fi
msg_info "Downloading FreeBSD Image"
# A mirror serving an error page returns 200, so size decides whether this
# is an image. Anything real here is far above 5 MB.
@@ -381,11 +372,12 @@ vm_fetch_image "$URL" "$CACHE_FILE" --cache --verify-xz --min-bytes $((5 * 1024
echo -en "\e[1A\e[0K"
msg_ok "Downloaded ${CL}${BL}$(basename "$CACHE_FILE")${CL}"
# Check disk space again before decompression
if ! check_disk_space "$TEMP_DIR" 15; then
NEED_GB=$(($(xz --robot -l "$CACHE_FILE" | awk '$1 == "totals" {print $5}') / 1024 / 1024 / 1024 + 1))
if ! check_disk_space "$TEMP_DIR" "$NEED_GB"; then
AVAILABLE_GB=$(df -h "$TEMP_DIR" | awk 'NR==2 {print $4}')
msg_error "Insufficient disk space for decompression."
msg_error "Available: ${AVAILABLE_GB}, Required: ~15GB for decompressed image."
msg_error "Insufficient disk space for decompression in ${TEMP_DIR}."
msg_error "Available: ${AVAILABLE_GB}, Required: ~${NEED_GB}GB for the decompressed image."
msg_error "Please free up space or ensure /tmp or /var/tmp has sufficient storage."
exit 214
fi
@@ -417,7 +409,7 @@ while :; do
alloc_delay=$((alloc_delay * 2))
continue
fi
echo -e "$alloc_err" >&2
msg_error "Could not allocate the EFI disk on ${STORAGE}: ${alloc_err}"
exit 220
done
vm_import_disk "$VMID" "$FILE" "$STORAGE"
@@ -442,7 +434,26 @@ msg_ok "Bridge interfaces have been successfully added."
msg_ok "Created a OPNsense VM ${CL}${BL}(${HN})"
msg_ok "Starting OPNsense VM (the bootstrap takes 10-30 minutes)"
$STD qm start $VMID
sleep 180
# The FreeBSD image prints its login prompt on the serial console too. Boot takes
# under a minute with DHCP, each NIC without a DHCP server adds a 60s timeout.
SERIAL_LOG="${TEMP_DIR}/serial-${VMID}.log"
timeout 900 socat -u "UNIX-CONNECT:/var/run/qemu-server/${VMID}.serial0" - >"$SERIAL_LOG" 2>/dev/null &
SERIAL_PID=$!
boot_wait=0
until grep -aq 'login:' "$SERIAL_LOG" 2>/dev/null || ! kill -0 "$SERIAL_PID" 2>/dev/null; do
sleep 5
boot_wait=$((boot_wait + 5))
done
kill "$SERIAL_PID" 2>/dev/null || true
if grep -aq 'login:' "$SERIAL_LOG" 2>/dev/null; then
msg_ok "FreeBSD booted after ${boot_wait}s"
elif [ $boot_wait -lt 180 ]; then
msg_warn "Could not read the serial console, waiting 3 minutes instead"
sleep $((180 - boot_wait))
else
msg_warn "No login prompt on the serial console after $((boot_wait / 60)) minutes; continuing"
fi
sleep 3
send_line_to_vm "root"
sleep 2
send_line_to_vm ""
+3 -2
View File
@@ -39,7 +39,7 @@ function truenas_iso_lookup() {
local pre_releases=()
local all_paths=$(
curl -sL "$BASE_URL" |
curl -fsSL "${_CS_CURL_RETRY[@]}" --max-time 90 "$BASE_URL" |
grep -oE 'href="[^"]+\.iso"' |
sed 's/href="//; s/"$//' |
grep -vE '(MASTER|ALPHA)' |
@@ -47,6 +47,7 @@ function truenas_iso_lookup() {
)
while read -r path; do
[[ -n "$path" ]] || continue
local filename=$(basename "$path")
local version=$(echo "$filename" | sed -E 's/.*TrueNAS-SCALE-([0-9]{2}\.[0-9]{2}(\.[0-9]+)*(-RC[0-9]|-BETA[0-9])?)\.iso.*/\1/')
if [[ "$version" =~ (RC|BETA) ]]; then
@@ -139,7 +140,7 @@ post_to_api_vm
vm_select_storage "$HN"
if [ -z "${SELECTED_ISO:-}" ]; then
SELECTED_ISO=$(truenas_iso_lookup | grep -vE 'RC|BETA' | sort -V | tail -n 1)
SELECTED_ISO=$(truenas_iso_lookup | grep -vE 'RC|BETA' | sort -V | tail -n 1) || true
if [ -z "$SELECTED_ISO" ]; then
msg_error "Could not find a stable ISO for fallback."
+1 -1
View File
@@ -4,7 +4,7 @@
# Author: MickLesk (CanbiZ)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
COMMUNITY_SCRIPTS_URL="${COMMUNITY_SCRIPTS_URL:-https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main}"
COMMUNITY_SCRIPTS_URL="${COMMUNITY_SCRIPTS_URL:-https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main}"
source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/pve/vm-core.func")
load_functions