# How to Configure Read-Only Root Filesystems and tmpfs Mounts in Apple Container

> Learn how to configure read-only root filesystems and tmpfs mounts in Apple Container. Use flags to secure your container environment and enhance performance.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-06-21

---

**Use the `--read-only` flag to mount the container's root filesystem as immutable and the `--tmpfs <path>` flag to add writable in-memory directories at specific paths.**

The Apple Container CLI provides native support for hardening container security through immutable root filesystems while maintaining flexibility via temporary filesystem mounts. These features allow you to run containers with enhanced security postures without sacrificing the ability to write to specific directories like `/tmp` or `/run`. Learning how to configure read-only root filesystems and tmpfs mounts enables you to implement defense-in-depth strategies and improve I/O performance for ephemeral data.

## Understanding Read-Only Root Filesystems

When you launch a container with the `--read-only` flag, the CLI transforms the root mount from read-write to read-only before the container runtime initializes. This prevents any modifications to the container's base image layers during execution.

### How the --read-only Flag Works Internally

The flag sets `ContainerConfiguration.readOnly = true` in [`Sources/ContainerResource/Container/ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerConfiguration.swift). During bundle creation, the `Bundle.cloneContainerRootFs` method (lines 43-48 in [`Sources/ContainerResource/Container/Bundle.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/Bundle.swift)) checks this boolean and appends the `"ro"` mount option:

```swift
var mutableFs = fs
if readonly && !mutableFs.options.contains("ro") {
    mutableFs.options.append("ro")
}

```

The resulting `Filesystem` object is written to the bundle's `rootfs` configuration, causing the kernel to mount the root partition with read-only constraints. When active, kernel logs will display `VFS: Mounted root (ext4 filesystem) readonly…` confirming the restriction is in effect.

## Implementing tmpfs Mounts

The `--tmpfs` flag creates ephemeral, memory-backed filesystems that disappear when the container stops. This is ideal for sensitive temporary data or high-speed cache directories that should not persist on disk.

### Parsing and Creating tmpfs Filesystems

Command-line arguments pass through `Parser.tmpfsMounts` (lines 332-338 in [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift)), which instantiates a `Filesystem` object via the `Filesystem.tmpfs` factory method (lines 128-131 in [`Sources/ContainerResource/Container/Filesystem.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/Filesystem.swift)):

```swift
let fs = Filesystem.tmpfs(destination: tmpfs, options: [])

```

This sets `type: .tmpfs` and `source: "tmpfs"`, generating a mount entry that the runtime service processes as a RAM-based volume. The mount receives default Linux tmpfs treatment, residing entirely in memory with no underlying block device.

## Combining Both Options for Secure Containers

You can use both flags simultaneously to create immutable containers with designated writable areas. This pattern follows security best practices by minimizing the attack surface while preserving necessary functionality.

Run a container with a read-only root and multiple tmpfs mounts:

```bash

# Mount root as read-only and add writable memory directories

container run --read-only \
             --tmpfs /tmp \
             --tmpfs /run \
             --name secure-demo alpine:latest \
             sh -c "echo 'volatile data' > /run/status && cat /run/status"

```

Verify the configuration inside the container:

```bash

# Check root mount options

mount | grep ' / '

# Verify tmpfs mounts

mount | grep tmpfs

```

## Verification and Kernel Logs

After starting a read-only container, confirm the configuration using standard Linux utilities. The `mount` command will show `ro` (read-only) in the options for the root filesystem, while tmpfs mounts display `type tmpfs`.

According to the project documentation in [`docs/how-to.md`](https://github.com/apple/container/blob/main/docs/how-to.md) (lines 95-98), successful activation generates kernel log entries showing the root filesystem mounted as read-only, providing audit evidence of the security posture.

## Summary

- **Use `--read-only`** to append the `"ro"` option to the root filesystem via `ContainerConfiguration.readOnly` and `Bundle.cloneContainerRootFs`, preventing modifications to container layers.
- **Use `--tmpfs <path>`** to create memory-backed mounts parsed by `Parser.tmpfsMounts` and constructed by `Filesystem.tmpfs`, providing ephemeral storage without disk I/O.
- **Combine both flags** to achieve hardened container environments where the base image remains immutable but specific paths remain writable in RAM.
- **Verify configuration** using `mount` commands and check kernel logs for `VFS: Mounted root... readonly` messages.

## Frequently Asked Questions

### Can I use --tmpfs without --read-only?

Yes, tmpfs mounts function independently of the root filesystem's read-only status. You can add memory-backed directories to standard read-write containers using `container run --tmpfs /path` without affecting the root mount's mutability. This is useful for improving performance of cache directories without enforcing full immutability.

### What happens if I try to write to the root filesystem with --read-only enabled?

The kernel will reject write operations with a "Read-only file system" error. Any process attempting to modify files in the root hierarchy (such as installing packages or writing to `/etc`) will fail unless the specific path is covered by a writable overlay, volume mount, or tmpfs mount.

### How do I specify mount options for tmpfs directories?

The current implementation in [`Sources/ContainerResource/Container/Filesystem.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/Filesystem.swift) creates tmpfs mounts with empty options lists by default. Advanced options like size limits or uid mappings specified via the CLI are parsed through `Parser.tmpfsMounts` but currently result in default tmpfs configurations. Check the specific version of [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift) for your release to verify supported option parsing.

### Where are the tmpfs mounts actually created in the source code?

The `Filesystem` structures representing tmpfs mounts are generated in [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift) and defined in [`Sources/ContainerResource/Container/Filesystem.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/Filesystem.swift). These are passed to the runtime service ([`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift)), which translates them into actual Linux mount system calls when the container starts.