Skip to main content
Mole wiring connections

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
Automatic TLS

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:

  1. Your request goes to Agent A's SOCKS5 proxy
  2. Agent A finds that Agent B advertises a route to the destination
  3. Agent A tunnels the connection through to Agent B
  4. Agent B opens the real TCP connection to example.com
  5. 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