
Your First Mesh Network
This guide shows you how to tunnel traffic through a remote network. You will connect two agents so that traffic entering one exits from the other - reaching destinations that would otherwise be inaccessible.
What you will build:
- An ingress agent that accepts your SOCKS5 connections
- An exit agent on a remote network that opens connections to destinations
- A secure tunnel between them that traverses any network path
The Setup
Here is what you are building:
- Agent A (your machine): Where you connect with curl, SSH, or browser
- Agent B (remote network): Opens connections to destinations you want to reach
Prerequisites
- Muti Metroo installed
- Two machines or terminals (can use same machine with different ports)
- Network connectivity between agents
No certificate setup required. Agents auto-generate TLS certificates and E2E encryption secures all traffic. For strict verification, see TLS/mTLS.
Step 1: Initialize Agent Identities
Agent A
muti-metroo init -d ./data-a
# Note the Agent ID: aaaa1111....
Agent B
muti-metroo init -d ./data-b
# Note the Agent ID: bbbb2222....
Step 2: Configure Agent B (Exit Node)
Create config-b.yaml:
agent:
id: "auto"
display_name: "Agent B (Exit)"
data_dir: "./data-b"
log_level: "info"
# Listen for peer connections
listeners:
- transport: quic
address: "0.0.0.0:4433"
# Exit node - open connections to internet
exit:
enabled: true
routes:
- "0.0.0.0/0" # Default route - all traffic
# HTTP API
http:
enabled: true
address: ":8081" # Different port if on same machine
Start Agent B:
muti-metroo run -c ./config-b.yaml
Note the Agent ID from the output (e.g., bbbb2222333344445555666677778888).
Step 3: Configure Agent A (Ingress Node)
Create config-a.yaml with Agent B's ID:
agent:
id: "auto"
display_name: "Agent A (Ingress)"
data_dir: "./data-a"
log_level: "info"
# Listen for peer connections (optional, for other agents)
listeners:
- transport: quic
address: "0.0.0.0:4434" # Different port if on same machine
# Connect to Agent B
peers:
- id: "bbbb2222333344445555666677778888" # Agent B's ID
transport: quic
address: "192.168.1.20:4433" # Agent B's address
# SOCKS5 proxy for client connections
socks5:
enabled: true
address: "127.0.0.1:1080"
# HTTP API
http:
enabled: true
address: ":8080"
Start Agent A:
muti-metroo run -c ./config-a.yaml
Step 4: Verify Connection
Check Agent A's Peers
curl http://localhost:8080/healthz
Expected output:
{
"status": "healthy",
"agent_id": "aaaa1111...",
"peers": 1,
"routes": 1,
"streams": 0
}
Check Logs
Agent A should show:
INFO Connected to peer peer_id=bbbb2222... addr=192.168.1.20:4433
INFO Route added cidr=0.0.0.0/0 next_hop=bbbb2222... metric=1
Agent B should show:
INFO Accepted peer connection peer_id=aaaa1111... addr=192.168.1.10:xxxxx
Step 5: Test the Mesh
Now test that traffic flows through the mesh:
# From Agent A's machine
curl -x socks5://localhost:1080 https://example.com
You should see the webpage content. In the logs:
Agent A:
INFO SOCKS5 connect request dest=example.com:443
INFO Stream opened stream_id=1 dest=example.com:443
Agent B:
INFO Stream open request stream_id=1 dest=example.com:443
INFO Exit connection established dest=93.184.216.34:443
Step 6: Test More Applications
SSH Through the Mesh
ssh -o ProxyCommand='nc -x localhost:1080 %h %p' user@remote-server
Browser Proxy
Configure your browser to use localhost:1080 as SOCKS5 proxy.
curl with Verbose Output
curl -v -x socks5://localhost:1080 https://httpbin.org/ip
How It Works
When you run curl -x socks5://localhost:1080 https://example.com:
- Your request goes to Agent A's SOCKS5 proxy
- Agent A finds that Agent B advertises a route to the destination
- Agent A tunnels the connection through to Agent B
- Agent B opens the real TCP connection to example.com
- Data flows back through the tunnel to your curl command
The key insight: Agent B can reach destinations that Agent A cannot. Your traffic exits from Agent B's network.
Querying the Dashboard API
Check the mesh topology via the dashboard API:
# Agent A topology
curl http://localhost:8080/api/topology | jq
# Agent B dashboard overview
curl http://localhost:8081/api/dashboard | jq
The topology endpoint returns all agents and their connections.
Adding a Third Agent (Transit)
To add a transit node between A and B:
Agent C configuration:
agent:
id: "auto"
display_name: "Agent C (Transit)"
data_dir: "./data-c"
log_level: "info"
listeners:
- transport: quic
address: "0.0.0.0:4435"
# Connect to Agent B
peers:
- id: "bbbb2222..."
transport: quic
address: "192.168.1.20:4433"
# No socks5 or exit - pure transit
http:
enabled: true
address: ":8082"
Update Agent A to connect to Agent C instead of Agent B:
peers:
- id: "cccc3333..." # Agent C's ID
transport: quic
address: "192.168.1.30:4435"
Routes will propagate: Agent A learns about Agent B's 0.0.0.0/0 route through Agent C.
Troubleshooting
No Route to Host
Error: no route to 93.184.216.34
- Check Agent B is running and has exit enabled
- Verify connection between agents
- Check routes:
curl http://localhost:8080/healthz
Connection Refused
Error: connection refused
- Verify Agent B is listening on correct address
- Check firewall rules
- Verify TLS certificates
Certificate Error (strict TLS only)
If you enabled strict TLS verification:
Error: certificate verify failed
- Ensure both agents use certs signed by same CA
- Check certificate expiration
- Verify peer ID matches certificate
See Troubleshooting Guide for more help.
Next Steps
- Core Concepts - Understand the architecture
- Configuration Reference - All configuration options
- Deployment Scenarios - Real-world deployment patterns
- Security Best Practices - Production hardening