Sign inSign up

luizmoreiradev/mobile-uplink

By luizmoreiradev

•Updated 5 months ago

Turn a phone or USB modem into a NAT gateway for your LAN.

Image
0

1.6K

luizmoreiradev/mobile-uplink repository overview

Docker Image Version Docker Pulls Build License: MIT

Turn a phone or USB modem into a NAT gateway for your local network — in a single Docker container.

Built for the case where your ISP goes down and you need to fail over to mobile data quickly, without polluting the host OS. Works with iPhone, Android, and USB 4G/5G modems. Runs on Raspberry Pi (Alpine, Raspberry Pi OS, Debian) and any Linux host with USB access.

⁠How it works

Phone or USB modem ──USB──> Linux host running this container ──LAN──> Your devices
                             • usbmuxd pairs iPhones (optional)
                             • iptables MASQUERADE on the WAN iface
                             • IP forwarding enabled in host namespace

The container runs with network_mode: host so it operates directly on the host's network stack. The kernel (or usbmuxd, for iPhones) brings up the tethered device as a USB network interface; the entrypoint detects it and installs NAT rules.

⁠Compatibility

Device typeInterface nameWorks out of the box?Notes
iPhone (Personal Hotspot)eth1, usb0✅ (needs usbmuxd)Enable Personal Hotspot, tap "Trust" on first connect
Android (USB tethering)usb0, rndis0✅Toggle "USB tethering" in settings after plugging in
USB 4G/5G modem (NCM/CDC)usb0, eth1✅Many Huawei E3372, ZTE, etc.
USB 4G/5G modem (MBIM/QMI)wwan0⚠️Kernel exposes wwan0; you must run mbimcli/qmicli first
USB modem in "modem mode"/dev/ttyUSB*❌Requires pppd/wvdial; out of scope for this container

⁠Quick start

docker run -d \
  --name mobile-uplink \
  --restart unless-stopped \
  --network host \
  --cap-add NET_ADMIN --cap-add SYS_ADMIN \
  --device /dev/bus/usb:/dev/bus/usb \
  -v mobile-uplink-lockdown:/var/lib/lockdown \
  -e LAN_IF=eth0 \
  luizmoreiradev/mobile-uplink:latest

Or with Compose (docker-compose.yml included in the repo):

docker compose up -d
docker compose logs -f

You should see Uplink ACTIVE ✓ once everything is up. Then point your LAN clients at the host as their default gateway — see DHCP setup⁠.

⁠iPhone
  1. Settings → Personal Hotspot → Allow Others to Join: ON
  2. Connect to the host via USB
  3. When prompted, tap Trust This Computer (only the first time — the lockdown volume persists pairing)

Leave ENABLE_USBMUXD=true (the default).

⁠Android
  1. Plug the phone into the host via USB
  2. On the phone: Settings → Network → USB tethering: ON (the option is greyed out until USB is connected)

You can set ENABLE_USBMUXD=false to skip starting usbmuxd and drop SYS_ADMIN.

⁠USB 4G/5G modem (NCM/CDC mode)

Just plug it in. Most modern modems present usb0 or eth1 with DHCP from the carrier — no extra configuration needed.

Set ENABLE_USBMUXD=false.

⁠USB 4G/5G modem (MBIM/QMI mode)

The kernel creates wwan0, but it has no IP until you authenticate with the carrier. You need mbimcli or qmicli on the host:

# example for MBIM
mbim-network /dev/cdc-wdm0 start

Once wwan0 has an IP, this container picks it up via WAN_PATTERN.

⁠Configuration

Env varDefaultDescription
LAN_IFeth0Host interface facing your LAN
WAN_PATTERN^(eth[1-9][0-9]*|usb[0-9]+|enx.*|wwan[0-9]+|rndis[0-9]+)$Regex matching the WAN interface
ENABLE_USBMUXDtrueStart usbmuxd (required for iPhone, harmless otherwise)
DETECT_TIMEOUT300Seconds to wait for the WAN interface to appear
DHCP_TIMEOUT60Seconds to wait for the WAN interface to receive an IP

In docker-compose.yml, remember to double the $ in the regex ($$) so Compose does not interpolate.

⁠DHCP setup

The container only handles the uplink and NAT. You still need a DHCP server on the LAN telling clients to use this host as their gateway.

If you already run Pi-hole, dnsmasq, or your router as DHCP server, set the Router / Default Gateway option to this host's IP. To force clients to pick up the new gateway immediately:

# macOS
sudo ipconfig set en0 BOOTP && sudo ipconfig set en0 DHCP

# Linux (NetworkManager)
nmcli connection down "<name>" && nmcli connection up "<name>"

⁠Verifying it works

From the host:

docker logs mobile-uplink
ip route                                  # default route via WAN iface
iptables -t nat -L POSTROUTING -n -v      # MASQUERADE rule
docker inspect --format='{{.State.Health.Status}}' mobile-uplink

From a LAN client (after DHCP renewal):

curl -4 ifconfig.me                       # should return the carrier-assigned IP
traceroute 1.1.1.1                        # first hop is the host

⁠Troubleshooting

iPhone interface never appears Plug the cable in after the container starts, and accept the "Trust" prompt on the iPhone. If the popup never appears, unlock the iPhone first, then reconnect. The lockdown volume persists pairing across restarts so you only do this once.

Android USB tethering option is greyed out Connect the cable first, then toggle the option. Some phones require you to confirm "File transfer" mode first.

Slow throughput USB 2.0 caps at ~280 Mbps. Pi 4 / 5 expose USB 3.0 ports (blue), but phones often negotiate USB 2.0 anyway — bandwidth is plenty for 4G, may bottleneck 5G mmWave.

Container restarts every few minutes The watchdog kills the container if the WAN interface disappears, so Docker can restart it cleanly. Check the cable and tethering toggle.

SYS_ADMIN makes you nervous It's required by usbmuxd to operate on USB devices. If you don't need iPhone support, set ENABLE_USBMUXD=false and drop SYS_ADMIN from cap_add.

⁠Building locally

docker buildx build \
  --platform linux/arm64,linux/amd64,linux/arm/v7 \
  --build-arg VERSION="$(git describe --tags --always)" \
  --build-arg BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --build-arg VCS_REF="$(git rev-parse --short HEAD)" \
  -t luizmoreiradev/mobile-uplink:latest \
  --push .

Tagged releases are built and pushed automatically by GitHub Actions (.github/workflows/docker-publish.yml).

⁠License

MIT — see LICENSE⁠.

Tag summary

Content type

Image

Digest

sha256:9961319e1…

Size

35.2 MB

Last updated

5 months ago

docker pull luizmoreiradev/mobile-uplink