USB Device Passthrough
Use a USB device plugged into another machine.
Plug a USB device into one machine and use it on another, anywhere on your mesh — a serial adapter, a smart-card reader, a security token, a license dongle. The device appears in the remote system as if it were plugged in locally.
This needs no dedicated MeshHold feature. USB-over-network is a solved protocol — USB/IP — and it speaks plain TCP. MeshHold already moves arbitrary TCP over an encrypted, NAT-traversing, multi-hop tunnel, so the whole thing is one ordinary port-forward plus two off-the-shelf USB/IP endpoints.
Concepts
- Server — the machine the device is physically plugged into. It
runs
usbipdand "exports" the device. Built into the Linux kernel. - Client — the machine where the device appears. It runs the
usbipclient and "attaches" the exported device. - The tunnel — a single
forwardcarries USB/IP's TCP port 3240 between the two. Modern USB/IP multiplexes device listing, the import handshake, and all device traffic over that one connection, so one forward is enough — even for several devices at once.
LINUX (device here) WINDOWS (device appears here)
usbipd ──▶ 127.0.0.1:3240 usbip ──▶ 127.0.0.1:3240
▲ ▲
└──────────── MeshHold tunnel ───────────────┘
(a forward binds local 3240 → peer's 3240)
This guide uses the lowest-friction combination: device on Linux
(the export side is in the kernel) appearing on Windows (via the
actively-maintained usbip-win2 client). The reverse — exporting from
Windows — is possible with usbipd-win but out of scope here.
The device side needs a physical USB port — a real machine (laptop, mini-PC, Raspberry Pi), not a cloud VPS. A VPS can still serve as a relay hop in the middle of the tunnel.
1. Linux — export the device
Install the USB/IP tools and load the host-side kernel module.
On Debian:
sudo apt-get install -y usbip
On Ubuntu there is no standalone usbip package — the tools ship
inside linux-tools, and the kernel modules often sit in
linux-modules-extra (absent on minimal/cloud images):
sudo apt-get update
sudo apt-get install -y \
linux-tools-generic \
linux-tools-$(uname -r) \
linux-modules-extra-$(uname -r)
# The binaries may not be on PATH — locate them with:
# ls /usr/lib/linux-tools/*/usbip
Load the export module and start the daemon (it listens on TCP 3240):
sudo modprobe usbip-core
sudo modprobe usbip-host
sudo usbipd -D
The
usbipdfromlinux-toolshas no bind-address flag — it listens on all interfaces. MeshHold only ever dials127.0.0.1:3240, but if the box has a public IP, firewall the port to loopback:
bash sudo iptables -A INPUT -p tcp --dport 3240 -i lo -j ACCEPT sudo iptables -A INPUT -p tcp --dport 3240 -j DROP
List local devices, pick one, and bind it (this hands it from its normal driver to USB/IP):
usbip list -l
# - busid 1-4.1 (1a86:5722)
# QinHeng Electronics : USB Serial
sudo usbip bind --busid=1-4.1
usbip list -r 127.0.0.1 # confirm it is now "exportable"
Note the busid (1-4.1) — the client needs it. Bind several
devices if you want; each exports one more over the same port.
unable to bind devicealmost always means theusbip-hostmodule isn't loaded (lsmod | grep usbipis empty). Installlinux-modules-extra-$(uname -r)andmodprobe usbip-hostagain. A device held by another daemon (e.g. a smart-card reader claimed bypcscd) may need that service stopped first.
2. MeshHold — create the tunnel
On the Windows node, create a single forward binding local
127.0.0.1:3240 and tunneling it to the Linux node's 127.0.0.1:3240:
meshhold forwards add `
--name usbip --forward --proto tcp `
--peer-node <LINUX_NODE_ID> --peer-key <PEER_KEY_ID> `
--listen 127.0.0.1:3240 --remote 127.0.0.1:3240
<LINUX_NODE_ID> is the Linux node's peer ID; <PEER_KEY_ID> is a
management key with the tunnel capability (not password-gated)
authorising the circuit — both available from the Network page, or
issued with meshhold mgmt-keys add --caps=tunnel. Equivalent
config.yaml:
port_forwards:
- name: usbip
direction: forward
proto: tcp
peer_node_id: "<LINUX_NODE_ID>"
peer_key_id: "<PEER_KEY_ID>"
listen_addr: "127.0.0.1:3240"
remote_addr: "127.0.0.1:3240"
Confirm it's up — you want PHASE active:
meshhold forwards list
That one forward carries every exported device and inherits relay, multi-hop routing, and the masquerade transports from the tunnel for free. See The Private Mesh VPN for the full forwarding reference (CLI, REST, web UI).
3. Windows — attach the device
Download the client from the usbip-win2 releases page.
Pick a release whose notes say "attestation signed drivers"
(v0.9.7.2 and later). Those install with driver-signature enforcement
left on — no test-signing mode, no reboot dance. Install the .msi
(it installs the virtual USB host-controller driver) and reboot if
prompted.
Unsigned builds only: if you use an older build, first enable test signing in an admin prompt and reboot (
bcdedit /set testsigning on). The desktop then shows a "Test Mode" watermark. An attestation-signed release avoids this entirely and is strongly preferred.
Because the forward makes the remote daemon reachable at localhost,
point the client at 127.0.0.1 — the tunnel does the rest:
usbip list -r 127.0.0.1 # should show the same busids
usbip attach -r 127.0.0.1 -b 1-4.1 # attach by busid
usbip port # list active attachments
Within a second or two the device appears in Device Manager and
works like a locally-plugged device. Repeat usbip attach per busid to
add more; usbip detach -p <port> removes one.
What to expect
- It works like local hardware. HID devices, serial adapters, smart-card readers, and dongles all show up as real USB devices.
- USB/IP is round-trip sensitive. Keyboards, serial, and tokens stay responsive even over a WAN. Bandwidth-heavy or isochronous devices (webcams, audio, fast storage) are far more sensitive to tunnel latency — and devices sharing one tunnel share its round-trip budget.
- Security travels with the tunnel. The USB/IP stream is end-to-end
encrypted by the libp2p circuit and never exposed on the public
internet; keep
usbipdbound to loopback behind the forward.
Teardown
Symmetric to setup:
# Windows
usbip detach -p 00 # port from `usbip port`
meshhold forwards stop usbip
# Linux
sudo usbip unbind --busid=1-4.1 # return the device to its normal driver
sudo killall usbipd
Download: github.com/vadimgrn/usbip-win2/releases