Databases
Reference for the database and search engine helpers in lib/db.func - PostgreSQL, MariaDB, MySQL, MongoDB, ClickHouse and MeiliSearch.
Source: lib/db.func.
It is loaded through lib/tools.func on every container that is not Alpine, so an install
script calls these functions directly after update_os. Alpine containers load
lib/alpine.func instead, which has none of them (see Alpine).
| Function | Purpose |
|---|---|
setup_postgresql | Install or upgrade PostgreSQL |
setup_postgresql_db | Create a PostgreSQL role and database |
setup_mariadb | Install or upgrade MariaDB |
setup_mariadb_db | Create a MariaDB database and user |
setup_mysql | Install or upgrade MySQL |
setup_mysql_db | Create a MySQL database and user |
setup_mongodb | Install or upgrade MongoDB |
mongodb_get_fcv | Read MongoDB's featureCompatibilityVersion |
mongodb_set_fcv | Set MongoDB's featureCompatibilityVersion |
setup_clickhouse | Install or upgrade ClickHouse |
setup_meilisearch | Install or update MeiliSearch |
There is no Redis or Valkey helper. Scripts install those from the distribution, for
example $STD apt install -y redis-server in ct/snapotter.sh.
How these functions are called
None of the installers takes positional arguments. They read environment variables, and every variable has a default.
PG_VERSION="17" PG_MODULES="postgis" setup_postgresql # prefix formThe prefix form is safe for the engine installers (setup_postgresql, setup_mariadb,
setup_mongodb, ...): they copy the value into a local variable and nothing reads it
afterwards.
The *_db functions are different. The script reads PG_DB_NAME, PG_DB_USER and
PG_DB_PASS (or the MARIADB_DB_* / MYSQL_DB_* equivalents) after the call to
write the application's config. Bash 5.3 no longer keeps a prefix assignment once the
function has returned, so name and user come back empty there. Put the assignments on
their own lines:
PG_DB_NAME="myapp"
PG_DB_USER="myapp"
setup_postgresql_db
echo "DATABASE_URL=postgresql://${PG_DB_USER}:${PG_DB_PASS}@localhost:5432/${PG_DB_NAME}"Most existing scripts still use the prefix form for these three functions; new scripts should not.
All functions return their status. Install scripts run under catch_errors, so a
non-zero return stops the script with that code. The numbers are explained in
Exit codes.
Upgrade handling at a glance
Each installer checks what is already installed, so calling it again from
update_script() is the supported way to update the engine.
| Engine | Same version installed | Different version installed |
|---|---|---|
| PostgreSQL | Upgrades the packages, installs missing PG_MODULES | pg_dumpall to /var/lib/postgresql/backup_<date>_v<old>.sql, purges the old packages, installs the new major, replays the dump |
| MariaDB | Upgrades the packages | Removes the old version, sets up the repository for the new one |
| MySQL | Upgrades the packages | Removes the old version, sets up the repository for the new one |
| MongoDB | Upgrades mongodb-org | Purges and reinstalls, or upgrades in place when another package depends on MongoDB |
| ClickHouse | Upgrades the packages | Stops the service, removes the old version, reinstalls |
| MeiliSearch | Nothing | Replaces the binary; backs up and migrates the data when major.minor changes |
PostgreSQL
setup_postgresql
Installs PostgreSQL from the PGDG repository (or the distribution), enables the service and installs optional extension packages.
[PG_VERSION=<major>] [PG_MODULES=<list>] [USE_PGDG_REPO=false] setup_postgresql| Variable | Default | Meaning |
|---|---|---|
PG_VERSION | 16 | Major version to install from PGDG |
PG_MODULES | empty | Comma-separated list. Each entry is installed as the apt package postgresql-<version>-<entry>, for example pgvector, postgis, cron |
USE_PGDG_REPO | true | Anything other than true, TRUE or 1 installs the distribution's postgresql and postgresql-client packages; PG_VERSION is then ignored |
Behaviour worth knowing:
- A module that cannot be installed produces a warning, not an error.
- If
PG_MODULEScontainscron,pg_cronis added toshared_preload_librariesand PostgreSQL is restarted. - On Debian
trixie,forkyandsidthe suitetrixie-pgdgis used. If PGDG is not reachable for it, the function warns and installs the distribution's PostgreSQL instead, which may be a different major than requested. - Unless
/etc/environmentalready mentions/usr/lib/postgresql, the file is overwritten with a singlePATHline that ends in/usr/lib/postgresql/<version>/bin. - When a different major is installed, the databases are dumped first. If the dump fails the function stops before removing anything. A failed restore only warns.
| Returns | When |
|---|---|
0 | Installed or updated |
100 | APT, repository or package failure |
150 | The pre-upgrade pg_dumpall failed |
127 | psql is missing after installation |
Example from install/adventurelog-install.sh:
PG_VERSION="17" PG_MODULES="postgis" setup_postgresqlsetup_postgresql_db
Creates a login role and a database owned by it, optionally with extensions, and appends the credentials to a file.
PG_DB_NAME=<name>
PG_DB_USER=<user>
setup_postgresql_db| Variable | Default | Meaning |
|---|---|---|
PG_DB_NAME | required | Database name |
PG_DB_USER | required | Role name |
PG_DB_PASS | generated | Password. If empty, 13 alphanumeric characters are generated |
PG_DB_EXTENSIONS | empty | Comma-separated names for CREATE EXTENSION IF NOT EXISTS, for example postgis,vector |
PG_DB_SCHEMA_PERMS | empty | true grants all privileges on the database and the public schema, default privileges on tables and sequences, and CREATEDB |
PG_DB_GRANT_SUPERUSER | empty | true makes the role a superuser |
PG_DB_SKIP_ALTER_ROLE | empty | true skips the three ALTER ROLE defaults below |
PG_DB_CREDS_FILE | ~/<app>.creds | File the credentials are appended to. <app> is APPLICATION lowercased with spaces removed |
APPLICATION | set by the framework | Only used for the default credentials file name |
What it does:
CREATE ROLE ... WITH LOGIN PASSWORDandCREATE DATABASE ... WITH OWNER ... ENCODING 'UTF8' TEMPLATE template0. Names are quoted, so a name such as4gaboardsworks.- Unless skipped, sets
client_encodingtoutf8,default_transaction_isolationtoread committedandtimezonetoUTCon the role. - If
PG_DB_EXTENSIONScontainspg_cron, it setscron.database_nameto this database andcron.timezonetoUTC, restarts PostgreSQL before creating the extension, and grants the role access to thecronschema. - Exports
PG_DB_NAME,PG_DB_USERandPG_DB_PASS.
The extension name and the package name can differ: pgvector is installed with
PG_MODULES="pgvector" and enabled with PG_DB_EXTENSIONS="vector".
| Returns | When |
|---|---|
0 | Database created |
65 | PG_DB_NAME or PG_DB_USER is not set |
Example, the call from install/adventurelog-install.sh with the assignments moved
onto their own lines:
PG_DB_NAME="adventurelog_db"
PG_DB_USER="adventurelog_user"
PG_DB_EXTENSIONS="postgis"
setup_postgresql_dbMariaDB
setup_mariadb
Installs MariaDB from the distribution, or a specific version from the official MariaDB repository.
[MARIADB_VERSION=<version>] setup_mariadb| Variable | Default | Meaning |
|---|---|---|
MARIADB_VERSION | latest | latest or empty installs mariadb-server and mariadb-client from the distribution. Any other value installs that version from http://mirror.mariadb.org/repo/<version> |
Behaviour worth knowing:
- With
latest, an existing official MariaDB repository file is removed. If the installed major version is higher than what the distribution offers, the existing installation is kept and the function returns0. - With a specific version, a failed install from the official repository falls back to the distribution packages with a warning.
- Every install path writes
/etc/tmpfiles.d/mariadb.confso/run/mysqldexists after a container reboot. The plain package update of an already matching version from the official repository does not touch it.
| Returns | When |
|---|---|
0 | Installed, updated or existing installation kept |
100 | APT, repository or package failure |
1 | The old version could not be removed because another package depends on it |
Example from install/projectsend-install.sh:
setup_mariadbsetup_mariadb_db
Creates a database and a '<user>'@'localhost' account with full access to it.
MARIADB_DB_NAME=<name>
MARIADB_DB_USER=<user>
setup_mariadb_db| Variable | Default | Meaning |
|---|---|---|
MARIADB_DB_NAME | required | Database name. Created with utf8mb4 / utf8mb4_unicode_ci |
MARIADB_DB_USER | required | User name |
MARIADB_DB_PASS | generated | Password. If empty, 13 alphanumeric characters are generated |
MARIADB_DB_EXTRA_GRANTS | empty | Comma-separated GRANT ... statements without the TO part; the function appends TO '<user>'@'localhost' to each |
MARIADB_DB_SQL_MODE | empty | If non-empty, runs SET GLOBAL sql_mode='<value>'. An empty value is ignored |
MARIADB_DB_CREDS_FILE | ~/<app>.creds | File the credentials are appended to |
APPLICATION | set by the framework | Only used for the default credentials file name |
Exports MARIADB_DB_NAME, MARIADB_DB_USER and MARIADB_DB_PASS.
| Returns | When |
|---|---|
0 | Database created |
65 | MARIADB_DB_NAME or MARIADB_DB_USER is not set |
Example from install/projectsend-install.sh, which then writes
${MARIADB_DB_NAME}, ${MARIADB_DB_USER} and ${MARIADB_DB_PASS} into .env:
MARIADB_DB_NAME="projectsend"
MARIADB_DB_USER="projectsend"
setup_mariadb_dbinstall/glpi-install.sh shows an extra grant
(MARIADB_DB_EXTRA_GRANTS="GRANT SELECT ON \mysql`.`time_zone_name`") and a custom credentials file (MARIADB_DB_CREDS_FILE="$HOME/glpi_db.creds"`).
MySQL
setup_mysql
Installs MySQL from the official MySQL repository, or whatever MySQL-compatible server the distribution ships.
[MYSQL_VERSION=<version>] [USE_MYSQL_REPO=false] setup_mysql| Variable | Default | Meaning |
|---|---|---|
MYSQL_VERSION | 8.0 | Version to install from repo.mysql.com, for example 8.0 or 8.4 |
USE_MYSQL_REPO | true | Anything other than true, TRUE or 1 installs from the distribution: default-mysql-server, then mysql-server, then mariadb-server, whichever is available |
Behaviour worth knowing:
- On Debian
trixie,forkyandsidthe function installs MySQL 8.4 LTS from thebookwormsuite regardless ofMYSQL_VERSION. If that fails it installs MariaDB and returns0. - With
USE_MYSQL_REPO=falseon a distribution without MySQL packages, the result is MariaDB.
| Returns | When |
|---|---|
0 | Installed or updated |
100 | APT, repository or package failure |
7 | The MySQL signing key could not be imported |
127 | mysql is missing after installation |
1 | The old version could not be removed because another package depends on it |
No script in ProxmoxVE calls setup_mysql at the moment. install/fleet-install.sh,
the one script that needs MySQL, installs mysql-server with apt and uses
setup_mysql_db only. A call looks like this:
MYSQL_VERSION="8.4" setup_mysqlsetup_mysql_db
Creates a database and a '<user>'@'%' account with full access to it. The host is
% because MySQL treats localhost (socket) and 127.0.0.1 (TCP) as different
hosts.
MYSQL_DB_NAME=<name>
MYSQL_DB_USER=<user>
setup_mysql_db| Variable | Default | Meaning |
|---|---|---|
MYSQL_DB_NAME | required | Database name. Created with utf8mb4 / utf8mb4_unicode_ci |
MYSQL_DB_USER | required | User name |
MYSQL_DB_PASS | generated | Password. If empty, 13 alphanumeric characters are generated |
MYSQL_DB_CREDS_FILE | ~/<app>.creds | File the credentials are appended to |
APPLICATION | set by the framework | Only used for the default credentials file name |
Exports MYSQL_DB_NAME, MYSQL_DB_USER and MYSQL_DB_PASS.
| Returns | When |
|---|---|
0 | Database created |
65 | MYSQL_DB_NAME or MYSQL_DB_USER is not set |
Example, the call from install/fleet-install.sh with the assignments moved onto
their own lines:
MYSQL_DB_NAME="fleet"
MYSQL_DB_USER="fleet"
setup_mysql_dbMongoDB
setup_mongodb
Installs mongodb-org from the official MongoDB repository and starts mongod.
[MONGO_VERSION=<major.minor>] setup_mongodb| Variable | Default | Meaning |
|---|---|---|
MONGO_VERSION | 8.0 | Release series, for example 7.0, 8.0, 8.2 |
Behaviour worth knowing:
- CPU check first. On x86 a CPU without AVX is refused for every version above 5; on
arm64 the CPU must report
asimd. - Only Debian and Ubuntu are supported.
- When a different version is installed and no other package depends on MongoDB, the
old packages are purged and the new ones installed. The data in
/var/lib/mongodbstays. - When another package depends on
mongodb-org-server(Omada does), the upgrade happens in place. That path refuses a downgrade, refuses to skip a major release, raises the featureCompatibilityVersion to the installed release first, and simulates the apt transaction. If the simulation shows that other packages would be removed, the old repository is restored and the function returns1. - After an in-place upgrade the featureCompatibilityVersion of the default instance
is set to the new version. An app that runs its own
mongodon another port has to callmongodb_set_fcvfor that instance. - For MongoDB 8 and newer on a kernel 6.19 or newer, a systemd drop-in sets
GLIBC_TUNABLES=glibc.pthread.rseq=1formongod.
| Returns | When |
|---|---|
0 | Installed or updated |
236 | The CPU lacks the required instruction set |
238 | Distribution is neither Debian nor Ubuntu |
100 | APT, repository or package failure |
127 | mongod is missing after installation |
1 | The upgrade path was refused (downgrade, skipped major, apt would remove other packages) |
Example from install/graylog-install.sh:
MONGO_VERSION="8.2" setup_mongodbmongodb_get_fcv
Prints the featureCompatibilityVersion of a running mongod, for example 8.0.
mongodb_get_fcv [port]| Argument | Default | Meaning |
|---|---|---|
port | 27017 | Port of the instance to ask |
Returns non-zero when mongosh is not installed or no version could be read. It
prints nothing in that case.
No script in ProxmoxVE calls it directly; setup_mongodb uses it before an in-place
upgrade.
fcv="$(mongodb_get_fcv 27217)"mongodb_set_fcv
Sets the featureCompatibilityVersion of a running mongod. Data left at an older
value keeps the next major's binary from starting.
mongodb_set_fcv <version> [port]| Argument | Default | Meaning |
|---|---|---|
version | required | Target version, for example 8.0. From 7 on, confirm: true is added to the command |
port | 27017 | Port of the instance to change |
Returns 0 on success and 1 (with a warning) when mongosh is missing or the
command fails.
No script in ProxmoxVE calls it directly yet. After an in-place upgrade
setup_mongodb prints a reminder to run it for apps with their own instance:
mongodb_set_fcv 8.0 27217ClickHouse
setup_clickhouse
Installs clickhouse-server and clickhouse-client from the official ClickHouse
repository and starts the service.
[CLICKHOUSE_VERSION=<version>] setup_clickhouse| Variable | Default | Meaning |
|---|---|---|
CLICKHOUSE_VERSION | latest | latest is resolved from packages.clickhouse.com, with the GitHub release as fallback |
The version decides whether the function updates in place or reinstalls, and it is what gets recorded as installed. The packages themselves are installed without a version pin, so the repository's current stable release is what apt delivers.
On x86 the CPU must support AVX2.
| Returns | When |
|---|---|
0 | Installed or updated |
236 | x86 CPU without AVX2 |
250 | The latest version could not be determined |
100 | APT, repository or package failure |
127 | clickhouse-server is missing after installation |
1 | The old version could not be removed because another package depends on it |
Example from install/clickhouse-install.sh:
setup_clickhouseMeiliSearch
setup_meilisearch
Installs the MeiliSearch binary to /usr/bin/meilisearch, writes
/etc/meilisearch.toml and a systemd unit, and starts the service. When the binary
already exists it updates it instead.
[MEILISEARCH_BIND=<host:port>] [MEILISEARCH_DB_PATH=<dir>] setup_meilisearch| Variable | Default | Meaning |
|---|---|---|
MEILISEARCH_BIND | 127.0.0.1:7700 | http_addr in the config |
MEILISEARCH_ENV | production | env in the config |
MEILISEARCH_DB_PATH | /var/lib/meilisearch/data | Data directory |
MEILISEARCH_DUMP_DIR | /var/lib/meilisearch/dumps | Dump directory |
MEILISEARCH_SNAPSHOT_DIR | /var/lib/meilisearch/snapshots | Snapshot directory |
On a fresh install the function generates a master key and exports:
| Variable | Content |
|---|---|
MEILISEARCH_MASTER_KEY | The generated master key (openssl rand -base64 32) |
MEILISEARCH_API_KEY | The first key returned by the /keys endpoint |
MEILISEARCH_API_KEY_UID | The UID of that key |
On an update nothing is exported; the keys stay in /etc/meilisearch.toml.
Update behaviour: the function asks check_for_gh_release whether a newer release
exists. If major.minor changes, the on-disk format changes too. The function then
stops the service, writes /var/lib/meilisearch/pre-upgrade-<old version>.tar.gz,
replaces the binary, starts it once with --upgrade-db and waits up to 300 seconds
for /health. If the migration fails, the error message contains the restore
command for the backup.
| Returns | When |
|---|---|
0 | Installed, updated or already current |
250 | The binary could not be downloaded |
7 | The default config could not be downloaded |
150 | The service did not start after a fresh install |
100 | The pre-upgrade backup of the data directory failed |
Example from install/meilisearch-install.sh:
MEILISEARCH_BIND="0.0.0.0:7700" setup_meilisearchinstall/bar-assistant-install.sh calls plain setup_meilisearch and then writes
${MEILISEARCH_MASTER_KEY} into the application's .env.
Internal functions
These are called by the functions above. Do not call them from a script.
| Function | Used by | What it does |
|---|---|---|
_setup_mariadb_runtime_dir | setup_mariadb | Writes /etc/tmpfiles.d/mariadb.conf and creates /run/mysqld |
_configure_pg_cron_preload | setup_postgresql | Adds pg_cron to shared_preload_libraries when cron is in PG_MODULES |
_mongodb_in_place_precheck | setup_mongodb | Refuses downgrades and skipped majors, raises the featureCompatibilityVersion |
_mongodb_in_place_simulate | setup_mongodb | Simulates the apt upgrade and fails if packages other than MongoDB's would be removed |
Runtimes and tools
Reference for the language runtime and tool installers in lib/runtime.func - Node.js, uv/Python, Go, Rust, Ruby, Java, .NET, PHP, Docker, FFmpeg and more.
Hardware acceleration
Reference for setup_hwaccel in lib/hwaccel.func and the GPU passthrough the Proxmox VE host side sets up for it.