Skip to main content

Server Environment

A server deployment runs the whole Runtime on a Linux host the tenant owns and is reached through the public Runtime Origin you confirm in the Control Plane. The examples use Ubuntu or Debian packages.

The copyable route on this page is Ubuntu 24.04 with systemd, not a generic Linux installation script. Other distributions require administrator-adapted repositories. After SSH login, run sudo -i and use the same root shell throughout.

Check first:

cat /etc/os-release
uname -m
ps -p 1 -o comm=

Expect Ubuntu 24.04, x86_64 or aarch64, and systemd. Stop and confirm the deployment plan for other results. Root can operate Docker without joining the docker group.

Capacity and Data Volume Planning​

ItemPlanning guidance
Entry configuration for the complete single-machine stack2 vCPU and 4 GiB RAM; add 2 GiB swap on small hosts. Validate business capacity against actual workloads
System diskAt least 60 GiB recommended for public dependencies, product images, logs, offline transfer files, and upgrades
Tenant data volumePrefer a separate encrypted data disk for new enterprise deployments, sized for database, attachments, and workflow growth. Small deployments can also use an encrypted file container with sufficient capacity
Larger workloads8 vCPU, 16 GiB RAM, and a 200 GiB SSD can be an initial planning point; adjust after representative concurrency, document parsing, and storage tests, rather than applying this to every tenant
CLI disk checkAt least 10 GiB free on the deployment directory's filesystem; this is a free-space check, not the total installation size

2 GiB RAM is no longer the recommended entry configuration for the current complete stack. The CLI does not enforce a 4 GiB RAM minimum. HTTP 200 from the health endpoint establishes readiness, not workload capacity. Swap does not replace physical RAM.

The complete stack includes document parsing. In one Linux AMD64 deployment, Docling reported about 8 GB and all images about 14 GB. Sizes vary with release, architecture, and shared layers. A 40 GiB system disk with an 8 GiB encrypted file container and 2 GiB swap had only about 11 GiB free after installation; prefer at least 60 GiB for new deployments. Import only the target architecture to avoid unnecessary disk use.

Small Hosts: Check and Create Swap​

In the root shell, run free -h, swapon --show, and df -h /. Check existing swap before creating another file. If no swap is active and the system disk has sufficient space, create a new 2 GiB file:

(
set -e
if [ -e /swapfile ]; then
echo '/swapfile already exists; stop and inspect it first'
exit 1
fi
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
if ! grep -qE '^[[:space:]]*/swapfile[[:space:]]' /etc/fstab; then
printf '/swapfile none swap sw 0 0\n' >> /etc/fstab
fi
swapon --show
free -h
)

Expect /swapfile in the active swap list and about 2 GiB total swap. Stop on failure; do not overwrite an existing file. Swap does not replace physical RAM or production capacity planning.

Prerequisites​

  • Docker Engine, Docker Compose v2, and Docker Buildx
  • Node.js 22, to run npx @soln/cli
  • Cosign, to verify image signatures
  • disk encryption (LUKS) enabled, and SOLN_DATA_AT_REST_ENCRYPTED=true in the deployment .env
  • a trusted TLS certificate for the exact Runtime Origin
  • outbound HTTPS access to the Control Plane, Soln’s private Registry, and selected public image registries; public images can also be imported as described in the installation guide
  • at least 10 GiB free on the deployment directory filesystem; plan total capacity using the table above
  • a synchronized system clock

Concept Notes​

  • Runtime Origin: the "origin" of the deployment address, meaning scheme + host + port, for example https://runtime.customer.example.com (HTTPS defaults to port 443, so the port is optional). It never contains a path, query string, or # fragment, and it must match the address confirmed in the Control Plane exactly
  • soln / npx @soln/cli: the command-line tool used for installation. The npm package is @soln/cli and the command is soln (alias sl). No global install is needed: run npx @soln/cli <command>
  • sl deployment prepare: generates the deployment files (docker-compose.yml, .env.example, agent.config.json, and the reverse proxy and tunnel configuration) directly in the deployment directory, so nothing has to be downloaded elsewhere and copied over. See Deployment Files and Directories
  • soln doctor: the CLI's own self-check command, run as soln doctor --dir <deployment directory>. It verifies that Docker, Compose, Buildx, and Cosign are available, that file permissions are safe, that required environment values are present, and that the deployment directory has at least 10 GiB free. Installation and upgrade run it first and stop when any check fails

