How to Configure Network Isolation and Custom Subnets for Containers in Apple Container

Use the container network create command with the --internal flag for isolation and --subnet/--subnet-v6 flags to specify custom CIDR ranges, which are validated by the DefaultNetworkService and configured via the macOS vmnet framework.

The apple/container repository provides a robust networking stack that allows you to create isolated container networks with precise IP addressing control. When you need to configure network isolation and custom subnets for containers, the platform exposes a dedicated CLI sub-command that translates high-level flags into low-level VM-net interfaces. This implementation leverages the macOS vmnet framework to enforce traffic boundaries while supporting both IPv4 and IPv6 custom address ranges.

Understanding the Network Architecture

The networking system consists of several coordinated components that handle everything from CLI flag parsing to kernel-level network interface creation.

Core Components

Creating an Isolated Network with Custom Subnets

To achieve true network isolation, you must specify the --internal flag, which sets the NetworkMode to hostOnly. This prevents NAT and blocks external internet access, restricting communication to the host and other containers on the same network.

Step-by-Step CLI Usage

The container network create command accepts specific CIDR notation for both IPv4 and IPv6 ranges. The DefaultNetworkService validates these ranges using the validateSubnet method to ensure no overlap with existing networks before creating the interface.


# Create an isolated network with custom IPv4 and IPv6 subnets

container network create \
    --internal \
    --subnet 10.42.0.0/16 \
    --subnet-v6 fd00:1234::/48 \
    isolated-net

This command triggers the following sequence:

  1. CLI Parsing: NetworkCreate.swift (lines 44-55) parses --internal into NetworkMode.hostOnly and converts the subnet strings into CIDRv4/CIDRv6 objects.
  2. API Transmission: NetworkClient sends the NetworkConfiguration to the server via POST /networks.
  3. Validation: DefaultNetworkService (lines 36-44) checks for subnet collisions and creates either a ReservedVmnetNetwork (if you specified a subnet) or an AllocationOnlyVmnetNetwork (for automatic allocation).
  4. Interface Creation: ReservedVmnetNetwork (lines 122-140) configures the macOS vmnet interface with your exact IPv4 CIDR using vmnet_network_configuration_set_ipv4_subnet.

Attaching Containers to the Isolated Network

Once created, attach containers using the network name. Containers on this network receive IP addresses from your specified CIDR range and cannot reach external networks.

container run \
    --network isolated-net \
    nginx:latest

Implementation Details

CLI Flag Processing

In Sources/ContainerCommands/Network/NetworkCreate.swift, the NetworkCreate command handles the --subnet and --internal flags. The --internal flag specifically sets the network mode to .hostOnly, which disables NAT and creates an isolated segment. The subnet values are validated as proper CIDR notation before being packaged into the NetworkConfiguration struct.

Configuration Model

The NetworkConfiguration struct in Sources/ContainerResource/Network/NetworkConfiguration.swift (lines 35-55) holds the optional CIDR fields. This model determines whether the network operates in nat mode (default) or hostOnly mode (isolated), and stores the NetworkMode enum value defined in Sources/ContainerResource/Network/NetworkMode.swift.

Server-Side Subnet Validation

The DefaultNetworkService in Sources/Services/Network/Server/DefaultNetworkService.swift performs critical validation before interface creation. The service maintains a registry of existing networks and uses the validateSubnet method to detect overlapping IPv4 ranges. If you omit the --subnet flag, the service automatically allocates a non-overlapping subnet; if you specify one, it creates a ReservedVmnetNetwork with your exact range.

Low-Level VM-net Configuration

The actual network isolation is enforced by the macOS vmnet framework. In Sources/Services/NetworkVmnet/Server/ReservedVmnetNetwork.swift, the initialization code calls vmnet_network_configuration_set_ipv4_subnet to program the kernel-level interface with your custom CIDR. This ensures that the DHCP-style allocator built into vmnet only hands out addresses within your specified range to attached containers.

Summary

  • Use container network create --internal to enable NetworkMode.hostOnly and achieve true network isolation from external traffic.
  • Specify --subnet and --subnet-v6 to define custom CIDR ranges; the DefaultNetworkService validates these against existing networks to prevent collisions.
  • The architecture flows from CLI (NetworkCreate.swift) to API client (NetworkClient.swift) to server validation (DefaultNetworkService.swift) to kernel interface (ReservedVmnetNetwork.swift).
  • Isolated networks restrict container communication to the host and other containers on the same network, with IP assignment strictly limited to your configured subnets.

Frequently Asked Questions

What is the difference between --internal and omitting the flag?

When you use --internal, the NetworkConfiguration sets NetworkMode to hostOnly, which creates an isolated network without NAT. Containers can only communicate with the host and other containers on the same network. Without the flag, the network uses nat mode, allowing containers to reach external networks through the host's internet connection.

How does the system prevent subnet collisions?

The DefaultNetworkService in Sources/Services/Network/Server/DefaultNetworkService.swift implements the validateSubnet method, which checks your requested CIDR against all existing networks. If an overlap is detected, the API returns an error before creating the ReservedVmnetNetwork interface, preventing routing conflicts at the macOS vmnet level.

Can I use IPv6 automatic allocation like IPv4?

Currently, automatic allocation is fully implemented for IPv4 only. For IPv6, you must explicitly provide a CIDR using the --subnet-v6 flag. The server validates that the IPv6 prefix does not overlap with existing networks, but it will not generate an IPv6 range automatically if you omit the flag.

What happens if I don't specify a subnet?

If you omit the --subnet flag, the DefaultNetworkService creates an AllocationOnlyVmnetNetwork instead of a ReservedVmnetNetwork. This automatically selects a non-overlapping IPv4 CIDR from the available pool and configures the vmnet interface without reserving a specific range, simplifying network creation when precise IP control is not required.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →