Sign inSign up

per2jensen/dar-backup

By per2jensen

β€’Updated 2 days ago

Automated backup using DAR and par2 for redundancy.

Image
Security
Integration & delivery
Databases & storage
1

5.1K

per2jensen/dar-backup repository overview

⁠dar-backup image β€” verifiable backups and a long-term restore time capsule

Tag CI Large scale torture test cosign badge ⁠ License

Docker Pulls

# clones Milestone 🎯 Stats powered by ClonePulse⁠


GitHub: per2jensen/dar-backup-image⁠

Docker Hub: per2jensen/dar-backup⁠


⁠dar-backup-image

dar-backup-image packages dar-backup, dar, PAR2, and their runtime dependencies into a versioned, auditable Docker image.

It has two equally important purposes:

  1. Run backups and restores today in a clean, isolated environment without installing dar, Python tooling, or PAR2 on the host.
  2. Preserve a known-working restore environment for the future by saving a versioned image alongside your archives.

The second use is deliberate: the image is a restore time capsule. If you need to recover an archive years from now, you can use the packaged toolchain preserved with the backup instead of hunting for compatible packages or reconstructing an old software environment.

For long-term archival use, save a specific versioned image rather than relying only on :latest. The mutable :latest tag is useful for current operations and receives regular security refreshes; a pinned and locally archived version is the artifact you want to retain with your backups.

A helper script, scripts/save-dar-backup-image.sh⁠, is provided for this purpose. It selects the highest-numbered release or refresh in doc/build-history.json⁠ and saves that versioned image as a compressed tar archive. Its current integrity limitations are documented in Preserve the restore environment with your archives⁠.

The image also works well as an everyday backup runner for cron jobs, systemd timers, and CI pipelines. Its default entrypoint is dar-backup; dar, par2, or an interactive shell can be invoked directly by overriding the entrypoint.

At its core, dar-backup wraps dar and PAR2 for reliable FULL, DIFF, and INCR backups. It validates archives, performs restore tests, manages catalog databases, and can generate redundancy files to protect archives against bit rot.

⁠Bundled documentation

The image preserves documentation from the installed dar-backup distribution. It works without network access, backup configuration, or mounted volumes, so a saved image remains self-documenting years later.

IMAGE=per2jensen/dar-backup:latest

# Discover the documentation (a bare invocation does the same thing)
docker run --rm "$IMAGE" docs
docker run --rm "$IMAGE"

# Display a topic bundled by dar-backup
docker run --rm "$IMAGE" docs overview
docker run --rm "$IMAGE" docs getting-started

# Show paths, component versions, provenance, and project links
docker run --rm "$IMAGE" docs --path
docker run --rm "$IMAGE" info

# Verify every recorded documentation SHA-256
docker run --rm "$IMAGE" docs --verify

Use docs --list to see the topics available in a particular image. Topic names follow the documentation actually present in its installation; for example, the expanded dar_backup/doc/ collection first appears with dar-backup 1.1.11.

The stable filesystem location is /usr/share/doc/dar-backup/. It contains:

  • image/README.md β€” this image repository's exact build-context README
  • README.md, the Markdown description embedded in package metadata
  • doc/, every file included under dar_backup/doc/ or dar_backup/docs/
  • licenses/ and raw METADATA
  • INDEX.md and the integrity/provenance record MANIFEST.json

/usr/share/doc/dar-backup-image/README.md and /README.md link to the embedded image operating guide for simple filesystem discovery. Use docs image to print it and docs overview for the dar-backup overview. The standalone executables dar-backup-image-docs and dar-backup-image-info remain usable when the container entrypoint is overridden. The OCI labels org.opencontainers.image.documentation, org.dar-backup.documentation.command, and org.dar-backup.documentation.path provide discovery without starting the image.

The image contains man pages for dar and par2 which make the image self-documenting for all commands used to restore or backup.

⁠Highlights
  • Long-term restore time capsule, preserve a known-working dar-backup / dar / PAR2 environment with your archives
  • Reproducible backup runner, no host installation of dar, Python tooling, or PAR2 required
  • Self-documenting, all dar-backup, dar-backup-image, dar and par2 documentation is included and easily discoverable by future users
  • Versioned and auditable, released images are tested, scanned, signed, and accompanied by an SBOM
  • Stateless and portable, archive the image itself and move it with your backup sets
  • Built-in configuration, automatically loads /etc/dar-backup/dar-backup.conf unless overridden
  • Ready for automation, usable from cron, systemd timers, and CI pipelines

Current operation vs. long-term preservation

Use :latest when you want the current tested and security-refreshed image.

For disaster recovery years into the future, pin a version and save the image itself alongside your archives.

⁠Table of Contents

⁠Preserve the restore environment with your archives

Long-term backups need more than durable data. They also need a practical way to run the software required to inspect, verify, repair, and restore that data.

A DAR archive is intentionally portable, and dar itself remains the essential restore tool. The container adds another layer of resilience by preserving a complete, known-working environment containing:

  • dar
  • dar-backup
  • PAR2 tooling
  • Python and required runtime libraries
  • the image's baked-in configuration
  • build metadata identifying the exact component versions

