Ubuntu Nightly Website Backups with Restic, rclone & Cron
A client lost an entire site—files, database, everything. This guide shows Australian site owners how to back up multiple Ubuntu websites nightly at 2am with restic, rclone, and cron so recovery is routine, not a crisis.
If you run websites on an Ubuntu server and still rely on hope instead of tested backups, this guide is for you. By the end you will have restic, rclone, and cron backing up multiple site roots (and optional databases) every night at 2am to cheap object storage—set once, then verify on a schedule.
Last year a client lost a full site. Everything. Gone. Host panel snapshots were empty, the developer copy was months old, and restore meant rebuilding from scratch. We now back up about twenty websites automatically every night at 2am for roughly a dollar a month in object storage using restic, rclone, and cron on Ubuntu. For remote website support across Australia, Fixwebnode helps owners lock this in without turning backup into another unpaid side job.
Why automatic nightly backups matter after a total site loss
Manual zip downloads fail when you are busy. Provider “backups” often exclude databases, custom paths, or the week you actually need. A total loss usually arrives as a blank document root, a wiped VPS, a bad deploy, or ransomware—not a polite warning. Restic gives encrypted, deduplicated snapshots. rclone ships those snapshots to off-server storage. cron runs the job at 2am while traffic is low. Together they turn “everything gone” into “restore last night’s snapshot.”
This walkthrough assumes Ubuntu Server 22.04 or 24.04 with sudo access, sites under paths such as /var/www, and outbound HTTPS allowed for your storage provider. Work is fully remote: SSH, packages, and a restore test.
How do I set up restic and rclone nightly website backups on Ubuntu in Australia?
Install restic and rclone, point rclone at object storage, initialise an encrypted restic repository through that remote, then run a small backup script from cron at 02:00 in your server timezone (use Australia/Sydney or your state zone). Verify with a dry-run restore and check logs the next morning so a silent failure does not wait until the next disaster.
| Symptom | Quick fix | When to call Fixwebnode |
|---|---|---|
| Cron ran but no new snapshot | Check script exit code, restic unlock, path permissions | Multiple sites, mixed stacks, or unclear logs |
| rclone auth / 401 errors | Re-run rclone config, refresh keys, test lsd | Keys rotated by host or shared team access |
| Cannot restore or repo locked | Check locks, run check, restore to a temp path | Production down and you need a clean cutover |
Common issues with restic, rclone, and cron website backups
These are the failures we see after someone “set backups once” and never looked again.
- Silent cron success with zero new snapshots — mail is off, the script returns 0 after a partial path miss, or restic never runs because the environment in cron lacks PATH or the password file.
- rclone remote authentication failures — API keys rotated, wrong endpoint, or bucket region mismatch; uploads die after local snapshot work.
- Repository locks and failed restores under pressure — a killed job left a lock, or nobody ever practised restore so the first real restore is during an outage.
- Wrong 2am because of timezone drift — server stays on UTC; “2am” is afternoon local time in Australia, colliding with peak traffic or deploys.
Issue 1 — Cron “succeeds” but no restic snapshot appears
Symptoms: grep CRON /var/log/syslog shows the job, yet restic snapshots lists nothing new. Sites still have no off-box copy.
Step 1 — Confirm the job and capture output
sudo grep -i backup /var/log/syslog | tail -n 50
sudo crontab -u root -l
ls -la /var/log/site-backup.log
Step 2 — Run the script in a clean cron-like environment
sudo env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
HOME=/root \
bash -x /usr/local/bin/backup-sites.sh 2>&1 | tee /tmp/backup-debug.log
Step 3 — Fix typical causes
- Ensure the restic password file is readable only by root:
sudo chmod 600 /root/.restic-password. - Export the same variables the script needs (
RESTIC_REPOSITORY,RESTIC_PASSWORD_FILE,RCLONE_CONFIG) inside the script—not only in your interactive shell. - Make the script executable:
sudo chmod 750 /usr/local/bin/backup-sites.sh. - Fail hard on errors: start the script with
set -euo pipefailso a missing path does not look like success.
Step 4 — Verify
sudo restic -r rclone:offsite:sites-backup snapshots --password-file /root/.restic-password | tail
If logs still lie or twenty vhosts each have different owners, book remote help rather than guessing under load.
Issue 2 — rclone cannot authenticate to storage
Symptoms: restic errors mentioning rclone, HTTP 401/403, or rclone lsd fails while local disk still has data.
Step 1 — Test the remote alone
rclone listremotes
rclone lsd offsite: -vv
Step 2 — Repair config
rclone config
# update access key, secret, endpoint, and bucket
rclone mkdir offsite:sites-backup
rclone touch offsite:sites-backup/.write-test && rclone deletefile offsite:sites-backup/.write-test
Step 3 — Point restic at the fixed remote
export RESTIC_REPOSITORY="rclone:offsite:sites-backup"
export RESTIC_PASSWORD_FILE="/root/.restic-password"
restic snapshots
Re-create keys in the storage console if a former staff member still has the old pair. When billing accounts, buckets, and production SSH are tangled, Fixwebnode can separate them remotely without exposing long-lived keys in chat logs carelessly.
Issue 3 — Locks, corruption fears, or first restore fails
Symptoms: repository is already locked, restic check reports errors, or restore produces an empty tree when the site is already down.
Step 1 — Inspect locks (only if no backup is running)
restic -r rclone:offsite:sites-backup list locks --password-file /root/.restic-password
# If a stale lock remains after a confirmed dead process:
restic -r rclone:offsite:sites-backup unlock --password-file /root/.restic-password
Step 2 — Integrity check
restic -r rclone:offsite:sites-backup check --password-file /root/.restic-password
Step 3 — Practise restore to a temporary path (not over live files)
sudo mkdir -p /var/tmp/restore-test
sudo restic -r rclone:offsite:sites-backup restore latest \
--target /var/tmp/restore-test \
--password-file /root/.restic-password \
--include /var/www/example.com
sudo ls -la /var/tmp/restore-test/var/www/example.com | head
If the site is offline and you need a cutover plan (web root, database dump, DNS, TLS), stop improvising on the live path and get a specialist on the session.
Issue 4 — “2am” is wrong for Australia
Symptoms: Jobs fire at midday local time; CPU spikes during business hours; logs show UTC stamps you misread.
Step 1 — Set timezone
timedatectl
sudo timedatectl set-timezone Australia/Sydney
# or Australia/Melbourne, Australia/Brisbane, Australia/Perth, Australia/Adelaide
timedatectl
Step 2 — Confirm cron schedule after the change
date
sudo crontab -l
Use 0 2 * * * only after the zone is correct. For multi-state fleets, document each server’s zone instead of assuming one “Australia time.”
Install restic and rclone on Ubuntu
Use distribution packages first; upgrade restic from the official binary only if you need a newer feature set.
Step 1 — Update and install
sudo apt update
sudo apt install -y restic rclone cron curl ca-certificates
restic version
rclone version
Step 2 — Optional: refresh restic self-update (if appropriate for your policy)
sudo restic self-update
Confirm cron is enabled:
sudo systemctl enable --now cron
systemctl is-active cron
Configure rclone remote storage
Pick durable object storage (S3-compatible, B2, or similar). Keep credentials off the web root.
Step 1 — Interactive remote
sudo rclone config
Create a remote named offsite, choose your provider, paste keys, set endpoint if required, then quit.
Step 2 — Restrict config permissions
sudo chmod 600 /root/.config/rclone/rclone.conf
sudo chown root:root /root/.config/rclone/rclone.conf
rclone lsd offsite:
rclone mkdir offsite:sites-backup
Initialise the restic repository
Step 1 — Password file
sudo install -m 600 /dev/null /root/.restic-password
sudo nano /root/.restic-password
# one long random line only, no trailing spaces
Generate a strong secret if needed:
openssl rand -base64 48 | sudo tee /root/.restic-password >/dev/null
sudo chmod 600 /root/.restic-password
Step 2 — Init repo through rclone
sudo restic -r rclone:offsite:sites-backup init --password-file /root/.restic-password
Store a copy of the password in an offline password manager. Without it, snapshots are unrecoverable by design.
Backup script for multiple websites
Back up document roots every night. Add database dumps if your sites are dynamic.
Step 1 — Optional database dump directory
sudo mkdir -p /var/backups/db-dumps
sudo chmod 700 /var/backups/db-dumps
Example MySQL/MariaDB dump loop (adjust user and socket auth to your setup):
sudo tee /usr/local/bin/dump-site-dbs.sh >/dev/null <<'EOF'
#!/bin/bash
set -euo pipefail
OUT=/var/backups/db-dumps
STAMP=$(date +%F)
# List DB names you own; do not dump system schemas blindly in shared hosts
for db in site1 site2 site3; do
mysqldump --single-transaction --routines --triggers "$db" \
| gzip -c > "$OUT/${db}_${STAMP}.sql.gz"
done
# keep dumps 3 days locally; restic holds history offsite
find "$OUT" -type f -name '*.sql.gz' -mtime +3 -delete
EOF
sudo chmod 750 /usr/local/bin/dump-site-dbs.sh
Step 2 — Main backup script
sudo tee /usr/local/bin/backup-sites.sh >/dev/null <<'EOF'
#!/bin/bash
set -euo pipefail
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export RESTIC_REPOSITORY="rclone:offsite:sites-backup"
export RESTIC_PASSWORD_FILE="/root/.restic-password"
export RCLONE_CONFIG="/root/.config/rclone/rclone.conf"
LOG=/var/log/site-backup.log
exec >>"$LOG" 2>&1
echo "==== $(date -Is) backup start ===="
if [[ -x /usr/local/bin/dump-site-dbs.sh ]]; then
/usr/local/bin/dump-site-dbs.sh
fi
# Add every site root you must keep. Exclude caches and huge throwaway trees.
restic backup \
/var/www \
/var/backups/db-dumps \
/etc/nginx \
/etc/apache2 \
/etc/letsencrypt \
--exclude=/var/www/*/wp-content/cache \
--exclude=/var/www/*/node_modules \
--exclude=/var/www/*/vendor/cache \
--tag websites \
--tag nightly
# Retention: adjust to your recovery needs
restic forget --prune \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--tag nightly
echo "==== $(date -Is) backup ok ===="
EOF
sudo chmod 750 /usr/local/bin/backup-sites.sh
Step 3 — First manual run
sudo /usr/local/bin/backup-sites.sh
sudo restic -r rclone:offsite:sites-backup snapshots --password-file /root/.restic-password
sudo tail -n 100 /var/log/site-backup.log
Schedule cron for 2am and log rotation
Step 1 — Root crontab
sudo crontab -e
Add:
0 2 * * * /usr/local/bin/backup-sites.sh
Step 2 — Logrotate so logs cannot fill the disk
sudo tee /etc/logrotate.d/site-backup >/dev/null <<'EOF'
/var/log/site-backup.log {
weekly
rotate 12
compress
missingok
notifempty
create 640 root root
}
EOF
Step 3 — Verify scheduling
sudo crontab -l
date
sudo systemctl status cron --no-pager
Verification checklist (do this before you “forget it forever”)
- Confirm a new snapshot ID after a manual run.
- Restore one small site tree to
/var/tmp/restore-testand compare file counts. - Restore one database dump and import into a non-production database name.
- Confirm object storage size and billing alerts so a runaway retain policy cannot surprise you.
- Document repository path, password location, and remote name in your operations notes—not in the web root.
sudo restic -r rclone:offsite:sites-backup stats --password-file /root/.restic-password
sudo restic -r rclone:offsite:sites-backup check --password-file /root/.restic-password
When DIY is enough vs when to book Fixwebnode
DIY is enough when you have root SSH, a short list of static or simple PHP sites, working object-storage keys, and time to complete one successful restore test. The steps above are enough for a careful owner or in-house admin.
Book Fixwebnode when any of these apply: production is already down; you manage many vhosts, containers, or mixed nginx/Apache stacks; database replication or staging cutover is involved; cron has been “fine” for months with no restore drill; or you need a second pair of eyes on retention, encryption keys, and offsite layout. Fixwebnode works as a direct specialist provider for remote website support—not a freelance marketplace. Geography and remote coverage are listed on the service areas page for Australian operators who want clear reach without shopfront theatre.
Talk to Fixwebnode about hardening your backup routine
A lost site teaches the same lesson every time: snapshots you have never restored are a story, not a plan. If you want restic, rclone, and cron installed, scheduled at 2am, logged, and restore-tested on Ubuntu—or you already have failures in the log and need a clean path back—start a conversation with the team via website repair and support Australia. Bring SSH access notes and a list of site roots; we will focus on durable nightly backups you can actually use when something disappears again.