Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Project Status: Active – The project has reached a stable, usable state and is being actively developed.


Docker container to proxy HTTP(S) via USB PPP modem using Twilio Programmable Wireless.


Well... suppose you have a dedicated machine running home automation/alarm system and video surveillance. You want some out-of-band (i.e. cellular) notification if you lose your normal route to the WAN or if the alarm is triggered while normal connectivity is down. But you're using Twilio Programmable Wireless on a small, cheap plan (~10 MB/month) and don't want HD video streaming to offsite storage or other data-intensive things trying to go over the cellular link.

So, we use an application-level solution:

  1. Run a HTTP proxy in a Docker container, which routes over the cellular link.
  2. At the application level, send data through the proxy only if normal connectivity fails.

Essentially, a whole lot of ugly complexity and engineering to get $3/month out-of-band notifications.


This has been tested with a Huawei E397u-53 USB 4G modem.

Upon first plugging in your modem, run lsusb | grep Huawei. If you see ID 12d1:1505 Huawei Technologies Co., Ltd. E398 LTE/UMTS/GSM Modem/Networkcard, the USB modem is in mass storage mode. Run usb_modeswitch -v 12d1 -p 1505 -J to fix that; lsusb | grep Huawei should now report 12d1:1506 Huawei Technologies Co., Ltd. Modem/Networkcard.


Working versions are tagged in git, which triggers an automated build on the Docker Hub. Images will be tagged with both the git tag (version) and "latest".

docker run -d \
    --name twilio-proxy \
    -e MODEM_DEV=ttyUSB0 \
    --privileged \
    -p 8888:8888 \
    --restart always \
  • If you'd like to execute a command before starting up tinyproxy in the container, the content of the PREPROXY_EXEC environment variable will be passed to bash -c if set. An example of this is if you want to allow access from other machines on the same LAN as the docker host; with a LAN and a Docker host of, you could set PREPROXY_EXEC="ip route add via dev eth0".
  • By default, the container runs a healthcheck using curl against every 15 minutes, starting 5 minutes after container start, with a 1-minute timeout. This should be a suitable default, but these values can be overridden in the docker run command using the --health-interval, --health-start-period, and --health-timeout options, respectively, or disabled with the --no-healthcheck option.

Test that it's working:

  1. Point a browser to and find your current WAN IP.
  2. curl should show your real/current WAN IP
  3. curl should show the same real/current WAN IP
  4. http_proxy= https_proxy= curl -L should show a different IP, the cellular gateway (not necessarily your PPP client IP)
  5. http_proxy= https_proxy= curl should show a different IP, the cellular gateway (not necessarily your PPP client IP)


Try restarting the container, unplugging and re-plugging the USB modem, or issuing a network reset from Twilio's site.

Setting a DEBUG environment variable for the container will enable both trace output in the bash scripts as well as passing the "debug" and "dump" options to pon (and on to pppd).


  • Try to make this a bit smaller and more efficient. Right now, this image is just using a giant hammer to get things working as quickly as possible.
  • Do something better for logging than running rsyslog?
  • Figure out if we can specify certain needed capabilities instead of --privileged.
  • Ensure that the container exits if the connection breaks/fails.
  • Automatically find the modem if MODEM_DEV isn't specified?


Docker container to proxy HTTP via USB PPP modem using Twilio Programmable Wireless






No packages published