# Apple Container Networking: How It Works and What Modes Are Supported

> Discover how Apple Container networking works on macOS vmnet. Learn about supported modes like nat and hostOnly, and understand the underlying architecture for seamless container orchestration.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: internals
- Published: 2026-07-11

---

**Apple Container implements networking on top of the macOS vmnet framework, supporting two distinct modes—`nat` (default) and `hostOnly`—which are enforced by the `container-network-vmnet` XPC service and defined in the `NetworkMode` enum.**

The `apple/container` project leverages macOS-native virtualization APIs rather than Linux-style bridge networking to connect containers to the host and external networks. When you run `container system start`, the system initializes a virtual Ethernet switch using the vmnet framework, creating a `default` network that automatically assigns IP addresses to containers from a reserved subnet. This architecture ensures secure isolation while allowing flexible configuration through NAT or host-only segmentation.

## Core Networking Architecture

Apple Container builds its networking stack directly on the **vmnet framework**, a macOS API that provides virtual NICs and an Ethernet switch for connecting containers to the host. When the `container system start` command executes, it launches the **container-network-vmnet** XPC service, which runs in the background to manage virtual interfaces.

According to the technical documentation in [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md), this helper service performs three critical functions:

- Allocates IP addresses from predefined subnets (defaulting to `192.168.64.0/24`)
- Configures virtual Ethernet interfaces for each container
- Forwards traffic between the host and containers based on the selected network mode

Every container attaches to the `default` vmnet network unless a custom network is specified via the `--network` flag.

## Supported Network Modes

