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

> Learn to configure read-only root filesystems and tmpfs mounts in Apple containers. Secure your containers by making roots immutable and adding writable in-memory directories efficiently.

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

---

**Use the `--read-only` flag to mount the container root as immutable and `--tmpfs` to add writable in-memory directories, with configurations flowing from CLI parsing in [`Flags.swift`](https://github.com/apple/container/blob/main/Flags.swift) to runtime enforcement via `ContainerConfiguration`.**

Apple Container provides mechanisms to harden container filesystems by preventing writes to the base image while allowing temporary data in memory. By configuring **read-only root filesystems** and **tmpfs mounts**, you can enhance security without sacrificing functionality for ephemeral data.

## Understanding Read-Only Root Filesystems

The `--read-only` flag instructs the runtime to mount the container’s root filesystem as read-only, preventing any write operations on the base image layers.

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

The flag is defined in [`Sources/Services/ContainerAPIService/Client/Flags.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Flags.swift) at line 319. When the CLI parses the command, the value flows through [`Utility.swift`](https://github.com/apple/container/blob/main/Utility.swift) at line 255, which copies `management.readOnly` into the runtime configuration. This ultimately sets the `readOnly` property in [`Sources/ContainerResource/Container/ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerConfiguration.swift) at line 53.

When the sandbox initializes, the runtime checks `ContainerConfiguration.readOnly`. If `true`, it passes the `--read-only` option to the underlying OCI runtime, mounting the rootfs with the `ro` flag.

### Validation and Testing

The unit test `TestCLIRunCommand.testRunCommandReadOnly` in [`Tests/CLITests/Subcommands/Run/TestCLIRunCommand.swift`](https://github.com/apple/container/blob/main/Tests/CLITests/Subcommands/Run/TestCLIRunCommand.swift) at line 998 validates this behavior by attempting to create a file inside the container and verifying that the operation returns an error.

## Implementing tmpfs Mounts

The `--tmpfs` flag adds an in-memory filesystem at a specified destination, creating a writable area that disappears when the container stops.

### Parsing --tmpfs Arguments

The flag is defined in [`Sources/Services/ContainerAPIService/Client/Flags.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Flags.swift) at line 337. The `Parser.tmpfsMounts` method (lines 332-340 in [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift)) processes these arguments, creating `Filesystem` objects via the `Filesystem.tmpfs` factory method found in [`Sources/ContainerResource/Container/Filesystem.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/Filesystem.swift) at lines 28-34.

### Filesystem Configuration and Options

The `Filesystem.tmpfs` factory sets `type = .tmpfs`, `source = "tmpfs"`, and stores the destination path. These objects populate the `ContainerConfiguration.mounts` array. The parser handles `size` and `mode` options (lines 13-30 in [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift)), passing them to the kernel during mount as `-o size=…,mode=…` parameters.

## Practical Configuration Examples

### Running a Container with Read-Only Root

```bash
container run --read-only -it ubuntu:latest /bin/bash

```

*The container’s root filesystem mounts as `ro`. Any attempt to modify files in `/` returns a permission error.*

### Adding a tmpfs Mount with Size Limits

```bash
container run \
    --tmpfs /run:size=64M,mode=1777 \
    -it ubuntu:latest /bin/bash

```

*This creates a 64 MiB tmpfs at `/run` with permissions 1777. Data written here exists only in memory and vanishes when the container exits.*

### Combining Both Flags

```bash
container run \
    --read-only \
    --tmpfs /tmp:size=128M \
    alpine:latest /bin/sh -c "echo hello > /tmp/hi && cat /tmp/hi"

```

*The base image remains immutable, while `/tmp` provides a writable, high-performance scratch space.*

### Programmatic Configuration in Swift

```swift
import ContainerizationOCI
import Container

// Build a configuration programmatically
var cfg = ContainerConfiguration(
    id: "demo",
    image: ImageDescription(name: "ubuntu:latest"),
    process: ProcessConfiguration(command: ["/bin/bash"])
)
cfg.readOnly = true               // read-only rootfs
cfg.mounts.append(.tmpfs(
    destination: "/run",
    options: ["size=64M", "mode=1777"]
))

// Pass `cfg` to the ContainerAPIService runtime

```

## Summary

- The `--read-only` flag creates an immutable root filesystem by setting `ContainerConfiguration.readOnly` to `true`, which the OCI runtime enforces with the `ro` mount flag.
- The `--tmpfs` flag creates in-memory filesystems through the `Parser.tmpfsMounts` method, which generates `Filesystem.tmpfs` objects stored in `ContainerConfiguration.mounts`.
- You can combine both flags to run containers with hardened, immutable base layers while maintaining writable temporary directories.
- Configuration values flow from [`Flags.swift`](https://github.com/apple/container/blob/main/Flags.swift) → [`Utility.swift`](https://github.com/apple/container/blob/main/Utility.swift) → [`ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/ContainerConfiguration.swift) before the runtime applies them to the sandbox.

## Frequently Asked Questions

### What does the --read-only flag do in Apple Container?

The `--read-only` flag mounts the container’s root filesystem as read-only, preventing any modifications to the base image layers. According to the source code in [`Sources/ContainerResource/Container/ContainerConfiguration.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/ContainerConfiguration.swift), this sets the `readOnly` boolean property, which the runtime translates to the OCI `--read-only` option during sandbox creation.

### How do I specify size limits for tmpfs mounts?

Append the `size` option to the `--tmpfs` flag using the format `--tmpfs /path:size=64M`. The [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift) file (lines 13-30) handles these options, extracting the size and mode parameters and passing them to the kernel mount syscall. You can also specify `mode` (e.g., `mode=1777`) to control directory permissions.

### Can I use both --read-only and --tmpfs together?

Yes. Combining `--read-only` with `--tmpfs` is a common security pattern that keeps the base image immutable while providing writable, ephemeral storage in memory. The `ContainerConfiguration` struct accommodates both the `readOnly` property and the `mounts` array simultaneously, as shown in the Swift example above.

### How do I configure these options programmatically rather than via CLI?

Import the `Container` and `ContainerizationOCI` modules, create a `ContainerConfiguration` instance, set `cfg.readOnly = true`, and append `.tmpfs(destination:options:)` objects to the `cfg.mounts` array. This mirrors the CLI flag processing logic found in [`Utility.swift`](https://github.com/apple/container/blob/main/Utility.swift) and [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift), allowing direct integration with the `ContainerAPIService`.