Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 when keyless is 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. Blocks mount, 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 = 80 when 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 RSS
  • glibc.malloc.mmap_threshold = "131072" – reduce fragmentation
  • glibc.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.hwcaps for 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:

  1. systemd WorkingDirectory
  2. service dataDir (e.g., /var/lib/postgresql for PostgreSQL)
  3. 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 config
  • containerId : the container’s attribute name
  • system : the host build system
  • pkgs : 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 config
  • perSystemConfig: the perSystem config
  • system: the current system
  • pkgs: nixpkgs for current system
  • lib: 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. Blocks mount, 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 = 80 when 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 RSS
  • glibc.malloc.mmap_threshold = "131072" – reduce fragmentation
  • glibc.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.hwcaps for 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:

  1. systemd WorkingDirectory
  2. service dataDir (e.g., /var/lib/postgresql for PostgreSQL)
  3. 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: