Installation
Ready to turn your plain Ubuntu VPS into a hardened, LXD-powered container host? The Terrarium installer makes it quick and easy.
Requirements
- Ubuntu Server 24.04 LTS
- root access on the host
- SSH key-based access
- Optional Docker Hardened Images registry access. Terrarium first uses the upstream DHI registry when
/root/.docker/config.jsonis present, then uses Terrarium's public GHCR mirror of the same pinned DHI image indexes, and only uses pinned upstream public fallbacks when hardened image use or mirrors are disabled. Setterrarium_docker_hardened_images: trueor explicit image variables when you want installation to fail closed unless the upstream DHI images are available. - either:
- a dedicated extra disk for the LXD ZFS pool, which is the recommended setup
- or enough root-disk space to use
--storage-mode file
If you still need to create the VPS itself, start with the provider setup guides:
Or browse the full Provider Guides section first.
Recommended Install
Most users should use the interactive installer. Just run this single command:
curl -fsSL https://github.com/terion-name/terrarium/releases/latest/download/install.sh | bashThe published install.sh is intentionally thin. It downloads the matching release bundle from GitHub Releases, unpacks the compiled terrariumctl binary plus the Ansible provisioning assets into /opt/terrarium, and runs the real installer there. Default and tag-like release installs fail closed if the release cannot be resolved or downloaded; source builds require an explicit branch-like --ref, for example main.
If you want to pin a specific release instead of latest, use the tagged asset directly:
curl -fsSL https://github.com/terion-name/terrarium/releases/download/0.0.0-beta3/install.sh | bashInstall Modes
Interactive mode is the default and is the best fit for most first installs. It guides you through the process, asking a few simple questions.
curl -fsSL https://github.com/terion-name/terrarium/releases/latest/download/install.sh | bashNon-interactive mode is for automation, templates, or repeated installs:
curl -fsSL https://github.com/terion-name/terrarium/releases/latest/download/install.sh | bash -s -- \
--non-interactive \
--email admin@your-domain.tld \
--acme-email certs@your-domain.tld \
--idp local \
--generate-root-pwd \
--storage-mode file \
--yesStorage Modes
Terrarium supports three storage modes:
diskUse a dedicated non-root disk for the ZFS pool. This is the recommended production setup.partitionUse an existing unused partition or allocatable free space on a non-root disk.fileCreate a file-backed ZFS pool on the root filesystem. This is the fallback when there is no extra disk.
Important notes:
- Terrarium does not shrink the mounted root filesystem.
- In interactive mode,
partitionmode discovers allocatable targets, suggests the largest one, and asks for confirmation. - In non-interactive mode,
--storage-sourceis required fordiskandpartition. - You can use
--storage-source autoto let Terrarium pick the largest valid non-root target automatically.
First Decisions During Install
The installer will guide you through:
- Contact email and ACME email for SSL certificates.
- Root password setup for Cockpit when the host does not already have a usable local root password.
- Domain setup (custom domain or default
traefik.me). - IDP mode:
localfor self-hosted ZITADELoidcfor an external OIDC provider
- Storage mode and storage source.
- Optional S3 archive backups.
- Optional syncoid replication.
Terrarium also verifies the most failure-prone integrations while you configure them:
- Password and secret prompts are masked in interactive mode.
- External OIDC settings are probed against the issuer, callback flow, and client credentials before install continues.
- S3 settings are tested with a real write/delete probe against the configured bucket.
Container Image Sources
Terrarium pins the upstream oauth2-proxy and local ZITADEL Postgres image sources by digest. The default source order is:
- upstream Docker Hardened Images from
dhi.iowhen Docker registry credentials exist on the host. - Terrarium's GHCR mirror of those same DHI multi-arch indexes when upstream DHI credentials are not present.
- the pinned public upstream images when
terrarium_docker_hardened_imagesorterrarium_docker_hardened_image_mirrorsis disabled.
The GHCR mirror is refreshed by CI with Docker Hub credentials, copies every platform in the pinned index, and verifies the copied index and required linux/amd64 and linux/arm64 manifests before publishing.
In interactive mode, failed verification sends you back to the relevant prompts. In non-interactive mode, install exits with an error instead of persisting broken settings.
For non-interactive automation, use generated or file-based secret inputs so secrets do not travel through shell history or process arguments:
--generate-root-pwd--root-pwd-file--oidc-secret-file--lxd-oidc-secret-filewhen using a separate LXD OIDC client--s3-secret-key-file
After Install
Terrarium keeps:
- the installed Terrarium bundle at
/opt/terrarium - the canonical config in LXD's dqlite-backed
terrarium-systemproject after LXD is initialized - canonical config in LXD's dqlite-backed store, with an optional root-only YAML export available through
terrariumctl config export
From there, the main commands you will use are:
terrariumctl statusterrariumctl set ...terrariumctl proxy syncterrariumctl backup ...
For full command details, see terrariumctl Reference.