The networking layer supports exactly two operational modes, defined in [`Sources/ContainerResource/Network/NetworkMode.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Network/NetworkMode.swift) as a Swift enum:

```swift
enum NetworkMode {
    case nat
    case hostOnly
}

```

Concrete implementations in [`Sources/Services/NetworkVmnet/Server/ReservedVmnetNetwork.swift`](https://github.com/apple/container/blob/main/Sources/Services/NetworkVmnet/Server/ReservedVmnetNetwork.swift) and [`AllocationOnlyVmnetNetwork.swift`](https://github.com/apple/container/blob/main/AllocationOnlyVmnetNetwork.swift) enforce these modes. If you attempt to configure an unsupported mode, the system returns an error such as *"invalid network mode"* and rejects the network creation request.

### NAT Mode (Default)

**NAT mode** is the default configuration where containers receive IP addresses from a private subnet (e.g., `192.168.64.0/24`) but cannot be reached directly from external networks. The host performs Network Address Translation, allowing outbound connections from containers while isolating them from inbound traffic unless explicitly exposed.

To allow external access to a service running inside a container, you must publish the port using the `--publish` (`-p`) flag:

```bash
container run -d --name web --network default -p 127.0.0.1:8080:80 nginx:latest

```

In this example, the container receives an address like `192.168.64.2/24` from the vmnet helper, but external clients can only reach it through `localhost:8080` on the host.

### Host-Only Mode

**Host-only mode** creates an isolated subnet where containers can communicate with each other but cannot reach external networks or the internet. This mode is useful for isolated testing environments where you need inter-container communication without exposing services externally.

Create a host-only network and attach a container using:

```bash
container network create isolated --mode hostOnly
container run --network isolated ubuntu:latest ip addr show eth0

```

The container will show an IP address from the host-only subnet, but attempts to reach external addresses will fail unless traffic is explicitly forwarded through the host.

## macOS Version Limitations

Networking capabilities vary significantly based on the host macOS version:

- **macOS 26 or later**: Full support for user-defined networks, multiple concurrent networks, and both NAT and host-only modes
- **macOS 15**: The vmnet framework only provides isolated networks. All containers must attach to the **default** network; the `container network` commands are unavailable, and the `--network` flag will error out. Container-to-container communication over the virtual network is **not possible** on this version

This limitation is documented in [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md) under the network isolation section.

## Configuring Container Networks

### Creating Custom Networks

On supported macOS versions, you can create isolated networks with specific subnets using `container network create`:

```bash

# Create a custom NAT network with specific CIDR

container network create frontend --subnet 192.168.65.0/24

# Create an IPv6-enabled network

container network create backend --subnet-v6 fd00:dead:beef::/64

```

Each custom network is isolated from others; containers attached to `frontend` cannot reach containers on `backend` unless explicitly routed through the host.

### Attaching Containers and Publishing Ports

When running a container, specify the network using the `--network` flag with optional MAC address and MTU parameters:

```bash
container run --network default,mac=02:42:ac:11:00:02,mtu=1500 ubuntu:latest

```

The syntax follows `--network <name>[,mac=XX:XX:XX:XX:XX:XX][,mtu=VALUE]`. The vmnet helper validates the MAC address uniqueness and configures the interface accordingly.

For NAT networks, remember that inbound connections require port publishing. The host listens on the specified address and forwards traffic to the container's internal port.

### Inspecting Network Configuration

Verify a container's network attachment using `container inspect`, which returns a JSON `networks` array containing the assigned IP, gateway, and network name:

```bash
container inspect web | jq '.networks[0]'

```

Example output includes:
- `address`: The assigned IP with CIDR notation (e.g., `"192.168.64.2/24"`)
- `gateway`: The gateway address for the subnet
- `name`: The network identifier (e.g., `"default"` or `"frontend"`)

### Network Cleanup

Remove unused networks with:

```bash
container network delete frontend
container network prune  # Remove all unused networks

```

The system will prevent deletion if any running containers remain attached to the network.

## Practical Examples

```bash

# 1. Create a custom isolated network named "foo" (default NAT mode)

container network create foo

# 2. Run a container attached to that network, publishing port 8080 → 80

container run -d --name web --network foo -p 127.0.0.1:8080:80 nginx:latest

# 3. Verify the container's address inside the network

container inspect web | jq '.networks[0].address'

# → "192.168.65.2/24" (foo's subnet)

# 4. Use a host-only network (no address translation)

container network create bar --mode hostOnly
container run --network bar ubuntu:latest ip addr show eth0

# 5. Set a deterministic MAC address (useful for repeatable tests)

container run --network default,mac=02:42:ac:11:00:02 ubuntu:latest \
    cat /sys/class/net/eth0/address

# → 02:42:ac:11:00:02

# 6. Delete an unused network

container network delete foo

```

## Summary

- Apple Container networking relies on the **vmnet framework** and the `container-network-vmnet` XPC service to manage virtual interfaces and IP allocation
- Two **network modes** are supported: `nat` (default) for outbound internet access via address translation, and `hostOnly` for isolated container-to-container communication
- Configuration is defined in [`Sources/ContainerResource/Network/NetworkMode.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Network/NetworkMode.swift) and enforced by [`ReservedVmnetNetwork.swift`](https://github.com/apple/container/blob/main/ReservedVmnetNetwork.swift) and [`AllocationOnlyVmnetNetwork.swift`](https://github.com/apple/container/blob/main/AllocationOnlyVmnetNetwork.swift)
- **macOS 15** has significant limitations, supporting only the default network with no custom network creation, while **macOS 26+** supports multiple user-defined networks with both NAT and host-only modes
- Containers attach to the `default` network (`192.168.64.0/24`) automatically, but can be assigned to custom networks using `--network` with optional MAC and MTU parameters
- External access requires explicit port publishing via `--publish` or `-p` flags

## Frequently Asked Questions

### What is the difference between NAT and host-only mode in Apple Container?

**NAT mode** (the default) allows containers to reach external networks through Network Address Translation performed by the host, while keeping container IPs private and non-routable from outside. **Host-only mode** creates an isolated subnet where containers can communicate with each other but cannot access the internet or external networks unless traffic is explicitly forwarded through the host. Both modes are defined in [`NetworkMode.swift`](https://github.com/apple/container/blob/main/NetworkMode.swift) and validated by the vmnet network server implementations.

### Why can't I create custom networks on macOS 15?

On macOS 15, the vmnet framework only supports isolated network configurations, meaning all containers must attach to the single `default` network. The `container network` commands are disabled on this version, and attempting to use `--network` with a custom name will result in an error. Container-to-container communication over the virtual network is not possible on macOS 15. You must upgrade to macOS 26 or later to create user-defined networks with specific subnets and modes.

### How do I expose a container port to my Mac host?

For containers running in NAT mode, you must use the `--publish` (or `-p`) flag when running the container to map a host port to a container port. For example, `container run -p 127.0.0.1:8080:80 nginx` maps port 80 in the container to port 8080 on localhost. In host-only mode, the container is already accessible on its assigned IP address within the host-only subnet, but external access still requires port forwarding configuration if needed.

### Can I assign a specific MAC address to my container?

Yes, you can specify a deterministic MAC address when attaching a container to a network using the extended `--network` syntax: `--network <name>,mac=02:42:ac:11:00:02`. This is particularly useful for testing scenarios requiring consistent network identifiers. The vmnet helper validates the MAC address format and ensures uniqueness before configuring the virtual Ethernet interface.