This page checks and installs host tools. On a new server without encrypted storage, prepare the tools first, then choose one storage route in Single-Machine Installation. A missing mount is not permission to guess a device or format the system disk. Encryption and HTTPS checks must pass before Runtime installation.

Step 1: Connect to the Server and Check Encryption​

Every command on this page runs on the server, not on your own computer. ssh is the standard way to reach a Linux host from your machine: it opens a remote shell, so whatever you run afterwards runs on the server.

ssh deploy@runtime.example.com
  • deploy is the account you use on that server, and runtime.example.com is its address or IP, both provided by your hosting provider. Replace them with your own values
  • Success: the prompt becomes something like deploy@runtime:~$ — from here on you are typing on the server
  • Already connected through a cloud console, a jump host, or a terminal on the server itself? Skip this command and start with the check below
  • Permission denied (publickey) — wrong user or key; try ssh -i ~/.ssh/id_ed25519 user@host
  • Could not resolve hostname — the address is wrong or DNS is unavailable
  • On a Windows computer, use the ssh client that ships with PowerShell (Windows 10 1809 and newer). ssh : The term 'ssh' is not recognized means the OpenSSH Client optional feature is missing

After connecting, enter the root shell before continuing:

sudo -i
lsblk -f
  • A crypto_LUKS block device helps identify the encrypted container, but does not prove that SOLN_DATA_ROOT is mounted on it. File-backed LUKS containers may not appear directly in this list
  • For a cloud-native encrypted disk, confirm the attached disk identity and encryption status in the cloud console. Linux may show ordinary ext4 on /dev/vdb or a partition; this does not identify the provider's encryption status
  • Encryption not enabled yet — choose cloud-native disk encryption or LUKS in Single-Machine Installation. Set SOLN_DATA_AT_REST_ENCRYPTED=true only after verifying encryption and the correct data mount
  • command not found: lsblk — install the util-linux package, or check with sudo cryptsetup status

Single-machine deployments also need the tenant data directory that .env points at with SOLN_DATA_ROOT (default /srv/soln/data). It must sit on the encrypted volume and be private to the deployment user:

sudo install -d -m 0700 /srv/soln/data
findmnt /srv/soln/data
stat -c '%a %U:%G %n' /srv/soln/data
  • findmnt must identify the intended data filesystem mounted at /srv/soln/data. For cloud-native encryption, match its device and UUID to the attached cloud disk; for LUKS, check the mapping with sudo cryptsetup status soln-tenant-data, using your actual mapping name
  • ls -ld /srv/soln/data should show drwx------; correct permissions alone do not prove that the volume is encrypted or mounted
  • Mounted the encrypted volume elsewhere? Create the directory there and update SOLN_DATA_ROOT in .env to match
  • soln doctor rejects a SOLN_DATA_ROOT that is not absolute, that is /, that does not exist, or that is readable by group or other users
  • External services mode stores state with the tenant's own PostgreSQL, Temporal, and object storage, so this directory is only required in single-machine mode

For unattended recovery on a cloud host, prefer cloud-native encrypted storage, configure its UUID mount in fstab, and give Docker a RequiresMountsFor dependency plus AssertPathIsMountPoint=/srv/soln/data on a dedicated host. The manual LUKS passphrase route still needs unlocking after every reboot, including instance resizing; an external key service requires separate configuration. The CLI does not create disks or configure unlocking. Follow the storage routes and restart verification before completing delivery.

Step 2: Install Docker Engine​

2.1 Authorize sudo once​

sudo -v
  • Success: it asks for your password once, then returns to the prompt with no output
  • you are not in the sudoers file — use an administrator account or ask your administrator to grant sudo

Authorizing once means the rest of this step does not stop for a password in the middle.

2.2 Add the Docker package repository​

sudo apt-get update
  • Success: ends with Reading package lists... Done
  • E: Could not get lock /var/lib/dpkg/lock-frontend — another apt process is running; wait for it, then retry
  • Could not resolve 'archive.ubuntu.com' — network or DNS problem; fix it before continuing
sudo apt-get install -y ca-certificates curl gnupg
  • Success: ends with Setting up ... lines for those packages
  • E: Unable to locate package gnupg — run sudo apt-get update again first
sudo install -m 0755 -d /etc/apt/keyrings
  • Success: no output; the directory now exists
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  • Success: no output
  • curl: (7) Failed to connect — cannot reach download.docker.com; check the network or proxy
  • gpg: no valid OpenPGP data found — the download failed; fix the network and run the command again