For a backup intended to survive many years, preserve the image as data, not merely as a Docker Hub tag.

A typical workflow is:

# Pin a released image
VERSION=0.5.27
IMAGE=per2jensen/dar-backup:${VERSION}

# Pull the exact version
docker pull "$IMAGE"

# Save it as a portable compressed artifact
docker save "$IMAGE" | gzip > "dar-backup-image-${VERSION}.tar.gz"

Years later, on a machine with a compatible container runtime:

gunzip -c dar-backup-image-0.5.27.tar.gz | docker load
docker run --rm --entrypoint dar per2jensen/dar-backup:0.5.27 --version

The supplied scripts/save-dar-backup-image.sh⁠ automates the pull and docker save operation. It is intended for cron or a systemd timer and saves a new archive when build history gains a higher-numbered release or weekly refresh.

The current helper is an availability tool, not a complete provenance archiver. It does not yet compare the pulled tag with the recorded digest, run Cosign, or preserve the build-history record, SBOM, signature, and attestation beside the image. Cosign material stored in the registry is not included by docker save. The helper does create and subsequently validate a SHA-256 file for each compressed archive, and it validates an existing archive before reporting success. Verify the immutable digest and Cosign identity as described below and save the relevant evidence beside the archive.

When creating an archive manually with the commands above, generate and verify its checksum yourself:

sha256sum "dar-backup-image-${VERSION}.tar.gz" \
  > "dar-backup-image-${VERSION}.tar.gz.sha256"
sha256sum --check "dar-backup-image-${VERSION}.tar.gz.sha256"

Container images are architecture-specific. Record the image architecture with docker image inspect --format '{{.Architecture}}' "$IMAGE" and ensure the future recovery host can run it natively or through tested emulation.

The practical preservation model is therefore:

DAR archive slices
        +
PAR2 recovery data
        +
dar_manager catalogs
        +
documentation
        +
saved versioned dar-backup image
        =
a self-contained recovery set

This does not mean Docker Hub should be treated as part of your disaster-recovery dependency chain. The opposite is the goal: save the image locally so recovery does not depend on Docker Hub, PyPI, Ubuntu repositories, the original host, or this GitHub repository still being available.

The signed image digest, SBOM, build history, and Rekor record provide provenance only when they are preserved and verified with the image; the locally saved image provides availability.

⁠Hands-on Demo: dar-backup in a Container

Curious how it all works in practice?

Check out the step-by-step demo⁠, which walks through:

  • A full backup from mounted directories
  • Archive listing and contents inspection
  • Selective file restore (e.g., .JPG only)
  • Output logs, par2 generation, and verification

All performed using docker run, no host installation required.

⁠dar versions

Starting with dar-backup-image 0.5.15, dar (v2.7.18) is compiled from source rather than using Ubuntu 24.04’s older package.

The pinned dar release is compiled with the feature set verified by this project, including zstd, lz4, Argon2, GPGME, and remote repository support.

The Dockerfile⁠ verifies the source tarball using Denis Corbin’s GPG key, checks all critical features, and only includes the built binary if everything passes.

To view the embedded dar version:

docker run -it --entrypoint /usr/local/bin/dar dar-backup:<tag> --version

Expected (abridged) output for tag 0.5.16, confirming core capabilities:

 dar version 2.7.19, Copyright (C) 2002-2025 Denis Corbin

 Using libdar 6.8.3 built with compilation time options:
   gzip compression (libz)      : YES
   Strong encryption (libgcrypt): YES
   Public key ciphers (gpgme)   : YES
   Large files support (> 2GB)  : YES
   Remote repository (libcurl)  : YES (HTTPS, zstd, SSH, HTTP/2)

⁠Recent releases uploaded to Docker Hub

Weekly image refreshes (:latest) are not listed here, see the full audit trail in build-history.json⁠.

Tagdar-backupdarRelease dateGit RevisionDocker HubNote
1.0.0-rc11.1.112.7.212026-09-069a27ba88a11ae340c9ea95ec72e6271269c5ff2etag:1.0.0-rc1⁠-
0.9.11.1.112.7.212026-08-265576be82b9fedf44df6c9e3d0eb6b6c274ec5274tag:0.9.1⁠-
0.9.01.1.112.7.212026-08-16cfaadb1tag:0.9.0⁠-
0.5.281.1.102.7.212026-07-08c2b576etag:0.5.28⁠-
0.5.271.1.92.7.212026-07-061948e6ctag:0.5.27⁠-

The table is generated from doc/build-history.json. Refresh it at any time with python3 scripts/update_readme_releases.py, or verify it without writing with python3 scripts/update_readme_releases.py --check.

⁠Release Pipeline and Supply Chain Security

Every image released to Docker Hub is produced by a fully automated GitHub Actions workflow, no manual docker push, no local machine involvement. The pipeline enforces a strict sequence of gates before any image becomes publicly available.

