Duplicacy is a backup tool that splits files into content-defined chunks, deduplicates them and uploads them, encrypted, to cloud or remote storage. Its lock-free design lets several servers back up to the same storage at once and share deduplicated data. In this tutorial you will install the Duplicacy command-line client on Ubuntu 24.04, back up /var/www to an S3-compatible bucket, keep a second copy on an SFTP server, restore files, and schedule backups and pruning with a systemd timer.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS. The steps are the same on Debian 12.
- A non-root user with
sudoprivileges. Backups run asrootso they can read every file. - An S3-compatible bucket (AWS S3, Wasabi, Backblaze B2 S3 API, MinIO and similar), with its endpoint, region, access key and secret key.
- Optional, for the second copy: an SFTP server with a user that can log in with an SSH key.
NoteThe Duplicacy CLI is free for personal use. Commercial use requires a license; check the terms on the Duplicacy website before using it at work.
Key concepts
Duplicacy uses its own vocabulary:
| Term | Meaning |
|---|---|
| Repository | The local directory being backed up, here /var/www |
| Storage | Where backups are stored (a bucket, an SFTP path, a local disk). A repository can have several |
| Snapshot ID | A name that identifies this repository's backups inside a storage, for example web01-www |
| Revision | One backup run. Each revision is a full, restorable snapshot |
Step 1 - Installing the Duplicacy CLI
Duplicacy is distributed as a single static binary on GitHub. Check the latest version on the releases page and set it in a variable (use arm64 instead of x64 on ARM servers):
DUPLICACY_VERSION=3.2.4
curl -fL -o duplicacy "https://github.com/gilbertchen/duplicacy/releases/download/v${DUPLICACY_VERSION}/duplicacy_linux_x64_${DUPLICACY_VERSION}"
Install the binary into your PATH:
sudo install -m 0755 duplicacy /usr/local/bin/duplicacy
rm duplicacy
Verify it:
duplicacy -version
duplicacy version 3.2.4 (1A6B2E)
Step 2 - Initializing the repository
By default Duplicacy stores its settings, including credentials, in a .duplicacy directory inside the folder being backed up. For a web root that is a bad idea, because the web server could expose it. Keep the settings in a root-only directory instead and point to the data with -repository:
sudo mkdir -p /etc/duplicacy/www
sudo chmod 700 /etc/duplicacy
cd /etc/duplicacy/www
Initialize an encrypted repository. The storage URL format for S3-compatible storage is s3://region@endpoint/bucket/path. Replace the values with yours:
sudo duplicacy init -e -repository /var/www web01-www s3://[email protected]_provider.com/your_bucket/duplicacy
Duplicacy asks for the access key, the secret key and a storage password. The storage password encrypts all data and metadata in the bucket.
WarningStore the storage password in a password manager. Without it, nobody can restore the backups, including you.
/var/www will be backed up to s3://[email protected]_provider.com/your_bucket/duplicacy with id web01-www
Step 3 - Saving credentials for unattended runs
Scheduled backups cannot answer prompts, so save the credentials in the repository preferences with duplicacy set:
sudo duplicacy set -key password -value "your_storage_password"
sudo duplicacy set -key s3_id -value "your_access_key"
sudo duplicacy set -key s3_secret -value "your_secret_key"
These values are stored in plain text in /etc/duplicacy/www/.duplicacy/preferences. Make sure only root can read it:
sudo chmod 600 /etc/duplicacy/www/.duplicacy/preferences
sudo ls -l /etc/duplicacy/www/.duplicacy/preferences
-rw------- 1 root root 612 Sep 25 10:12 /etc/duplicacy/www/.duplicacy/preferences
Step 4 - Excluding files you do not need
Create a filters file to skip caches, logs and dependencies that can be rebuilt:
sudo nano /etc/duplicacy/www/.duplicacy/filters
-*.log
-*/cache/
-*/node_modules/
-*/.git/
Each line starts with - (exclude) or + (include). Paths are relative to /var/www, directories end with /, and the first pattern that matches a path wins. Adjust the list to your own sites.
Step 5 - Running the first backup
Run a backup and print statistics at the end. -threads uploads several chunks in parallel, which speeds up the first run over the network:
cd /etc/duplicacy/www
sudo duplicacy backup -stats -threads 4
...
Files: 18342 total, 1,204M bytes; 18342 new, 1,204M bytes
All chunks: 312 total, 1,210M bytes; 312 new, 1,210M bytes, 402M bytes uploaded
Total running time: 00:02:41
Backup for /var/www at revision 1 completed
Run it again. Only changed chunks are uploaded, so the second run takes seconds. List the revisions in the storage:
sudo duplicacy list
Snapshot web01-www revision 1 created at 2026-09-25 10:15 -hash
Snapshot web01-www revision 2 created at 2026-09-25 10:17
Step 6 - Adding a second storage over SFTP
One copy of your backups is not enough. Add an SFTP storage that is copy-compatible with the first one, so Duplicacy can copy chunks between them without re-reading /var/www. The double slash in the URL means an absolute path on the server:
cd /etc/duplicacy/www
sudo duplicacy add -e -copy default offsite web01-www sftp://[email protected]_domain//srv/backups/duplicacy
Use a different storage password for this storage if you like. Then save the password and the SSH key that root will use to log in:
sudo duplicacy set -storage offsite -key password -value "your_offsite_password"
sudo duplicacy set -storage offsite -key ssh_key_file -value /root/.ssh/id_ed25519
Make sure root already has the server's host key in /root/.ssh/known_hosts by connecting once with sudo ssh [email protected]_domain.
Copy all revisions from the default storage to the new one:
sudo duplicacy copy -from default -to offsite -threads 4
Confirm that the revisions are there:
sudo duplicacy list -storage offsite
Step 7 - Restoring files
Test a restore before you need one. There are three common cases.
To see which files a revision contains:
cd /etc/duplicacy/www
sudo duplicacy list -r 2 -files | head
To recover a single file without touching the live data, print it to a new location with cat:
sudo duplicacy cat -r 2 example.com/index.php > /tmp/index.php
To restore a whole revision to a different directory, initialize a second repository that uses the same snapshot ID and storage, then restore into it:
sudo mkdir -p /srv/restore-www
cd /srv/restore-www
sudo duplicacy init web01-www s3://[email protected]_provider.com/your_bucket/duplicacy
sudo duplicacy restore -r 2 -stats -threads 4
Duplicacy asks for the same credentials as in Step 2. Compare the result with the live site:
sudo diff -rq /var/www /srv/restore-www --exclude=.duplicacy
Running duplicacy restore -r N -overwrite from /etc/duplicacy/www restores in place over /var/www. Use it only when you really want to roll the live data back.
Step 8 - Pruning old revisions
Revisions accumulate forever unless you prune them. -keep n:m means "keep one revision every n days for revisions older than m days", and n = 0 means "delete all revisions older than m days". List the rules from the largest m to the smallest:
cd /etc/duplicacy/www
sudo duplicacy prune -dry-run -keep 0:360 -keep 30:90 -keep 7:30 -keep 1:7
This policy keeps every revision from the last 7 days, one per day up to 30 days, one per week up to 90 days, one per month up to a year, and deletes everything older. The -dry-run flag shows what would be removed without deleting anything. Remove it to apply the policy, and run the same command with -storage offsite for the second storage.
Step 9 - Scheduling backups with a systemd timer
A oneshot service can run several commands in order and stops at the first failure, which is all this job needs. Create the service:
sudo nano /etc/systemd/system/duplicacy-www.service
[Unit]
Description=Duplicacy backup of /var/www
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
WorkingDirectory=/etc/duplicacy/www
Nice=10
IOSchedulingClass=idle
ExecStart=/usr/local/bin/duplicacy -log backup -stats -threads 4
ExecStart=/usr/local/bin/duplicacy -log copy -from default -to offsite -threads 4
ExecStart=/usr/local/bin/duplicacy -log prune -keep 0:360 -keep 30:90 -keep 7:30 -keep 1:7
ExecStart=/usr/local/bin/duplicacy -log prune -storage offsite -keep 0:360 -keep 30:90 -keep 7:30 -keep 1:7
The global -log option adds timestamps and log levels to the output, which ends up in the journal. Create the timer:
sudo nano /etc/systemd/system/duplicacy-www.timer
[Unit]
Description=Nightly Duplicacy backup of /var/www
[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=30min
Persistent=true
[Install]
WantedBy=timers.target
Enable the timer and run the service once by hand to test it:
sudo systemctl daemon-reload
sudo systemctl enable --now duplicacy-www.timer
sudo systemctl start duplicacy-www.service
Check the result and the next scheduled run:
sudo journalctl -u duplicacy-www.service -n 20 --no-pager
systemctl list-timers duplicacy-www.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Fri 2026-09-26 03:12:40 UTC 16h left Thu 2026-09-25 10:31:02 UTC 2min ago duplicacy-www.timer duplicacy-www.service
To be alerted when a nightly run fails or does not happen at all, add a ping to a monitoring service such as Healthchecks with ExecStopPost=.
Step 10 - Verifying the storage
Once a week or so, check that every chunk referenced by your revisions exists in the storage:
cd /etc/duplicacy/www
sudo duplicacy check -stats
sudo duplicacy check -storage offsite
check only verifies that chunks exist. The restore test in Step 7 is still the only proof that your backups work end to end, so repeat it from time to time.
Troubleshooting
The job stops and asks for a password. A credential is missing from the preferences file. Run the command by hand from /etc/duplicacy/www to see which prompt appears, then save the value with duplicacy set (add -storage offsite for the second storage).
SFTP storage fails with a host key error. Root does not know the server's host key yet. Connect once with sudo ssh [email protected]_domain and accept the key.
Access denied from S3. Check the region and endpoint in the storage URL and that the key has list, read, write and delete permissions on the bucket and prefix.
Backups are slow. Increase -threads for the upload, and add large directories that do not need backing up (caches, build output) to the filters file.
Conclusion
You now have encrypted, deduplicated backups of /var/www in an S3-compatible bucket, a second copy on an SFTP server, a retention policy, and a tested restore procedure, all running from a systemd timer. Next, create a repository for each other directory you need to protect (for example /etc and your database dumps), reuse the same storage from other servers with their own snapshot IDs to benefit from cross-server deduplication, and add monitoring so you hear about failed runs.
