← All Guides
intermediate

How to Pass Through USB Devices in Proxmox (VMs and LXC)

Pass a USB drive, scanner, or other device from your Proxmox host into a VM or LXC container. Covers both the web UI method and the config file approach, with the Paperless-ngx scanner use case as the example.

Budget Homelab ·
proxmoxhow-tointermediate

USB passthrough in Proxmox is one of those things that sounds harder than it is. The basic case — passing a USB scanner, drive, or dongle into a VM — takes about two minutes in the web UI. The LXC case is a bit more work, but it’s still a config file edit and a container restart.

This guide covers both paths, with a document scanner into a Paperless-ngx setup as the running example. If you haven’t installed Proxmox yet, start with the Proxmox install guide and come back here once you have a running node.

This guide contains affiliate links. If you buy something through them, I earn a small commission at no extra cost to you.

Why you would do this

The most common homelab reason: you have a scanner or USB drive connected to your Proxmox host and you want a VM or container to see it as if it were directly attached.

For Paperless-ngx, a USB scanner is the obvious use case. You scan a document, the scanner pushes the file to the consume folder, and Paperless automatically OCRs and archives it. To make that work, the Paperless container needs direct access to the scanner — not a network scan path, just the USB device.

Other reasons people set up USB passthrough:

The method is the same regardless of what the device does.

Identify the device on the Proxmox host

First, plug the device into the Proxmox host. Then SSH in and run:

lsusb

Output looks like this:

Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 04a9:220e Canon, Inc. CanoScan
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

The important part: 04a9:220e is the vendor ID (04a9) and product ID (220e). This pair identifies the specific device model, not just the port. Using vendor/product ID means the mapping survives unplugging and replugging the device.

Pass through to a VM

This is the easier path. Proxmox’s web UI handles it directly.

  1. Shut down the VM if it’s running. USB passthrough additions require the VM to be stopped.

  2. Select the VM in the left panel. Go to Hardware in the right panel.

  3. Click Add at the top of the Hardware tab, then USB Device.

  4. A dialog appears with two options:

    • Use USB Port: maps by physical port. If you ever move the cable, the mapping breaks.
    • Use USB Vendor/Device ID: maps by device identity. Use this one.
  5. Select Use USB Vendor/Device ID and enter the ID from lsusb. For the Canon scanner: vendor 04a9, device 220e.

  6. Click Add, then Start the VM.

Once the VM is running, SSH in and verify:

lsusb

The device should appear. For a scanner, also run:

# Install sane-utils if not present
sudo apt install sane-utils
scanimage -L

If the scanner shows up in scanimage -L, it’s ready. For Paperless-ngx, that’s the last step — the application handles everything from there.

Pass through to an LXC container

The Proxmox web UI does not support USB passthrough for LXC containers. You do it by editing the container config file on the host. It’s a few extra steps, but not complicated.

Step 1: Find the device’s major and minor numbers

On the Proxmox host:

lsusb -v 2>/dev/null | grep -A5 "04a9:220e"

Or look in sysfs directly. First find the device bus and device number from lsusb:

Bus 001 Device 004: ID 04a9:220e Canon, Inc. CanoScan

Then:

ls -la /dev/bus/usb/001/004

Output:

crw-rw-r-- 1 root plugdev 189, 3 May 14 09:12 /dev/bus/usb/001/004

The numbers 189, 3 are the major (189) and minor (3) numbers. You need these for the cgroup rules.

Step 2: Edit the container config

The config file lives at /etc/pve/lxc/<CTID>.conf on the Proxmox host. Replace <CTID> with your container ID (visible in the Proxmox UI left panel).

nano /etc/pve/lxc/101.conf

Add these lines at the end of the file:

lxc.cgroup2.devices.allow: c 189:* rwm
lxc.mount.entry: /dev/bus/usb/001/004 dev/bus/usb/001/004 none bind,optional,create=file 0 0

The first line tells the cgroup to allow the container access to character devices with major number 189 (the USB device major on most Linux kernels). The * wildcard covers all minor numbers for that major, which is fine for a dedicated scanner setup.

The second line bind-mounts the specific device node into the container.

Step 3: Restart the container

pct stop 101
pct start 101

Then attach to the container and verify:

pct exec 101 -- lsusb

The device should appear.

The major:minor stability problem

One thing to be aware of: the minor number in /dev/bus/usb/001/004 reflects the bus and device number, which can change if you unplug and replug the device or if the kernel assigns a different number on boot. For a device that’s always connected and rarely unplugged, this is fine in practice. If you need more reliability, use a udev rule on the Proxmox host to create a stable symlink:

# On the Proxmox host, create /etc/udev/rules.d/99-scanner.rules
SUBSYSTEM=="usb", ATTRS{idVendor}=="04a9", ATTRS{idProduct}=="220e", SYMLINK+="scanner"

Then mount /dev/scanner in the container config instead of the bus path. This survives reboots and replugs.

The Paperless-ngx scanner setup

If your goal is a scan-to-Paperless pipeline, here’s what the full chain looks like once USB passthrough is working:

  1. USB scanner attached to the Proxmox host
  2. Scanner passed through to the Docker VM (or directly to an LXC container running Paperless)
  3. Inside the Docker VM, install SANE to provide scanner access to applications: sudo apt install sane-utils libsane
  4. Paperless-ngx uses the consume folder for input. Set up a scan script that sends output directly there

A simple scan script inside the Docker VM:

#!/bin/bash
# scan-to-paperless.sh
CONSUME_DIR="/path/to/docker/paperless-ngx/consume"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
scanimage --format=pdf --output-file="$CONSUME_DIR/scan-$TIMESTAMP.pdf"
echo "Scan complete: scan-$TIMESTAMP.pdf"

Run this from the VM, and Paperless picks up the file within a minute or two, OCRs it, and adds it to the archive.

For a dedicated document scanner, the Fujitsu ScanSnap iX1300 and the Canon DR-C225 II are two commonly recommended USB scanners in the Paperless-ngx community. Both work with SANE on Linux. If you’re just starting out, a basic flatbed like the Epson Perfection V39 does the job at a significantly lower price point.

Troubleshooting

Device not appearing in VM after adding hardware: Check that the VM was fully stopped (not just suspended) before adding the device. Also verify the vendor/product ID matches exactly what lsusb shows on the host.

Device appears in VM but application can’t use it: Permissions issue. The application user inside the VM may need to be in the scanner or plugdev group. For Docker containers, you may need to add the device to the container’s device list in the compose file:

services:
  scanner-app:
    image: yourimage
    devices:
      - /dev/bus/usb/001/004:/dev/bus/usb/001/004

LXC container can’t see the device after config edit: Double-check that you restarted the container (pct stop / pct start, not just a reboot command inside the container). Also verify the major:minor numbers haven’t changed — run ls -la /dev/bus/usb/... on the host again.

Multiple USB devices: Add a separate lxc.cgroup2.devices.allow and lxc.mount.entry line for each device. They stack cleanly.

For the full picture of what Proxmox can do, including snapshots, backups, and VM migration, the Proxmox Beginner’s Guide covers everything in one place. If you’re building out a document management workflow alongside this, the Paperless-ngx setup guide walks through the full compose stack, OCR configuration, and consume folder setup.

See the full homelab stack at /stack/.