infra-proxmox-bindsnap · git:20261031.d7eb3c6 · 2026-10-31 · sha256 1880c8658baafc4a
infra-proxmox-bindsnap git:20261031.d7eb3c6B
Immutable. This exact content never changes and is served at /api/v1/blob/1880c8658baafc4a.
--- name: infra-proxmox-bindsnap description: Use when snapshotting or cloning Proxmox LXC containers that have bind/device mounts (mpN -> host paths) - the snapshot button is greyed out or pct snapshot refuses the container with "snapshot feature is not available", or pct clone fails with "unable to clone mountpoint 'mpN' (type bind)", or you cannot snapshot a bind-mount container. Covers pve-bindsnap install, verify, the BINDSNAP-FORCE-RUNNING / BINDSNAP-UNSUPPORTED / BINDSNAP-EXCLUDE markers, the checksum guard for an untested pve-container build, clone, and uninstall on a Proxmox VE node. --- # proxmox-bindsnap Install, verify, configure and operate **pve-bindsnap** -- a small Perl overlay that lets Proxmox snapshot AND clone LXC containers that carry bind/device mounts (`mpN` pointing at host paths), which stock Proxmox greys out or refuses with `unable to clone mountpoint 'mp0' (type bind)`. It delegates to Proxmox's real snapshot/clone code (it does not fork it) by dpkg-diverting `PVE::LXC::Config` (snapshots) and `PVE::API2::LXC` (clone). Source: https://github.com/bitranox/pve-bindsnap **Run on the Proxmox VE node, as root.** If you are driving the node from elsewhere, prefix each command with `ssh root@<node>`. All `pct`/`journalctl`/`perl` commands below run on the node. ## When to use - A container with a bind mount can't be snapshotted: the GUI button is greyed out, or `pct snapshot` fails with `snapshot feature is not available` (exit 255), running or stopped, and creates nothing. - `pct clone` / GUI Clone fails: `unable to clone mountpoint 'mpN' (type bind)`. - You need scheduled snapshots of bind-mount CTs (e.g. cv4pve-autosnap). - You want to clone a bind-mount CT and control whether the copy inherits the bind mounts. **Not for:** containers without bind/device mounts (they already snapshot/clone stock -- the overlay never touches them). If you only need a rootfs snapshot and not the GUI/scheduler, plain `zfs snapshot <pool>/subvol-<vmid>-disk-0@name` on the stopped CT is simpler and needs none of this. ## 1. Install Two ways; both install the same files. **Prefer the apt package** when the node should keep pve-bindsnap current through Proxmox's own updates (GUI Node -> Updates, or `apt-get upgrade`): ``` curl -fsSL https://raw.githubusercontent.com/bitranox/pve-bindsnap/main/install-apt.sh | bash ``` It adds the signed pve-bindsnap repository (key fingerprint `1445 C598 166A 481A C529 2FE1 A5A5 351D 2BC8 8FDC`, trusted for that repository only) and installs the `pve-bindsnap` package, which takes over a node installed by `install.sh`. Options: `--no-install`, `--remove [--purge]`, `--repo-url URL`. While the package is installed, `install.sh` and `uninstall.sh` refuse; use apt. Details: docs/install-apt.md in the repo. **Or the script**, updated by re-running it. The model is "read the source, then install from it." Inspect first: ``` curl -fsSL https://raw.githubusercontent.com/bitranox/pve-bindsnap/main/install.sh | less ``` Then install (one node; idempotent; restarts pvedaemon/pveproxy/pvestatd): ``` curl -fsSL https://raw.githubusercontent.com/bitranox/pve-bindsnap/main/install.sh | bash ``` Or clone and run locally: `git clone https://github.com/bitranox/pve-bindsnap && cd pve-bindsnap && less install.sh && ./install.sh`. It installs the overlay module and its clone variants to `/usr/local/lib/site_perl`, adds two dpkg-diverts (Config.pm and API2/LXC.pm) with thin wrappers, pre-flights the load, and rolls back automatically (EXIT trap) if anything fails before the daemons restart -- so a failed install leaves the node stock. ## 2. Verify Read the activation line from the journal: ``` journalctl -u pvedaemon -b --no-pager | grep pve-bindsnap | tail -3 ``` - `overlay active (... checksum-validated ...)` and `clone overlay active (... checksum-validated ...)` -> this pve-container build is tested; bind-mount snapshots and clones work with no keyword. - `overlay active in TEST mode: ... is untested` -> build not in the table; bind-mount snapshots are refused unless opted in (section 5), and `clone overlay loaded but NOT active` -> clone stays stock (bind clones refused). See section 5 to get the build vetted. Optional direct check: ``` perl -e 'require PVE::LXC::Config; require PVE::API2::LXC; printf "APPLIED=%d CLONE_APPLIED=%d\n", $PVE::LXC::BindSnap::APPLIED, $PVE::LXC::BindSnap::CLONE_APPLIED' ``` ## 3. Decision quick reference | Situation | Do this | |------------------------------------------------|--------------------------------------------------------------------| | Snapshot a STOPPED bind-mount CT, tested build | Just `pct snapshot <vmid> <name>` | | Snapshot a RUNNING CT | Add `BINDSNAP-FORCE-RUNNING` (section 4) | | Build shows TEST mode / untested | Opt in with `BINDSNAP-UNSUPPORTED`, then get it vetted (section 5) | | Need a safety net NOW on an untested build | `vzdump <vmid> --storage <store>`, snapshot mode (section 5) | | Keep a managed data disk out of the snapshot | `BINDSNAP-EXCLUDE: mpN` in CT Notes (section 4) | | Clone a bind-mount CT | `pct clone` works; binds are carried (section 6) | | Clone must NOT inherit a bind/data mount | `BINDSNAP-EXCLUDE: mpN` in the SOURCE CT Notes | ## 4. Configure: the BINDSNAP- markers All UPPERCASE and case-sensitive. The two booleans are read BOTH from a snapshot's name or description (per-snapshot) AND as a standing line in the CT Notes (its description). They match as their own token: a hyphen, underscore or space delimits them; gluing onto a letter/digit or the wrong case does not match. - **`BINDSNAP-FORCE-RUNNING`** -- snapshot a *running* CT (a running CT is otherwise refused; the snapshot briefly freezes the filesystem, which can stall on FUSE/CIFS mounts). Standing form in the CT Notes is the opt-in for schedulers that can't set a per-snapshot keyword. No standing risk. Example: `pct snapshot 123 pre-change --description "BINDSNAP-FORCE-RUNNING"`. - **`BINDSNAP-UNSUPPORTED`** -- snapshot on a pve-container build not in the tested table. Prefer the per-snapshot form. A **standing** `BINDSNAP-UNSUPPORTED` in the Notes is RISKY: after a PVE update to a future untested build it silently covers that too instead of re-gating. Do not leave it long-term -- get the build vetted (section 5). - **`BINDSNAP-EXCLUDE: mp1 mp2`** -- a line in the CT Notes (write it as `#### BINDSNAP-EXCLUDE: mp1` so it renders small). ALWAYS needs the colon. A directive in a snapshot's own description overrides the Notes default; an empty `BINDSNAP-EXCLUDE:` means exclude nothing. `rootfs` is never excluded. NOTE the mirror behaviour: for a SNAPSHOT it drops named MANAGED volumes; for a CLONE it drops named BIND/DEVICE mounts. ## 5. Snapshot, and the checksum guard Stopped CT on a tested build: `pct snapshot <vmid> <name>` (or the GUI). Each snapshot/rollback/ delete writes a summary to the task log. Only bind-mount CTs are gated; plain CTs are untouched. **What snapshot/rollback does to a bind/device mount -- setting vs data:** only the mount *setting* (the `mpN`/`devN` config line) is captured in the snapshot and restored on rollback. The mount is NEVER dropped or lost. The host *data* behind it is never snapshotted, cloned, or rolled back: a rollback rewinds the managed volumes (rootfs and `volume` disks), but the bind/device host data stays exactly as it is now, untouched. So a rollback is not a point-in-time restore of what a bind mount points at -- only managed-volume data is versioned. (Bind data is host data outside Proxmox storage; stock Proxmox never versions it either.) The guard is a content checksum of the upstream Proxmox source (two SEPARATE guards: snapshot hashes `Config.pm`+`AbstractConfig.pm`; clone hashes `API2/LXC.pm`). On an **untested** build, bind snapshots are refused and clone stays stock. The correct response is NOT to force forever: 1. Opt in once with `BINDSNAP-UNSUPPORTED` to TEST (the task finishes as a yellow `TASK WARNINGS`). 2. Run the test plan: https://github.com/bitranox/pve-bindsnap/blob/main/docs/testing.md 3. Report the version + combined checksum (both printed by the overlay) at https://github.com/bitranox/pve-bindsnap/issues so the build joins the known-good list -- after which it works with no keyword. Which builds count as vetted is decided by the overlay, not from memory: the journal line in section 2 tells you about THIS node's build, and https://github.com/bitranox/pve-bindsnap/blob/main/docs/compatible-versions.md is the authoritative list. As of pve-bindsnap **1.4.0** it holds, for both guards, each **pve-container build from 6.0.18 to 6.1.16** (PVE 9.1 and 9.2) together with the `libpve-guest-common-perl` version it shipped with; each row of the list names that pairing. The pairing matters because the snapshot checksum also covers `AbstractConfig.pm`, which ships in `libpve-guest-common-perl` rather than in `pve-container`, so an apt upgrade of EITHER package can move a node into TEST mode. A **known-BAD** build is a hard block: `BINDSNAP-UNSUPPORTED` will NOT override it; update pve-container or use `zfs snapshot` directly. **A pre-change safety net on a build the guard refuses:** take a stock backup, `vzdump <vmid> --storage <store>`. The overlay passes every `vzdump` call straight to stock code on any build, tested, untested or known-BAD, and stock `vzdump` leaves bind and device mounts out of the archive (their data is host data, outside Proxmox storage) and backs up only the rootfs and the `volume` mount points marked `backup=1`. It needs no marker and no raw `zfs snapshot`. Keep the default `--mode snapshot`; `--mode stop` stops the container for the backup and starts it again, which re-runs everything the container does at boot. A boot unit that pulls and recreates its containers then performs, before you are ready, the very change the backup was meant to precede. ## 6. Clone `pct clone <vmid> <newid>` of a bind-mount CT now works: managed volumes (rootfs and `volume` `mpN`) clone as stock, and each bind/device mount is **carried to the clone unchanged -- pointing at the SAME host path as the source** (not a copy). The clone task finishes as a yellow `TASK WARNINGS` naming the carried mounts, because the two CTs then share that host data. Otherwise the clone behaves exactly as the node's own Proxmox clone does: the override runs that build's own upstream `clone_vm` with only the bind-mount change applied (one shipped variant per upstream version; the journal's `clone overlay active` line names it, e.g. `clone_vm variant v6_1_7`). To stop the clone inheriting a bind/data mount, add `#### BINDSNAP-EXCLUDE: mp0` to the **source** CT's Notes before cloning. A full clone of a RUNNING CT still needs `--snapname` (Proxmox rule): snapshot it first with `BINDSNAP-FORCE-RUNNING`, then `pct clone <vmid> <newid> --snapname <snap>`. ## 7. Uninstall Installed with apt: `install-apt.sh --remove --purge` (purges the package and removes the repository), or `apt-get purge pve-bindsnap` to keep the repository. Installed with the script: ``` curl -fsSL https://raw.githubusercontent.com/bitranox/pve-bindsnap/main/uninstall.sh | bash ``` Either reverts both diverts and restores stock Proxmox. Snapshots you already took persist as zfs snapshots and in the CT config (`zfs list -t snapshot | grep subvol-<vmid>`). ## Troubleshooting | Symptom | Cause / fix | |----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------| | Snapshot button greyed for a bind-mount CT | Not installed, or daemons not restarted. Install (section 1), verify (section 2). | | `pct snapshot`: `snapshot feature is not available` | CLI form of the greyed button: not installed, or daemons not restarted. Install (section 1), verify (section 2). | | `unable to clone mountpoint 'mpN' (type bind)` | Clone override not active: not installed, OR build untested (clone stays stock). Install / get the build vetted (section 5). | | `CT <vmid> is running ... stop ... or BINDSNAP-FORCE-RUNNING` | Stop the CT, or add `BINDSNAP-FORCE-RUNNING` (section 4). | | `pve-container <ver> is ... untested ... BINDSNAP-UNSUPPORTED` | Build not in the table. Opt in to TEST and get it vetted (section 5). | | `on the overlay's known-BAD list ... BLOCKED` | Hard block; update pve-container or use `zfs snapshot`. | | Clone inherited a data mount it should not have | Add `BINDSNAP-EXCLUDE: mpN` to the SOURCE CT Notes (section 6). | | No `pve-bindsnap:` line in the journal | Banner only prints from a PVE daemon (not a TTY). Check `journalctl -u pvedaemon -b`; confirm `$APPLIED`/`$CLONE_APPLIED` (section 2). | ## Further reading Self-contained above; for depth, read these (WebFetch the URL, or read the local clone if you have it): | Topic | URL | |--------------------------------------------|--------------------------------------------------------------------------------| | Overview, install, "Using it" | https://github.com/bitranox/pve-bindsnap/blob/main/README.md | | Apt repository, package, key, migration | https://github.com/bitranox/pve-bindsnap/blob/main/docs/install-apt.md | | How it works, limits, mechanism | https://github.com/bitranox/pve-bindsnap/blob/main/docs/design.md | | The checksum guard, adding a version | https://github.com/bitranox/pve-bindsnap/blob/main/docs/checksum-guard.md | | Supported / hard-blocked / untested builds | https://github.com/bitranox/pve-bindsnap/blob/main/docs/compatible-versions.md | | BINDSNAP-EXCLUDE in depth | https://github.com/bitranox/pve-bindsnap/blob/main/docs/bindsnap-exclude.md | | On-node test plan | https://github.com/bitranox/pve-bindsnap/blob/main/docs/testing.md |