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):
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):
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?