
I have a server running Red Hat Enterprise Linux 10 on aarch64, because apparently choosing an enterprise distribution was not enough. I also wanted the architecture to make package availability interesting. I will call it server01 here. Hostnames and repository addresses in the examples and log excerpts are anonymized.
I also have a Proxmox Backup Server. The goal was simple: back up the machine to PBS, with encryption and incremental uploads, using the infrastructure I already have.
The missing piece was a convenient native Proxmox Backup Client package for this particular combination of operating system and architecture.
There was, however, a container image with the client inside it.
You can probably see where this is going.
Table of Contents
- Table of Contents
- A Packaging Problem With a Container-Shaped Solution
- The Command
- The SELinux Incantation
- A Stable Name and an Ephemeral Container
- The Part Where It Actually Works
- “Full Machine” Needs an Asterisk
- PostgreSQL Does Not Get a Free Pass
- An Old Image With a Useful Passenger
- The Other Half of a Backup
A Packaging Problem With a Container-Shaped Solution
The official client installation instructions cover Debian packages and a static client for x86-64 Linux. That static binary does not solve my ARM64 problem. This is not a claim that nobody has ever built an RPM or an alternative client. It is the absence of the straightforward, supported package I wanted on this machine.
Ayufan’s unofficial PBS builds provide another route, including ARM64 support. For this experiment, I used the client already present in the v3.4 server image.
The arrangement is wonderfully inelegant:
- Start the image with rootful Podman.
- Replace its entrypoint with
proxmox-backup-client. - Make the host’s
/available at/mnt/root, read-only. - Pass in the encryption key and inject the passwords using Podman secrets.
- Upload the host’s files to the actual PBS server.
I am borrowing the image’s userspace and executable. The backup server still lives elsewhere. No PBS service needs to start inside this container. It is the same packaging idea behind running Citrix Workspace in a Podman container: give an awkward application the userspace it expects, then expose the host resources it needs.
The Command
This assumes Podman is installed, the repository is reachable, the PBS account can write backups, and /root/server01-backup.key already contains my passphrase-protected PBS encryption key. The passwords must match that account and that key.
The two secrets live in root’s Podman secret store, because the backup container also runs through rootful Podman. My Podman production guide covers secrets and Quadlets in more detail. To create the secrets interactively from Bash:
read -rsp 'PBS repository password: ' pbs_repo_password
printf '\n'
printf '%s' "$pbs_repo_password" | sudo podman secret create pbs_repo_password -
unset pbs_repo_password
read -rsp 'PBS encryption key passphrase: ' pbs_key_passphrase
printf '\n'
printf '%s' "$pbs_key_passphrase" | sudo podman secret create pbs_key_passphrase -
unset pbs_key_passphrase
These are one-time creation commands. Skip them if those secrets already exist. The prompt keeps the values out of the command text and shell history.
Then the actual backup:
sudo podman run --rm -it \
--name pbs-backup-job \
--security-opt label=type:spc_t \
--hostname server01 \
--entrypoint /usr/bin/proxmox-backup-client \
-e PBS_REPOSITORY='backup@pbs@pbs.example.net:data' \
-v /:/mnt/root:ro \
-v /root/server01-backup.key:/etc/proxmox/server01-backup.key:ro,Z \
--secret pbs_repo_password,type=env,target=PBS_PASSWORD \
--secret pbs_key_passphrase,type=env,target=PBS_ENCRYPTION_PASSWORD \
docker.io/ayufan/proxmox-backup-server:v3.4 \
backup root.pxar:/mnt/root \
--keyfile /etc/proxmox/server01-backup.key
The repository string identifies the backup@pbs account, the server pbs.example.net, and the datastore data. Replace those, the hostname, and the key paths with your own values.
This is the command from my successful run with two redundant environment variables removed: PBS_PASSWORD_SECRET and PBS_KEY_PASSPHRASE_SECRET. I had pointed those at /run/secrets/..., but this invocation overrides the image entrypoint and injects the secrets directly into environment variables. There are no corresponding secret-file mounts here.
The native client consumes PBS_PASSWORD and PBS_ENCRYPTION_PASSWORD. Those are the names that matter. See the client’s environment-variable documentation.
And yes: Podman secrets, not Podman sockets. The secret options map each stored secret to the named environment variable with type=env,target=.... No container-engine API socket is involved.
The SELinux Incantation
This is the line doing the interesting work:
--security-opt label=type:spc_t
A normal confined container is not supposed to wander through an entire RHEL host filesystem. Backing up that filesystem makes this restriction rather inconvenient.
If process domains and file labels are unfamiliar, my practical SELinux guide for Fedora and RHEL explains how those checks work and how to investigate denials.
spc_t is the broadly privileged container domain in container-selinux policy. Selecting it relaxes SELinux confinement for this process. It does not switch SELinux off globally, nor does it grant every capability associated with Podman’s --privileged option.
Still, this is a trusted backup tool with access to host data and credentials. The container is a packaging solution, not a place to run a binary I distrust.
Notice the different volume options:
-v /:/mnt/root:ro
-v /root/server01-backup.key:/etc/proxmox/server01-backup.key:ro,Z
The host root is mounted read-only without relabeling. The dedicated key file has :Z, which requests private container labeling and changes that file’s host label. Do not add :Z to the host root mount: recursively relabeling the operating system is a very different sort of afternoon. Podman documents this distinction under volume labeling.
Read-only also does not mean frozen. The host keeps writing while the backup reads.
A Stable Name and an Ephemeral Container
--hostname server01 gives the client a stable host identity. In the run below, the backup lands under host/server01/..., rather than acquiring an identity derived from a disposable container’s hostname.
--rm removes the container after it exits. The image remains cached, and the backup remains on PBS. root.pxar:/mnt/root tells the client which directory to archive. Backing up the container’s own / would be a successful backup of entirely the wrong machine.
The -it flags suit this manual invocation. A scheduled job would drop them and needs its own logging, failure reporting, and overlap handling.
The Part Where It Actually Works
On September 17, the client started with:
Starting backup: host/server01/2026-09-17T17:43:30Z
Client name: server01
Using encryption key from '/etc/proxmox/server01-backup.key'..
storing login ticket failed: $XDG_RUNTIME_DIR must be set
Downloading previous manifest (Sat May 30 15:18:26 2026)
The ticket-cache warning did not prevent this run from authenticating and completing. It is visible in the transcript. I am not quietly editing it into a cleaner success story.
After a procession of skipped mounts and progress messages:
root.pxar: had to backup 22.778 GiB of 40.588 GiB (compressed 10.378 GiB) in 304.93 s (average 76.49 MiB/s)
root.pxar: backup was done incrementally, reused 17.811 GiB (43.9%)
Uploaded backup catalog (13.255 MiB)
Duration: 306.42s
End Time: Thu Sep 17 17:48:37 2026
Roughly 40.6 GiB processed in five minutes, with 43.9% reused from existing data. The 22.778 GiB figure is before compression. The client reports 10.378 GiB compressed for the archive’s new data, with catalog and other overhead separate.
RHEL on ARM64. Client borrowed from a server container. Encrypted, incremental backup accepted by PBS.
I would like the record to show that the computer agreed with me.
“Full Machine” Needs an Asterisk
The goal was a full-machine backup. This particular command produces a file archive of the root filesystem, with mount boundaries that need attention before calling it complete.
My output explicitly includes:
skipping mount point: "boot/efi"
skipping mount point: "dev"
skipping mount point: "proc"
skipping mount point: "run"
skipping mount point: "sys"
It also skips container overlay mounts, container shared-memory mounts, and var/lib/nfs/rpc_pipefs.
PBS deliberately skips additional mount points unless asked to include them. For an EFI filesystem visible inside the container, the backup arguments could instead be:
backup root.pxar:/mnt/root \
--include-dev /mnt/root/boot/efi \
--keyfile /etc/proxmox/server01-backup.key
Alternatively, add separate archives for additional filesystems. The backup creation documentation covers both approaches. Paths here must be paths inside the container.
Audit the host’s mounts first, for example with findmnt -R /, and verify that every required filesystem is visible to the container and included in the archive. Separate /home, /var, database storage, and container volumes deserve particular attention. Skipping an overlay mount does not prove the persistent application data elsewhere was captured.
This is also not a bootable disk image. Partition layout, bootloader installation, and a tested route back to a booting host remain part of recovery planning.
PostgreSQL Does Not Get a Free Pass
The machine stays online during the backup. The log is quite explicit about the consequences:
warning: file size increased while reading: "var/log/messages", file will be truncated!
warning: file size increased while reading: "var/log/traefik/access.log", file will be truncated!
For these log files, I can live with that. My first reaction to the databases was similarly relaxed: PostgreSQL is crash-resistant enough, surely?
There is an important catch. Crash recovery does not make an arbitrary live file copy consistent. A filesystem walk collects different files at different times. That is not the same state as a machine losing power at one instant.
PostgreSQL’s filesystem backup documentation explains the requirement: stop the database for an ordinary file copy, or use a consistent snapshot covering all the necessary data and WAL. For online backups, use a database-aware method such as pg_basebackup with the required WAL, or take logical dumps and include those in the backup.
I can accept the risk for my own machine. I cannot turn that preference into a promise that the copied database files will restore. This run proves the upload worked. It does not prove database recovery.
An Old Image With a Useful Passenger
The image tag is deliberate:
docker.io/ayufan/proxmox-backup-server:v3.4
In my testing, newer server images after 3.4.0 no longer shipped the client at the path used here. Moving to latest therefore broke the premise of this trick. That is an observation about the images I tried, not a claim that the client has disappeared from every distribution channel.
The upstream project also describes these builds as unofficial and unmaintained, and offers separate client artifacts. This working image is a convenient starting point, not a maintenance strategy. A maintained ARM64 client image would be the natural replacement.
I am currently working on exactly that: a container image for x86_64 and aarch64 containing only proxmox-backup-client and its runtime dependencies. I plan to publish it on GitHub Container Registry (ghcr.io) later this year. Until then, the old server image keeps its temporary job.
For repeatability, record the working image digest and pin that exact artifact after verifying it. A version tag is more descriptive than latest, but it is still mutable. An old binary also carries its own security and future compatibility questions. Successful communication with today’s server is the evidence I have.
The Other Half of a Backup
Keep the encryption key and its passphrase recoverable somewhere independent of server01 and this encrypted backup. A copy of the key inside the archive it unlocks is an especially elegant circular dependency.
Before depending on this arrangement, restore files into an isolated scratch directory, inspect ownership and permissions, and test the applications that matter. The run shown here is an upload result, not a completed disaster-recovery exercise.
The wider question of where this copy belongs, and what survives losing a host or a backup destination, is the subject of my multi-stage backup strategy. This container solves one transfer step in that larger problem.
But the original packaging problem? Solved. RHEL did not need a native client package for the client to read its files and talk to PBS.
A server image donated an executable, Podman supplied the userspace, SELinux received an unusually permissive explanation, and five minutes later the backup was there.
Cursed? A little. Working? Yes, within those boundaries.
Comments
You can use your Mastodon or other ActivityPub account to comment on this article by replying to the associated post.
Search for the copied link on your Mastodon instance to reply.
Loading comments...