Feedback welcome! Report issues on GitHub, ask questions on the Forum, or chat with us on Discord.
Using Containerized Networks
Run ICP test networks in Docker containers for isolated, reproducible development environments.
Windows Users
On Windows, icp-cli automatically uses Docker for all local networks—no configuration needed. Just ensure Docker Desktop is installed and running, then use icp network start as normal.
- "8000:4943"# Maps container port 4943 to host port 8000
The ghcr.io/dfinity/icp-cli-network-launcher image is the official ICP test network image and includes:
ICP ledger canister
Cycles ledger canister
Cycles minting canister
Pre-funded anonymous principal for development
See Image Contract for details on what the image provides and why these components are required.
Note: Network state is ephemeral—deployed canisters and their data are lost when the network stops. Persistence is not yet supported.
2. Start the Network
Terminal window
icpnetworkstartdocker-local
This will:
Pull the Docker image (first time only)
Start a container with an ICP test network
Expose the network on http://localhost:8000
You’ll see output indicating the network is ready:
✓ Network docker-local started
Gateway: http://localhost:8000
3. Deploy Your Canisters
Create an environment that uses your containerized network:
environments:
- name: docker
network: docker-local
canisters:
- my-canister
Then deploy:
Terminal window
icpdeploy--envdocker
4. Stop the Network
Terminal window
# Graceful shutdown
icpnetworkstopdocker-local
# Or press Ctrl-C in the terminal where it's running
Common Configurations
Dynamic Port Allocation
Let Docker choose an available port automatically:
networks:
- name: docker-local
mode: managed
image: ghcr.io/dfinity/icp-cli-network-launcher
port-mapping:
- "0:4943"# Docker assigns a random available host port
Find the assigned port:
Terminal window
icpnetworkstatusdocker-local
# Shows: Port: 54321 (example)
Multiple Networks
Run multiple isolated networks simultaneously:
networks:
- name: docker-dev
mode: managed
image: ghcr.io/dfinity/icp-cli-network-launcher
port-mapping:
- "8000:4943"
- name: docker-test
mode: managed
image: ghcr.io/dfinity/icp-cli-network-launcher
port-mapping:
- "8001:4943"
Start both:
Terminal window
icpnetworkstartdocker-dev
icpnetworkstartdocker-test
Custom Environment Variables
Pass environment variables to the container:
networks:
- name: docker-local
mode: managed
image: ghcr.io/dfinity/icp-cli-network-launcher
port-mapping:
- "8000:4943"
environment:
- LOG_LEVEL=debug
- POCKET_IC_MUTE_SERVER=false
Passing Arguments to the Container
Use the args field to pass command-line arguments to the container’s entrypoint. This is how you configure image-specific behavior such as enabling Internet Identity, NNS, Bitcoin integration, or other flags supported by the image:
networks:
- name: docker-local
mode: managed
image: ghcr.io/dfinity/icp-cli-network-launcher
port-mapping:
- "8000:4943"
args:
- "--ii"
The args field passes values directly to the container entrypoint with no processing. The Docker image determines what arguments it accepts — see the image’s documentation for available options.
Comparison with native launcher mode: When using native managed networks (without image), settings like bitcoind-addr, ii, nns, and subnets are configured as top-level YAML fields. In Docker image mode, these are passed via args instead, since the image could be any Docker image — not necessarily the official network launcher.
Docker networking note: When referencing services running on the host machine from inside a container (e.g., a local Bitcoin node), use host.docker.internal instead of 127.0.0.1 or localhost. Inside a container, 127.0.0.1 refers to the container’s own loopback, not the host. For example: --bitcoind-addr=host.docker.internal:18444. Docker Desktop (macOS/Windows) resolves host.docker.internal automatically. On Linux Docker Engine, add the extra-hosts option to ensure it resolves:
extra-hosts:
- "host.docker.internal:host-gateway"
Remove Container on Exit
Automatically delete the container when stopped:
networks:
- name: docker-local
mode: managed
image: ghcr.io/dfinity/icp-cli-network-launcher
port-mapping:
- "8000:4943"
rm-on-exit: true# Clean up container on stop
Useful for CI/CD or temporary testing.
Pinning a Launcher Version
Pin the native network launcher to a specific version for reproducible environments across your team and CI:
networks:
- name: local
mode: managed
version: "v1.0.0"
If omitted, the latest released version is used. To update the launcher when no version is pinned:
Terminal window
icpnetworkupdate
When autocontainerize is enabled (see Always Use Containers), the launcher version is used as the Docker image tag.
For explicit Docker image configurations, specify the version as part of the image tag:
When using a containerized network, the Docker image must fulfill a specific contract with icp-cli. The official ghcr.io/dfinity/icp-cli-network-launcher image implements this contract. If you’re building a custom image, see Advanced: Custom Images for full details.
Status File
The container must write a status file to /app/status/status.json (configurable via status-dir) when the network is ready. This file tells icp-cli how to connect to the network.
The network must pre-fund the anonymous principal (2vxsx-fae) with ICP tokens. This is required because icp-cli uses the anonymous identity to seed ICP and cycles to user identities when the network starts.
Seeding flow:
icp-cli connects to the network using the anonymous identity
For each user identity (excluding anonymous), icp-cli transfers ICP from anonymous to that identity
For each identity (including anonymous), icp-cli mints cycles by acquiring ICP from anonymous and converting it through the cycles minting canister
Seeding amounts per identity:
ICP: 1,000,000 ICP (100,000,000,000,000 e8s)
Cycles: 1,000 T cycles (1,000,000,000,000,000 cycles)
The anonymous principal must have sufficient ICP balance to fund all identities that will be seeded.
Required System Canisters
The network must include these system canisters:
ICP ledger - For ICP token transfers during seeding
Cycles ledger - For cycles management
Cycles minting canister (CMC) - For converting ICP to cycles
Troubleshooting
”Cannot connect to Docker daemon”
Problem: Docker is not running.
Solution: Start Docker Desktop or the Docker daemon:
Terminal window
sudosystemctlstartdocker# Linux
# On macOS/Windows, open the Docker Desktop application
“Port already in use”
Problem: Another process is using the host port.
Solutions:
Change the host port in port-mapping:
port-mapping:
- "8001:4943"# Try a different port
Or use dynamic allocation:
port-mapping:
- "0:4943"
“Container fails to start”
Problem: Container exits immediately or fails to start.
Solution: Check container logs:
Terminal window
# Find container ID
dockerps-a|grepicp-cli-network-launcher
# View logs
dockerlogs<container-id>
Common issues:
Image pull failed (check internet connection)
Port conflict inside container (check port-mapping)
If the file is missing or incomplete, the container may still be initializing. Wait a few seconds and try again.
Configuration Reference
All available configuration options for containerized networks:
Field
Type
Required
Description
name
string
Yes
Unique network identifier
mode
string
Yes
Must be managed
image
string
Yes
Docker image to use (append :tag for version pinning)
port-mapping
string[]
Yes
Port mappings in [host-ip:]host-port:container-port format
rm-on-exit
bool
No
Delete container when stopped (default: false)
volumes
string[]
No
Docker volumes in name:container_path[:options] format
mounts
string[]
No
Bind mounts in host_path:container_path[:flags] format (flags: ro or rw)
environment
string[]
No
Environment variables in VAR=VALUE format
args
string[]
No
Additional arguments to container entrypoint (aliases: cmd, command)
entrypoint
string[]
No
Override container entrypoint
platform
string
No
Platform selection (e.g., linux/amd64)
user
string
No
User to run as in user[:group] format (group is optional)
shm-size
number
No
Size of /dev/shm in bytes
status-dir
string
No
Status directory path (default: /app/status)
extra-hosts
string[]
No
Extra hosts entries (e.g., host.docker.internal:host-gateway)
Example with multiple options:
networks:
- name: docker-local
mode: managed
image: ghcr.io/dfinity/icp-cli-network-launcher
port-mapping:
- "8000:4943"
volumes:
- icp-data:/data
mounts:
- "./config:/app/config:ro"# Mount local config as read-only
environment:
- LOG_LEVEL=info
- POCKET_IC_MUTE_SERVER=true
rm-on-exit: false
shm-size: 2147483648# 2GB
Advanced: Custom Images
If the default image doesn’t meet your needs, you can create a custom Docker image that implements the icp-cli network launcher interface.
Interface Version
Your container must support the icp-cli network launcher interface. The environment variable ICP_CLI_NETWORK_LAUNCHER_INTERFACE_VERSION is provided by icp-cli.
Current interface version: 1.0.0
Your container should:
Read ICP_CLI_NETWORK_LAUNCHER_INTERFACE_VERSION
Verify it supports the version
Exit early if the version is incompatible
Status File Requirements
Your container must write a status file to the status directory (default: /app/status/status.json) when the network is ready.
Important: The CLI automatically mounts the status directory as read-write, so your container can write to it. The file must contain a single line of JSON ending with a newline character.
Required fields:
v: string, must be "1" (status file format version)
gateway_port: number, the container port where the ICP HTTP gateway listens
root_key: string, hex-encoded root key of the network
Optional fields (primarily for PocketIC-based networks):
instance_id: number or null, PocketIC instance ID
config_port: number or null, PocketIC admin port
default_effective_canister_id: string or null, principal for provisional canister calls
Start automatically - Launch the network when the container starts
Write status file only when ready - Wait until the gateway API is accessible
Handle stop signals - Gracefully shut down on SIGTERM (or SIGINT if you set STOPSIGNAL)
Exit cleanly - Exit after shutdown completes
Example Dockerfile:
FROM ubuntu:22.04
# Install your ICP network implementation
RUN apt-get update && apt-get install -y curl
# ... install network software ...
# Create status directory
RUN mkdir -p /app/status
# Set stop signal if needed
STOPSIGNAL SIGTERM
# Copy startup script
COPY start-network.sh /app/start-network.sh
RUN chmod +x /app/start-network.sh
ENTRYPOINT ["/app/start-network.sh"]
Network Requirements
Your custom network must include the system canisters and pre-funded accounts described in Image Contract. In summary:
Required system canisters:
ICP ledger canister (ryjl3-tyaaa-aaaaa-aaaba-cai) - For ICP token transfers
Cycles ledger canister (um5iw-rqaaa-aaaaq-qaaba-cai) - For cycles management
Cycles minting canister (rkp4c-7iaaa-aaaaa-aaaca-cai) - For converting ICP to cycles
Pre-funded anonymous principal:
The anonymous principal (2vxsx-fae) must be pre-funded with ICP by the network itself. When icp-cli starts a containerized network, it seeds user identities by:
Using the anonymous identity to transfer ICP to each user identity (excluding anonymous itself)
Acquiring ICP from anonymous and converting it to cycles through the CMC for each identity (including anonymous)
The CLI does not seed the anonymous principal—your network must do this. The official image pre-funds anonymous with sufficient ICP for typical development use.
Recommended minimum balance: The anonymous principal should have at least 10,000,000 ICP (1,000,000,000,000,000 e8s) to support seeding multiple identities with 1,000,000 ICP each plus transaction fees.
Port Binding
The gateway port (the port your ICP HTTP gateway listens on inside the container) must be mapped to a host port:
port-mapping:
- "8000:4943"# host:container
You can use 0 for dynamic host port allocation:
port-mapping:
- "0:4943"
Testing Your Custom Image
Build your image:
Terminal window
dockerbuild-tmy-icp-network.
Test it manually:
Terminal window
dockerrun-p8000:4943my-icp-network
# In another terminal, check status
curlhttp://localhost:8000/api/v2/status
Configure in icp.yaml:
networks:
- name: custom-network
mode: managed
image: my-icp-network
port-mapping:
- "8000:4943"
Start with icp-cli:
Terminal window
icpnetworkstartcustom-network
Advanced: Manual dockerd in WSL2
If you’re on Windows and want to use a manually instantiated dockerd in a WSL2 instance instead of Docker Desktop, set these environment variables:
ICP_CLI_DOCKER_WSL2_DISTRO=<distro> — the WSL2 distribution name running dockerd
DOCKER_HOST=tcp://<ip>:<port> — the TCP address where dockerd is listening
Always Use Containers
If you prefer containers for all local networks without configuring each one individually, enable the autocontainerize setting:
Terminal window
icpsettingsautocontainerizetrue
This makes all managed networks (including the implicit local network) run in Docker containers automatically. To check the current value or disable it:
Terminal window
icpsettingsautocontainerize# Print current value
icpsettingsautocontainerizefalse# Disable
Note that this is the default behavior on Windows, where the setting will be ignored.