
September 13, 2026
11 min read
By Kokil Thapa | Last reviewed: September 2026
Production data disappears when disks fail, accounts get compromised, or someone runs the wrong command. You need a backup tool that encrypts by default, deduplicates efficiently, and runs unattended on a schedule. To Automate Backups with restic, you install the binary, initialize an encrypted repository, store credentials outside scripts, and trigger snapshots through Linux system administration patterns such as cron or systemd timers. I've used this stack on shared EC2 hosts that run Laravel legal-tech portals and sister sites deployed with Deployer 7 and GitLab CI — the same servers that need reliable nightly dumps without manual babysitting.
restic backup and restic forget --prune through cron or systemd. Point the repo at local disk, SFTP, or S3-compatible storage and test restores monthly.What is restic and why should you Automate Backups with restic?
restic is a single-binary backup program written in Go. It creates encrypted, content-addressed snapshots of files and directories. Only changed data blocks are stored, so repeated runs stay fast and cheap on bandwidth.
Compared with plain tar plus rsync, restic gives you snapshot history, encryption at rest, and built-in integrity checks. Compared with cloud-only agents, you keep control of retention, scheduling, and storage location — important for Nepal-based clients on budget VPS plans where off-site copy to S3 or Backblaze B2 is often Rs 500–2,000/month (~USD 4–15) instead of a full managed backup SKU.
On production Laravel applications I maintain, restic complements application-level tools. Spatie Laravel Backup handles in-app database exports; restic then snapshots those dump files together with storage/ and config. That layered approach mirrors what we describe in Laravel Spatie backup automation and broader backup strategy design guidance.
| Approach | Encryption | Deduplication | Snapshot history | Best fit |
|---|---|---|---|---|
| restic | AES-256 by default | Yes | Yes, with tags | Full-server or mixed file backups |
| rsync only | No (unless filesystem-level) | No | Manual rotation | Mirror sync, low complexity |
| mysqldump + tar | No | No | Manual | DB-only, small servers |
| Cloud agent | Vendor-dependent | Varies | Yes | Hands-off, higher cost |
For a deeper comparison of sync tools, see rsync vs rclone for server backups. restic often pairs with rclone-backed repositories when you need exotic backends.
How do you install restic and initialize an encrypted repository?
Start on Ubuntu 22.04 or 24.04 with a dedicated backup user or root-only automation. Install restic from your package manager or the official release binary documented at restic installation docs.
Install restic
sudo apt update
sudo apt install restic
restic version Confirm you are on a current 0.16.x or 0.17.x release. Pin the version in your runbook so staging and production match.
Create a password file and repository
Never pass passwords on the command line; process listings leak them. Use a root-readable env file:
sudo install -d -m 0700 /root/.config/restic
sudo bash -c 'openssl rand -base64 32 > /root/.config/restic/password'
sudo chmod 0400 /root/.config/restic/password
export RESTIC_PASSWORD_FILE=/root/.config/restic/password
export RESTIC_REPOSITORY=/var/backups/restic-repo
sudo mkdir -p /var/backups/restic-repo
sudo restic init For S3-compatible storage (AWS, Cloudflare R2, Wasabi), set the repository URL instead:
export RESTIC_REPOSITORY=s3:https://s3.amazonaws.com/my-restic-bucket/host1
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=... Follow the patterns in automate off-site backups to S3 and off-site backups to S3 or R2 with restic when wiring bucket policies and lifecycle rules.
First manual backup
sudo restic backup /var/www \
--exclude-file=/etc/restic/excludes.txt \
--tag daily \
--verbose Typical excludes for Laravel stacks: node_modules, vendor if you rebuild on deploy, and ephemeral cache paths. Keep database dumps in a known directory such as /var/backups/db/ populated by a pre-backup script — the same idea as automate database backups on Linux.
How do you Automate Backups with restic using cron and systemd?
Automation fails when credentials live in crontab lines or when jobs overlap. Use a wrapper script, file locks, and structured logging.
Wrapper script at /usr/local/bin/restic-backup.sh
#!/bin/bash
set -euo pipefail
LOCKFILE=/var/run/restic-backup.lock
exec 9>"$LOCKFILE"
flock -n 9 || { echo "Backup already running"; exit 0; }
set -a
source /root/.config/restic/env
set +a
/usr/local/bin/pre-backup.sh
restic backup /var/www /etc /var/backups/db \
--exclude-file=/etc/restic/excludes.txt \
--tag "host-$(hostname -s)" \
--tag daily
restic forget --tag daily \
--keep-daily 7 --keep-weekly 4 --keep-monthly 6 \
--prune
restic check --read-data-subset=5% Store all variables in /root/.config/restic/env:
RESTIC_PASSWORD_FILE=/root/.config/restic/password
RESTIC_REPOSITORY=s3:https://s3.amazonaws.com/my-bucket/prod-web-01
AWS_DEFAULT_REGION=ap-south-1 Protect that file with mode 0400. Generate strong repository passwords with a password generator and record them in your team vault — not in ticket comments.
cron entry
sudo crontab -e
15 2 * * * /usr/local/bin/restic-backup.sh >> /var/log/restic-backup.log 2>&1 Run during low-traffic windows. For Nepal-hosted sites, 02:15 NPT often clears the midnight batch of WordPress cron and Laravel scheduler jobs. Stagger multi-server fleets so S3 egress and API rate limits are not hit at once.
systemd timer alternative
systemd gives you journald integration and dependency ordering — useful when backup must run after MySQL flush scripts. Define /etc/systemd/system/restic-backup.service and a matching timer unit. Official timer syntax is documented in the systemd.timer manual.
- Create the oneshot service invoking your wrapper script.
- Create a timer with
OnCalendar=*-*-* 02:15:00andPersistent=true. - Enable with
systemctl enable --now restic-backup.timer. - Inspect failures via
journalctl -u restic-backup.service.
This matches the operational style in automated server backups complete setup and Ubuntu server backup strategies.
How do you send restic snapshots to off-site S3 or SFTP storage?
Local repositories protect against accidental deletes, not datacenter loss. Copy snapshots off the machine. restic speaks S3 natively; for SFTP use restic init --repo sftp:user@backup-host:/path with SSH keys.
S3 bucket hardening checklist
- Dedicated IAM user with
s3:ListBucketscoped to the prefix ands3:GetObject/s3:PutObjectonly. - Bucket versioning enabled; block public access at account level.
- Separate bucket per environment — never share prod and staging credentials.
- Lifecycle transition to Glacier only if restore drills account for retrieval latency.
On sister sites I maintain — including Notary Kathmandu and Translation Nepal — identical restic env files differ only by repository prefix and tags. That keeps Deployer releases and user uploads recoverable from one playbook.
Sync a second copy with:
restic copy --from-repo /var/backups/restic-repo \
--to-repo s3:https://s3.amazonaws.com/my-bucket/dr-copy Schedule restic copy weekly after your daily backup window. Read restic fast encrypted backups for performance tuning when repositories grow past a few hundred gigabytes.
How do you verify, restore, and monitor automated restic backups?
Backups you never restore are wishful thinking. Build verification into the same automation that creates snapshots.
Listing and testing restores
restic snapshots
restic ls latest
restic restore latest --target /tmp/restic-restore-test --include /var/www/example.com/.env
diff /var/www/example.com/.env /tmp/restic-restore-test/var/www/example.com/.env Monthly, restore a random file and a database dump to a staging path. Document steps in your runbook per test and validate your backups. For MySQL-heavy stacks, combine file restore with logical dumps described in database backup strategies for small servers.
Monitoring and alerts
Parse exit codes in your wrapper. restic returns non-zero on failure. Send mail or webhook alerts when:
restic backupfails or skips expected paths.restic checkreports pack corruption.- No new snapshot appears within 26 hours.
- Repository size jumps more than 40% day-over-day — possible ransomware or log runaway.
Hook alerts into the same channels you use for SSL expiry and deploy failures. Support and maintenance retainers should include quarterly restore drills, not just disk space graphs.
Common production gotchas
I've encountered these during real deployments:
- Stale opcache after restore: reload PHP-FPM after restoring PHP files so workers serve fresh code.
- Wrong RESTIC_REPOSITORY in env: staging credentials writing into prod prefix — use hostname tags and separate env files.
- Overlapping cron jobs: without
flock, two backups corrupt snapshot metadata under load. - Forgetting prune: repositories grow until the disk fills; always pair backup with
forget --prune. - Password loss: encrypted data is unrecoverable without RESTIC_PASSWORD — store offline copies.
Legal-tech portals with uploaded PDFs and client documents — like those in our Court Marriage in Nepal and Mijar Law Associates work — need document paths included explicitly. Verify storage/app and private upload dirs are not excluded by a overly broad pattern.
For hosting migrations, pair restic with website migration planning so DNS cutover happens only after a verified restore on the target VM. Domain and hosting choices affect which S3 region keeps latency acceptable for nightly runs.
Key Takeaways
- Initialize an encrypted restic repository, keep passwords in a root-only file, and never commit secrets to Git.
- Automate Backups with restic through a locked wrapper script plus cron or systemd timers that run backup, forget, and check in sequence.
- Mirror snapshots off-site with S3 or SFTP repos; use
restic copyfor a second location. - Tag snapshots by host and environment; apply daily/weekly/monthly retention with
forget --prune. - Restore to staging monthly and alert on missing snapshots or failed checks — backups exist to be tested.
- Layer restic file snapshots atop logical database dumps for complete Laravel and WordPress recovery paths.
People Also Ask
Is restic suitable for large MySQL databases?
restic backs up files, not live InnoDB tables safely by itself. Dump databases first with mysqldump or Percona tools, then snapshot the dump directory. For very large datasets, consider binary log strategies from our MySQL replication article alongside file-level restic runs.
How much disk space does a restic repository need?
First snapshot size approximates source data. Later snapshots store only changed blocks — often 1–5% of full size for typical web apps. Plan headroom for prune operations, which temporarily need extra space while repacking.
Can restic run without root?
Yes, if the backup user can read all target paths. System configs and other users' web roots usually require root or ACL adjustments. Running as root with locked-down env files is simpler on single-tenant VPS hosts.
Does restic work with Cloudflare R2 or Wasabi?
Any S3-compatible endpoint works when you set the correct region and path-style URL. Test with a small repository before pointing production schedules at the bucket.
Build a backup pipeline you will actually restore from
Automate Backups with restic when you want encrypted, deduplicated snapshots under your control — not when you want a set-and-forget checkbox. Wire the wrapper script this week, schedule off-site copy next, and book a restore drill before your next framework upgrade. If you want help auditing an existing Ubuntu fleet or wiring restic into a Laravel deploy pipeline, see our Linux administration services or contact us for a scoped review. Related reading: backup and disaster recovery on the cloud, automate server backups with rsync and cron, and the home page for more engineering guides from Kokil Thapa.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

