Skip to main content
Version: Development

Run a node in a Linux container

This guide builds a non-root image from an authenticated LSF release and runs the node in the foreground. Use a Linux amd64 Docker host with a kernel of at least 6.8, readable CPU and memory pressure information, and private local storage. The image supplies Ubuntu 24.04 and glibc; it cannot supply host kernel features. On Windows, prepare the image in your Linux/WSL workspace.

The maintained qualification uses real local Docker containers and persistent volumes. Azure Container Apps, Azure Files, NFS and SMB are unqualified. No cloud resources or simulated cloud results are part of this profile. For a deployment you can operate today, use a Linux host whose prerequisites you can verify, with local durable storage and an explicitly configured ingress.

Build from an authenticated release​

Follow Install LSF to obtain the release directory, an independently installed GitHub verifier, trusted Sigstore roots and an approved publisher policy. These are the same trust inputs as the native installer. Keep them outside directories writable by an application. This step checks the publisher, exact release identities, archive contents and file modes before creating a fresh Docker context:

python3 tools/prepare_container_runtime.py --release-directory "$ReleaseDirectory" --version "$Version" --publisher-policy "$PublisherPolicy" --trusted-root "$TrustedRoot" --verifier "$GitHubVerifier" --output "$ImageContext"
docker build --tag lsf-runtime:reviewed "$ImageContext"

Keep build-inputs.json with the resulting image ID. It records authentication and recipe identities; it does not claim that building an image qualifies a host. The image has root-owned executable files, UID/GID 10001:10001, no Rust toolchain, and a small Python preflight which becomes the native process using exec. There is no shell supervisor or additional resident service.

Prepare private configuration and storage​

Use your reviewed node configuration, private operator client configuration and current admission policy. The disposable signing keys in the qualification test are never deployment keys. Set these container paths explicitly:

InputContainer locationRequired protection
Node configuration/etc/lsf/node.jsonUID 10001, mode 0600, or root/group 10001, mode 0640; directory not writable by other users
Admission policy and operator clientPaths under /etc/lsfPrivate reviewed files, read-only mount
Durable state/var/lib/lsfUID/GID 10001, directory mode 0700, persistent local filesystem
Compiler/cache files/var/cache/lsfUID/GID 10001, directory mode 0700, separate persistent writable mount

Set dataDirectory to /var/lib/lsf, select securityProfile explicitly, and use supplyChain.mode: "enforced" with your policy file. Configure shutdownGraceMillis at most 5000 and allow at least ten seconds for container termination. Readiness still requires a usable pressure source, private state and valid credentials even if no capsules have been deployed.

For componentless static publications, local-experimental-v1 avoids the isolated compiler prerequisite. This remains the T0 local profile: it is not the security boundary for untrusted guest execution. Static packaging and serving do not activate an application Store. A privileged operator could still deploy a capsule, so protect management and restrict its credentials accordingly.

For untrusted capsule execution, select external-capsule-v1. It additionally requires an approved /opt/lsf/release/bin/latent-aot-compiler, its exact release digest, a protected native AOT key and /var/cache/lsf/native-blobs and /var/cache/lsf/native-receipts. The native check must establish the Landlock/seccomp compiler profile. A container that lacks those capabilities cannot silently fall back to the local profile. See execution security profiles.

Check and start the node​

Here ConfigDirectory, DataDirectory and CacheDirectory are the prepared absolute host directories. On the Linux Docker host, run the same image and mounts first with check:

docker run --rm --read-only --cap-drop ALL --security-opt no-new-privileges --network host --mount "type=bind,source=$ConfigDirectory,target=/etc/lsf,readonly" --mount "type=bind,source=$DataDirectory,target=/var/lib/lsf" --mount "type=bind,source=$CacheDirectory,target=/var/cache/lsf" lsf-runtime:reviewed check

A successful result includes the observed kernel, libc, pressure visibility and native security profile. It opens no serving listener. Start using those same mount arguments, add --name lsf-node --cpus 2 --memory 1g --pids-limit 128, and replace check with serve. Set log rotation in your Docker daemon policy. Keep the management bind on literal loopback. Linux host networking lets a reviewed local edge and operator reach that loopback endpoint; it grants no public management access. For application traffic, configure the HTTP/TLS ingress explicitly. A container's separate loopback namespace cannot be reached merely by publishing an unrelated port. For a separate TLS terminator, use the qualified local HTTPS edge with its exact native peer and private probe topology.

Readiness is an authenticated operation:

docker exec lsf-node /opt/lsf/release/bin/latent --config /etc/lsf/client.json --output json node get "$NodeId"
docker stop --time 10 lsf-node

Require a known successful result, the expected node identity and data.inventory.health.ready: true. A listening TCP port is insufficient. SIGTERM reaches native PID 1, which owns bounded drain and orderly persistence. Supervisors that require HTTP checks can use the optional private readiness adapter, with explicit resource limits. Retain all state and configuration together; use the stopped local backup and restore workflow. Wait for the configured supply-chain clock lease before a restart; the persisted lease can reject an early restart. Always wait for the old owner to exit before starting its replacement. Use the container handover procedure for overlap rejection, interrupted replacement and explicitly eligible recovery. Use the private CI publishing workflow to change publications and routes without restarting the runtime or exposing management.

Diagnose a rejected host​

DiagnosticAction
run-as-uid-and-gid-10001Run the image with its declared user; correct mount ownership outside the runtime.
kernel-6.8-or-newer-requiredChoose a supported host; changing the image cannot upgrade its kernel.
readable-cpu-and-memory-pressure-requiredMake the required host pressure files readable through a supported deployment profile. Do not invent pressure values.
private-node-storage-required / filesystem-lock-exclusion-unavailableFix the mount or use a qualified local filesystem. A generic mount probe does not qualify remote storage.
root-owned-release-executable-identity-mismatchRebuild from the authenticated context; do not replace a binary in a running image.
native-check-config-failed-check-profile-sandbox-and-protected-configurationRun the native check-config command privately and inspect its bounded diagnostic. Correct the policy, key or host sandbox; keep the selected profile.

Reproduce the maintained check​

The Native container runtime workflow authenticates the released archive and builds the image. Its finite drill generates fresh test identities, uses the released CLI to sign and publish two actual sites, verifies GET/HEAD bytes and ETags, stops and restarts the node on persistent volumes, and checks unchanged routes and zero prepared capsules. It also verifies rejection of root startup. Only its own labelled disposable resources are removed. Public receipts retain the release/image identities, host preflight and measured restart duration.

This establishes the recorded local static-serving profile. It does not claim external-capsule execution, managed-host support or power-loss durability for an unqualified filesystem. The architecture decision defines these support boundaries.