PVE + OpenWrt VM: USB WiFi Passthrough with Multi-SSID, LAN Isolation & Bandwidth Control

Overview

Running ImmortalWrt 24.10.5 as a VM on a PVE N5095 host (16GB DDR4), with a passed-through USB WiFi adaptor (MT7612U/RTL8811AU) broadcasting a visitor SSID. The setup enforces LAN isolation, bandwidth caps, and BitTorrent port blocking.

VM IP: 192.168.2.49 | Gateway: 192.168.2.254


1. VM Creation

# Download ImmortalWrt
wget https://downloads.immortalwrt.org/releases/24.10.5/x86_64/immortalwrt-24.10.5-x86-64-generic-ext4-combined.qcow2.gz

# Create VM (ID 100)
qm create 100 --name openwrt --memory 512 --net0 virtio,bridge=vmbr0 --cores 2 --cpu host
qm importdisk 100 immortalwrt-24.10.5-x86-64-generic-ext4-combined.qcow2.local qcow
qm set 100 --scsi0 local-lvm:qcow2
qm set 100 --boot order=scsi0
qm start 100

Attach the USB WiFi adaptor to the VM via PVE web UI (Hardware → Add → USB Device).


2. USB WiFi Adaptor Identification

Inside the VM:

opkg update
opkg install usbutils
lsusb
Field Value
Device Realtek 802.11ac WLAN Adapter
USB ID 0bda:0811 (RTL8811AU)
Driver tried kmod-rtl8xxxudid not bind
Driver used kmod-rtl8812au-ctworked
opkg install kmod-rtl8812au-ct hostapd

The 0bda:0811 device needs rtl8812au-ct, not the generic rtl8xxxu. If wlan0 doesn't appear, check dmesg | grep rtl.


3. Network Config (/etc/config/network)

# LAN bridge (eth0, native)
uci set network.lan.device='br-lan'
uci set network.lan.ipaddr='192.168.2.49'
uci set network.lan.netmask='255.255.255.0'
uci set network.lan.gateway='192.168.2.254'
uci add_list network.lan.dns='8.8.8.8'

# Visitor bridge (wlan0.20)
uci add network device
set network.@device[-1].name='br-visitor'
set network.@device[-1].type='bridge'
set network.@device[-1].ports='wlan0.20'

uci add network interface
set network.@interface[-1].name='vlan20'
set network.@interface[-1].device='br-visitor'
set network.@interface[-1].proto='static'
set network.@interface[-1].ipaddr='192.168.20.1'
set network.@interface[-1].netmask='255.255.255.0'

# IoT bridge (wlan0.30) — optional
uci add network device
set network.@device[-1].name='br-iot'
set network.@device[-1].type='bridge'
set network.@device[-1].ports='wlan0.30'

uci add network interface
set network.@interface[-1].name='vlan30'
set network.@interface[-1].device='br-iot'
set network.@interface[-1].proto='static'
set network.@interface[-1].ipaddr='192.168.30.1'
set network.@interface[-1].netmask='255.255.255.0'

uci commit network

4. Wireless Config (/etc/config/wireless)

# Radio0 — 5GHz, channel 36
uci set wireless.radio0=wifi-device
set wireless.radio0.type='mac80211'
set wireless.radio0.path='pci0000:00/0000:00:1e.0/usb2/2-1/2-1:1.0'
set wireless.radio0.band='5g'
set wireless.radio0.channel='36'
set wireless.radio0.country='CN'
set wireless.radio0.disabled='0'

# Visitor SSID (no encryption for demo — add WPA2 in production)
uci add wireless wifi-iface
set wireless.@wifi-iface[-1].device='radio0'
set wireless.@wifi-iface[-1].mode='ap'
set wireless.@wifi-iface[-1].ssid='Visitor'
set wireless.@wifi-iface[-1].network='vlan20'
set wireless.@wifi-iface[-1].ifname='wlan0.20'
set wireless.@wifi-iface[-1].encryption='none'

# IoT SSID
uci add wireless wifi-iface
set wireless.@wifi-iface[-1].device='radio0'
set wireless.@wifi-iface[-1].mode='ap'
set wireless.@wifi-iface[-1].ssid='IoT'
set wireless.@wifi-iface[-1].network='vlan30'
set wireless.@wifi-iface[-1].ifname='wlan0.30'
set wireless.@wifi-iface[-1].encryption='none'

uci commit wireless
wifi

5. Firewall — LAN Isolation & NAT (/etc/config/firewall)

⚠️ Known Issue: LAN isolation rules added via iptables directly are NOT persistent — they disappear after reboot. Must use UCI firewall config or add to /etc/firewall.user.

5a. Persistent Firewall Zones (UCI way)

# WAN zone (default)
uci set firewall.@zone[0].name='wan'
list firewall.@zone[0].network='wan'
set firewall.@zone[0].masq='1'
set firewall.@zone[0].mtu_fix='1'

# Visitor zone
uci add firewall zone
set firewall.@zone[-1].name='visitor'
list firewall.@zone[-1].network='vlan20'
set firewall.@zone[-1].input='REJECT'
set firewall.@zone[-1].output='ACCEPT'
set firewall.@zone[-1].forward='REJECT'

# Visitor → WAN forwarding
uci add firewall forwarding
set firewall.@forwarding[-1].src='visitor'
set firewall.@forwarding[-1].dest='wan'

