Skip to content

Tunnel -> Pi -> OpenVPN

Question:

If I have a series of Raspberry Pi’s running OpenWRT - can I somehow make them show up as a “virtual” ethernet connection if they are connected to a shared Ethernet network.

Just as I would see a new device on a linux box if I connected via Wifi.

I have 20 of these and want to use them for outbound communications.

I’ve tried setting them up as proxies, but it only works for HTTP - I want to effectively use it as an entire IP device.

Response:

Yes, absolutely. What you’re describing is essentially creating point-to-point tunnels from each Pi back to a central host, where each tunnel appears as a distinct network interface. There are several approaches:

Best Options

1. WireGuard (Recommended)

Each Pi runs WireGuard and connects to your host. You get a separate wg0, wg1, … wg19 interface per Pi on the host machine.

On the host:

# For each Pi, create a WireGuard interface
ip link add wg0 type wireguard
wg set wg0 private-key /path/to/host-private-key listen-port 51820
ip addr add 10.200.0.1/32 dev wg0
ip link set wg0 up

# Add peer (the Pi)
wg set wg0 peer <pi-public-key> allowed-ips 10.200.0.2/32,0.0.0.0/0 endpoint <pi-ip>:51820

On each Pi (OpenWRT has native WireGuard support):

opkg update && opkg install wireguard-tools

2. GRE Tunnels (Layer 3)

Simpler setup, no encryption, creates gre-pi1, gre-pi2, etc:

# On host - for each Pi
ip tunnel add gre-pi1 mode gre remote <pi1-ip> local <host-ip>
ip addr add 10.100.1.1/30 dev gre-pi1
ip link set gre-pi1 up

3. VXLAN (Layer 2, good for scale)

If you need Layer 2 connectivity (MAC-level bridging):

ip link add vxlan1 type vxlan id 100 remote <pi1-ip> dport 4789
ip link set vxlan1 up

Using Them for Outbound Traffic

Once you have the interfaces, use policy routing to direct specific traffic out specific Pis:

# Create routing tables
echo "100 via-pi1" >> /etc/iproute2/rt_tables

# Route traffic marked 0x1 through pi1
ip route add default via 10.200.0.2 table via-pi1
ip rule add fwmark 0x1 table via-pi1

# Then use iptables to mark traffic
iptables -t mangle -A OUTPUT -p tcp --dport 443 -m statistic --mode nth --every 20 --packet 0 -j MARK --set-mark 0x1

Why WireGuard is Best for Your Use Case

Given your VPN cluster work, WireGuard gives you:

  • Native interface per Pi (full IP stack, not just HTTP)
  • Encrypted tunnel (useful if Pis are remote)
  • Very low overhead (~3% CPU on Pi 4B)
  • OpenWRT has excellent support via LuCI
  • Easy to script peer management for 20+ devices

Want me to put together a complete deployment script for the WireGuard approach? I can include the OpenWRT UCI commands for the Pi side and a host-side setup script that auto-generates configs for all 20 devices.​​​​​​​​​​​​​​​​

Host Machine
    ├── wg0 → Pi1 → OpenVPN → Internet (Exit IP A)
    ├── wg1 → Pi2 → OpenVPN → Internet (Exit IP B)
    ├── wg2 → Pi3 → OpenVPN → Internet (Exit IP C)
    └── ... (20 different exit IPs)

The Key Configuration

On each Pi, you just need to ensure traffic arriving via WireGuard gets routed out the VPN tunnel, not the local network:

Pi Side (OpenWRT)

# /etc/config/wireguard or via UCI

# WireGuard interface
uci set network.wg_host=interface
uci set network.wg_host.proto='wireguard'
uci set network.wg_host.private_key='<pi-private-key>'
uci set network.wg_host.listen_port='51820'
uci add_list network.wg_host.addresses='10.200.1.2/24'  # Pi1 uses .1.x, Pi2 uses .2.x, etc.

# Peer (your host)
uci set network.wg_peer=wireguard_wg_host
uci set network.wg_peer.public_key='<host-public-key>'
uci set network.wg_peer.allowed_ips='10.200.1.1/32'
uci set network.wg_peer.persistent_keepalive='25'

uci commit network

Firewall - Forward WireGuard → VPN:

# Allow forwarding from WireGuard zone to VPN zone
uci set firewall.wg_zone=zone
uci set firewall.wg_zone.name='wireguard'
uci set firewall.wg_zone.input='ACCEPT'
uci set firewall.wg_zone.output='ACCEPT'
uci set firewall.wg_zone.forward='ACCEPT'
uci set firewall.wg_zone.network='wg_host'

# Forward rule: WireGuard → VPN (not WAN)
uci set firewall.wg_to_vpn=forwarding
uci set firewall.wg_to_vpn.src='wireguard'
uci set firewall.wg_to_vpn.dest='vpn'  # Your OpenVPN zone

# Masquerade on VPN interface
uci set firewall.vpn_zone.masq='1'

uci commit firewall

Critical Routing Part:

Traffic from WireGuard must exit via tun0 (VPN), not eth0:

# Policy route for WireGuard subnet
ip rule add from 10.200.1.0/24 table vpn priority 100
ip route add default dev tun0 table vpn

Or in OpenWRT UCI:

uci set network.vpn_route=route
uci set network.vpn_route.interface='vpn'
uci set network.vpn_route.target='0.0.0.0/0'
uci set network.vpn_route.table='100'

uci set network.wg_rule=rule
uci set network.wg_rule.src='10.200.1.0/24'
uci set network.wg_rule.lookup='100'
uci set network.wg_rule.priority='100'

Host Side

#!/bin/bash
# generate_wg_interfaces.sh

HOST_PRIVATE_KEY=$(wg genkey)
HOST_PUBLIC_KEY=$(echo $HOST_PRIVATE_KEY | wg pubkey)
BASE_PORT=51820

for i in $(seq 1 20); do
    IFACE="wg${i}"
    PI_IP="192.168.1.$((100 + i))"  # Adjust to your Pi IPs
    TUNNEL_NET="10.200.${i}"

    # Create interface
    ip link add $IFACE type wireguard
    wg set $IFACE private-key <(echo $HOST_PRIVATE_KEY) listen-port $((BASE_PORT + i))
    ip addr add ${TUNNEL_NET}.1/24 dev $IFACE
    ip link set $IFACE up

    # Add Pi as peer (you'll need each Pi's public key)
    wg set $IFACE peer <pi${i}-public-key> allowed-ips ${TUNNEL_NET}.0/24 endpoint ${PI_IP}:51820

    # Create routing table for this interface
    echo "$((100 + i)) via-pi${i}" >> /etc/iproute2/rt_tables
    ip route add default via ${TUNNEL_NET}.2 table via-pi${i}
done

Using It

From the host, bind to specific interfaces or use policy routing:

# Test - curl using Pi3's VPN exit
curl --interface wg3 https://ifconfig.me

# Or with SO_BINDTODEVICE in code
# Or with policy routing based on marks/source IPs

This gives you 20 distinct network interfaces, each tunneling through a different VPN exit point. Want me to put together a complete deployment package with the OpenWRT configs and a provisioning script?​​​​​​​​​​​​​​​​