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.
Source: lib/runtime.func.
It is loaded through lib/tools.func on every container that is not Alpine. Alpine
containers load lib/alpine.func instead, which carries its own setup_yq,
setup_adminer, setup_uv, setup_java, setup_go and setup_composer; the rest
of this page does not exist there (see Alpine).
| Function | Purpose |
|---|---|
setup_nodejs | Node.js from NodeSource, npm, global modules |
setup_uv | uv, and optionally a Python version |
setup_nltk | NLTK data packages without Python |
setup_go | Go from go.dev |
setup_rust | Rust through rustup, optional crates |
rust_prune_toolchains | Remove all Rust toolchains but the default |
setup_ruby | Ruby through rbenv, optionally Rails |
setup_java | Temurin JDK |
setup_java_memory | Size the JVM heap from the container's memory |
setup_dotnet | .NET SDK or runtime |
setup_php | PHP with modules, Apache or FPM |
setup_composer | Composer |
get_php_fpm_socket | Path of the active PHP-FPM socket |
nginx_enable_site | Enable an nginx site, test, restart |
setup_adminer | Adminer |
setup_docker | Docker Engine, optionally Portainer |
ensure_docker | Docker precondition for add-on scripts |
setup_ffmpeg | FFmpeg from the distribution, a prebuilt build or source |
setup_gs | Ghostscript from source |
setup_imagemagick | ImageMagick 7 from source |
setup_yq | mikefarah's yq |
There is no setup_python. Python comes from the distribution or from
setup_uv with PYTHON_VERSION.
How these functions are called
Most installers take no positional arguments. They read environment variables, which scripts pass as a prefix on the same line:
NODE_VERSION="24" NODE_MODULE="pnpm" setup_nodejsEvery variable has a default, so a bare setup_nodejs is valid. The functions are
idempotent: called again from update_script() they update what is installed, or
switch versions when the requested one differs.
All functions return their status unless noted. Install scripts run under
catch_errors, so a non-zero return stops the script with that code. The numbers are
explained in Exit codes.
Node.js
setup_nodejs
Installs Node.js from the NodeSource repository, brings npm up to date and installs global npm modules.
[NODE_VERSION=<major>] [NODE_MODULE=<list>] setup_nodejs| Variable | Default | Meaning |
|---|---|---|
NODE_VERSION | 24 | Node.js major version. It selects the repository https://deb.nodesource.com/node_<version>.x |
NODE_MODULE | empty | Comma-separated global modules, each optionally with a version: pnpm, pnpm@12, yarn,corepack, @postlight/parser@latest |
NODE_COREPACK_ENABLE | 1 | Run corepack enable after installing corepack. Any other value skips it |
NPM_VERSION | latest | npm version installed with npm install -g npm@<version> |
NODE_MAX_OLD_SPACE_SIZE | unset | Heap limit in MB, see below |
NODE_OPTIONS | unset | If it already contains --max-old-space-size, the heap limit is left alone |
var_ram | set by the framework | Fallback for the heap calculation when /proc/meminfo cannot be read |
What it changes besides installing packages:
- The working directory becomes
/opt. COREPACK_ENABLE_DOWNLOAD_PROMPT=0andNPM_CONFIG_UPDATE_NOTIFIER=falseare exported.NODE_OPTIONSis exported with--max-old-space-size. The value isNODE_MAX_OLD_SPACE_SIZEif set, otherwise 75 % of the container's memory, clamped to 1024..12288 MB. Other flags already inNODE_OPTIONSare kept.- For npm 11 and newer,
dangerously-allow-all-scriptsis set totrue; for npm 12 and newer,allow-gitandallow-remoteare set toall. Both are written to the global and the user npm config. - If
pnpmis present,strictDepBuildsis set tofalseand the fetch timeout is raised. Ifyarnis present, its network timeout is raised.
Module rules:
- A bare
pnpminstallspnpm@^10. Name a version (pnpm@12) to get another major. - From Node.js 25 on,
corepackis added to the list automatically. - If
corepackis in the list it is installed and enabled first, andpnpmandyarnare then provided throughcorepack prepare ... --activateinstead of npm. - A module that fails to install produces a warning, not an error. After the loop
every unscoped module is checked with
command -vand reinstalled if its binary is missing.
Version changes: with a different major installed, Node.js is purged and reinstalled
from the new repository. That also uninstalls the global npm modules, so list the
ones the app needs in NODE_MODULE. If another package depends on nodejs, the
function upgrades in place instead and refuses a downgrade.
| Returns | When |
|---|---|
0 | Installed or updated |
250 | The NodeSource repository could not be set up |
100 | APT or package failure |
127 | /opt is not usable, or node / npm is missing after installation |
1 | npm could not be restored, a downgrade was refused, or an in-place upgrade would remove other packages |
Example from ct/archivebox.sh:
NODE_VERSION="22" NODE_MODULE="@postlight/parser@latest,single-file-cli@latest" setup_nodejsct/iobroker.sh pins npm: NODE_VERSION="24" NPM_VERSION="11" setup_nodejs.
Python
setup_uv
Installs uv to /usr/local/bin/uv from its
GitHub release and optionally installs a Python version with it.
[PYTHON_VERSION=<version>] [UV_PROJECT_DIR=<dir>] setup_uv| Variable | Default | Meaning |
|---|---|---|
PYTHON_VERSION | unset | If set, runs uv python install <version> |
UV_VERSION | unset | Exact uv version to install |
UV_PROJECT_DIR | unset | Project directory. If its pyproject.toml or uv.toml sets required-version, that decides the uv version: an exact pin is used as is, a range resolves to the newest release inside it |
USE_UVX | NO | YES also writes /usr/local/bin/uvx, a wrapper for uv tool run |
UV_HTTP_TIMEOUT | 600 | Exported for uv itself |
The uv version is chosen in this order: UV_VERSION, the project's
required-version, the latest release. Variables that uv itself reads pass through
to uv python install; ct/authentik.sh sets UV_PYTHON_INSTALL_DIR this way.
Supported architectures are x86_64, aarch64 and i686.
| Returns | When |
|---|---|
0 | Installed, upgraded or already at the target version |
236 | Unsupported architecture |
7 | The latest version could not be fetched, or the download failed |
251 | The tarball could not be extracted |
127 | No uv binary in the tarball |
252 | The binary or the uvx wrapper could not be written |
150 | uv python install failed |
Example from ct/beaverhabits.sh:
PYTHON_VERSION="3.14" UV_PROJECT_DIR="/opt/beaverhabits" setup_uvsetup_nltk
Downloads NLTK data packages straight from the nltk_data index, without running
Python.
setup_nltk "<package ids>" [target_dir]| Argument | Default | Meaning |
|---|---|---|
package ids | required | Space-separated NLTK package IDs in one string |
target_dir | /usr/share/nltk_data | Directory the packages are placed in |
Returns 0 when every package was downloaded and 1 when the index could not be
fetched or any package failed. The remaining packages are still attempted.
Example from ct/paperless-ngx.sh:
setup_nltk "snowball_data stopwords punkt_tab" "/usr/share/nltk_data"Go
setup_go
Installs Go from the official tarball to /usr/local/go and links go and gofmt
into /usr/local/bin.
[GO_VERSION=<version>] setup_go| Variable | Default | Meaning |
|---|---|---|
GO_VERSION | latest | latest, a full version such as 1.22.2, or a bare major.minor such as 1.22, which is resolved to the newest patch release of that line |
Because a bare major.minor is accepted, the go directive of a go.mod can be
passed directly.
| Returns | When |
|---|---|
0 | Installed, or already at the requested version |
236 | Architecture is neither x86_64 nor aarch64 |
250 | The version could not be resolved or the download failed |
251 | The tarball could not be extracted |
100 | jq, needed to resolve a major.minor, could not be installed |
1 | The old version could not be removed |
Example from ct/bitmagnet.sh:
GO_VERSION="$(grep -m1 '^go ' /opt/bitmagnet/go.mod | awk '{print $2}')" setup_goRust
setup_rust
Installs Rust through rustup, or updates the toolchain if rustup is already there, and installs global crates.
[RUST_TOOLCHAIN=<toolchain>] [RUST_PROFILE=<profile>] [RUST_CRATES=<list>] setup_rust| Variable | Default | Meaning |
|---|---|---|
RUST_TOOLCHAIN | stable | Toolchain to install and set as default |
RUST_PROFILE | default | rustup profile for a fresh install, for example minimal |
RUST_CRATES | empty | Comma-separated crates for cargo install, each optionally with a version: monolith, wasm-pack@0.12.1 |
HOME | set by the shell | Cargo lives in $HOME/.cargo |
What it changes besides installing:
$HOME/.cargo/binis added toPATHfor the current script. A fresh install also adds it to$HOME/.profileand writes/etc/profile.d/99-cargo.sh.[net] retry = 5is appended to the cargo config if it has no[net]section.- When
RUST_CRATESis set, every binary in$HOME/.cargo/binis linked into/usr/local/bin, so systemd units find it. - At the end it calls
rust_prune_toolchains.
| Returns | When |
|---|---|
0 | Installed or updated |
7 | The rustup installer could not be downloaded or failed |
127 | rustc is missing after installation |
250 | The Rust version could not be determined |
150 | A toolchain or crate failed to install |
Example from install/linkwarden-install.sh:
RUST_CRATES="monolith" setup_rustct/authentik.sh uses the minimal profile: RUST_PROFILE="minimal" RUST_TOOLCHAIN="stable" setup_rust.
rust_prune_toolchains
Uninstalls every rustup toolchain except the default one. A source tree with a
rust-toolchain.toml makes rustup install that exact version during a build and
never remove it; this frees the space again.
rust_prune_toolchainsNo arguments, no variables. Returns 0, also when rustup is not installed.
No script in ProxmoxVE calls it directly; setup_rust runs it at the end of every
call. Call it yourself after a build that came after setup_rust.
Ruby
setup_ruby
Installs rbenv and ruby-build into $HOME/.rbenv, compiles the requested Ruby
version and sets it as the global version.
[RUBY_VERSION=<version>] [RUBY_INSTALL_RAILS=false] setup_ruby| Variable | Default | Meaning |
|---|---|---|
RUBY_VERSION | 3.4.4 | Full Ruby version |
RUBY_INSTALL_RAILS | true | true runs gem install rails afterwards. A failure there only warns |
HOME | set by the shell | Location of .rbenv and of the profile files that get the rbenv PATH lines. The directory is created if missing |
Ruby is built from source, which takes several minutes. If the requested version is already the rbenv global version the function returns immediately.
| Returns | When |
|---|---|
0 | Installed or already at the requested version |
100 | APT is not working or no build dependency is available |
7 | rbenv or ruby-build could not be downloaded |
251 | An archive could not be extracted |
150 | rbenv or Ruby failed to build |
Example from ct/discourse.sh:
RUBY_VERSION="${RUBY_TARGET:-4.0.7}" RUBY_INSTALL_RAILS="false" setup_rubyJava
setup_java
Installs the Temurin JDK from the Adoptium repository.
[JAVA_VERSION=<major>] setup_java| Variable | Default | Meaning |
|---|---|---|
JAVA_VERSION | 21 | JDK major version. The package installed is temurin-<version>-jdk |
If a different Temurin JDK is installed it is purged first. The same version is upgraded through apt.
Returns 0 on success and 100 on any repository or package failure.
Example from ct/apache-guacamole.sh:
JAVA_VERSION="17" setup_javasetup_java_memory
Makes a Java service size its heap from the container's memory instead of the
host's. For each unit it writes the drop-in
/etc/systemd/system/<unit>.service.d/java-memory.conf. On every service start the
drop-in reads MemTotal from /proc/meminfo and sets
JAVA_TOOL_OPTIONS=-XX:MaxRAM=<MemTotal>k.
setup_java_memory <unit> [<unit> ...]| Argument | Meaning |
|---|---|
unit | systemd unit name without .service. Several can be given |
The function does nothing and returns 0 unless all three conditions hold: the
cgroup reports no memory limit (/sys/fs/cgroup/memory.max is max),
/proc/meminfo is served by lxcfs, and systemd is running. It always returns 0.
No script in ProxmoxVE calls it yet. A call for a service named myapp looks like
this:
setup_java_memory myapp.NET
setup_dotnet
Installs a .NET SDK or runtime. Debian and Ubuntu 22.04 get it from
packages.microsoft.com; Ubuntu 24.04 and newer get it from the distribution
archive. Major versions install side by side, so an existing one is left alone.
[DOTNET_VERSION=<major>] [DOTNET_TYPE=sdk|runtime|aspnetcore] setup_dotnet| Variable | Default | Meaning |
|---|---|---|
DOTNET_VERSION | 10 | Major version. 8.0 is accepted and treated as 8 |
DOTNET_TYPE | sdk | sdk installs dotnet-sdk-<v>.0, runtime installs dotnet-runtime-<v>.0, aspnetcore installs aspnetcore-runtime-<v>.0 |
| Returns | When |
|---|---|
0 | Installed or updated |
65 | Invalid DOTNET_TYPE |
100 | No Microsoft feed for this release, package not available, or apt failure |
Example from install/shoko-install.sh:
DOTNET_VERSION="8" DOTNET_TYPE="aspnetcore" setup_dotnetPHP and web server
setup_php
Installs PHP with a default module set, optional extra modules and optional Apache
or FPM integration. Debian uses the Sury repository, Ubuntu the ondrej/php PPA.
[PHP_VERSION=<major.minor>] [PHP_FPM=YES] [PHP_APACHE=YES] [PHP_MODULE=<list>] setup_php| Variable | Default | Meaning |
|---|---|---|
PHP_VERSION | 8.4 | Version as major.minor |
PHP_MODULE | empty | Extra modules, comma-separated, without the php<version>- prefix |
PHP_FPM | NO | YES installs and enables php<version>-fpm |
PHP_APACHE | NO | YES installs apache2 and libapache2-mod-php<version> and enables the module |
PHP_MEMORY_LIMIT | 512M | memory_limit |
PHP_UPLOAD_MAX_FILESIZE | 128M | upload_max_filesize |
PHP_POST_MAX_SIZE | 128M | post_max_size |
PHP_MAX_EXECUTION_TIME | 300 | max_execution_time |
Always installed: cli, common, bcmath, curl, dom, gd, gmp, intl,
mbstring, readline, xml, zip, mysql, sqlite3, pgsql, redis, imagick,
bz2, apcu, and opcache below PHP 8.5 (it is built in from 8.5 on). Modules that
are part of php-common (ctype, fileinfo, iconv, tokenizer, pdo, exif
and others) are filtered out of PHP_MODULE, and a module without a package is
skipped with a notice.
Behaviour worth knowing:
- If a different PHP version is installed it is removed first with
apt purge "php*". - The four
php.inivalues are written to the CLI ini, and to the FPM and Apache ini when those are enabled. - With
PHP_FPM=YESa systemd override setsRuntimeDirectory=phpfor the FPM service. PHP_FPMandPHP_APACHEare compared against the literalYES.
| Returns | When |
|---|---|
0 | Installed |
100 | Repository or package failure, or the version is not in the repository |
127 | php is missing afterwards or reports a different version than requested |
Example from install/projectsend-install.sh:
PHP_VERSION="8.4" PHP_FPM="YES" PHP_MODULE="ldap,pcntl" setup_phpsetup_composer
Installs Composer to /usr/local/bin/composer, or runs composer self-update if it
is already there. Call it after setup_php.
setup_composerNo variables. It exports COMPOSER_ALLOW_SUPERUSER=1 and sets Composer's global
process-timeout to 600.
| Returns | When |
|---|---|
0 | Installed or updated |
250 | The installer could not be downloaded |
150 | The installer failed |
127 | The binary is missing afterwards |
Example from install/bookstack-install.sh:
setup_composerget_php_fpm_socket
Prints the path of the PHP-FPM socket that exists on the system, for use in an nginx
fastcgi_pass or a Caddy php_fastcgi line.
PHP_SOCK=$(get_php_fpm_socket)| Variable | Default | Meaning |
|---|---|---|
PHP_VERSION | unset | If set and /run/php/php<version>-fpm.sock exists, that path is returned. Otherwise the highest version found under /run/php |
PHP-FPM has to be running; the socket only exists after the service has started.
Returns 1 with an error when no socket is found.
Example from ct/paymenter.sh:
PHP_SOCK=$(get_php_fpm_socket)
sed -i "s|fastcgi_pass unix:.*|fastcgi_pass unix:${PHP_SOCK};|" /etc/nginx/sites-available/paymenter.confnginx_enable_site
Links a site from sites-available into sites-enabled, removes the packaged
default site, runs nginx -t, enables the nginx unit and restarts it.
nginx_enable_site <site>| Argument | Meaning |
|---|---|
site | File name below /etc/nginx/sites-available/. It is used as given, including any .conf suffix |
Returns 1 when no name is given, the file does not exist or nginx -t fails.
Otherwise it returns the result of the restart.
Example from ct/paymenter.sh:
nginx_enable_site paymenter.confsetup_adminer
Installs Adminer. On Debian and Ubuntu it installs the adminer package, enables
its Apache configuration with a2enconf adminer and reloads Apache, so Apache has to
be present. The function also has an Alpine branch that downloads adminer.php to
/var/www/localhost/htdocs/adminer/index.php.
setup_adminerNo variables.
| Returns | When |
|---|---|
0 | Installed |
150 | The Apache configuration could not be enabled or Apache did not reload |
250 | The download failed (Alpine branch) |
Example from install/linkwarden-install.sh:
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
setup_adminer
fiDocker
setup_docker
Installs or updates Docker Engine, optionally installs Portainer, and on an existing installation offers to update running containers.
[USE_DOCKER_REPO=false] [DOCKER_PORTAINER=true] setup_docker| Variable | Default | Meaning |
|---|---|---|
USE_DOCKER_REPO | true | true, TRUE or 1 installs docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin and docker-compose-plugin from download.docker.com. Any other value installs docker.io from the distribution |
DOCKER_PORTAINER | unset | true installs Portainer CE on ports 9000 and 9443, or offers its update |
DOCKER_LOG_DRIVER | journald | Log driver written to /etc/docker/daemon.json. Only used when that file does not exist yet |
DOCKER_LXCFS_VISIBILITY | no | yes or true registers a runc wrapper as Docker's default runtime so nested containers see the LXC container's memory and CPU limits instead of the host's |
var_docker_lxcfs | unset | Same switch, read when DOCKER_LXCFS_VISIBILITY is not set |
DOCKER_NONINTERACTIVE | unset | 1 or true suppresses every prompt |
The header comment of the function also lists DOCKER_SKIP_UPDATES; the code does
not read it.
Prompts: when Docker was already installed, the function pulls the image of every
running container and, for each one whose image changed, asks whether to update it.
Compose-managed
containers are updated with docker compose pull and up -d; for standalone
containers only the image is pulled. Each prompt answers itself with "no" after 60
seconds. The whole check is skipped when the run is unattended, when
DOCKER_NONINTERACTIVE is set or when stdin is not a terminal.
The lxcfs option is described in core's
Docker inside LXC.
It never replaces an existing default-runtime.
Returns 0 on success and 100 when APT is not working or the Docker packages
cannot be installed or updated.
Example from ct/docker.sh, which keeps an existing docker-ce installation on the
official repository:
if dpkg-query -W -f='${Status}' docker-ce 2>/dev/null | grep -q "ok installed"; then
USE_DOCKER_REPO="true" setup_docker
else
setup_docker
fiensure_docker
Precondition check for add-on scripts that ship a Compose stack. If Docker and the
Compose plugin are present it returns. If Docker is missing it asks
Install Docker now? (y/N) and installs it: through setup_docker on Debian and
Ubuntu, through apk on Alpine.
ensure_docker| Variable | Default | Meaning |
|---|---|---|
APP | this script | Name used in the error messages |
DOCKER_NONINTERACTIVE | unset | 1 or true counts as an unattended run |
This function exits the script instead of returning an error.
| Exits with | When |
|---|---|
254 | Docker is missing and the run is unattended, or the user did not answer yes |
237 | Docker is installed without the Compose plugin, the installation failed, or Docker or Compose is still unavailable afterwards |
Returns 0 when Docker and Compose are available.
Example from tools/addon/dockge.sh:
function install() {
ensure_dockerMedia and tools
setup_ffmpeg
Installs FFmpeg in one of three ways: the distribution package, a prebuilt static build from BtbN/FFmpeg-Builds, or a build from source.
[FFMPEG_TYPE=<type>] [FFMPEG_VERSION=<version>] [FFMPEG_LICENSE=gpl|lgpl] setup_ffmpeg| Variable | Default | Meaning |
|---|---|---|
FFMPEG_TYPE | repo | See the table below |
FFMPEG_VERSION | latest | github: latest (master) or a release line such as n7.1. Source builds: a git tag; latest picks the newest stable tag |
FFMPEG_LICENSE | gpl | github only: gpl or lgpl |
FFMPEG_TYPE | What you get | Installed to |
|---|---|---|
repo | apt install ffmpeg | /usr/bin |
github | Prebuilt static build for amd64 or arm64. binary is accepted as an old name for it | /usr/local/bin |
minimal | Source build with x264, vpx, mp3 | /usr/local/bin |
medium | minimal plus freetype, libass, opus, vorbis | /usr/local/bin |
full | medium plus x265, dav1d, zlib, VA-API | /usr/local/bin |
Source builds use --enable-gpl --enable-nonfree and take a long time on a small
container. Use repo unless the app needs a codec or version the distribution does
not ship.
| Returns | When |
|---|---|
0 | Installed |
100 | The distribution package could not be installed |
106 | Unsupported architecture for a github build |
250 | A download failed or no source version could be determined |
251 | An archive could not be extracted |
150 | Configure, compile or install failed |
65 | Unknown FFMPEG_TYPE |
Examples: install/lychee-install.sh calls plain setup_ffmpeg;
install/pinchflat-install.sh uses the prebuilt build:
FFMPEG_TYPE="binary" setup_ffmpegsetup_gs
Builds the latest Ghostscript release from source and installs it system-wide. If the installed version is already current it does nothing.
setup_gsNo variables. If the latest version cannot be determined but gs is installed, the
function keeps the existing one and returns 0.
| Returns | When |
|---|---|
0 | Installed, or already current |
250 | The version could not be determined and nothing is installed, or the download failed |
251 | The archive could not be extracted |
252 | The source directory is missing after extraction |
150 | Configure, compile or install failed |
Example from install/transmute-install.sh:
setup_gssetup_imagemagick
Builds ImageMagick 7 from the latest GitHub source release and installs it to
/usr/local. The binary is /usr/local/bin/magick; the source stays in
/opt/imagemagick.
setup_imagemagickNo variables. It installs the build dependencies itself.
| Returns | When |
|---|---|
0 | Installed |
250 | The source could not be downloaded |
251 | The source directory could not be entered |
150 | Configure, compile or install failed |
Example from install/lychee-install.sh:
setup_imagemagicksetup_yq
Installs the latest mikefarah/yq to
/usr/local/bin/yq. A yq from another implementation is removed first.
setup_yqNo variables. If the installed version is already the latest it does nothing.
| Returns | When |
|---|---|
0 | Installed, or already current |
250 | The latest version could not be fetched or the download failed |
252 | The binary could not be moved into place |
Example from install/forgejo-runner-install.sh:
setup_yqInternal functions
These are called by the functions above. Do not call them from a script.
| Function | Used by | What it does |
|---|---|---|
_docker_is_noninteractive | setup_docker, ensure_docker | True when DOCKER_NONINTERACTIVE is set, the run is unattended or stdin is not a terminal |
_docker_setup_lxcfs_visibility | setup_docker | Writes /usr/local/bin/runc-lxcfs and registers it in daemon.json |
_setup_npm | setup_nodejs | Installs npm@${NPM_VERSION:-latest} and reports the result in NPM_SETUP_VERSION |
_cs_drop_pm_shim | setup_nodejs | Removes a pnpm, yarn or yarnpkg shim right before npm installs that module |
_nodejs_in_place_simulate | setup_nodejs | Simulates an in-place Node.js upgrade and fails if a dependent package would be removed |
_cs_write_cargo_profile | setup_rust | Writes /etc/profile.d/99-cargo.sh |
_cs_write_cargo_net | setup_rust | Appends [net] retry = 5 to the cargo config |
_uv_required_version | setup_uv | Reads required-version from a project's pyproject.toml or uv.toml |
_uv_release_list | setup_uv | Lists uv releases, newest first |
_uv_ver_ge | setup_uv | Version comparison |
_uv_pick_version | setup_uv | Picks the newest release that satisfies a version range |
_install_uvx_wrapper | setup_uv | Writes /usr/local/bin/uvx |