The tport.space pixel t and cloud mark on a violet-to-pink tile

A server copy is not automatically a backup. It can be incomplete, it can overwrite the only previous version, and it may be impossible to put back under pressure. A good small-site plan has separate dated snapshots for files and data, an off-machine destination, a retention rule you can explain, and a restore test that proves the order of operations.

This guide uses rclone and an S3-compatible bucket. It works for a static site, a CMS export, or a small app with uploads and a PostgreSQL or MySQL database. Commands use tport:site-backups as the remote and bucket; replace the local paths and database command for your own system. Run them as the account that can read the files — never paste access keys into a script.

Decide what you are protecting

text
Part                     Typical source                         Why it is separate
Published site files     /srv/site/current or public/           code, uploads and generated assets
Database                pg_dump or mysqldump output             needs a consistent export
Configuration record    encrypted password-manager entry        endpoint, key ownership, restore notes
Not a backup             node_modules, caches, logs, secrets     rebuild or retain elsewhere

Do not copy a live database directory while the database is running. Use its export tool: pg_dump for PostgreSQL or mysqldump for MySQL. A logical dump is slower to restore than a raw disk snapshot, but it is portable and has a clear point-in-time meaning. Keep secrets out of the object prefix; the backup job should load them from the machine’s secret store or protected environment.

Configure the rclone remote once

ini
# rclone config create tport s3
[tport]
type = s3
provider = Other
access_key_id = your-access-key
secret_access_key = your-secret-key
endpoint = https://s3.tport.space
region = auto
force_path_style = true
bash
rclone lsd tport:
rclone mkdir tport:site-backups/snapshots
printf 'rclone can read and write\n' > /tmp/tport-check.txt
rclone copy /tmp/tport-check.txt tport:site-backups/tests
rclone cat tport:site-backups/tests/tport-check.txt
rclone deletefile tport:site-backups/tests/tport-check.txt

Do this four-command probe before creating automation. It confirms bucket visibility, write, read and delete separately. rclone supports S3 as a backend and documents both provider selection and endpoint configuration; provider = Other avoids importing assumptions from a named provider profile.

Make an immutable-looking dated snapshot

bash
#!/usr/bin/env bash
set -euo pipefail
STAMP=$(date -u +%Y-%m-%dT%H%M%SZ)
BASE="tport:site-backups/snapshots/$STAMP"

# Files first; --copy-links is optional and only if your deployment uses safe symlinks.
rclone copy /srv/site/current "$BASE/files" --fast-list --checkers 8 --transfers 4

# PostgreSQL example: do not put the password in this script.
pg_dump --format=custom --file "/tmp/site-$STAMP.dump" your_database
rclone copy "/tmp/site-$STAMP.dump" "$BASE/database" --checksum
rclone size "$BASE"
rm -f "/tmp/site-$STAMP.dump"

A timestamped prefix prevents today’s job from overwriting yesterday’s good copy. set -euo pipefail makes a missing variable or failed command stop the run instead of claiming success. rclone size records an object count and byte total; save that output with the job log so a sudden 90% size drop becomes visible. Start conservatively with four transfers. Raising concurrency may finish sooner, but can overload a small server or a database dump’s disk.

Retention: calculate it before deletion

A simple schedule is one daily snapshot for 14 days, one Sunday snapshot for 8 weeks, and one first-of-month snapshot for 12 months. That is at most 14 + 8 + 12 = 34 retained snapshots, before a snapshot qualifies for more than one tier. If each compressed files-plus-database snapshot is 2.4 GiB, the upper bound is 34 × 2.4 = 81.6 GiB. Real usage can be lower when some dates overlap, but budget and capacity should use the upper bound.

text
Retention tier       Keep             Maximum copies
Daily                latest 14 days   14
Weekly               latest 8 Sundays  8
Monthly              latest 12 months 12
Upper bound                            34

Do not start with an automatic delete command until you have listed and reviewed several snapshots. Prefix names are data: use UTC timestamps in a fixed YYYY-MM-DDTHHMMSSZ form so a lexical list is also chronological. Keep the retention script separate from the copy script, log every deletion, and never run it on the same day you first enable backups.

The restore test: one release into an empty directory

bash
STAMP='2026-10-31T020000Z'   # choose a known completed snapshot
RESTORE=/tmp/site-restore-test
rm -rf "$RESTORE"
mkdir -p "$RESTORE/files" "$RESTORE/database"
rclone copy "tport:site-backups/snapshots/$STAMP/files" "$RESTORE/files" --checksum
rclone copy "tport:site-backups/snapshots/$STAMP/database" "$RESTORE/database" --checksum
find "$RESTORE/files" -type f | wc -l
pg_restore --list "$RESTORE/database/site-$STAMP.dump" | head -20

This test deliberately restores somewhere empty; it cannot damage the live site. --checksum asks rclone to compare checksums when the backend and objects provide them. Count restored files and inspect the database archive with pg_restore --list before progressing to a disposable database. A full application restore should be practised on a staging machine or isolated database, never by pointing an untested dump at production.

A pass/fail restore record

text
Snapshot tested:       2026-10-31T020000Z
Files copied:          1,842 expected / 1,842 restored
Object bytes:          2,516,582,991 expected / 2,516,582,991 restored
Database archive:      pg_restore --list exits 0
Application smoke test: home page and one uploaded file load in isolated environment
Result:                PASS only when every line is true

Run the restore drill after the first backup and after meaningful changes to deployment, uploads or the database. A nightly job can tell you that a command exited zero; only the drill tells you that the backup contains enough data, in a usable format, for the version of the application you need to recover.

Avoid the two destructive rclone mistakes

Use rclone copy for a snapshot: it adds or updates destination objects but does not remove destination-only objects. rclone sync makes the destination match the source and can delete old destination objects; it is useful for a mirrored deployment, not as the first version of a retention backup. Likewise, do not put --delete-excluded or a broad purge command in a backup job without rehearsing its exact target against a disposable prefix.

Once the restore routine is written, you can also use rclone for a one-off migration. Read our S3-compatible client guide to configure AWS CLI, boto3 or s3cmd against the same endpoint, then use rclone check before changing a production application’s destination.

Set up a bucket for your site backups, then start with the small read/write/delete test.

Open tport.space

Sources

rclone, Amazon S3 backend documentation (configuration, compatible S3 providers, checksums and S3 backend options), consulted 31 October 2026.
rclone, copy command documentation (copy behaviour and destination-only files), consulted 31 October 2026.
rclone, sync command documentation (destination matching and delete risk), consulted 31 October 2026.
PostgreSQL, pg_dump documentation and pg_restore documentation (logical backup formats and archive inspection), consulted 31 October 2026.