Switching GPU Binding (Live) Toggle GPU Driver Script (vfio-pci ↔ nvidia)

A single NVIDIA GPU cannot:

  • Be passed through to a VM (via vfio-pci)
  • And be used on the host or in LXC at the same time

Why?

Because when you bind the GPU to vfio-pci on boot, it’s invisible to the host and cannot be used by NVIDIA’s kernel driver (nvidia.ko).

Switch Between VM and LXC Use (Rebind on demand)

If you don’t need both at the same time, you can manually switch the GPU between:

  1. Passthrough to VM (bind to vfio-pci)
  2. Use on host / LXC (bind to nvidia)

This lets you:

Then later give it back to the VM

Use the GPU for nvidia-smi or CUDA in an LXC container

here’s a single script that checks which driver is currently bound to your GPU, and automatically toggles between:

  • vfio-pci (for passthrough to VM)
  • nvidia (for use on host or LXC)
#!/bin/bash

# === CONFIGURATION ===
GPU="0000:0a:00.0"
AUDIO="0000:0a:00.1"
VMID=131         # Your Windows VM ID
LXCID=115        # Your LXC container ID using the GPU

# === FUNCTIONS ===

get_driver() {
    basename "$(readlink /sys/bus/pci/devices/$1/driver 2>/dev/null)"
}

unbind_driver() {
    echo "$1" > "/sys/bus/pci/devices/$1/driver/unbind"
}

bind_driver() {
    echo "$1" > "/sys/bus/pci/drivers/$2/bind"
}

switch_to_nvidia() {
    echo "→ Switching to NVIDIA driver (LXC use)..."

    echo "Stopping VM $VMID..."
    qm stop $VMID
    sleep 3

    echo "Unbinding GPU from current driver..."
    unbind_driver "$GPU"
    unbind_driver "$AUDIO"

    echo "Loading NVIDIA modules..."
    modprobe nvidia nvidia_uvm nvidia_drm nvidia_modeset

    echo "Binding GPU to nvidia..."
    bind_driver "$GPU" nvidia
    bind_driver "$AUDIO" snd_hda_intel

    echo "Starting LXC container $LXCID..."
    pct start $LXCID

    echo "✔ Switched to NVIDIA mode."
}

switch_to_vfio() {
    echo "→ Switching to VFIO (VM passthrough)..."

    echo "Stopping LXC container $LXCID..."
    pct stop $LXCID
    sleep 3

    echo "Unbinding GPU from current driver..."
    unbind_driver "$GPU"
    unbind_driver "$AUDIO"

    echo "Loading VFIO modules..."
    modprobe vfio-pci

    echo "Binding GPU to vfio-pci..."
    bind_driver "$GPU" vfio-pci
    bind_driver "$AUDIO" vfio-pci

    echo "Starting VM $VMID..."
    qm start $VMID

    echo "✔ Switched to VFIO mode."
}

# === MAIN ===

MODE="$1"
CURRENT_DRIVER=$(get_driver "$GPU")
echo "Detected GPU driver: ${CURRENT_DRIVER:-none}"

case "$MODE" in
    --to-nvidia)
        switch_to_nvidia
        ;;
    --to-vfio)
        switch_to_vfio
        ;;
    "")
        if [ "$CURRENT_DRIVER" == "vfio-pci" ]; then
            switch_to_nvidia
        elif [ "$CURRENT_DRIVER" == "nvidia" ]; then
            switch_to_vfio
        elif [ -z "$CURRENT_DRIVER" ]; then
            echo "⚠️ No driver bound. Defaulting to NVIDIA..."
            switch_to_nvidia
        else
            echo "❌ Unknown driver bound: $CURRENT_DRIVER"
            exit 1
        fi
        ;;
    *)
        echo "Usage: $0 [--to-nvidia | --to-vfio]"
        exit 1
        ;;
esac

# === FINAL STATUS DISPLAY ===
echo
echo "🔍 Final GPU driver status:"
SHORT_GPU=$(echo "$GPU" | cut -d':' -f2-)
lspci -k | grep "$SHORT_GPU" -A 3

Auto-toggle based on current driver

./toggle-gpu.sh

Force switch to NVIDIA for LXC

./toggle-gpu.sh --to-nvidia 

Force switch to VFIO for VM passthrough

./toggle-gpu.sh --to-vfio 

passing NVIDIA GPUs to Windows VMs

passing NVIDIA GPUs to Windows VMs because NVIDIA detects you’re running in a virtualized environment and blocks the driver


The /etc/pve/qemu-server/131.conf

