Data persistence strategy using ZFS and bind mounts for LXC containers.
Overview
Storage Type: ZFS with 4 pools
Primary Data Pool: ssd_pool (3.62T)
Service Data Location: /lxcdata/<service>/ on Proxmox host
Container Mount Point: /data (inside LXC)
ZFS Pools
| Pool | Size | Used | Free | Purpose |
|---|---|---|---|---|
backup_pool |
1.81T | 762G | 1.07T | Backups, ISOs, templates |
nvme_pool |
928G | 121G | 807G | Container root disks, VM disks |
rpool |
230G | 14G | 216G | Proxmox boot/system |
ssd_pool |
3.62T | 1.21T | 2.42T | Service data, VM data, media |
ssd_pool Datasets
| Dataset | Mount Point | Contents | Compression |
|---|---|---|---|
lxcdata |
/lxcdata |
Service bind mounts | lz4 |
vmdata |
/vmdata |
VM images, Immich photos | on |
media |
/ssd_pool/media |
Films, series, videos | off |
databases |
/databases |
MSSQL | lz4 |
Architecture
graph LR
subgraph Host["Proxmox Host"]
N8["/lxcdata/n8n/<br/>└── config/<br/>└── data/"]
PL["/lxcdata/planka/<br/>└── postgres/"]
end
subgraph CT["LXC Container"]
D1["/data/<br/>└── config/<br/> └── n8n/"]
D2["/data/<br/>└── postgres/"]
end
N8 --"bind mount"--> D1
PL --"bind mount"--> D2
style Host fill:#e3f2fd
style CT fill:#fff3e0
style N8 fill:#ffffff
style PL fill:#ffffff
style D1 fill:#ffffff
style D2 fill:#ffffff
ZFS Benefits
- Snapshots: Point-in-time recovery
- Compression: Transparent storage savings (lz4 on most datasets)
- Send/Receive: Efficient backup/replication
- Data Integrity: Automatic checksum verification
Data Directory Structure
Each service has dedicated data on the host:
/lxcdata/
├── ai/ # CT 124 - Ollama models
├── grav/ # CT 123 - Flat-file content
├── jellyfin/ # CT 125 - Media metadata
├── lanproxy/ # CT 127 - Caddy config
├── n8n/ # CT 120 - Workflow data
├── planka/ # CT 122 - Project data
├── wordpress-db/ # CT 128 - MariaDB data
├── wordpress-jokegoudriaan/ # CT 129 - WordPress files
├── wordpress-kledingruil/ # CT 130 - WordPress files
└── wordpress-pgh/ # CT 131 - WordPress files
VM Data
/vmdata/
├── dump/ # VM exports
├── images/ # VM images
├── immich-photos/ # Immich photo storage
├── imports/ # Imported VM images
├── laptop.qcow2 # ~296GB laptop image
├── private/ # Private VM data
└── template/ # VM templates
Creating Data Directory
When deploying a new service:
# On Proxmox host - create dataset
mkdir -p /lxcdata/<service>
# Add mount point to container config
pct set <CT_ID> -mp0 /lxcdata/<service>,mp=/data
Backup Strategy
What to Backup
Service Data: /lxcdata/<service>/ on host
- Application data (databases, uploads, configs)
VM Data: /vmdata/ on host
- Immich photos, VM images, templates
Proxmox Configs: Container/VM definitions
# LXC config backup
cat /etc/pve/lxc/<CT_ID>.conf > /backups/lxc-<CT_ID>-$(date +%F).conf
# VM config backup
cat /etc/pve/qemu-server/<VM_ID>.conf > /backups/vm-<VM_ID>-$(date +%F).conf
Backup Methods
ZFS Snapshots:
# Snapshot specific service data
zfs snapshot ssd_pool/lxcdata/<service>@before-update
# List snapshots
zfs list -t snapshot
# Restore snapshot
zfs rollback ssd_pool/lxcdata/<service>@before-update
File Backup:
# Service data to backup pool
rsync -av /lxcdata/<service>/ /backup_pool/lxcdata-backups/<service>/
# VM data to backup pool
rsync -av /vmdata/<service>/ /backup_pool/vmdata-backups/<service>/
Database Dumps: See Backup & Restore
Restore Procedures
From ZFS Snapshot
# Rollback to snapshot (destructive - reverts changes)
zfs rollback ssd_pool/lxcdata/<service>@snapshot-name
# Clone snapshot (non-destructive - creates copy)
zfs clone ssd_pool/lxcdata/<service>@snapshot-name ssd_pool/lxcdata/<service>-restore
From File Backup
# Restore service data
rsync -av /backup_pool/lxcdata-backups/<service>/ /lxcdata/<service>/
# Restart container to pick up restored data
pct restart <CT_ID>
Permissions
Unprivileged LXC UID Mapping
Unprivileged LXC containers map UIDs with +100000 offset:
| Container UID | Host UID | Common Use |
|---|---|---|
| 33 (www-data) | 100033 | Web servers |
| 70 (postgres) | 100070 | PostgreSQL |
| 999 (mysql) | 100999 | MariaDB |
| 1000 | 101000 | App-specific |
Fixing Permissions
If service can't write to /data:
# On Proxmox host
chown -R <container_uid + 100000>:<container_gid + 100000> /lxcdata/<service>/<dir>
# Example: Fix WordPress permissions (www-data = 33 → 100033)
chown -R 100033:100033 /lxcdata/wordpress-jokegoudriaan/
Related
Note: Legacy directory cleanup completed on 2026-02-16 (~27GB freed). ZFS snapshot ssd_pool/lxcdata@before-cleanup-20260216 created as backup.