Sharing my experience setting up a TP-Link TL-MR3020 v3 as a dedicated travel router with VPN. This took several days of trial and error, and I hope it helps others with similar low-memory devices.
Hardware
- Device: TP-Link TL-MR3020 v3
- SoC: MT7628 (ramips/mt76x8)
- RAM: 58 MB usable
- Flash: 8 MB NOR
- USB: 1x USB 2.0
Final working setup (OpenWrt 25.12.4 official)
- Extroot: USB drive, ext4 without journal, 503 MB overlay
- VPN: WireGuard (NordVPN), full tunnel
- WiFi: AP (travel network) + STA (upstream hotel/airport WiFi)
- Travelmate: 5 uplinks configured, captive portal support
- DNS hotplug: Automatic VPN DNS when VPN is up, upstream DNS when VPN is down (for captive portal login)
- LuCI: Accessible for WiFi management
- Packages: 188 installed on extroot
Key findings and lessons
1. CONFIG_SWAP is removed from mt76x8 kernel
As reported in #21853, CONFIG_SWAP was deliberately removed from the ramips/mt76x8 subtarget. /proc/swaps does not exist on official images.
Custom build attempt: I compiled a custom image with CONFIG_SWAP=y and it worked — 289 MB swap (USB + zram). However, the larger image left only 192-256 KB for rootfs_data, and jffs2 requires a minimum of 5 erase blocks (320 KB on this device with 64 KB erase size). With fewer blocks, jffs2 fails with Too few erase blocks and the overlay falls back to tmpfs — nothing persists.
The tradeoff: On 8 MB flash, you can have either swap OR a working jffs2 overlay, but not both. I chose jffs2 (persistence) and no swap.
2. ext4 without journal is critical for extroot
On a 64 MB RAM device, ext4 journal recovery during boot will OOM-kill the system. Always format the USB partition without journal:
mkfs.ext4 -O ^has_journal -L MR3020 /dev/sda1
3. CIDR notation required in OpenWrt 25.12
This one cost me several TFTP recoveries. When changing the LAN IP via UCI:
# WRONG (becomes /32, device unreachable):
uci set network.lan.ipaddr='192.168.3.1'
# CORRECT:
uci set network.lan.ipaddr='192.168.3.1/24'
See #21370 and this forum thread.
4. WireGuard installation via manual .apk extraction
The official apk add fails on 64 MB devices (OOM during package index download). Workaround:
- Download
.apkfiles on another machine - Transfer via SSH pipe:
cat file.apk | ssh root@router 'cat > /tmp/file.apk' - Extract:
apk extract --allow-untrusted --destination / /tmp/file.apk - Load modules manually:
insmod /lib/modules/6.12.87/wireguard.ko
Important module load order:
insmod scsi_common.ko # MUST be first
insmod scsi_mod.ko
insmod sd_mod.ko
insmod usb-storage.ko
5. DNS hotplug for captive portal compatibility
WireGuard with AllowedIPs = 0.0.0.0/0 captures all traffic. For captive portal login to work, DNS must fall back to upstream when VPN is down:
# /etc/hotplug.d/iface/95-wireguard-dns
#!/bin/sh
case "$ACTION" in
ifup)
[ "$INTERFACE" = "wg_vpn" ] && {
sleep 3
uci set dhcp.@dnsmasq[0].noresolv="1"
uci delete dhcp.@dnsmasq[0].resolvfile 2>/dev/null
uci delete dhcp.@dnsmasq[0].server 2>/dev/null
uci add_list dhcp.@dnsmasq[0].server="YOUR_VPN_DNS_1"
uci add_list dhcp.@dnsmasq[0].server="YOUR_VPN_DNS_2"
uci commit dhcp
/etc/init.d/dnsmasq restart
logger -t wg-dns "VPN UP: DNS via VPN provider"
}
;;
ifdown)
[ "$INTERFACE" = "wg_vpn" ] && {
uci set dhcp.@dnsmasq[0].noresolv="0"
uci set dhcp.@dnsmasq[0].resolvfile="/tmp/resolv.conf.d/resolv.conf.auto"
uci delete dhcp.@dnsmasq[0].server 2>/dev/null
uci commit dhcp
/etc/init.d/dnsmasq restart
logger -t wg-dns "VPN DOWN: DNS upstream (captive portal mode)"
}
;;
esac
6. Travelmate VPN management must be disabled
If using travelmate with an external VPN (WireGuard), set trm_vpn=0. Otherwise travelmate will try to manage the VPN interface and may tear it down repeatedly.
What didn't work
- Swap on official image: Impossible,
CONFIG_SWAPnot in kernel - Custom build with swap + working jffs2: Image too large, not enough erase blocks
- Custom build with swap + WireGuard built-in: Even larger, definitely not enough
- OpenVPN on boot with 58 MB RAM: OOM boot loop. Must start VPN after WiFi is connected.
apk addonline on 64 MB device: OOM during repo index processing
Tips for similar devices (4/64 MB flash/RAM)
- Use official image + extroot USB (don't fight the flash size)
- Format ext4 without journal (
-O ^has_journal) - Install packages via manual
.apkextraction, notapk add - Don't enable VPN on boot — use hotplug to start after connectivity
- Use
delay_root=15in fstab for USB detection - Keep TFTP recovery image handy — you will brick it at least once
- Remember CIDR notation for IP changes in 25.12+
Hope this helps someone! Happy to answer questions.