sudo chmod a+r /etc/apt/keyrings/docker.gpg
  • Success: no output
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  • Success: no output (tee writes the file)
  • On Debian, replace linux/ubuntu with linux/debian

2.3 Install the packages​

sudo apt-get update
  • Success: ends with Reading package lists... Done and includes a download.docker.com line
  • NO_PUBKEY ... — the GPG key step failed; repeat 2.2
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
  • Success: ends with Setting up docker-compose-plugin ...
  • E: Unable to locate package docker-ce — the repository line above is wrong or apt-get update failed
  • docker-buildx-plugin and docker-compose-plugin install Buildx and Compose as Docker CLI plugins; the CLI reads both plugin paths from docker info and fails with DOCKER_PLUGIN_PATH_INVALID when they are missing
sudo systemctl enable --now docker
  • Success: prints Created symlink ... for the docker service
  • System has not been booted with systemd — this machine does not use systemd; start Docker with your init system instead

2.4 Confirm the engine answers​

systemctl is-active docker
  • Success: active
  • inactive or failed — start it with sudo systemctl start docker and check systemctl status docker
docker version
  • Success: Client: and Server: sections are both present
  • permission denied while trying to connect to the Docker daemon socket — log out and back in (or run newgrp docker) so the docker group applies

Step 3: Install Node.js 22​

3.1 Add the NodeSource repository and install​

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
  • Success: prints lines starting with ## Installing the NodeSource Node.js 22.x repo... and ends with a hint to run sudo apt-get install -y nodejs
  • curl: (7) Failed to connect — network or proxy problem
sudo apt-get install -y nodejs
  • Success: ends with Setting up nodejs ...
  • E: Unable to locate package nodejs — the repository script above did not run; repeat 3.1

3.2 Confirm​

node -v
  • Success: v22.x.y
  • A different major version — another Node.js install is first on PATH; check which -a node
  • command not found: node — the install failed; repeat 3.1

Step 4: Install Cosign​

4.1 Download the binary​

For mainland China servers, use Single-Machine Installation: Install Cosign from a Mirror to install v3.1.2 from GitCode or the Soln GitHub backup. Choose either that route or the official-source route below.

Select a version from the official Cosign release page and record its version and the SHA-256 for the architecture-specific file. Do not guess the checksum. Replace both placeholders with values from that release:

SOLN_COSIGN_VERSION='REPLACE_WITH_RELEASE_TAG'
SOLN_COSIGN_SHA256='REPLACE_WITH_PUBLISHED_SHA256_FOR_THIS_ARCH'
(
set -e
case "$(uname -m)" in
x86_64) SOLN_COSIGN_ARCH=amd64 ;;
aarch64) SOLN_COSIGN_ARCH=arm64 ;;
*) echo 'Unsupported architecture'; exit 1 ;;
esac
test "$SOLN_COSIGN_VERSION" != REPLACE_WITH_RELEASE_TAG
test "$SOLN_COSIGN_SHA256" != REPLACE_WITH_PUBLISHED_SHA256_FOR_THIS_ARCH
SOLN_COSIGN_TMP=$(mktemp -d)
trap 'rm -rf "$SOLN_COSIGN_TMP"' EXIT
curl -fSL "https://github.com/sigstore/cosign/releases/download/$SOLN_COSIGN_VERSION/cosign-linux-$SOLN_COSIGN_ARCH" \
-o "$SOLN_COSIGN_TMP/cosign"
printf '%s %s\n' "$SOLN_COSIGN_SHA256" "$SOLN_COSIGN_TMP/cosign" | sha256sum -c -
install -m 0755 "$SOLN_COSIGN_TMP/cosign" /usr/local/bin/cosign
)

4.3 Confirm​

cosign version
  • Success: the output contains a GitVersion: line
  • command not found: cosign — /usr/local/bin is not on PATH; run /usr/local/bin/cosign version to check the binary itself

Verify the download against the checksums published with the Cosign release before installing it on a production host.

Step 5: Verify Every Tool​

Each command must succeed before you continue; these are the same checks soln doctor performs.

