Skip to content

USB/IP — sing-box ​

Two services share USB devices over USB/IP: usbip-server exports local devices, and usbip-client imports devices from a remote server. Both are built on sing-usbip, which adds enhancements such as hotplug on top of the standard protocol while staying interoperable with it: a standard USB/IP client can import from usbip-server, but usbip-client needs a sing-box (sing-usbip) server.

Server — usbip-server ​

type: "usbip-server" under services[]:

FieldTypeDefaultAllowed valuesDescription
providerstringdefaultdefault | dynamicWhere exported devices come from. default exports the local devices matched by devices (CLI on Linux, Windows and macOS only, with elevated privileges). dynamic takes devices at runtime from a sing-box API client instead — the graphical clients on macOS and Android, or the sing-box Dashboard in a Chromium-based browser.

Source: option/usbip.go:17-21 · pinned at v1.14.2 (af6e64c)

The server also embeds ListenOptions (see Inbounds); listen_port defaults to 3240, the standard USB/IP port. With provider: "default" it takes:

FieldTypeDefaultAllowed valuesDescription
devices[]USBIPDeviceMatch(required)[USBIPDeviceMatch]Which local devices to export. Required with the default provider.

Source: option/usbip.go:77-79 · pinned at v1.14.2 (af6e64c)

The dynamic provider has no extra fields.

Device match ​

FieldTypeDefaultAllowed valuesDescription
bus_idstring(any)<bus-port>USB bus ID, e.g. 1-2.
vendor_iduint16(any)<uint16>USB vendor ID as a JSON number (decimal — e.g. 1133 for 0x046d).
product_iduint16(any)<uint16>USB product ID as a JSON number.
serialstring(any)<string>Device serial number.

Source: option/usbip.go:70-75 · pinned at v1.14.2 (af6e64c)

Every field set in one object must match; several objects are combined as a union. Each object needs at least one field.

Client — usbip-client ​

type: "usbip-client" under services[]:

FieldTypeDefaultAllowed valuesDescription
serverstring(required)<host>Address of the remote usbip-server.
server_portuint163240<port>Port of the remote usbip-server.

Source: option/outbound.go:183-186 · pinned at v1.14.2 (af6e64c)

FieldTypeDefaultAllowed valuesDescription
devices[]USBIPDeviceMatch(all exported)[USBIPDeviceMatch]Which remote devices to import, using the same match objects as the server. Empty imports every exported device.

Source: option/usbip.go:64-68 · pinned at v1.14.2 (af6e64c)

The client embeds the dial fields (see Outbounds), but only detour takes effect.

Minimal example ​

Server exporting a keyboard by vendor/product ID plus whatever is plugged into bus port 1-2:

json
{
  "services": [
    {
      "type": "usbip-server",
      "tag": "usb-share",
      "listen": "0.0.0.0",
      "devices": [
        { "vendor_id": 1133, "product_id": 49948 },
        { "bus_id": "1-2" }
      ]
    }
  ]
}

Client importing only the device on bus port 1-2:

json
{
  "services": [
    {
      "type": "usbip-client",
      "tag": "usb-remote",
      "server": "192.0.2.10",
      "devices": [{ "bus_id": "1-2" }]
    }
  ]
}

Notes ​

  • Requires the with_usbip build tag and is only built for Linux, Windows and macOS with CGO. Elsewhere (including iOS) both types exist but fail at startup with "USB/IP is not included in this build".
  • provider: "default" only works when sing-box runs directly from the CLI, and needs elevated privileges; exporting on macOS additionally requires disabling System Integrity Protection.
  • With provider: "dynamic", devices are shared at runtime through the API service — from the graphical clients, the Dashboard, or the sing-box api command.
  • Standard USB/IP has no encryption or authentication, and neither service has credential fields. Expose usbip-server only on trusted networks, or reach it through a tunnel via the client's detour.

Cross-core notes ​

  • Neither Xray-core nor mihomo has a USB/IP equivalent.

Source: option/usbip.go:17-81 · v1.14.2 (af6e64c)

Core Tutorial by Argsment