# Allow DHCP/DNS for visitor
uci add firewall rule
set firewall.@rule[-1].name='Visitor DHCP/DNS'
list firewall.@rule[-1].src='visitor'
list firewall.@rule[-1].dest='wan'
set firewall.@rule[-1].proto='udp'
list firewall.@rule[-1].dest_port='53 67'
set firewall.@rule[-1].target='ACCEPT'

# Allow gateway access (192.168.2.254)
uci add firewall rule
set firewall.@rule[-1].name='Allow Gateway'
list firewall.@rule[-1].src='visitor'
set firewall.@rule[-1].dest='wan'
set firewall.@rule[-1].dest_ip='192.168.2.254'
set firewall.@rule[-1].proto='all'
set firewall.@rule[-1].target='ACCEPT'

# ❌ Drop all other access to LAN (192.168.2.0/24)
uci add firewall rule
set firewall.@rule[-1].name='Drop LAN Access'
list firewall.@rule[-1].src='visitor'
set firewall.@rule[-1].dest='wan'
set firewall.@rule[-1].dest_ip='192.168.2.0/24'
set firewall.@rule[-1].proto='all'
set firewall.@rule[-1].target='REJECT'

uci commit firewall
/etc/init.d/firewall restart

5b. Persistent iptables Rules (fallback — /etc/firewall.user)

# Append to /etc/firewall.user — survives reboot
cat >> /etc/firewall.user << 'EOF'

# --- Visitor LAN Isolation ---
# Allow gateway only
iptables -A forwarding_rule -i br-visitor -d 192.168.2.254 -j ACCEPT
# Drop everything else to LAN
iptables -A forwarding_rule -i br-visitor -d 192.168.2.0/24 -j DROP
EOF

6. Bandwidth Cap — HTB on br-visitor (/etc/config/sqm)

opkg update
opkg install sqm-scripts kmod-sched
# /etc/config/sqm
config queue
    option enabled '1'
    option interface 'br-visitor'
    option qdisc 'htb'
    option script 'queue.sh'
    option linklayer 'ethernet'
    option overhead '22'
    option download '4000'   # 4Mbit down
    option upload '512'       # 512Kbit up
uci set sqm.eth0.interface='br-visitor'
uci set sqm.eth0.qdisc='htb'
uci set sqm.eth0.linklayer='ethernet'
uci set sqm.eth0.download='4000'
uci set sqm.eth0.upload='512'
uci commit sqm
/etc/init.d/sqm enable
/etc/init.d/sqm start

Verify:

tc qdisc show dev br-visitor
tc class show dev br-visitor

Expected output shows htb root with 4Mbit ceiling.


7. BitTorrent Port Blocking

# /etc/firewall.user — add before "Return" line
cat >> /etc/firewall.user << 'EOF'

# --- Block BitTorrent ---
# Common BitTorrent ports
iptables -A FORWARD -i br-visitor -p tcp --dport 6881:6889 -j DROP
iptables -A FORWARD -i br-visitor -p tcp --dport 51413 -j DROP
iptables -A FORWARD -i br-visitor -p udp --dport 51413 -j DROP
EOF
/etc/init.d/firewall restart

8. DHCP for Visitor Network

# /etc/config/dhcp
config dhcp 'vlan20'
    option interface 'vlan20'
    option start '100'
    option limit '150'
    option leasetime '1h'
    list dhcp_option '6,8.8.8.8,8.8.4.4'

uci commit dhcp
/etc/init.d/dnsmasq restart

9. Verification Checklist

Feature Command Expected
NAT masquerade iptables -t nat -L POSTROUTING -v MASQUERADE on WAN
LAN isolation iptables -L forwarding_rule -v 192.168.2.0/24 DROP packets
Gateway access ping 192.168.2.254 from visitor client ✓ reply
Bandwidth cap tc qdisc show dev br-visitor htb with 4Mbit
Torrent block `iptables -L FORWARD -v grep 688`
SSID up logread -e hostapd wlan0.20, wlan0.30 active

10. Known Issue: LAN Isolation Not Persistent After Reboot

Symptom: After OpenWrt VM reboots, LAN isolation stops working — visitor clients can reach 192.168.2.0/24.

Root cause: Direct iptables commands issued via CLI are ephemeral. They are lost on reboot.

Fix: Rules must be in /etc/firewall.user or UCI firewall config (see Section 5 above).

If you already have broken rules: Clear and restart:

# Flush all forwarding rules
iptables -F forwarding_rule
iptables -F FORWARD

# Restart firewall to load persistent rules
/etc/init.d/firewall restart

# Verify
iptables -L forwarding_rule -v

11. Full Config File Summary

File Purpose
/etc/config/network Bridges, VLAN sub-interfaces, static IPs
/etc/config/wireless Radio0, SSIDs, encryption
/etc/config/firewall Zones, forwarding, masquerade
/etc/config/dhcp DHCP pools for visitor/IoT
/etc/config/sqm HTB bandwidth shaping
/etc/firewall.user Persistent iptables custom rules

Hardware Used

  • PVE Host: N5095 / 16GB DDR4
  • USB WiFi: Realtek 0bda:0811 (MT7612U/RTL8811AU based)
  • Working driver: kmod-rtl8812au-ct
  • OS inside VM: ImmortalWrt 24.10.5 x86_64