How to Create an Isolated Container Network with Custom Subnets

Use the container network create command with the --internal and --subnet flags to define a private, isolated network with a specific CIDR range that prevents overlap with existing networks.

The apple/container CLI provides a dedicated network sub-command for defining private container networks with precise IP addressing requirements. When you need to isolate containers from external networks while controlling their IP allocation, the tool constructs a NetworkConfiguration object and processes it through the NetworkClient to the Container API server, which validates the requested subnets and configures the underlying VM-net interface.

Understanding the Network Architecture

Creating an isolated container network with custom subnets involves a coordinated flow between the CLI, API client, and server-side network service. The architecture ensures that your specified CIDR ranges are validated against existing networks before the system reserves the address space.

In Sources/ContainerCommands/Network/NetworkCreate.swift, the Application.NetworkCreate struct parses user-provided flags like --subnet and --internal to build a configuration object. This NetworkConfiguration model, defined in Sources/ContainerResource/Network/NetworkConfiguration.swift, holds the optional CIDRv4 and CIDRv6 values alongside the network mode selection.

The NetworkClient transmits this configuration via a POST /networks request to the Container API server. On the server side, Sources/Services/Network/Server/DefaultNetworkService.swift implements the DefaultNetworkService class, which validates that requested subnets do not overlap with existing networks using the validateSubnet method. For custom subnets, the service creates a ReservedVmnetNetwork instance that configures the exact IPv4 CIDR you specified through the macOS vmnet framework.

Creating an Isolated Network with Custom Subnets

Step 1: Define the Network Configuration via CLI

The CLI entry point in NetworkCreate.swift processes your command-line arguments to construct the network definition. When you specify --internal, the system sets the NetworkMode to hostOnly, creating an isolated network that prevents containers from reaching external networks or the internet.

The --subnet flag accepts a CIDR notation (e.g., 10.42.0.0/16) that the CLI parses into the NetworkConfiguration structure. If you require IPv6 addressing, use --subnet-v6 with an appropriate prefix like fd00:1234::/48.

Step 2: Server-Side Validation and Allocation

Once the NetworkClient submits the configuration, the DefaultNetworkService performs collision detection. It checks your requested IPv4 subnet against all existing networks to ensure no overlap exists. This validation occurs before any system resources are allocated.

If you omit the --subnet flag, the service automatically allocates a non-overlapping subnet from the available pool. However, specifying a custom subnet triggers the creation of a ReservedVmnetNetwork rather than an AllocationOnlyVmnetNetwork, ensuring the system reserves your exact CIDR requirements.

Step 3: VM-Net Interface Initialization

In Sources/Services/NetworkVmnet/Server/ReservedVmnetNetwork.swift, the service calls vmnet_network_configuration_set_ipv4_subnet to configure the macOS VM-net framework with your specific subnet. This low-level configuration enforces the isolation boundaries while respecting your custom IP address range.

The server returns the newly created network's UUID, which the CLI prints to stdout for use in subsequent container attachment commands.

Complete CLI Examples

Create a completely isolated network with custom IPv4 and IPv6 subnets:


# Create an isolated network with specific CIDR ranges

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

The command outputs the network UUID:


4e2d5a1b-c0f9-4c1a-a3e7-7e9f8c1d2b57

Attach a container to your isolated network:

container run \
    --network isolated-net \
    -p 8080:80 \
    nginx:latest

Configuration Flags Explained

  • -internal: Forces NetworkMode.hostOnly, creating an isolated network where containers can only communicate with each other and the host, blocking external internet access.
  • --subnet <CIDR>: Specifies the IPv4 address range (e.g., 192.168.100.0/24). The service validates this against existing networks to prevent overlap.
  • --subnet-v6 <CIDR>: Defines the IPv6 prefix for the network. Unlike IPv4, IPv6 subnets must be explicitly provided if required; the service rejects overlapping prefixes.
  • <network-name>: The human-readable identifier used when attaching containers via the --network flag in run commands.

Summary

  • Use container network create with --internal to achieve true network isolation via NetworkMode.hostOnly.
  • Specify custom subnets with --subnet and --subnet-v6 to control IP allocation within your container network.
  • The DefaultNetworkService validates all custom subnets against existing networks to prevent CIDR collisions before creating the VM-net interface.
  • Source files NetworkCreate.swift, NetworkConfiguration.swift, and ReservedVmnetNetwork.swift handle the complete pipeline from CLI parsing to low-level network configuration.
  • Isolated networks restrict containers to host-only communication while custom subnets determine the available IP address ranges for attached containers.

Frequently Asked Questions

How does the container tool prevent subnet overlap?

The DefaultNetworkService in Sources/Services/Network/Server/DefaultNetworkService.swift implements a validateSubnet method that checks your requested CIDR against all existing networks before allocation. If the requested range overlaps with an existing network, the API returns an error and the creation fails.

Can I create an isolated network without specifying a subnet?

Yes. If you omit the --subnet flag, the system automatically allocates a non-overlapping subnet from the available pool and creates an AllocationOnlyVmnetNetwork. However, if you require specific IP ranges for firewall rules or service discovery, you should explicitly define the subnet using the --subnet flag.

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

The --internal flag sets NetworkMode.hostOnly in the NetworkConfiguration, which disables NAT and prevents the containers from reaching external networks. Without this flag, the network operates in NAT mode, allowing containers to access the internet through the host while remaining isolated from other container networks.

Does the custom subnet configuration support IPv6?

Yes. Use the --subnet-v6 flag to specify an IPv6 prefix such as fd00:1234::/48. The validation logic in DefaultNetworkService checks IPv6 prefixes for collisions similarly to IPv4, though IPv6 allocation is not automatic—you must explicitly provide the CIDR if you require IPv6 addressing.

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 →