Based on analysis of latest 30 scripts (koel, wallabag, invoiceninja, etc.) Templates updated to reflect current best practices: ct/AppName.sh: - Use check_for_gh_release + fetch_and_deploy_gh_release pattern - CLEAN_INSTALL=1 for updates - Proper backup/restore workflow - Simplified configuration comments install/AppName-install.sh: - fetch_and_deploy_gh_release as primary download method (no separate RELEASE variable) - Real-world examples from Node.js, Python, PHP apps - import_local_ip called early - Setup runtimes/databases before app installation - cleanup_lxc at the end HELPER_FUNCTIONS.md: - fetch_and_deploy_gh_release as preferred method (documented first) - CLEAN_INSTALL=1 environment variable documented - prebuild type with asset_pattern documented - Clarified when to use get_latest_github_release vs fetch_and_deploy Closes #10194
16 KiB
🛠️ Helper Functions Reference
Quick reference for all helper functions available in tools.func
These functions are automatically available in install scripts via
$FUNCTIONS_FILE_PATH
📋 Table of Contents
- Scripts to Watch
- Runtime & Language Setup
- Database Setup
- GitHub Release Helpers
- Tools & Utilities
- SSL/TLS
- Utility Functions
- Package Management
📚 Scripts to Watch
Learn from real, well-implemented scripts. Each app requires TWO files that work together:
| File | Location | Purpose |
|---|---|---|
| CT Script | ct/appname.sh |
Runs on Proxmox host - creates container, contains update_script() |
| Install Script | install/appname-install.sh |
Runs inside container - installs and configures the app |
⚠️ Both files are ALWAYS required! The CT script calls the install script automatically during container creation.
Node.js + PostgreSQL
Koel - Music streaming with PHP + Node.js + PostgreSQL
| File | Link |
|---|---|
| CT (update logic) | ct/koel.sh |
| Install | install/koel-install.sh |
Actual Budget - Finance app with npm global install
| File | Link |
|---|---|
| CT (update logic) | ct/actualbudget.sh |
| Install | install/actualbudget-install.sh |
Python + uv
MeTube - YouTube downloader with Python uv + Node.js + Deno
| File | Link |
|---|---|
| CT (update logic) | ct/metube.sh |
| Install | install/metube-install.sh |
Endurain - Fitness tracker with Python uv + PostgreSQL/PostGIS
| File | Link |
|---|---|
| CT (update logic) | ct/endurain.sh |
| Install | install/endurain-install.sh |
PHP + MariaDB/MySQL
Wallabag - Read-it-later with PHP + MariaDB + Redis + Nginx
| File | Link |
|---|---|
| CT (update logic) | ct/wallabag.sh |
| Install | install/wallabag-install.sh |
InvoiceNinja - Invoicing with PHP + MariaDB + Supervisor
| File | Link |
|---|---|
| CT (update logic) | ct/invoiceninja.sh |
| Install | install/invoiceninja-install.sh |
BookStack - Wiki/Docs with PHP + MariaDB + Apache
| File | Link |
|---|---|
| CT (update logic) | ct/bookstack.sh |
| Install | install/bookstack-install.sh |
PHP + SQLite (Simple)
Speedtest Tracker - Speedtest with PHP + SQLite + Nginx
| File | Link |
|---|---|
| CT (update logic) | ct/speedtest-tracker.sh |
| Install | install/speedtest-tracker-install.sh |
Runtime & Language Setup
setup_nodejs
Install Node.js from NodeSource repository.
# Default (Node.js 22)
setup_nodejs
# Specific version
NODE_VERSION="20" setup_nodejs
NODE_VERSION="22" setup_nodejs
NODE_VERSION="24" setup_nodejs
setup_go
Install Go programming language (latest stable).
setup_go
# Use in script
setup_go
cd /opt/myapp
$STD go build -o myapp .
setup_rust
Install Rust via rustup.
setup_rust
# Use in script
setup_rust
source "$HOME/.cargo/env"
$STD cargo build --release
setup_uv
Install Python uv package manager (fast pip/venv replacement).
setup_uv
# Use in script
setup_uv
cd /opt/myapp
$STD uv sync --locked
setup_ruby
Install Ruby from official repositories.
setup_ruby
setup_php
Install PHP with configurable modules and FPM/Apache support.
# Basic PHP
setup_php
# Full configuration
PHP_VERSION="8.3" \
PHP_MODULE="mysqli,gd,curl,mbstring,xml,zip,ldap" \
PHP_FPM="YES" \
PHP_APACHE="YES" \
setup_php
Environment Variables:
| Variable | Default | Description |
|---|---|---|
PHP_VERSION |
8.3 |
PHP version to install |
PHP_MODULE |
"" |
Comma-separated list of modules |
PHP_FPM |
NO |
Install PHP-FPM |
PHP_APACHE |
NO |
Install Apache module |
setup_composer
Install PHP Composer package manager.
setup_php
setup_composer
# Use in script
$STD composer install --no-dev
setup_java
Install Java (OpenJDK).
# Default (Java 21)
setup_java
# Specific version
JAVA_VERSION="17" setup_java
JAVA_VERSION="21" setup_java
Database Setup
setup_mariadb
Install MariaDB server.
setup_mariadb
setup_mariadb_db
Create a MariaDB database and user. Sets $MARIADB_DB_PASS with the generated password.
setup_mariadb
MARIADB_DB_NAME="myapp_db" MARIADB_DB_USER="myapp_user" setup_mariadb_db
# After calling, these variables are available:
# $MARIADB_DB_NAME - Database name
# $MARIADB_DB_USER - Database user
# $MARIADB_DB_PASS - Generated password (saved to ~/[appname].creds)
setup_mysql
Install MySQL server.
setup_mysql
setup_postgresql
Install PostgreSQL server.
# Default (PostgreSQL 17)
setup_postgresql
# Specific version
PG_VERSION="16" setup_postgresql
PG_VERSION="17" setup_postgresql
setup_postgresql_db
Create a PostgreSQL database and user. Sets $PG_DB_PASS with the generated password.
PG_VERSION="17" setup_postgresql
PG_DB_NAME="myapp_db" PG_DB_USER="myapp_user" setup_postgresql_db
# After calling, these variables are available:
# $PG_DB_NAME - Database name
# $PG_DB_USER - Database user
# $PG_DB_PASS - Generated password (saved to ~/[appname].creds)
setup_mongodb
Install MongoDB server.
setup_mongodb
setup_clickhouse
Install ClickHouse analytics database.
setup_clickhouse
GitHub Release Helpers
Note
:
fetch_and_deploy_gh_releaseis the preferred method for downloading GitHub releases. It handles version tracking automatically. Only useget_latest_github_releaseif you need the version number separately.
fetch_and_deploy_gh_release
Primary method for downloading and extracting GitHub releases. Handles version tracking automatically.
# Basic usage - downloads tarball to /opt/appname
fetch_and_deploy_gh_release "appname" "owner/repo"
# With explicit parameters
fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/appname"
# Pre-built release with specific asset pattern
fetch_and_deploy_gh_release "koel" "koel/koel" "prebuild" "latest" "/opt/koel" "koel-*.tar.gz"
# Clean install (removes old directory first) - used in update_script
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/appname"
Parameters:
| Parameter | Default | Description |
|---|---|---|
name |
required | App name (for version tracking) |
repo |
required | GitHub repo (owner/repo) |
type |
tarball |
Release type: tarball, zipball, prebuild, binary |
version |
latest |
Version tag or latest |
dest |
/opt/[name] |
Destination directory |
asset_pattern |
"" |
For prebuild: glob pattern to match asset (e.g. app-*.tar.gz) |
Environment Variables:
| Variable | Description |
|---|---|
CLEAN_INSTALL=1 |
Remove destination directory before extracting (for updates) |
check_for_gh_release
Check if a newer version is available. Returns 0 if update needed, 1 if already at latest. Use in update_script() function.
# In update_script() function in ct/appname.sh
if check_for_gh_release "appname" "owner/repo"; then
msg_info "Updating..."
# Stop services, backup, update, restore, start
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "appname" "owner/repo"
msg_ok "Updated successfully"
fi
get_latest_github_release
Get the latest release version from a GitHub repository. Only use if you need the version number separately (e.g., for manual download or display).
RELEASE=$(get_latest_github_release "owner/repo")
echo "Latest version: $RELEASE"
Examples
fetch_and_deploy_gh_release "bookstack" "BookStackApp/BookStack" fetch_and_deploy_gh_release "appname" "owner/repo" "tarball" "latest" "/opt/myapp"
**Parameters:**
| Parameter | Default | Description |
|-----------|---------|-------------|
| `name` | required | App name (for version tracking) |
| `repo` | required | GitHub repo (`owner/repo`) |
| `type` | `tarball` | Release type: `tarball`, `zipball`, `binary` |
| `version` | `latest` | Version tag or `latest` |
| `dest` | `/opt/[name]` | Destination directory |
---
## Tools & Utilities
### `setup_yq`
Install yq YAML processor.
```bash
setup_yq
# Use in script
yq '.server.port = 8080' -i config.yaml
setup_ffmpeg
Install FFmpeg with common codecs.
setup_ffmpeg
setup_hwaccel
Setup GPU hardware acceleration (Intel/AMD/NVIDIA).
# Only runs if GPU passthrough is detected (/dev/dri, /dev/nvidia0, /dev/kfd)
setup_hwaccel
setup_imagemagick
Install ImageMagick 7 from source.
setup_imagemagick
setup_docker
Install Docker Engine.
setup_docker
setup_adminer
Install Adminer for database management.
setup_mariadb
setup_adminer
# Access at http://IP/adminer
SSL/TLS
create_self_signed_cert
Create a self-signed SSL certificate.
create_self_signed_cert
# Creates files at:
# /etc/ssl/[appname]/[appname].key
# /etc/ssl/[appname]/[appname].crt
Utility Functions
import_local_ip
Set the $LOCAL_IP variable with the container's IP address.
import_local_ip
echo "Container IP: $LOCAL_IP"
# Use in config files
sed -i "s/localhost/$LOCAL_IP/g" /opt/myapp/config.yaml
ensure_dependencies
Ensure packages are installed (installs if missing).
ensure_dependencies "jq" "unzip" "curl"
msg_info / msg_ok / msg_error / msg_warn
Display formatted messages.
msg_info "Installing application..."
# ... do work ...
msg_ok "Installation complete"
msg_warn "Optional feature not available"
msg_error "Installation failed"
Package Management
cleanup_lxc
Final cleanup function - call at end of install script.
# At the end of your install script
motd_ssh
customize
cleanup_lxc # Handles autoremove, autoclean, cache cleanup
install_packages_with_retry
Install packages with automatic retry on failure.
install_packages_with_retry "package1" "package2" "package3"
prepare_repository_setup
Prepare system for adding new repositories (cleanup old repos, keyrings).
prepare_repository_setup "mariadb" "mysql"
Complete Examples
Example 1: Node.js App with PostgreSQL (install script)
#!/usr/bin/env bash
# Copyright (c) 2021-2025 community-scripts ORG
# Author: YourUsername
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/example/myapp
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"
# Setup runtimes and databases FIRST
NODE_VERSION="22" setup_nodejs
PG_VERSION="17" setup_postgresql
PG_DB_NAME="myapp" PG_DB_USER="myapp" setup_postgresql_db
import_local_ip
# Download app using fetch_and_deploy (handles version tracking)
fetch_and_deploy_gh_release "myapp" "example/myapp" "tarball" "latest" "/opt/myapp"
msg_info "Setting up MyApp"
cd /opt/myapp
$STD npm ci --production
msg_ok "Setup MyApp"
msg_info "Configuring MyApp"
cat <<EOF >/opt/myapp/.env
DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost/${PG_DB_NAME}
HOST=${LOCAL_IP}
PORT=3000
EOF
msg_ok "Configured MyApp"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/myapp.service
[Unit]
Description=MyApp
After=network.target postgresql.service
[Service]
Type=simple
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/node /opt/myapp/server.js
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now myapp
msg_ok "Created Service"
motd_ssh
customize
cleanup_lxc
Example 2: Matching Container Script (ct script)
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/build.func)
# Copyright (c) 2021-2025 community-scripts ORG
# Author: YourUsername
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/example/myapp
APP="MyApp"
var_tags="${var_tags:-webapp}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-2048}"
var_disk="${var_disk:-6}"
var_os="${var_os:-debian}"
var_version="${var_version:-12}"
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/myapp ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
# check_for_gh_release returns true if update available
if check_for_gh_release "myapp" "example/myapp"; then
msg_info "Stopping Service"
systemctl stop myapp
msg_ok "Stopped Service"
msg_info "Creating Backup"
cp /opt/myapp/.env /tmp/myapp_env.bak
msg_ok "Created Backup"
# CLEAN_INSTALL=1 removes old dir before extracting
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "myapp" "example/myapp" "tarball" "latest" "/opt/myapp"
msg_info "Restoring Config & Rebuilding"
cp /tmp/myapp_env.bak /opt/myapp/.env
rm /tmp/myapp_env.bak
cd /opt/myapp
$STD npm ci --production
msg_ok "Restored Config & Rebuilt"
msg_info "Starting Service"
systemctl start myapp
msg_ok "Started Service"
msg_ok "Updated Successfully"
fi
exit
}
start
build_container
description
msg_ok "Completed Successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Access it using the following URL:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:3000${CL}"
Example 3: PHP App with MariaDB (install script)
#!/usr/bin/env bash
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"
# PHP with FPM and common modules
PHP_VERSION="8.4" PHP_FPM="YES" PHP_MODULE="bcmath,curl,gd,intl,mbstring,mysql,xml,zip" setup_php
setup_composer
setup_mariadb
MARIADB_DB_NAME="myapp" MARIADB_DB_USER="myapp" setup_mariadb_db
import_local_ip
# Download pre-built release (with asset pattern)
fetch_and_deploy_gh_release "myapp" "example/myapp" "prebuild" "latest" "/opt/myapp" "myapp-*.tar.gz"
msg_info "Configuring MyApp"
cd /opt/myapp
cp .env.example .env
sed -i "s|APP_URL=.*|APP_URL=http://${LOCAL_IP}|" .env
sed -i "s|DB_DATABASE=.*|DB_DATABASE=${MARIADB_DB_NAME}|" .env
sed -i "s|DB_USERNAME=.*|DB_USERNAME=${MARIADB_DB_USER}|" .env
sed -i "s|DB_PASSWORD=.*|DB_PASSWORD=${MARIADB_DB_PASS}|" .env
$STD composer install --no-dev --no-interaction
$STD php artisan key:generate --force
$STD php artisan migrate --force
chown -R www-data:www-data /opt/myapp
msg_ok "Configured MyApp"
# ... nginx config, service creation ...
motd_ssh
customize
cleanup_lxc