Kopia: Fast, Encrypted Backups With a Modern Web UI
You already know you need backups. The 3-2-1 rule has been hammered into every sysadmin's skull: three copies of your data, on two different media types, with one off-site. Ransomware, drive failures, accidental rm -rf commands, silent data corruption -- any one of these can wipe out years of irreplaceable data in seconds. The question isn't whether to back up, but which tool to trust with the job.
Photo by Joan Gamell on Unsplash
If you've looked at self-hosted backup tools, you've probably landed on BorgBackup or Restic. Both are excellent. But there's a third option that's been gaining serious traction: Kopia. It combines the content-addressable storage and encryption of Restic with the one thing both Borg and Restic lack -- a built-in web UI for managing snapshots, policies, and restores without touching the terminal.
Kopia vs the Competition
Before diving into setup, here's how Kopia stacks up against the other major self-hosted backup tools.
| Feature | Kopia | Restic | BorgBackup | Duplicati |
|---|---|---|---|---|
| Language | Go | Go | Python/C | C#/.NET |
| Interface | CLI + Web UI | CLI only | CLI only | Web UI only |
| Encryption | AES-256-GCM or ChaCha20-Poly1305 | AES-256-CTR + Poly1305 | AES-256-CTR + HMAC-SHA256 | AES-256 |
| Deduplication | Content-addressable, variable-size blocks | Content-defined chunking | Content-defined chunking | Block-level |
| Compression | zstd, gzip, pgzip, s2, deflate | zstd (since 0.16) | lz4, zstd, zlib, lzma | Built-in (zip-based) |
| Cloud backends | S3, B2, GCS, Azure, SFTP, rclone, WebDAV | S3, B2, SFTP, rclone, REST | SSH only (native) | 20+ native |
| Multi-machine | Built-in server mode | Manual (REST server) | Manual (SSH) | Manual |
| Snapshot policies | Per-directory, per-host, global | Manual forget rules | Manual prune rules | Per-job via UI |
| Performance | Fast, multi-threaded | Fast, multi-threaded | Fast, single-threaded | Moderate |
| Windows support | Yes | Yes | No | Yes |
| Project age | 2019 | 2015 | 2010 (as attic) | 2008 |
When to choose Kopia
You want the power of Restic -- content-addressable storage, strong encryption, cloud-native backends -- but you also want a web interface for managing policies and monitoring snapshots. You're backing up multiple machines and want a central server that handles everything. You like granular snapshot policies that you can set per directory, per host, or globally without writing custom scripts.
When to choose Restic
You want the most battle-tested cloud backup tool with the largest community. You're comfortable with CLI-only workflows and already have monitoring wrappers in place. Restic's ecosystem of third-party tools (resticprofile, rustic, autorestic) is larger than Kopia's.
When to choose BorgBackup
You're backing up to a local NAS or another machine over SSH, you want the widest range of compression algorithms, and you run Linux exclusively. Borg's compression options are still the most flexible of any backup tool.
When to choose Duplicati
You want a GUI-first experience, need to back up to consumer cloud storage (Google Drive, OneDrive, Dropbox), or you're setting up backups for someone who won't touch a terminal. Duplicati has the most backend options, though it trades performance for accessibility.
Core Features
Before getting into the install, here's what makes Kopia interesting as a backup engine.
Content-addressable storage. Kopia splits your files into variable-size blocks, hashes each one, and stores only unique blocks. If you have the same file in three places, Kopia stores it once. If a 10 GB file changes by one byte, Kopia stores only the changed block, not the entire file again.
Client-side encryption. All data is encrypted before it leaves your machine. Kopia supports AES-256-GCM (hardware-accelerated on modern CPUs) and ChaCha20-Poly1305 (faster on machines without AES-NI). The repository password never leaves the client.
Deduplication across machines. When running Kopia in server mode, multiple machines back up to the same repository. Deduplication works across all of them. If three machines all have the same 500 MB log file, it's stored once.
Compression. Kopia compresses data before encryption using your choice of algorithm. The default is zstd, which offers a good balance of speed and ratio. You can configure compression per directory -- use aggressive compression for text-heavy directories and skip it for already-compressed media.
Built-in web UI. Kopia ships a web interface for browsing snapshots, configuring policies, monitoring backup status, and restoring files. It's not an afterthought bolted on with a separate project -- it's part of the core binary.
Snapshot policies. This is where Kopia really differentiates. You define retention, scheduling, compression, and error handling rules at multiple levels: global, per-host, per-user, or per-directory. Policies inherit and cascade, so you set sensible defaults globally and override them where needed.
Installing Kopia With Docker Compose
The simplest way to run Kopia as a backup server with the web UI is Docker Compose. This gives you a central server that you can point multiple machines at.
# docker-compose.yml
services:
kopia:
image: kopia/kopia:latest
hostname: kopia-server
restart: unless-stopped
ports:
- "51515:51515" # Kopia server API + Web UI
command:
- server
- start
- --tls-generate-cert
- --address=0.0.0.0:51515
- --server-control-username=admin
- --server-control-password=${KOPIA_ADMIN_PASSWORD}
environment:
KOPIA_PASSWORD: ${KOPIA_REPO_PASSWORD}
TZ: America/Los_Angeles
volumes:
- kopia_config:/app/config
- kopia_cache:/app/cache
- kopia_logs:/app/logs
- /mnt/backup/kopia-repo:/repository # local repository storage
# Mount directories you want to back up (read-only)
- /home:/sources/home:ro
- /var/lib/docker/volumes:/sources/docker-volumes:ro
- /etc:/sources/etc:ro
volumes:
kopia_config:
kopia_cache:
kopia_logs:
Create a .env file alongside your compose file:
KOPIA_ADMIN_PASSWORD=your-secure-admin-password
KOPIA_REPO_PASSWORD=your-repository-encryption-password
Important: The KOPIA_REPO_PASSWORD is your encryption key. If you lose it, your backups are unrecoverable. Store it in a password manager and print a physical copy.
Initialize the repository
Before starting the server, you need to create the repository:
docker compose run --rm kopia repository create filesystem \
--path=/repository
Then start the server:
docker compose up -d
The web UI is at https://your-server:51515. Note the https -- Kopia generates a self-signed TLS certificate by default. Your browser will show a security warning; accept it or configure a reverse proxy with a proper certificate.
Log in with the admin username and password you set in the compose file.
Like what you're reading? Subscribe to Self-Hosted Weekly — free weekly guides in your inbox.
Configuring Snapshots
Creating your first snapshot
From the web UI, navigate to Snapshots and click New Snapshot. Select a source directory (one of the paths you mounted into the container under /sources/). Kopia will run an initial snapshot immediately.
From the CLI inside the container:
docker compose exec kopia kopia snapshot create /sources/home
docker compose exec kopia kopia snapshot create /sources/docker-volumes
docker compose exec kopia kopia snapshot create /sources/etc
The first snapshot captures everything. Subsequent snapshots only process changed blocks and typically complete in seconds for datasets that haven't changed much.
Setting up snapshot policies
Policies control how often snapshots run, how long they're kept, what gets compressed, and what gets excluded. You can set them globally or per directory.
Global scheduling and retention:
docker compose exec kopia kopia policy set --global \
--keep-latest 10 \
--keep-hourly 24 \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 12 \
--keep-annual 3 \
--snapshot-interval 1h
This keeps hourly snapshots for a day, daily for a week, weekly for a month, monthly for a year, and annual snapshots for three years. Adjust to fit your needs and storage capacity.
Per-directory overrides:
# Keep Docker volumes longer -- they contain your service data
docker compose exec kopia kopia policy set /sources/docker-volumes \
--keep-daily 14 \
--keep-monthly 24
# Snapshot home directory less frequently
docker compose exec kopia kopia policy set /sources/home \
--snapshot-interval 6h
Compression policy:
# Use zstd compression globally
docker compose exec kopia kopia policy set --global \
--compression zstd
# Skip compression for media (already compressed)
docker compose exec kopia kopia policy set /sources/home/photos \
--compression none
Exclude patterns:
docker compose exec kopia kopia policy set --global \
--add-ignore "*.tmp" \
--add-ignore "*.cache" \
--add-ignore "node_modules/" \
--add-ignore ".cache/" \
--add-ignore "*.log"
All of this is also configurable through the web UI under Policies.
Cloud and Remote Backends
The Docker Compose example above uses local filesystem storage. For off-site backups, Kopia supports several remote backends.
Backblaze B2
docker compose run --rm kopia repository create b2 \
--bucket=your-bucket-name \
--key-id=your-key-id \
--key=your-application-key
B2 costs $6/TB/month for storage and $0.01/GB for downloads. For a typical homelab with 500 GB of deduplicated backup data, that's about $3/month.
Amazon S3
docker compose run --rm kopia repository create s3 \
--bucket=your-bucket-name \
--region=us-east-1 \
--access-key=your-access-key \
--secret-access-key=your-secret-key
S3-compatible storage (MinIO, Wasabi, etc.)
docker compose run --rm kopia repository create s3 \
--bucket=your-bucket-name \
--endpoint=s3.wasabisys.com \
--access-key=your-access-key \
--secret-access-key=your-secret-key
SFTP
docker compose run --rm kopia repository create sftp \
--path=/backup/kopia \
--host=backup-server.example.com \
--username=backup-user \
--keyfile=/app/config/ssh-key
Mount your SSH key into the container if using key-based authentication.
Google Cloud Storage
docker compose run --rm kopia repository create gcs \
--bucket=your-bucket-name \
--credentials-file=/app/config/gcp-credentials.json
You can also use rclone as a backend, which opens up access to virtually any storage provider rclone supports (over 40).
Multi-Machine Backup
One of Kopia's strongest features is centralized multi-machine backup. The server you set up with Docker Compose can accept connections from Kopia clients running on other machines.
On the server
Add users for each machine that will connect:
docker compose exec kopia kopia server user add \
backupuser@workstation \
--user-password=client-password
On each client machine
Install Kopia (it's a single binary):
# Debian/Ubuntu
curl -s https://kopia.io/signing-key | sudo gpg --dearmor -o /etc/apt/keyrings/kopia-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kopia-keyring.gpg] http://packages.kopia.io/apt/ stable main" | sudo tee /etc/apt/sources.list.d/kopia.list
sudo apt update && sudo apt install kopia
# Fedora
sudo rpm --import https://kopia.io/signing-key
sudo dnf install kopia
# macOS
brew install kopia
# Windows
winget install kopia
Connect to the server:
kopia repository connect server \
--url=https://your-server:51515 \
--server-cert-fingerprint=FINGERPRINT \
--override-username=backupuser \
--override-hostname=workstation \
--password=client-password
Get the certificate fingerprint from the server logs or the web UI.
Now create snapshots from the client:
kopia snapshot create /home/user
kopia snapshot create /etc
All clients share the same repository, so deduplication works across machines. If your laptop and desktop both have the same 2 GB VM image, it's stored once.
Pre/Post-Snapshot Hooks
Kopia can run commands before and after taking a snapshot. This is critical for databases -- you need to dump them before backing up the files.
# Create a pre-snapshot script
docker compose exec kopia kopia policy set /sources/docker-volumes \
--before-snapshot-root-action="/app/config/pre-backup.sh"
Example pre-backup.sh:
#!/bin/bash
set -euo pipefail
# Dump PostgreSQL (Immich, Gitea, etc.)
docker exec immich_postgres pg_dumpall -U postgres > /sources/docker-volumes/db-dumps/postgres.sql
# Dump MariaDB
docker exec mariadb mariadb-dump --all-databases -u root -p"$MYSQL_ROOT_PASSWORD" > /sources/docker-volumes/db-dumps/mariadb.sql
echo "Database dumps complete"
Mount this script into the container and make sure it has execute permissions.
Retention Policies in Depth
Kopia's retention system is more flexible than most backup tools. Instead of a single set of keep rules, you define retention at multiple policy levels that cascade.
Policy hierarchy (most specific wins):
- Per-directory -- Rules for a specific path
- Per-user@host -- Rules for a specific machine
- Per-host -- Rules for all users on a machine
- Per-user -- Rules for a user across all machines
- Global -- Default rules for everything
This means you can set a conservative global policy (keep 7 daily, 4 weekly, 12 monthly) and then override it for specific paths that need more or fewer snapshots.
Example: Keep database dumps for two years, but only keep log directories for one week:
kopia policy set /sources/docker-volumes/db-dumps \
--keep-monthly 24 \
--keep-annual 5
kopia policy set /sources/home/logs \
--keep-daily 7 \
--keep-weekly 0 \
--keep-monthly 0
Resource Requirements
Kopia is efficient, but requirements vary by workload.
| Scenario | RAM | CPU | Cache Disk |
|---|---|---|---|
| Single machine, < 500 GB data | 512 MB | 1 core | 1-5 GB |
| Single machine, 1-5 TB data | 1-2 GB | 2 cores | 5-20 GB |
| Server, 3-5 clients, < 2 TB each | 2-4 GB | 2-4 cores | 20-50 GB |
| Server, 10+ clients, mixed workloads | 4-8 GB | 4+ cores | 50-100 GB |
Cache: Kopia maintains a local metadata cache to speed up operations. The cache size depends on the number of files and snapshots in your repository. For large repositories (millions of files), allocate generous cache space or operations will be slow.
Network: Initial backups transfer everything, so plan for that. Subsequent snapshots only transfer changed blocks. A homelab with 500 GB of data and typical daily churn (1-5 GB of changes) uses minimal bandwidth for incremental snapshots.
Restoring Files
From the web UI
Navigate to Snapshots, select the source directory, and browse the snapshot history. Click any snapshot to explore its file tree. Select files or directories and click Restore to download them or write them to a path on the server.
From the CLI
# List snapshots
kopia snapshot list
# Browse a specific snapshot
kopia ls <snapshot-id>
# Restore a full snapshot to a target directory
kopia restore <snapshot-id> /tmp/restore/
# Restore a specific file
kopia restore <snapshot-id>/path/to/file.txt /tmp/restored-file.txt
# Mount a snapshot as a filesystem (FUSE)
kopia mount <snapshot-id> /mnt/kopia-browse &
Disaster recovery
If your Kopia server is gone, you can restore from any machine with Kopia installed:
# Connect directly to the repository backend
kopia repository connect b2 \
--bucket=your-bucket-name \
--key-id=your-key-id \
--key=your-application-key
# List all snapshots from all machines
kopia snapshot list --all
# Restore what you need
kopia restore <snapshot-id> /recovery/
You need the repository password and backend credentials. Store both somewhere safe outside the system you're backing up.
Honest Limitations
Kopia is a strong tool, but it has real trade-offs you should know about.
Younger project. Kopia's first stable release was in 2022. BorgBackup has been around since 2010, Restic since 2015. Kopia has fewer years of production battle-testing. It's stable enough for homelab and small business use, but large organizations tend to prefer Restic for its longer track record.
Smaller community. Restic has roughly 3x as many GitHub stars and a larger ecosystem of third-party tools, wrappers, and guides. When you hit a problem with Kopia, you're more likely to be the first person searching for it.
Web UI is functional, not polished. The web interface covers the essentials -- snapshots, policies, restores, server management. But it's utilitarian. Don't expect Duplicati's guided setup wizard or a dashboard full of charts. It gets the job done without hand-holding.
Documentation has gaps. The official docs cover common use cases well, but advanced configurations (complex policy hierarchies, rclone backend tuning, large-scale multi-tenant setups) sometimes require reading GitHub issues or source code.
Repository format changes. Kopia has made breaking repository format changes in the past during its pre-1.0 development. The format is stable now, but this history makes some people cautious. Always keep the ability to recreate your repository if needed.
No append-only mode for clients. Unlike Restic's append-only server mode, Kopia doesn't yet have a way to give clients write-only access that prevents them from deleting snapshots. If a compromised client connects to the server, it could potentially delete its own snapshots. The server access controls mitigate this, but it's not as hardened as Restic's append-only approach.
Practical Tips
Test restores regularly. A backup you've never restored is a backup you hope works. Schedule a monthly test: pick a random file, restore it, verify it's correct. Automate this if you can.
Monitor backup health. Kopia's kopia snapshot verify command checks data integrity. Run it weekly:
kopia snapshot verify --verify-files-percent=5
This verifies 5% of your backed-up files by re-reading them from the repository and checking hashes. Over time, you'll cover the full dataset.
Integrate with monitoring. Point your Uptime Kuma or Healthchecks.io instance at a script that runs after each snapshot:
#!/bin/bash
kopia snapshot create /sources/home && curl -fsS https://hc-ping.com/your-check-uuid
If the ping stops arriving, you know backups are failing.
Choose your backend wisely. For local backups (fast restores), use filesystem or NAS storage. For off-site (disaster recovery), use B2 or S3. Many people run both: a local repository for fast restores and a cloud repository for catastrophic failure. Kopia supports connecting to multiple repositories, though not simultaneously from the same client.
Size your cache. If Kopia operations feel slow (listing snapshots, browsing files), the cache is probably too small. Check cache usage:
kopia cache info
Increase it if needed:
kopia cache set --content-cache-size-mb=5000 --metadata-cache-size-mb=5000
Use maintenance wisely. Kopia runs automatic maintenance to clean up old data and optimize the repository. By default, quick maintenance runs hourly and full maintenance runs daily. If you're on metered storage, be aware that full maintenance rewrites some data blobs and temporarily increases storage usage.
Resources
- Kopia official documentation -- Start here. The getting started guide and feature overview are solid.
- Kopia GitHub repository -- Issues and discussions are the best source for troubleshooting edge cases.
- Kopia Docker Hub -- Official container images.
- r/selfhosted -- Active community with frequent Kopia discussions and comparisons.
- Kopia vs Restic comparison -- The official comparison page, written by the Kopia team (read with that context in mind).
- 3-2-1 Backup Strategy -- Our guide to implementing a complete backup strategy with BorgBackup and Restic, which applies equally to Kopia.
The Bottom Line
Kopia sits in a sweet spot that didn't exist until recently: the performance and architecture of Restic, combined with a built-in web UI and the most flexible snapshot policy system of any open-source backup tool. Its server mode makes multi-machine backup straightforward instead of something you have to rig together with scripts.
The trade-off is maturity. Restic and BorgBackup have years more production use, larger communities, and deeper third-party ecosystems. If you're backing up critical business data and want the safest bet, Restic is still the default recommendation. But if you want a modern backup tool that you can manage through a browser, that handles multi-machine deduplication natively, and that's rapidly closing the maturity gap, Kopia is worth your attention. Set it up, automate it, test your restores, and you'll have a backup system that does its job without demanding constant maintenance.
