Platforms and architectures
How the engine decides whether it runs on Proxmox VE, Incus or inside a container, which CPU architectures it accepts, and which Proxmox VE versions pass the check.
A container script does not know where it runs. The engine works it out at load time and picks the backend:
| Platform | Backend | Host command |
|---|---|---|
| Proxmox VE | pve/backend.func | pct |
| Incus | incus/build.func and incus/backend.func | incus |
The wizard is the same on both. For running on Incus, see the Incus guide.
Platform detection
detect_lxc_platform in
lxc/platform.func
prints one of four values. The first rule that matches wins:
| Order | Test | Result |
|---|---|---|
| 1 | LXC_PLATFORM is set | its value |
| 2 | /dev/incus/sock is a socket, or /etc/profile.d/incus-motd.sh exists | incus-container |
| 3 | pveversion is on the PATH | pve |
| 4 | an incus client is found, and incus info works or /var/lib/incus exists or /var/run/incus/unix.socket is a socket | incus |
| 5 | none of the above | container |
The container markers come before the host tests on purpose: a container that
happens to carry the incus client must not be taken for a host.
The incus client is searched on the PATH and then in /usr/bin,
/usr/local/bin, /snap/bin and /opt/incus/bin. A non-login shell or
sudo can drop /snap/bin from the PATH; ensure_incus_on_path adds the
directory back so every later incus call resolves.
core/build.func
acts on the result:
| Result | What is loaded | What start does |
|---|---|---|
pve | ui/build-ui.func, pve/backend.func | Runs the checks and the install menu |
incus | incus/build.func (which loads the shared wizard and incus/backend.func) | Runs the checks and the install menu |
incus-container | incus/build.func | Update mode: the script's update_script |
container | ui/build-ui.func, pve/backend.func | Update mode: the script's update_script |
Inside a container (container or incus-container) the engine also fills
var_os and var_version from /etc/os-release when the script left them
unset, so a script that supports two operating systems updates the one that is
installed.
Overriding detection
If detection gets it wrong, set the answer:
LXC_PLATFORM=incus bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/Incus/main/ct/debian.sh)"Accepted values are pve, incus, incus-container and container. The
value is used as given; nothing validates it.
Architecture
_cs_host_arch in
core/core.func
returns the architecture of the machine that will run the container, in
Debian's spelling:
INCUS_SERVER_ARCH, if set.incus_targetsets it fromincus info, so a run against a remote Incus server uses the server's architecture.- Otherwise
dpkg --print-architecture, oruname -mwhere there is nodpkg.
x86_64 becomes amd64 and aarch64 becomes arm64. Everything else is
passed through unchanged.
arch_check and var_arm64
arch_check runs before the install menu. Any architecture other than amd64
and arm64 ends the run with exit code 106:
This script requires amd64 or arm64 (detected: armhf).On amd64 nothing else happens. On arm64 the script's var_arm64 decides:
var_arm64 | Meaning | On an arm64 host |
|---|---|---|
yes | Known to work | Continues without a word |
no | Known not to work: no arm64 build upstream, or an x86-only dependency | "This script does not support arm64.", exit 106 |
| unset | Nobody has verified it | Warns, asks Continue anyway? (y/N):. Anything but y or yes exits 106 |
The third state exists because "there is no arm64 build" and "nobody tried" are different facts, and only the second is worth an attempt. When the question cannot be asked (no terminal), the run does not guess:
Not running interactively - refusing to guess on arm64. Set var_arm64=yes to override.So an unattended install of an unverified script on arm64 needs the override:
var_arm64=yes mode=default bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/debian.sh)"Scripts declare the value near the top. ct/debian.sh sets
var_arm64="${var_arm64:-yes}"; ct/listenarr.sh sets
var_arm64="${var_arm64:-no}" with the reason in a comment ("upstream
publishes a linux-x64 build only"). Because of the ${var_arm64:-...} form, a
value from your environment wins over the script's. var_arm64 cannot be set
from a .vars file.
On a Proxmox VE arm64 host, arm64_notice additionally shows a dialog titled
ARM64 SUPPORT saying that arm64 support is in active development. The Incus
backend skips that dialog.
What the architecture changes
Templates on Proxmox VE. Templates are per architecture. The version
picker only lists catalog entries whose file name ends in _<arch>.tar.zst,
.tar.xz or .tar.gz. If Proxmox offers no template for the requested OS,
version and architecture, the backend looks the image up on
images.linuxcontainers.org and downloads it from there. On arm64 the two
template preflight checks are skipped for that reason ("ARM64 uses custom
template source"), and resolve_os_version does not consult the Proxmox
catalog.
Images on Incus. The image must exist for the architecture. If it only exists for another one, the run stops with exit code 106.
Base packages. On arm64, openssh-server, wget and gcc are installed
in addition to the usual sudo curl mc gnupg2 jq.
Downloads in scripts. Upstream projects name their release files
differently per architecture. arch_resolve returns its first argument on
amd64 and its second on arm64, defaulting to amd64 and arm64:
fetch_and_deploy_gh_release "redlib" "redlib-org/redlib" "prebuild" "latest" "/opt/redlib" \
"redlib-$(arch_resolve "x86_64" "aarch64")-unknown-linux-musl.tar.gz"That line is from ct/alpine-redlib.sh. Inside the container arch_resolve
uses PCT_ARCH, which the Proxmox backend exports. On any other architecture
it prints "Unsupported architecture" and returns 106.
Telemetry. The reported arch field uses the same spelling (amd64,
arm64). See Telemetry and diagnostics.
Supported Proxmox VE versions
Container scripts
pve_check in core/core.func runs after shell_check and root_check and
before the install menu. In order:
- Not a Proxmox VE host (
pveversionmissing): exit 232. pmxcfs_check:/etc/pvenot mounted, or/etc/pve/storage.cfgmissing: exit 228. A cluster node without quorum: exit 210. When/etc/pveis not mounted and a terminal is available, it first offers to restartpve-cluster.- The version test:
Version from pveversion | Result |
|---|---|
| 8.0 to 8.9 | accepted |
| 9.0 to 9.2 | accepted |
| 9.3 and later 9.x | "This version of Proxmox VE is not yet supported.", exit 1 |
| anything else (7.x, 10.x) | "This version of Proxmox VE is not supported.", exit 1 |
An unsupported version exits with code 1 here, not 105.
The test only looks at major and minor version. The check does not require a particular patch level.
VM scripts
VM scripts load
pve/vm-core.func,
which has its own pve_check. It accepts the same ranges, 8.0 to 8.9 and 9.0
to 9.2, but exits with code 105 ("Validation: Proxmox VE version not
supported" in the exit code table). It does not run pmxcfs_check.
vm_preflight runs the VM checks in this order:
| Check | Fails when | Exit |
|---|---|---|
check_root | not root, or started through sudo | 104 |
arch_check | dpkg --print-architecture is not amd64 | ends the script with a pointer to the arm64 fork, no error code |
pve_check | version outside 8.0 to 8.9 and 9.0 to 9.2 | 105 |
kvm_check | /dev/kvm is missing | 236 |
ssh_check | you answer "No" to the SSH warning; skipped with VM_UNATTENDED=1 | ends the script, no error code |
The VM arch_check is skipped when the script sets var_arm64="yes". Unlike
the container path it has no "ask" state: a VM script that does not declare
arm64 support does not run on arm64.
Host tools
Tools that drive the node (pct, pveam, pvesm, qm) call
require_pve_host. It exits 232 when pveversion is missing and then runs the
container pve_check described above.
On Incus
The Incus backend replaces pve_check with incus_check: the incus client
must exist, incus info must succeed, and there must be at least one storage
pool. Each failure exits with code 1 and a message naming the cause. No Incus
version is required. Inside an Incus container the check is skipped.
Incus VM scripts accept x86_64 and aarch64 and need /dev/kvm.