Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/chaitu426/minibox/llms.txt

Use this file to discover all available pages before exploring further.

MiniBox gives every container a private network namespace connected to the host through a Linux bridge. Outbound traffic is masqueraded through NAT, and inbound traffic is forwarded via iptables DNAT rules and a kernel-bypass TCP proxy. This page explains how the network is set up, how to expose ports, and how to troubleshoot common issues.

Architecture overview

Host
├── minibox0 bridge (172.19.0.1/24)
│   ├── veth-<id>  ─── vetp-<id> → eth0 (172.19.0.2/24) [Container A]
│   ├── veth-<id>  ─── vetp-<id> → eth0 (172.19.0.3/24) [Container B]
│   └── ...
└── iptables NAT (MASQUERADE + DNAT rules)
Each container gets its own network namespace (CLONE_NEWNET) and a dedicated veth pair connecting it to the bridge.

The minibox0 bridge

SetupBridge() in internal/network/network.go creates a Linux bridge named minibox0 and assigns it the address 172.19.0.1/24, making the host reachable from every container at 172.19.0.1. The bridge setup also:
  • Enables net.ipv4.ip_forward and route_localnet sysctls on the host so packets can traverse bridge → host → internet.
  • Adds two NAT masquerade rules to iptables POSTROUTING:
    • Traffic leaving the 172.19.0.0/24 subnet on any interface other than minibox0 is masqueraded (outbound internet access).
    • Traffic destined for 172.19.0.0/24 is also masqueraded (supports localhost DNAT hairpin).
By default the bridge is created at daemon startup. Set MINIBOX_BRIDGE_ON_STARTUP=0 to skip bridge creation at startup; minibox0 will then be created lazily the first time a container needs networking. This keeps daemon startup near-instant.

Per-container veth pairs

When a container starts, SetupContainerNetwork() runs the following sequence:
1

Create veth pair

A veth pair is created on the host: veth-<id> (host side) and vetp-<id> (peer side), where <id> is the first 8 characters of the container ID.
2

Attach host side to bridge

veth-<id> is attached to minibox0 and brought up.
3

Move peer into container netns

vetp-<id> is moved into the container’s network namespace (identified by the child process PID).
4

Configure interfaces inside the namespace

Inside the container’s network namespace:
  • Loopback (lo) is brought up.
  • The peer veth is renamed to eth0.
  • The allocated IP address is assigned to eth0 with a /24 prefix.
  • A default route via 172.19.0.1 (the bridge gateway) is added.
5

Program port-forwarding rules

For each -p host:container mapping, three iptables rules are installed and a TCP proxy listener is started on the host port:
  • nat/PREROUTING DNAT — rewrites the destination for external traffic arriving on hostPort.
  • nat/OUTPUT DNAT — rewrites the destination for localhost traffic (hairpin).
  • filter/FORWARD ACCEPT — allows forwarded TCP packets to reach the container IP.

IP address allocation

Container IPs are allocated sequentially from 172.19.0.2 upward using an atomic counter:
First container:  172.19.0.2
Second container: 172.19.0.3
Third container:  172.19.0.4
...
The gateway (host) is always 172.19.0.1. The full subnet is 172.19.0.0/24, giving room for up to 253 simultaneous containers before address exhaustion.

Port mapping with -p

Use -p host:container to forward a host port to a container port:
# Expose container port 80 on host port 9000
minibox run -d -p 9000:80 myapp

# Access the service from the host
curl http://127.0.0.1:9000

Multiple port mappings

Repeat -p for each additional port:
minibox run -d \
  -p 8080:80 \
  -p 8443:443 \
  myapp
Each mapping installs its own DNAT/FORWARD triplet and starts an independent TCP proxy listener.

How the DNAT rules look

For -p 9000:80 where the container IP is 172.19.0.2:
# iptables-save excerpt
-A PREROUTING  -p tcp --dport 9000 -j DNAT --to-destination 172.19.0.2:80
-A OUTPUT      -p tcp -o lo --dport 9000 -j DNAT --to-destination 172.19.0.2:80
-A FORWARD     -p tcp -d 172.19.0.2 --dport 80 -j ACCEPT
MiniBox cleans up stale DNAT rules for a host port before installing new ones. If a previous container used the same host port and was not properly removed, removeStaleMiniboxNATForHostPort() sweeps PREROUTING and OUTPUT for matching rules and deletes them first.

NAT masquerade for outbound traffic

Containers can reach the internet through the host’s default route because of the masquerade rule added to nat/POSTROUTING:
# Verify from inside a container shell
minibox exec -it a1b2c3d4 /bin/sh
# inside container:
wget -qO- https://icanhazip.com
The kernel replaces the container’s source IP (172.19.0.x) with the host’s external IP before the packet leaves the host NIC, and rewrites the reply back to the container.

Network teardown

When a container stops (via minibox stop, minibox kill, or natural exit), TeardownContainerNetwork() runs automatically:
  1. Deletes the host-side veth (veth-<id>). Deleting the host end automatically removes the peer inside the network namespace.
  2. Removes all DNAT/FORWARD iptables rules that were installed for this container’s port mappings.
  3. Closes and cleans up the TCP proxy listeners for each mapped port.
When the daemon shuts down, TeardownBridge() removes the global minibox0 bridge and the masquerade rules from nat/POSTROUTING.

Startup performance flag

MINIBOX_BRIDGE_ON_STARTUP
string
default:"1"
Set to 0 to skip bridge creation at daemon startup. The bridge is created lazily the first time a container needs networking. Useful in environments where you want near-instant daemon boot and are running your first container shortly after.
MINIBOX_BRIDGE_ON_STARTUP=0 sudo -E miniboxd

Troubleshooting

If the daemon crashes or is killed without cleanup, port-mapping rules may linger in iptables. List them and remove manually:
# List all DNAT rules targeting the minibox subnet
sudo iptables -t nat -L PREROUTING -n --line-numbers | grep 172.19.0

# Delete by line number (repeat for each stale rule)
sudo iptables -t nat -D PREROUTING <line-number>

# Also check OUTPUT chain
sudo iptables -t nat -L OUTPUT -n --line-numbers | grep 172.19.0
Running minibox system prune after a crash will also clean up orphaned container state, though it does not flush iptables rules automatically.
After an unclean shutdown, host-side veth interfaces may remain attached to the bridge:
# List all interfaces attached to minibox0
ip link show master minibox0

# Delete an orphaned veth
sudo ip link delete veth-a1b2c3d4
You can also delete the entire bridge and recreate it:
sudo ip link set minibox0 down
sudo ip link delete minibox0
# Restart miniboxd to recreate it
sudo -E miniboxd
If MiniBox reports bind: address already in use when starting a TCP proxy, another process is already listening on the requested host port. Find and stop it:
sudo ss -tlnp | grep :<hostPort>
Or choose a different host port in your -p flag.
Check that IP forwarding is enabled on the host:
cat /proc/sys/net/ipv4/ip_forward
# Should print: 1
If it is 0, enable it:
sudo sysctl -w net.ipv4.ip_forward=1
MiniBox enables this automatically in SetupBridge(), but some system configurations reset it.

Build docs developers (and LLMs) love