⁠Pipeline steps
  1. Build, The dar-backup:dev image is built using the repository's version pins. DAR is compiled from its GPG-verified source tarball; release images install the pinned dar-backup package from PyPI.
  2. Test, The full pytest suite runs against the dev image. The pipeline halts if any test fails.
  3. Finalize, The tested dev image is converted to the release tag with corrected OCI version and reference labels. Its application filesystem is retained without rebuilding packages.
  4. Verify, Focused checks validate OCI labels, the embedded dar-backup --version, the exact application revision, and the SHA-256 of /LICENSE before publication. The full pytest suite is not repeated against the relabeled image.
  5. SBOM, Syft⁠ generates a CycloneDX JSON Software Bill of Materials from the local image before it leaves the runner.
  6. Vulnerability scan, Grype⁠ scans the SBOM and fails the release if any High or Critical vulnerability is found. Results are uploaded to the GitHub Security tab as SARIF.
  7. Candidate push, Only the immutable version tag is initially pushed to Docker Hub; :latest still identifies the previous known-good image.
  8. Cosign signing, The candidate is signed by digest (not by mutable tag) using cosign⁠ keyless mode.
  9. SBOM attestation, The SBOM is attached to that digest as a signed in-toto attestation via cosign.
  10. Remote sanity check, The immutable digest is pulled back from Docker Hub and executed. Its dar-backup --version output and OCI image-version label must match exactly.
  11. Promotion, Only the remotely verified digest is pushed as :latest; :latest is then pulled and required to resolve to the signed digest.
  12. Rollback, If the candidate push, signing, attestation, or remote sanity check fails, the attempted unverified version tag is removed and the previous :latest remains untouched.

Manual releases and weekly image refreshes use the same tested publication component and a shared concurrency lock, so their signing, rollback, remote verification, :latest promotion, and always-run Docker credential cleanup cannot drift apart or race.

⁠What cosign keyless signing provides

Keyless signing means the project does not manage or store a long-lived signing private key in GitHub Secrets or on disk. Cosign generates an ephemeral key for the signing operation, and Fulcio⁠ issues a short-lived certificate bound to GitHub's OIDC identity for the workflow run.

Every signature is permanently recorded in Rekor⁠, Sigstore's public, append-only transparency log. This means:

  • The signing identity is public and auditable, the Rekor entry proves exactly which GitHub workflow, repository, branch, and run produced the signature.
  • Signing events are tamper-evident, inclusion in the append-only log makes unexpected or inconsistent events auditable; it does not make compromised OIDC identities, workflows, or signing infrastructure impossible.
  • No long-lived project key management burden, there is no persistent project signing key to rotate or retain.
  • Anyone can verify identity and content, without an account or contacting the author. Verify an immutable digest; Docker Hub remains a distribution and availability dependency until the image and evidence are archived locally.
⁠Verifying an image yourself
cosign verify per2jensen/dar-backup:<tag> \
  --certificate-identity-regexp='^https://github\.com/per2jensen/dar-backup-image/\.github/workflows/(release|image-refresh)\.yml@refs/heads/main$' \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com"

A successful verification proves the image was signed on main by this repository's manual-release or weekly-refresh workflow. Verification should use the immutable digest recorded in doc/build-history.json when auditing a specific publication.

⁠Verifying the SBOM attestation
cosign verify-attestation per2jensen/dar-backup:<tag> \
  --type cyclonedx \
  --certificate-identity-regexp='^https://github\.com/per2jensen/dar-backup-image/\.github/workflows/(release|image-refresh)\.yml@refs/heads/main$' \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  | jq '.payload | @base64d | fromjson | .predicate'

This retrieves and verifies the signed CycloneDX SBOM attached to the image, listing every package and library bundled inside.

⁠Inspecting the Rekor transparency log entry

Each release summary in the GitHub Actions tab includes a direct link to the Rekor entry for that release, for example:

https://search.sigstore.dev/?logIndex=1273042416

The entry records the signing certificate, the image digest that was signed, the GitHub workflow identity, the run URL, and the exact commit SHA, providing a complete, tamper-evident audit trail from source code to published image.


⁠Understanding Volume Mounts and Backup Definitions

The -v flag that maps host directories into the container is the key decision that controls how many backup definitions you can use, and which host paths are reachable at all.

In short:

  • Map host / β†’ container /data read-only, the entire host tree is visible; multiple definitions can target different subtrees, but the backup destination and special filesystems can also reappear below /data. Use explicit exclusions.
  • Map a single subdirectory β†’ container /data read-only, only that directory is visible inside the container.
  • Map several sources to distinct paths below /data read-only, multiple definitions work without exposing the full host; this is the preferred multi-source layout.

See doc/dar-backup-mount-scenarios.md⁠ for a full explanation with diagrams, worked examples, and a comparison table.


⁠License

dar-backup-image is licensed under GPL-3.0-or-later.

The complete license text is available in the repository LICENSE file⁠ and is embedded in every image at /LICENSE. Print it without installing or starting dar-backup:

Copyright and licensing information is also recorded per file using SPDX⁠ and the REUSE specification⁠. Clonepulse files retain their MIT licence, while bundled upstream DAR source archives retain their upstream

Tag summary

Content type

Image

Digest

sha256:7e58bfaa2…

Size

72.9 MB

Last updated

2 days ago

docker pull per2jensen/dar-backup