args: -cpu host,hv_vapic,hv_stimer,hv_time,hv_synic,hv_vpindex,+invtsc,-hypervisor
bios: ovmf
boot:
cores: 16
cpu: host
efidisk0: local-lvm:vm-131-disk-0,efitype=4m,pre-enrolled-keys=1,size=4M
hostpci0: 0000:0a:00,device-id=0x2882,pcie=1,vendor-id=0x10de,x-vga=1
ide0: PveSsd900:131/vm-131-disk-0.qcow2,size=180G
kvm: 1
machine: pc-q35-9.0
memory: 16384
meta: creation-qemu=9.2.0,ctime=1747334710
name: win10Gaming
net0: virtio=BC:24:11:77:A3:BC,bridge=vmbr2,firewall=1
numa: 0
onboot: 1
ostype: win10
scsihw: virtio-scsi-single
smbios1: uuid=45849243-d81c-4be4-9528-4620ee509da8,manufacturer=QkVTU1RBUiBURUNIIExJTUlURUQ=,product=SE04MA==,version=NS4xNg==,serial=RGVmYXVsdCBzdHJpbmc=,sku=RGVmYXVsdCBzdHJpbmc=,family=RGVmYXVsdCBzdHJpbmc=,base64=1
sockets: 1
tags: 5;sharegpu;windows
usb0: host=1532:0083
usb1: host=145f:0316
usb2: host=0a12:0001
vga: none
vmgenid: 87821f0a-458f-45da-8691-62fcd515c190

exposer Docker API

I had to edit /lib/systemd/system/docker.service on my Ubuntu 16.04.2 LTS system to modify the line

ExecStart=/usr/bin/docker daemon -H fd:// -H tcp://0.0.0.0:2375

then

sudo systemctl daemon-reload
sudo systemctl restart docker.service

and everything worked :-). The next step is to figure out how to protect the docker daemon form being hijacked.

nfs no_root_squash

Conclusion

When you are using NFS mount points with root account on client-side then export them with no_root_squash option. This will ensure you don’t face access related issues on NFS mount points

SSL pour le home lab

https://myhomelab.gr/linux/2019/12/13/local-ca-setup.html

Mon domain : daisy-street.fr

Pihole

configuration du dns pihole 192.168.1.50

Renvoyer les serveurs sur le dns/dhcp pihole

nano /etc/netplan/00-installer-config.yaml
nano /etc/resolv.conf
nano /etc/hostname

Installer traefik

docker-compose.yml

Generer password traefik

sudo apt install apache2-utils
echo $(htpasswd -nb <USER> <PASSWORD>) | sed -e s/\\$/\\$\\$/g
    volumes:
      - /SystemSvg/VM_109/traefik/data/traefik.yml:/traefik.yml:ro
      - /SystemSvg/VM_109/traefik/data/acme.json:/acme.json
      - /SystemSvg/VM_109/traefik/data/config.yml:/config.yml:ro
    labels:
      - "traefik.http.routers.traefik.rule=Host(`traefik-dashboard.local.daisy-street.fr`)"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=<USER>:<HASHED-PASSWORD>"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik-dashboard.local.daisy-street.fr`)"

Configurer SSL

openssl genrsa -des3 -out root.key 2048
david@legion2:/SystemSvg/clersa$ openssl req -x509 -new -nodes -key root.key -sha256 -days 7200 -out root.pem
Enter pass phrase for root.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:FR
State or Province Name (full name) [Some-State]:Hauts-de-Seine
Locality Name (eg, city) []:Antony
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Homelab
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:DaisyStreet HomeLab Authority
Email Address []:
david@legion2:/SystemSvg/clersa$
openssl genrsa -out wildcard.homelab.home.key 2048
nano opensslsan.cnf

[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
C = FR
ST = Hauts-de-Seine
L = Antony
O = Wildcard Homelab Inc
OU = IT
CN = *.homelab.home
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = *.homelab.home
openssl req -new -out wildcard.homelab.home.csr \
-key wildcard.homelab.home.key \
-config opensslsan.cnf
openssl x509 -req -in wildcard.homelab.home.csr \
-CA root.pem \
-CAkey root.key \
-CAcreateserial \
-out wildcard.homelab.home.crt \
-days 7200 \
-sha256 \
-extensions v3_req \
-extfile opensslsan.cnf

paperless retag

Document retagger

Say you’ve imported a few hundred documents and now want to introduce a tag or set up a new correspondent, and apply its matching to all of the currently-imported docs. This problem is common enough that there are tools for it.

document_retagger [-h] [-c] [-T] [-t] [-i] [--use-first] [-f]

optional arguments:
-c, --correspondent
-T, --tags
-t, --document_type
-i, --inbox-only
--use-first
-f, --overwrite

Connexion au bash docker

tmux
docker exec -it paperless bash

Sans écrasement

document_retagger -c -t --use-first
document_retagger -T

Avec ecrasement

document_retagger -c -t --use-first -f
document_retagger -T -f

a essayer en global

tmux
docker exec -it paperless bash
document_retagger -c -t --use-first -f;document_retagger -T;document_retagger -T;document_retagger -T;document_retagger -T;document_retagger -T;document_retagger -T

docker exec -d -it paperless-ng_webserver_1 document_retagger -c -T -t --use-first

document_retagger -T est repeter plusieurs fois car la commande s’arrete en database lock au bout de 10 minutes d’ouverture de database , l’enchainement de commande sans ecrasement permet de balayer toute la base.