Features
| Feature | Description |
|---|---|
| Pure Rust, static | No runtime deps; static glibc/musl binaries are published for common Linux targets |
| Sub-reaper mode | -s flag enables PR_SET_CHILD_SUBREAPER, reaps orphaned children |
| Parent-death signal | -p <SIG> mirrors tini -p (PR_SET_PDEATHSIG) |
| Signal forwarding | Forwards most signals; -g mode falls back gracefully if PGID can't be assigned |
| Graceful shutdown | SIGTERM → configurable wait → SIGKILL; timeout set via -t/--grace-ms |
| Exit-code remap | -e <code> maps specific child exit codes to zero for health-checks |
| Verbosity control | -v/-vv/-vvv or TINI_VERBOSITY=1..3 via tracing |
| Security-audited | #![deny(unsafe_op_in_unsafe_fn)], minimal unsafe surface, no dynamic allocation in hot paths |
| Cross-platform | Linux glibc / musl; works as PID 1 in Docker, LXC, Podman, Kubernetes, fire-cracker, etc. |
| Env overrides | TINI_SUBREAPER, TINI_KILL_PROCESS_GROUP, TINI_VERBOSITY act as defaults (CLI wins) |
| Command env expansion | --expand-env expands ${VAR} and ${VAR:-default} without requiring /bin/sh |
| Explain mode | --explain prints the effective config and child argv without spawning the child |
| Write restriction | --write-restrict limits filesystem writes to explicitly allowed directories (Linux; may need seccomp) |
| TCP port restriction | --bind-tcp-allow / --connect-tcp-allow limit child TCP bind/connect ports via Landlock |
| IPC scope restriction | --scope-signals / --scope-abstract-unix confine IPC to the same Landlock domain |
| Exec restriction | --exec-allow limits which executables the child may run after startup |
| Device ioctl restriction | --device-ioctl-allow limits which device nodes may receive ioctl operations |
Installation
# Install locally with Cargo
# Build a static binary (e.g. for PID 1 in Docker)
# Docker image (includes /sbin/tino)
Binary Releases
GitHub Releases publish stable, versioned archives with a single top-level directory:
tino-<version>-<os>-<arch>-<abi>/
├── tino
├── LICENSE
└── README.md
Supported platform matrix and asset mapping:
| OCI platform | Rust target | Release asset |
|---|---|---|
linux/amd64 |
x86_64-unknown-linux-gnu |
tino-<version>-linux-x86_64-gnu.tar.gz |
linux/amd64 |
x86_64-unknown-linux-musl |
tino-<version>-linux-x86_64-musl.tar.gz |
linux/arm64 |
aarch64-unknown-linux-musl |
tino-<version>-linux-aarch64-musl.tar.gz |
linux/arm/v6 |
arm-unknown-linux-gnueabihf |
tino-<version>-linux-arm-gnueabihf.tar.gz |
linux/arm/v7 |
armv7-unknown-linux-gnueabihf |
tino-<version>-linux-armv7-gnueabihf.tar.gz |
Every release also includes:
SHA256SUMScovering all published assets- per-asset
*.spdx.jsonSBOM files in SPDX JSON format - GitHub artifact attestations for the archives and attached SBOMs
Quick Start
# Replace tini in your Dockerfile
# Run locally
Runtime Notes
-g/--pgroup-killlogs a warning and falls back to single-process signalling when process-group creation fails (for example inside constrained PID namespaces).- tino's internal signalfd is opened with
CLOEXEC, ensuring child workloads do not inherit extra file descriptors. - Logging setup is idempotent: repeated initialisation (tests, embedding) no longer panics.
TINI_*env vars only apply when the corresponding CLI flag is not set (CLI wins).--expand-envexpands child command arguments beforeexecvp; supported forms are${VAR},${VAR:-default}, and$$for a literal dollar sign. Unbraced$VARis left unchanged. This is not a shell.--explainprints the effective configuration, resolved child argv, and write allowlist, then exits without spawning the child. It is an explanation mode, not a dry-run simulator.- Write restriction (optional, Linux):
--write-restrict --write-allow /path(repeatable) denies filesystem writes outside allowlisted directories; default is strict (use--write-warn-onlyto continue). --write-preset tmpexpands to/tmpand/var/tmp;--write-preset runtimeadds/run. Missing standard directories are skipped, and presets can be combined with--write-allow.- Write restriction keeps
/devwritable for TTY/stdout by default (disable with--write-no-dev). - TCP restriction (optional, Linux):
--bind-tcp-allow 8900limits which local TCP ports the child may bind;--connect-tcp-allow 443limits outbound TCP connections by remote port. These options require Landlock ABI v4+. - IPC scope restriction (optional, Linux):
--scope-signalsrestricts signal delivery to processes in the same or a nested Landlock domain;--scope-abstract-unixrestricts abstract UNIX socket connects to the same domain. These options require Landlock ABI v6+. - Exec restriction (optional, Linux):
--exec-allow /pathrestricts which executables the child may launch after startup. Allow entries that point to files automatically include direct shebang interpreters and ELF loaders; directory-based allow entries do not. - Device ioctl restriction (optional, Linux):
--device-ioctl-allow /dev/pts/0restricts ioctl(2) to explicit device nodes or directories. This option requires Landlock ABI v5+. - When any Landlock feature is requested,
--write-warn-onlyswitches startup failures to warnings and continues without applying the requested restriction. - Docker: if Landlock syscalls are blocked, use
--security-opt seccomp=./seccomp-landlock.json(orseccomp=unconfinedfor testing).
Landlock + Docker (seccomp)
Docker's default seccomp profile often blocks landlock_* syscalls. This repo includes
seccomp-landlock.json, based on moby/profiles (see seccomp-landlock.upstream.sha).
For scratch/distroless workloads that need simple parameter expansion without a shell:
For common runtime layouts, presets reduce boilerplate:
To restrict a service to a known listen port without a full firewall layer:
To keep plugin-like child processes from signalling or connecting to IPC resources outside their own Landlock domain:
To prevent a managed service from spawning helper commands except for an explicit allowlist:
To only permit device ioctl calls on a known PTY or device subtree:
To inspect the final argv and effective security settings without executing the child:
To make this the default for all containers, set Docker's daemon config:
Refresh the profile with python scripts/update-seccomp-landlock.py.
Testing
On Unix targets an integration suite in tests/unix_behaviour.rs covers the CLI licence output,
missing-command error path, and exit-code remapping flow.