docker version --format '{{.Server.Version}}'
docker compose version --short
docker buildx version
cosign version
node -v
timedatectl status
CommandSuccessTypical failure
docker version --format '{{.Server.Version}}'one version such as 27.5.1permission denied means the docker group change has not applied
docker compose version --shortone line such as v2.32.4'compose' is not a docker command means docker-compose-plugin is missing
docker buildx versiona line starting with github.com/docker/buildx'buildx' is not a docker command means docker-buildx-plugin is missing
cosign versionoutput containing GitVersion:command not found means /usr/local/bin is not on PATH
node -vv22.x.ya different version means another Node.js install is first on PATH
timedatectl statusa line such as System clock synchronized: yescommand not found means the host is not systemd; check NTP another way

Access tokens, session leases, Registry credentials, and TLS certificates are time-sensitive, so keep the clock synchronized.

Step 6: Prepare Domain and TLS​

The Runtime Origin must be an absolute HTTPS Origin without path, query, fragment, username, or password, and identical to the address confirmed in the Control Plane. The Control Plane rejects anything else with INTEGRATION_RUNTIME_ORIGIN_INVALID, and another tenant cannot register the same Origin.

dig +short runtime.customer.example.com
  • Success: prints the IP address the Origin resolves to
  • No output — the DNS record is missing; create it before installing
curl -fsS -o /dev/null -w '%{http_code}\n' \
https://runtime.customer.example.com/health/ready
  • Success: after the Runtime is installed this prints 200
  • Could not resolve host — DNS is not ready
  • SSL certificate problem — the certificate is missing or not trusted; install your certificate first

The reverse proxy inside the deployment binds to loopback, so terminate TLS on the host with your own certificate, or use the optional Cloudflare Named Tunnel described in Single-Machine Installation. Never expose the bundled PostgreSQL, Temporal, MinIO administration, or Temporal UI ports to the public Internet.

Step 7: Prepare Network and Ports​

The host needs outbound HTTPS to CP_URL, Soln's private Registry, and Docker Hub (registry-1.docker.io and auth.docker.io). Single-machine deployment also pulls public dependency images such as PostgreSQL, MinIO, nginx, and Temporal. Only the Runtime Origin needs to be reachable by users.

curl -fsS -o /dev/null -w '%{http_code}\n' "$CP_URL"
  • Success: prints an HTTP status such as 200 or 401
  • Could not resolve host or Connection timed out — outbound access to the Control Plane is blocked; open it in your firewall or proxy
dig +short registry.example.com
  • Success: prints the Registry address
  • No output — the Registry host is unresolvable; fix DNS before installing

To check Docker Hub access, keep image download failures separate from Runtime configuration errors:

docker pull --platform linux/amd64 postgres:17-alpine

This command is for an x86_64 host; use linux/arm64 on an ARM64 host. An i/o timeout means the Docker daemon cannot reach Docker Hub. Use the cloud provider's image accelerator for your account or import a same-architecture image from a machine that can reach Docker Hub. Continue to verify Soln release image signatures through the normal CLI flow. A release can also depend on other public Registries; inspect the image list with the release Compose override applied.

PortWherePurpose
8080server deploymentreverse proxy listener inside the deployment, kept on loopback behind your TLS proxy or tunnel
4100internalRuntime Service API, reachable only inside the Compose network

The CLI obtains short-lived, pull-only Registry credentials during soln install and soln upgrade, then logs out after pulling; manual docker login is not part of the supported path.

Step 8: Plan Disk Space​

df -h /opt
  • Success: the Avail column is at least 10Gi
  • Less than 10 GiB — installation stops with DEPLOYMENT_DISK_INSUFFICIENT

soln doctor checks free space on the deployment directory filesystem; it does not calculate a full capacity budget from image sizes. Reserve space for public dependencies, product images, offline archives and import, database backups, and old and new images during upgrades. Check again after allocating swap, creating an encrypted file container, importing images, and before each upgrade.

df -h /opt /srv/soln/data
du -h --max-depth=1 /srv/soln/data
docker system df

Do not add system disk free space to data volume free space. An 8 GiB LUKS file container provides roughly 7.8 GiB after formatting, shared by database, attachments, and workflow data. Enlarging the system disk does not enlarge the container. Existing containers with sufficient capacity can remain in use; plan growth and migration and keep off-host backups. Docker's reclaimable size does not establish that deletion is safe; do not bulk-delete required images or tenant volumes to pass the check.

One caveat: the check measures the deployment directory, while the images live in the Docker data root (by default /var/lib/docker). When that directory is on a separate disk, size that disk as well; the check does not cover it.

Next​

Continue with Deployment Files and Directories, then Single-Machine Installation or External Services Installation.