nix-oci
nix-oci is a flake-parts module designed to streamline the management of OCI (Open Container Initiative) repositories using the Nix package manager. By leveraging nix2container as its backend, nix-oci facilitates the declarative creation and handling of container images, ensuring reproducibility and efficiency in containerized environments.
Installation
See the readme.
Options
oci.enableDevShell
Whether to enable the flake development shell.
Type: boolean
Default:
false
Declared by:
oci.enableFlakeOutputs
Whether to automatically expose OCI apps, packages, and checks as flake outputs.
Type: boolean
Default:
true
Example:
false
Declared by:
oci.enabled
Whether to enable Enable the OCI module…
Type: boolean
Default:
false
Example:
true
Declared by:
oci.compliance
Configuration for CIS compliance checking in container images.
Type: submodule
Default:
{ }
Declared by:
oci.compliance.trivy
Configuration for CIS compliance checking using Trivy.
Type: submodule
Default:
{ }
Declared by:
oci.compliance.trivy.enabled
Whether to enable CIS compliance checking with Trivy.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.compliance.trivy.report
Compliance report format: all for detailed results or summary for a condensed overview.
Type: one of “all”, “summary”
Default:
"summary"
Declared by:
oci.compliance.trivy.spec
The compliance spec to check against. See trivy image --help for built-in specs.
Type: string
Default:
"docker-cis-1.6.0"
Example:
"docker-cis-1.6.0"
Declared by:
oci.credentialsLeak
Options for credential leak detection in container images.
Type: submodule
Default:
{ }
Declared by:
oci.credentialsLeak.configPath
Path where global credentials leak check configuration files will be stored.
Type: absolute path
Default:
config.oci.rootPath + "/credentials-leak/"
Declared by:
oci.credentialsLeak.trivy
Configuration for detecting credentials leaks using Trivy.
Type: submodule
Default:
{ }
Declared by:
oci.credentialsLeak.trivy.enabled
Whether to enable credentials leak detection with Trivy.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.cve
Configuration for Common Vulnerabilities and Exposures (CVE) scanning in container images.
Type: submodule
Default:
{ }
Declared by:
oci.cve.configPath
Path where CVE scanner configuration files will be stored.
Type: absolute path
Default:
cfg.oci.rootPath
Declared by:
oci.cve.grype
Configuration for CVE scanning using Grype.
Type: submodule
Default:
{ }
Declared by:
oci.cve.grype.enabled
Whether to enable CVE scanning with Grype.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.cve.grype.config
Configuration for Grype scanner settings.
Type: submodule
Default:
{ }
Declared by:
oci.cve.grype.config.enabled
Whether to enable Grype configuration file generation.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.cve.grype.config.rootPath
Path where Grype configuration files will be stored.
Type: absolute path
Default:
config.oci.cve.configPath + "/grype/"
Declared by:
oci.cve.trivy
Configuration for CVE scanning using Trivy.
Type: submodule
Default:
{ }
Declared by:
oci.cve.trivy.enabled
Whether to enable CVE scanning with Trivy.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.cve.trivy.ignore
Configuration for CVE exclusions in Trivy scans.
Type: submodule
Default:
{ }
Declared by:
oci.cve.trivy.ignore.extra
Additional CVE identifiers to ignore globally in Trivy scans.
Type: list of string
Default:
[ ]
Declared by:
oci.cve.trivy.ignore.fileEnabled
Whether to enable Trivy CVE ignore file generation.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.cve.trivy.ignore.rootPath
Path where Trivy CVE ignore files will be stored.
Type: absolute path
Default:
cfg.oci.cve.configPath
Declared by:
oci.cve.vulnix
Configuration for Nix-native CVE scanning using vulnix.
Type: submodule
Default:
{ }
Declared by:
oci.cve.vulnix.enabled
Whether to enable CVE scanning with vulnix.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.cve.vulnix.whitelist
Configuration for vulnix CVE whitelist.
Type: submodule
Default:
{ }
Declared by:
oci.cve.vulnix.whitelist.enabled
Whether to enable vulnix whitelist file.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.cve.vulnix.whitelist.rootPath
Path where vulnix whitelist files will be stored.
Type: absolute path
Default:
config.oci.cve.configPath + "/vulnix/"
Declared by:
oci.devShellPackage
The package to use for the development shell.
Type: package
Declared by:
oci.fromImageManifestRootPath
The root path to store the pulled OCI image manifest JSON lockfiles.
Type: absolute path
Default:
config.oci.rootPath + "/pulledManifestsLocks/"
Declared by:
oci.lint
Configuration for container image linting.
Type: submodule
Default:
{ }
Declared by:
oci.lint.dockle
Configuration for container image linting using Dockle (CIS Benchmarks & best practices).
Type: submodule
Default:
{ }
Declared by:
oci.lint.dockle.enabled
Whether to enable container image linting with Dockle.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.lint.dockle.exitLevel
Minimum severity level that causes a non-zero exit code.
Type: one of “info”, “warn”, “fatal”
Default:
"info"
Declared by:
oci.lint.dockle.ignore
List of Dockle checkpoint IDs to ignore (e.g. CIS-DI-0001).
Type: list of string
Default:
[
"CIS-DI-0005"
"CIS-DI-0006"
]
Example:
[
"CIS-DI-0001"
"DKL-DI-0006"
]
Declared by:
oci.registry
The OCI registry to use for pushing and pulling images.
Type: null or string
Default:
null
Declared by:
oci.rootPath
The root path to store the Nix OCI resources.
Type: absolute path
Default:
self + "/oci/"
Declared by:
oci.sbom
Configuration for Software Bill of Materials (SBOM) generation in container images.
Type: submodule
Default:
{ }
Declared by:
oci.sbom.path
Path where SBOM files will be stored.
Type: absolute path
Default:
cfg.oci.rootPath
Declared by:
oci.sbom.syft
Configuration for SBOM generation using Syft.
Type: submodule
Default:
{ }
Declared by:
oci.sbom.syft.enabled
Whether to enable SBOM generation with Syft.
Type: boolean
Default:
false
Declared by:
oci.sbom.syft.config
Configuration settings for Syft SBOM generation.
Type: submodule
Default:
{ }
Declared by:
oci.sbom.syft.config.enabled
Whether to enable Syft configuration file generation.
Type: boolean
Default:
false
Declared by:
oci.sbom.syft.config.rootPath
Path where Syft configuration files will be stored.
Type: absolute path
Default:
cfg.oci.sbom.path
Declared by:
oci.signing
Configuration for OCI image signing using cosign / Sigstore.
Type: submodule
Default:
{ }
Declared by:
oci.signing.cosign
Configuration for image signing with cosign.
Type: submodule
Default:
{ }
Declared by:
oci.signing.cosign.enabled
Whether to enable OCI image signing with cosign.
Type: boolean
Default:
false
Example:
true
Declared by:
oci.signing.cosign.annotations
Key-value annotations to attach to every cosign signature.
These appear in cosign verify output and can be used
for policy enforcement (e.g. with Kyverno or OPA).
Type: attribute set of string
Default:
{ }
Example:
{
build-system = "nix";
repo = "https://github.com/example/repo";
}
Declared by:
oci.signing.cosign.certificateIdentityRegexp
Regular expression to match the certificate identity when
verifying keyless signatures. Required for keyless verification.
Example: "https://github.com/myorg/.*" or an email pattern.
Type: null or string
Default:
null
Declared by:
oci.signing.cosign.certificateOidcIssuerRegexp
Regular expression to match the OIDC issuer when verifying
keyless signatures. Required for keyless verification.
Example: "https://token.actions.githubusercontent.com".
Type: null or string
Default:
null
Declared by:
oci.signing.cosign.key
Path or KMS URI for the cosign signing key. Supports local files, environment variables, and KMS URIs:
- Local file:
./cosign.key - Environment variable:
env://COSIGN_PRIVATE_KEY - AWS KMS:
awskms://[ENDPOINT]/[ID/ALIAS/ARN] - GCP KMS:
gcpkms://projects/[PROJECT]/locations/[LOC]/keyRings/[RING]/cryptoKeys/[KEY] - Azure Key Vault:
azurekms://[VAULT_NAME][VAULT_URI]/[KEY] - HashCorp Vault:
hashivault://[KEY]Only used whenkeylessis false.
Type: null or string
Default:
null
Declared by:
oci.signing.cosign.keyless
Use keyless (OIDC) signing via Sigstore Fulcio.
When true, cosign authenticates via an OIDC provider
(GitHub Actions, Google, Microsoft) and issues ephemeral
certificates. No key management required.
When false, key must be set.
Type: boolean
Default:
true
Declared by:
oci.signing.cosign.verify
Whether to verify the signature immediately after signing.
Type: boolean
Default:
true
Declared by:
oci.test
Global configuration for container testing tools.
Type: submodule
Default:
{ }
Declared by:
oci.test.containerStructureTest
Configuration for container-structure-test validation tool.
Type: submodule
Default:
{ }
Declared by:
oci.test.containerStructureTest.enabled
Whether to enable container-structure-test globally for all containers.
Type: boolean
Default:
false
Declared by:
oci.test.dgoss
Configuration for dgoss (Docker + goss) testing framework.
Type: submodule
Default:
{ }
Declared by:
oci.test.dgoss.enabled
Whether to enable dgoss testing globally for all containers.
Type: boolean
Default:
false
Declared by:
oci.test.dgoss.hermetic
Run dgoss as a pure Nix derivation (check) using podman
inside the Nix sandbox.
Requires extra-sandbox-paths = /sys/fs/cgroup in nix.conf.
Type: boolean
Default:
false
Declared by:
oci.test.dive
Configuration for Dive container image analysis tool.
Type: submodule
Default:
{ }
Declared by:
oci.test.dive.enabled
Whether to enable Dive analysis globally for all containers.
Type: boolean
Default:
false
Declared by:
perSystem.oci.packages.containerStructureTest
The package to use for container-structure-test.
Type: package
Default:
pkgs.container-structure-test
Example:
pkgs.container-structure-test
Declared by:
perSystem.oci.packages.cosign
The package to use for cosign.
Type: package
Default:
pkgs.cosign
Example:
pkgs.cosign
Declared by:
perSystem.oci.packages.dgoss
The package to use for dgoss.
Type: package
Default:
pkgs.dgoss
Example:
pkgs.dgoss
Declared by:
perSystem.oci.packages.dive
The package to use for dive.
Type: package
Default:
pkgs.dive
Example:
pkgs.dive
Declared by:
perSystem.oci.packages.dockle
The package to use for dockle.
Type: package
Default:
pkgs.dockle
Example:
pkgs.dockle
Declared by:
perSystem.oci.packages.grype
The package to use for grype.
Type: package
Default:
pkgs.grype
Example:
pkgs.grype
Declared by:
perSystem.oci.packages.nix2container
The nix2container package.
Type: attribute set
Default:
inputs.nix2container.packages.${system}.nix2container
Example:
inputs.nix2container.packages.${system}.nix2container
Declared by:
perSystem.oci.packages.podman
The package to use for podman.
Type: package
Default:
pkgs.podman
Example:
pkgs.podman
Declared by:
perSystem.oci.packages.regctl
The package to use for regctl (multi-arch manifest tool).
Type: package
Default:
pkgs.regclient
Example:
pkgs.regclient
Declared by:
perSystem.oci.packages.skaffold
The package to use for skaffold.
Type: package
Default:
pkgs.skaffold
Example:
pkgs.skaffold
Declared by:
perSystem.oci.packages.skopeo
The package to use for skopeo.
Type: package
Default:
inputs.nix2container.packages.${system}.skopeo-nix2container
Example:
inputs.nix2container.packages.${system}.skopeo-nix2container
Declared by:
perSystem.oci.packages.syft
The package to use for syft.
Type: package
Default:
pkgs.syft
Example:
pkgs.syft
Declared by:
perSystem.oci.packages.trivy
The package to use for trivy.
Type: package
Default:
pkgs.trivy
Example:
pkgs.trivy
Declared by:
perSystem.oci.packages.vulnix
The package to use for vulnix.
Type: package
Default:
pkgs.vulnix
Example:
pkgs.vulnix
Declared by:
perSystem.oci.containers
Container definitions. Each key is a container name.
Type: attribute set of (submodule)
Default:
{ }
Example:
{
my-app = {
package = pkgs.hello;
dependencies = [ pkgs.bash ];
};
}
Declared by:
perSystem.oci.containers.<name>.package
The main package for the container.
Type: null or package
Default:
null
Example:
pkgs.hello
Declared by:
perSystem.oci.containers.<name>.autoLabels
Whether to automatically generate OCI image labels from package metadata.
When enabled, the following labels are generated (user labels always override):
- OCI standard annotations (
org.opencontainers.image.*): title, version, description, licenses, base.name - Build info (
io.github.dauliac.nix-oci.build.*): system, optimized-layers, reproducible - Hardening hints (
io.github.dauliac.nix-oci.hardening.*): security posture - Kubernetes PSS level (
io.github.dauliac.nix-oci.kubernetes.pod-security-standard)
Type: boolean
Default:
true
Declared by:
perSystem.oci.containers.<name>.configFiles
Configuration file derivations to include in the container root.
Type: list of package
Default:
[ ]
Declared by:
perSystem.oci.containers.<name>.declaredVolumes
OCI volume mount point declarations baked into the image manifest. These tell the container runtime which paths contain persistent data.
For NixOS containers, auto-derived from systemd service directories:
- StateDirectory → /var/lib/<dir>
- RuntimeDirectory → /run/<dir>
- CacheDirectory → /var/cache/<dir>
- LogsDirectory → /var/log/<dir>
This is separate from deploy-time volumes (host bind mounts).
Type: list of string
Default:
[ ]
Example:
[
"/var/lib/postgresql"
"/var/log/nginx"
]
Declared by:
perSystem.oci.containers.<name>.dependencies
Additional dependencies packages to include in the container.
Type: list of package
Default:
[ ]
Example:
[ pkgs.bash pkgs.coreutils ]
Declared by:
perSystem.oci.containers.<name>.entrypoint
OCI entrypoint (command + arguments).
Type: list of string
Default:
[ ]
Declared by:
perSystem.oci.containers.<name>.environment
Environment variables baked into the OCI manifest and passed to the runner.
Type: attribute set of string
Default:
{ }
Example:
{
RUST_LOG = "info";
}
Declared by:
perSystem.oci.containers.<name>.hardening.enable
Enable container security hardening.
When enabled, applies build-time filesystem restrictions and generates runtime security hints consumed by deploy modules.
Three independent kernel primitives are available:
- Seccomp – syscall filtering (BPF at the syscall boundary)
- Landlock – object-level access control (LSM hooks at VFS level)
- Capabilities + flags – privilege restriction at runtime
For containers using nixosConfig, these options are forwarded
to the inner NixOS module at oci.container.hardening and can
be overridden through NixOS module composition.
Type: boolean
Default:
false
Declared by:
perSystem.oci.containers.<name>.hardening.capabilities
Linux capability restrictions applied at runtime by deploy modules.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.containers.<name>.hardening.capabilities.add
Linux capabilities to add back after dropping.
Deploy modules translate to --cap-add.
Type: list of string
Default:
[ ]
Example:
[
"NET_BIND_SERVICE"
]
Declared by:
perSystem.oci.containers.<name>.hardening.capabilities.drop
Linux capabilities to drop. Defaults to ["ALL"].
Deploy modules translate to --cap-drop.
Type: list of string
Default:
[
"ALL"
]
Declared by:
perSystem.oci.containers.<name>.hardening.disableDns
Disable DNS resolution inside the container.
Sets /etc/nsswitch.conf hosts line to files only (no dns
backend). Applications using IP addresses directly are unaffected.
NOTE: /etc/resolv.conf is NOT written into the image because
container runtimes (Docker, Podman) always bind-mount it at
startup, masking any baked-in content. To fully enforce DNS
restriction at runtime, use --dns=127.0.0.1 or network
policies.
Type: boolean
Default:
false
Declared by:
perSystem.oci.containers.<name>.hardening.landlock
Landlock LSM access control. Operates at the VFS/object level after path resolution – can restrict which files and ports are accessible, not just which syscalls are allowed.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.containers.<name>.hardening.landlock.enable
Enable Landlock LSM restrictions. Embeds a Landlock wrapper in the container entrypoint that self-restricts filesystem and network access before executing the real application.
Type: boolean
Default:
false
Declared by:
perSystem.oci.containers.<name>.hardening.landlock.allowedExecutePaths
Filesystem paths allowed for execution. Auto-populated
from the package’s /bin directory when empty.
Type: list of string
Default:
[ ]
Declared by:
perSystem.oci.containers.<name>.hardening.landlock.allowedReadPaths
Filesystem paths allowed for reading. When empty and
enable is true, auto-populated from the Nix closure
of the container’s package and dependencies.
Type: list of string
Default:
[ ]
Declared by:
perSystem.oci.containers.<name>.hardening.landlock.allowedTcpBind
TCP ports allowed for bind()/listen().
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Declared by:
perSystem.oci.containers.<name>.hardening.landlock.allowedTcpConnect
TCP ports allowed for outgoing connect().
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Declared by:
perSystem.oci.containers.<name>.hardening.landlock.allowedWritePaths
Filesystem paths allowed for writing (e.g. /tmp, /var/log).
Type: list of string
Default:
[ ]
Declared by:
perSystem.oci.containers.<name>.hardening.noNewPrivileges
Set the no_new_privs bit. Prevents privilege escalation
via setuid/setgid binaries or file capabilities.
Deploy modules translate to
--security-opt=no-new-privileges.
Type: boolean
Default:
true
Declared by:
perSystem.oci.containers.<name>.hardening.noTlsTrustStore
Remove the TLS certificate trust store (/etc/ssl/certs).
Prevents all outgoing HTTPS connections.
Only use for containers that never initiate TLS connections. This is a nuclear option – most applications that make any outbound HTTP requests will break.
Type: boolean
Default:
false
Declared by:
perSystem.oci.containers.<name>.hardening.readOnlyRootfs
Mount the container root filesystem as read-only at runtime.
Deploy modules translate to --read-only.
Prevents attackers from writing malware or achieving persistence if they gain initial access.
Type: boolean
Default:
true
Declared by:
perSystem.oci.containers.<name>.hardening.seccomp
Seccomp syscall filtering configuration.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.containers.<name>.hardening.seccomp.enable
Enable a custom seccomp profile for this container.
Type: boolean
Default:
false
Declared by:
perSystem.oci.containers.<name>.hardening.seccomp.customProfileJson
Path to a custom seccomp profile JSON file following the
OCI runtime specification format. When set, overrides
the profile option.
Type: null or absolute path
Default:
null
Declared by:
perSystem.oci.containers.<name>.hardening.seccomp.profile
Predefined seccomp profile level:
-
"strict"– allowlist of ~60 syscalls. Suitable for static binaries, Go/Rust services. Blocksmount,ptrace,execve, and most process/namespace ops. -
"moderate"– blocks ~44 dangerous syscalls (similar to Docker’s default profile). Allows most normal operations. -
"web-server"– strict base plus networking and threading syscalls. Suitable for HTTP servers.
In the inner NixOS module, the profile auto-defaults to
"web-server" when a known web server service (nginx,
httpd) is detected.
Type: one of “strict”, “moderate”, “web-server”
Default:
"moderate"
Declared by:
perSystem.oci.containers.<name>.healthcheck.command
Health check command (CMD form).
When non-empty, baked into the OCI image as Healthcheck.Test.
For NixOS-based containers, service adapters can auto-derive this from the NixOS module configuration (ports, endpoints, etc.).
Example: [ "curl" "-f" "http://localhost:8080/health" ]
Type: list of string
Default:
[ ]
Example:
[
"curl"
"-f"
"http://localhost:8080/health"
]
Declared by:
perSystem.oci.containers.<name>.healthcheck.interval
Seconds between health checks.
Type: signed integer
Default:
30
Declared by:
perSystem.oci.containers.<name>.healthcheck.retries
Number of consecutive failures before the container is considered unhealthy.
Type: signed integer
Default:
3
Declared by:
perSystem.oci.containers.<name>.healthcheck.startPeriod
Grace period (seconds) before the first health check runs after container start.
Type: signed integer
Default:
5
Declared by:
perSystem.oci.containers.<name>.healthcheck.timeout
Seconds to wait for a single health check to complete.
Type: signed integer
Default:
5
Declared by:
perSystem.oci.containers.<name>.initializeNixDatabase
Populate the Nix database (/nix/var/nix/db/db.sqlite) with the
closure of all store paths shipped in the image.
Enable this when you need to run Nix commands (nix build,
nix eval, nix-store -q, …) inside the container. Without it,
the Nix store directory contains packages but the database is empty,
causing Nix to believe no packages are installed.
Disabled by default because copyToRoot flattens store paths to /,
creating phantom database entries for the flattened derivations.
This is harmless for in-container Nix usage but may confuse workflows
that validate database-vs-disk consistency.
Type: boolean
Default:
false
Example:
true
Declared by:
perSystem.oci.containers.<name>.isRoot
Whether the container process runs as root.
Type: boolean
Default:
false
Example:
true
Declared by:
perSystem.oci.containers.<name>.labels
OCI image labels (metadata key-value pairs).
Type: attribute set of string
Default:
{ }
Declared by:
perSystem.oci.containers.<name>.name
OCI image name. Defaults to the container attribute name.
Type: string
Default:
"‹name›"
Declared by:
perSystem.oci.containers.<name>.optimizeLayers
Split container contents into deduplicated layers for optimal registry caching. Uses a two-level heuristic:
Level 1 – popularity-based splitting. Within each layer,
nix2container’s store-path popularity algorithm sorts paths by
how many other paths reference them. Foundational packages
(glibc, openssl, …) get their own sub-layers; application-specific
paths cluster together. Capped by a maxLayers budget per layer.
Level 2 – fold-based cross-layer deduplication. Layers are built in a chain where each layer references all predecessors. nix2container excludes any store path already present in an earlier layer, eliminating duplication across explicit layers.
The resulting layer stack (most stable first):
- Deps layer (runtime libraries,
maxLayers = 80when fine-grained) - App layer (package, shadow, configs)
- Debug layer (curl, strace, … – only when
debug.enabled)
Production and debug images share the same deps + app layers in the registry – only the debug layer is unique to the debug variant.
Use layerStrategy to control sub-splitting granularity:
"fine-grained" (default) for maximum cross-image sharing,
"minimal" for exactly one layer per concern.
See Nix and layered Docker images for the original algorithm and nix2container for the implementation used here.
Type: boolean
Default:
false
Example:
true
Declared by:
perSystem.oci.containers.<name>.performance.enable
Enable container performance tuning.
When enabled, applies build-time optimizations (allocator injection, glibc tunables, CPU-targeted libraries) and generates runtime hints consumed by deploy modules.
Three independent optimization axes are available:
- Allocator – replace glibc ptmalloc2 with mimalloc/tcmalloc via
LD_PRELOAD - glibc tunables – tune malloc arenas, tcache, mmap thresholds
- hwcaps – ship CPU-optimized library variants (glibc-hwcaps, per-arch)
Type: boolean
Default:
false
Declared by:
perSystem.oci.containers.<name>.performance.allocator
Alternative memory allocator injected via LD_PRELOAD.
-
"mimalloc"– Microsoft’s general-purpose allocator. Lowest RSS for small allocations, excellent for microservices. -
"tcmalloc"– Google’s per-CPU-cache allocator. Best throughput for large allocation patterns and high-concurrency servers. -
null– use glibc’s default ptmalloc2 (no injection).
The allocator library is added as a container dependency and
LD_PRELOAD is set in the OCI manifest Env.
Type: null or one of “mimalloc”, “tcmalloc”
Default:
null
Example:
"mimalloc"
Declared by:
perSystem.oci.containers.<name>.performance.compression
Compression algorithm for OCI image layers during transport (skopeo).
"gzip"– universal compatibility, slower."zstd"– 3-5x faster compress/decompress, 12% smaller. Requires OCI 1.1+ registry (Docker Hub, ECR, GCR, GHCR support it). containerd 2.0+ required; containerd 1.7.x does NOT support zstd.
Type: one of “gzip”, “zstd”
Default:
"gzip"
Example:
"zstd"
Declared by:
perSystem.oci.containers.<name>.performance.glibcTunables
glibc tunables set via the GLIBC_TUNABLES environment variable.
Keys are tunable names (e.g. glibc.malloc.arena_max), values
are strings. Multiple tunables are colon-joined automatically.
Recommended for containers:
glibc.malloc.arena_max = "2"– cap malloc arenas to reduce RSSglibc.malloc.mmap_threshold = "131072"– reduce fragmentationglibc.malloc.tcache_count = "7"– tune per-thread cache
Only effective with glibc-based containers (not musl).
Type: attribute set of string
Default:
{ }
Example:
{
"glibc.malloc.arena_max" = "2";
}
Declared by:
perSystem.oci.containers.<name>.performance.hwcaps
glibc-hwcaps: ship CPU-optimized library variants selected at runtime.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.containers.<name>.performance.hwcaps.enable
Build and ship CPU-optimized library variants via glibc-hwcaps.
The dynamic linker selects the best variant at process startup based on CPUID – zero application changes required.
Only effective on systems with hwcaps support (x86_64-linux). Auto-disabled on unsupported architectures in per-arch config.
Type: boolean
Default:
false
Declared by:
perSystem.oci.containers.<name>.performance.hwcaps.levels
Microarchitecture levels to build optimized libraries for. Valid values depend on the target system:
- x86_64-linux:
"x86-64-v2","x86-64-v3","x86-64-v4"
The baseline is always included as fallback (not listed here).
Type: list of string
Default:
[ ]
Example:
[
"x86-64-v3"
]
Declared by:
perSystem.oci.containers.<name>.performance.hwcaps.libraries
Packages whose shared libraries to rebuild at each hwcaps level.
Only .so files are extracted into the hwcaps layer.
Good candidates: crypto (openssl), compression (zlib, zstd), math-heavy libraries, string processing.
Type: list of package
Default:
[ ]
Example:
[ pkgs.openssl pkgs.zlib ]
Declared by:
perSystem.oci.containers.<name>.performance.march
Target CPU microarchitecture level for package compilation.
Sets -march and -mtune for all packages in this container.
For multi-arch containers, this sets the default for the host
architecture – override per-arch via archConfigs.
Valid values depend on the target system:
- x86_64-linux:
"x86-64","x86-64-v2","x86-64-v3","x86-64-v4" - aarch64-linux:
"armv8-a","armv8.2-a","armv8.4-a","armv9-a"
Query valid values: config.lib.oci.systemMarchValues "x86_64-linux"
Warning: loses the Hydra binary cache – everything rebuilds locally. Use
performance.hwcapsfor multi-level support without full cache loss.
Type: null or string
Default:
null
Example:
"x86-64-v3"
Declared by:
perSystem.oci.containers.<name>.ports
Port mappings (e.g. ["8080:8080"]).
Baked into OCI manifest ExposedPorts and used by the runner service.
Type: list of string
Default:
[ ]
Example:
[
"8080:8080"
"443:443"
]
Declared by:
perSystem.oci.containers.<name>.stopSignal
Signal to send for graceful container shutdown (e.g., “SIGQUIT”, “SIGINT”). When null, the container runtime default (SIGTERM) is used.
For NixOS containers, service adapters auto-derive this from the systemd KillSignal or per-service knowledge.
Type: null or string
Default:
null
Example:
"SIGQUIT"
Declared by:
perSystem.oci.containers.<name>.tag
OCI image tag.
Type: string
Default:
"latest"
Declared by:
perSystem.oci.containers.<name>.user
User to run the container process as.
Type: string
Default:
"root"
Declared by:
perSystem.oci.containers.<name>.workingDir
Working directory for the container process. When null, auto-derived for NixOS containers from:
- systemd WorkingDirectory
- service dataDir (e.g., /var/lib/postgresql for PostgreSQL)
- user home directory (/root or /home/<user>)
For non-NixOS containers, defaults to the user home directory.
Type: null or string
Default:
null
Example:
"/var/lib/postgresql"
Declared by:
perSystem.oci.debug
Add debug build in output.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.debug.enabled
Type: boolean
Default:
false
Declared by:
perSystem.oci.debug.packages
Type: list of package
Default:
with pkgs; [
coreutils
bash
curl
]
Declared by:
perSystem.oci.debug.entrypoint
Debug entrypoint wrapper configuration.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.debug.entrypoint.enabled
Whether to enable debug entrypoint wrapper.
Type: boolean
Default:
false
Declared by:
perSystem.oci.debug.entrypoint.wrapper
Default behavior run sleep infinity fallback if entrypoint fail.
Type: package
Default:
pkgs.writeShellScriptBin "entrypoint" (builtins.readFile ./debug-entrypoint.sh)
Declared by:
perSystem.oci.flake.packages
OCI container packages that can be exposed as flake outputs.
Type: attribute set of package (read only)
Default:
{ }
Declared by:
perSystem.oci.flake.apps
OCI-related apps that can be exposed as flake outputs.
Type: attribute set of (attribute set) (read only)
Default:
Apps for security scanning, SBOM generation, validation, and multi-arch builds, derived from oci.containers.
Declared by:
perSystem.oci.flake.checks
OCI-related checks that can be exposed as flake outputs.
Type: attribute set of package (read only)
Default:
{ }
Declared by:
perSystem.oci.perArchitecture
Per-architecture module definitions applied to every archConfigs entry.
Parallel to oci.perContainer – a top-level collector for per-architecture
options. Contributed modules are evaluated for every target architecture
within every container.
Each module receives these special arguments:
name: the target system string (e.g."aarch64-linux")containerConfig: the parent container’s evaluated configcontainerId: the container’s attribute namesystem: the host build systempkgs: nixpkgs for the host system
Example:
oci.perArchitecture = [
({ name, containerConfig, ... }: {
options.myArchOption = lib.mkOption { type = lib.types.str; };
})
];
Type: list of raw value
Default:
[ ]
Declared by:
perSystem.oci.perContainer
Per-container module definition.
Multiple modules can contribute to this option. Each contribution is a module that will be evaluated for every container with container-specific context.
The module receives these special arguments:
name: the attribute name of the container (from types.attrsOf)config: the container’s config (for reading within the module)globalConfig: the top-level flake configperSystemConfig: the perSystem configsystem: the current systempkgs: nixpkgs for current systemlib: nixpkgs lib
Type: per-container module
Default:
{ }
Declared by:
perSystem.oci.perContainer.package
The main package for the container.
Type: null or package
Default:
null
Example:
pkgs.hello
Declared by:
perSystem.oci.perContainer.autoLabels
Whether to automatically generate OCI image labels from package metadata.
When enabled, the following labels are generated (user labels always override):
- OCI standard annotations (
org.opencontainers.image.*): title, version, description, licenses, base.name - Build info (
io.github.dauliac.nix-oci.build.*): system, optimized-layers, reproducible - Hardening hints (
io.github.dauliac.nix-oci.hardening.*): security posture - Kubernetes PSS level (
io.github.dauliac.nix-oci.kubernetes.pod-security-standard)
Type: boolean
Default:
true
Declared by:
perSystem.oci.perContainer.configFiles
Configuration file derivations to include in the container root.
Type: list of package
Default:
[ ]
Declared by:
perSystem.oci.perContainer.declaredVolumes
OCI volume mount point declarations baked into the image manifest. These tell the container runtime which paths contain persistent data.
For NixOS containers, auto-derived from systemd service directories:
- StateDirectory → /var/lib/<dir>
- RuntimeDirectory → /run/<dir>
- CacheDirectory → /var/cache/<dir>
- LogsDirectory → /var/log/<dir>
This is separate from deploy-time volumes (host bind mounts).
Type: list of string
Default:
[ ]
Example:
[
"/var/lib/postgresql"
"/var/log/nginx"
]
Declared by:
perSystem.oci.perContainer.dependencies
Additional dependencies packages to include in the container.
Type: list of package
Default:
[ ]
Example:
[ pkgs.bash pkgs.coreutils ]
Declared by:
perSystem.oci.perContainer.entrypoint
OCI entrypoint (command + arguments).
Type: list of string
Default:
[ ]
Declared by:
perSystem.oci.perContainer.environment
Environment variables baked into the OCI manifest and passed to the runner.
Type: attribute set of string
Default:
{ }
Example:
{
RUST_LOG = "info";
}
Declared by:
perSystem.oci.perContainer.hardening.enable
Enable container security hardening.
When enabled, applies build-time filesystem restrictions and generates runtime security hints consumed by deploy modules.
Three independent kernel primitives are available:
- Seccomp – syscall filtering (BPF at the syscall boundary)
- Landlock – object-level access control (LSM hooks at VFS level)
- Capabilities + flags – privilege restriction at runtime
For containers using nixosConfig, these options are forwarded
to the inner NixOS module at oci.container.hardening and can
be overridden through NixOS module composition.
Type: boolean
Default:
false
Declared by:
perSystem.oci.perContainer.hardening.capabilities
Linux capability restrictions applied at runtime by deploy modules.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.perContainer.hardening.capabilities.add
Linux capabilities to add back after dropping.
Deploy modules translate to --cap-add.
Type: list of string
Default:
[ ]
Example:
[
"NET_BIND_SERVICE"
]
Declared by:
perSystem.oci.perContainer.hardening.capabilities.drop
Linux capabilities to drop. Defaults to ["ALL"].
Deploy modules translate to --cap-drop.
Type: list of string
Default:
[
"ALL"
]
Declared by:
perSystem.oci.perContainer.hardening.disableDns
Disable DNS resolution inside the container.
Sets /etc/nsswitch.conf hosts line to files only (no dns
backend). Applications using IP addresses directly are unaffected.
NOTE: /etc/resolv.conf is NOT written into the image because
container runtimes (Docker, Podman) always bind-mount it at
startup, masking any baked-in content. To fully enforce DNS
restriction at runtime, use --dns=127.0.0.1 or network
policies.
Type: boolean
Default:
false
Declared by:
perSystem.oci.perContainer.hardening.landlock
Landlock LSM access control. Operates at the VFS/object level after path resolution – can restrict which files and ports are accessible, not just which syscalls are allowed.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.perContainer.hardening.landlock.enable
Enable Landlock LSM restrictions. Embeds a Landlock wrapper in the container entrypoint that self-restricts filesystem and network access before executing the real application.
Type: boolean
Default:
false
Declared by:
perSystem.oci.perContainer.hardening.landlock.allowedExecutePaths
Filesystem paths allowed for execution. Auto-populated
from the package’s /bin directory when empty.
Type: list of string
Default:
[ ]
Declared by:
perSystem.oci.perContainer.hardening.landlock.allowedReadPaths
Filesystem paths allowed for reading. When empty and
enable is true, auto-populated from the Nix closure
of the container’s package and dependencies.
Type: list of string
Default:
[ ]
Declared by:
perSystem.oci.perContainer.hardening.landlock.allowedTcpBind
TCP ports allowed for bind()/listen().
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Declared by:
perSystem.oci.perContainer.hardening.landlock.allowedTcpConnect
TCP ports allowed for outgoing connect().
Type: list of 16 bit unsigned integer; between 0 and 65535 (both inclusive)
Default:
[ ]
Declared by:
perSystem.oci.perContainer.hardening.landlock.allowedWritePaths
Filesystem paths allowed for writing (e.g. /tmp, /var/log).
Type: list of string
Default:
[ ]
Declared by:
perSystem.oci.perContainer.hardening.noNewPrivileges
Set the no_new_privs bit. Prevents privilege escalation
via setuid/setgid binaries or file capabilities.
Deploy modules translate to
--security-opt=no-new-privileges.
Type: boolean
Default:
true
Declared by:
perSystem.oci.perContainer.hardening.noTlsTrustStore
Remove the TLS certificate trust store (/etc/ssl/certs).
Prevents all outgoing HTTPS connections.
Only use for containers that never initiate TLS connections. This is a nuclear option – most applications that make any outbound HTTP requests will break.
Type: boolean
Default:
false
Declared by:
perSystem.oci.perContainer.hardening.readOnlyRootfs
Mount the container root filesystem as read-only at runtime.
Deploy modules translate to --read-only.
Prevents attackers from writing malware or achieving persistence if they gain initial access.
Type: boolean
Default:
true
Declared by:
perSystem.oci.perContainer.hardening.seccomp
Seccomp syscall filtering configuration.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.perContainer.hardening.seccomp.enable
Enable a custom seccomp profile for this container.
Type: boolean
Default:
false
Declared by:
perSystem.oci.perContainer.hardening.seccomp.customProfileJson
Path to a custom seccomp profile JSON file following the
OCI runtime specification format. When set, overrides
the profile option.
Type: null or absolute path
Default:
null
Declared by:
perSystem.oci.perContainer.hardening.seccomp.profile
Predefined seccomp profile level:
-
"strict"– allowlist of ~60 syscalls. Suitable for static binaries, Go/Rust services. Blocksmount,ptrace,execve, and most process/namespace ops. -
"moderate"– blocks ~44 dangerous syscalls (similar to Docker’s default profile). Allows most normal operations. -
"web-server"– strict base plus networking and threading syscalls. Suitable for HTTP servers.
In the inner NixOS module, the profile auto-defaults to
"web-server" when a known web server service (nginx,
httpd) is detected.
Type: one of “strict”, “moderate”, “web-server”
Default:
"moderate"
Declared by:
perSystem.oci.perContainer.healthcheck.command
Health check command (CMD form).
When non-empty, baked into the OCI image as Healthcheck.Test.
For NixOS-based containers, service adapters can auto-derive this from the NixOS module configuration (ports, endpoints, etc.).
Example: [ "curl" "-f" "http://localhost:8080/health" ]
Type: list of string
Default:
[ ]
Example:
[
"curl"
"-f"
"http://localhost:8080/health"
]
Declared by:
perSystem.oci.perContainer.healthcheck.interval
Seconds between health checks.
Type: signed integer
Default:
30
Declared by:
perSystem.oci.perContainer.healthcheck.retries
Number of consecutive failures before the container is considered unhealthy.
Type: signed integer
Default:
3
Declared by:
perSystem.oci.perContainer.healthcheck.startPeriod
Grace period (seconds) before the first health check runs after container start.
Type: signed integer
Default:
5
Declared by:
perSystem.oci.perContainer.healthcheck.timeout
Seconds to wait for a single health check to complete.
Type: signed integer
Default:
5
Declared by:
perSystem.oci.perContainer.initializeNixDatabase
Populate the Nix database (/nix/var/nix/db/db.sqlite) with the
closure of all store paths shipped in the image.
Enable this when you need to run Nix commands (nix build,
nix eval, nix-store -q, …) inside the container. Without it,
the Nix store directory contains packages but the database is empty,
causing Nix to believe no packages are installed.
Disabled by default because copyToRoot flattens store paths to /,
creating phantom database entries for the flattened derivations.
This is harmless for in-container Nix usage but may confuse workflows
that validate database-vs-disk consistency.
Type: boolean
Default:
false
Example:
true
Declared by:
perSystem.oci.perContainer.isRoot
Whether the container process runs as root.
Type: boolean
Default:
false
Example:
true
Declared by:
perSystem.oci.perContainer.labels
OCI image labels (metadata key-value pairs).
Type: attribute set of string
Default:
{ }
Declared by:
perSystem.oci.perContainer.name
OCI image name. Defaults to the container attribute name.
Type: string
Default:
"‹name›"
Declared by:
perSystem.oci.perContainer.optimizeLayers
Split container contents into deduplicated layers for optimal registry caching. Uses a two-level heuristic:
Level 1 – popularity-based splitting. Within each layer,
nix2container’s store-path popularity algorithm sorts paths by
how many other paths reference them. Foundational packages
(glibc, openssl, …) get their own sub-layers; application-specific
paths cluster together. Capped by a maxLayers budget per layer.
Level 2 – fold-based cross-layer deduplication. Layers are built in a chain where each layer references all predecessors. nix2container excludes any store path already present in an earlier layer, eliminating duplication across explicit layers.
The resulting layer stack (most stable first):
- Deps layer (runtime libraries,
maxLayers = 80when fine-grained) - App layer (package, shadow, configs)
- Debug layer (curl, strace, … – only when
debug.enabled)
Production and debug images share the same deps + app layers in the registry – only the debug layer is unique to the debug variant.
Use layerStrategy to control sub-splitting granularity:
"fine-grained" (default) for maximum cross-image sharing,
"minimal" for exactly one layer per concern.
See Nix and layered Docker images for the original algorithm and nix2container for the implementation used here.
Type: boolean
Default:
false
Example:
true
Declared by:
perSystem.oci.perContainer.performance.enable
Enable container performance tuning.
When enabled, applies build-time optimizations (allocator injection, glibc tunables, CPU-targeted libraries) and generates runtime hints consumed by deploy modules.
Three independent optimization axes are available:
- Allocator – replace glibc ptmalloc2 with mimalloc/tcmalloc via
LD_PRELOAD - glibc tunables – tune malloc arenas, tcache, mmap thresholds
- hwcaps – ship CPU-optimized library variants (glibc-hwcaps, per-arch)
Type: boolean
Default:
false
Declared by:
perSystem.oci.perContainer.performance.allocator
Alternative memory allocator injected via LD_PRELOAD.
-
"mimalloc"– Microsoft’s general-purpose allocator. Lowest RSS for small allocations, excellent for microservices. -
"tcmalloc"– Google’s per-CPU-cache allocator. Best throughput for large allocation patterns and high-concurrency servers. -
null– use glibc’s default ptmalloc2 (no injection).
The allocator library is added as a container dependency and
LD_PRELOAD is set in the OCI manifest Env.
Type: null or one of “mimalloc”, “tcmalloc”
Default:
null
Example:
"mimalloc"
Declared by:
perSystem.oci.perContainer.performance.compression
Compression algorithm for OCI image layers during transport (skopeo).
"gzip"– universal compatibility, slower."zstd"– 3-5x faster compress/decompress, 12% smaller. Requires OCI 1.1+ registry (Docker Hub, ECR, GCR, GHCR support it). containerd 2.0+ required; containerd 1.7.x does NOT support zstd.
Type: one of “gzip”, “zstd”
Default:
"gzip"
Example:
"zstd"
Declared by:
perSystem.oci.perContainer.performance.glibcTunables
glibc tunables set via the GLIBC_TUNABLES environment variable.
Keys are tunable names (e.g. glibc.malloc.arena_max), values
are strings. Multiple tunables are colon-joined automatically.
Recommended for containers:
glibc.malloc.arena_max = "2"– cap malloc arenas to reduce RSSglibc.malloc.mmap_threshold = "131072"– reduce fragmentationglibc.malloc.tcache_count = "7"– tune per-thread cache
Only effective with glibc-based containers (not musl).
Type: attribute set of string
Default:
{ }
Example:
{
"glibc.malloc.arena_max" = "2";
}
Declared by:
perSystem.oci.perContainer.performance.hwcaps
glibc-hwcaps: ship CPU-optimized library variants selected at runtime.
Type: submodule
Default:
{ }
Declared by:
perSystem.oci.perContainer.performance.hwcaps.enable
Build and ship CPU-optimized library variants via glibc-hwcaps.
The dynamic linker selects the best variant at process startup based on CPUID – zero application changes required.
Only effective on systems with hwcaps support (x86_64-linux). Auto-disabled on unsupported architectures in per-arch config.
Type: boolean
Default:
false
Declared by:
perSystem.oci.perContainer.performance.hwcaps.levels
Microarchitecture levels to build optimized libraries for. Valid values depend on the target system:
- x86_64-linux:
"x86-64-v2","x86-64-v3","x86-64-v4"
The baseline is always included as fallback (not listed here).
Type: list of string
Default:
[ ]
Example:
[
"x86-64-v3"
]
Declared by:
perSystem.oci.perContainer.performance.hwcaps.libraries
Packages whose shared libraries to rebuild at each hwcaps level.
Only .so files are extracted into the hwcaps layer.
Good candidates: crypto (openssl), compression (zlib, zstd), math-heavy libraries, string processing.
Type: list of package
Default:
[ ]
Example:
[ pkgs.openssl pkgs.zlib ]
Declared by:
perSystem.oci.perContainer.performance.march
Target CPU microarchitecture level for package compilation.
Sets -march and -mtune for all packages in this container.
For multi-arch containers, this sets the default for the host
architecture – override per-arch via archConfigs.
Valid values depend on the target system:
- x86_64-linux:
"x86-64","x86-64-v2","x86-64-v3","x86-64-v4" - aarch64-linux:
"armv8-a","armv8.2-a","armv8.4-a","armv9-a"
Query valid values: config.lib.oci.systemMarchValues "x86_64-linux"
Warning: loses the Hydra binary cache – everything rebuilds locally. Use
performance.hwcapsfor multi-level support without full cache loss.
Type: null or string
Default:
null
Example:
"x86-64-v3"
Declared by:
perSystem.oci.perContainer.ports
Port mappings (e.g. ["8080:8080"]).
Baked into OCI manifest ExposedPorts and used by the runner service.
Type: list of string
Default:
[ ]
Example:
[
"8080:8080"
"443:443"
]
Declared by:
perSystem.oci.perContainer.stopSignal
Signal to send for graceful container shutdown (e.g., “SIGQUIT”, “SIGINT”). When null, the container runtime default (SIGTERM) is used.
For NixOS containers, service adapters auto-derive this from the systemd KillSignal or per-service knowledge.
Type: null or string
Default:
null
Example:
"SIGQUIT"
Declared by:
perSystem.oci.perContainer.tag
OCI image tag.
Type: string
Default:
"latest"
Declared by:
perSystem.oci.perContainer.user
User to run the container process as.
Type: string
Default:
"root"
Declared by:
perSystem.oci.perContainer.workingDir
Working directory for the container process. When null, auto-derived for NixOS containers from:
- systemd WorkingDirectory
- service dataDir (e.g., /var/lib/postgresql for PostgreSQL)
- user home directory (/root or /home/<user>)
For non-NixOS containers, defaults to the user home directory.
Type: null or string
Default:
null
Example:
"/var/lib/postgresql"
Declared by: