Backing up and restoring Rhinvoice
Rhinvoice backs up its whole database with restic: encrypted, deduplicated and compressed, daily and shortly after every issued or cancelled document, to a target you choose (S3, SFTP, Dropbox, Google Drive or a folder). The database holds everything: customers, articles, documents, the archived PDFs of issued documents, the logo and the settings.
When and how long
Section titled “When and how long”- When: daily (02:00 by default,
BACKUP_DAILY_AT) and about two minutes after documents were issued or cancelled (several in a row give one backup). Settings → Backup → Back up now asks for one at once. - Kept: 7 daily, 4 weekly, 12 monthly and every yearly backup. Invoices must be kept for ten years (Art. 958f CO, GoBD, BAO); yearly backups are never deleted. Old backups are removed on Sundays, when a sample of 5 % of the data is also verified.
- Not backed up: an installation without company data (a fresh one). Its empty database must never become the latest backup.
- Shown: the overview warns when the last successful backup is older than 24 hours or backups are not set up. Settings → Backup lists the last backups.
Setting it up
Section titled “Setting it up”Choose a target and write it to .env (next to compose.yml), then restart with docker compose up -d.
RESTIC_PASSWORD='a-long-random-password' # encrypts the backupsRESTIC_REPOSITORY=... # see belowWithout RESTIC_PASSWORD, nobody can restore the backups, not even you. Keep it in a password manager or printed in a safe. Create it with openssl rand -hex 32, or put it in single quotes: Docker Compose would otherwise change a $ in it.
S3-compatible storage
Section titled “S3-compatible storage”Backblaze B2, Infomaniak Swiss Backup, AWS, Wasabi and others:
RESTIC_REPOSITORY=s3:https://s3.eu-central-003.backblazeb2.com/my-bucket/rhinvoiceAWS_ACCESS_KEY_ID=...AWS_SECRET_ACCESS_KEY=...Use a key that may only access this bucket.
SFTP (NAS, server)
Section titled “SFTP (NAS, server)”RESTIC_REPOSITORY=sftp:backup@nas.example:/backups/rhinvoiceThe container needs the SSH key and the server’s host key (known_hosts). Mount them, e.g. in a compose.override.yml:
services: backup: volumes: - ./ssh:/home/backup/.ssh:ro # id_ed25519 and known_hostsssh-keyscan nas.example > ssh/known_hostssudo chown -R 10001 ssh && chmod 700 ssh && chmod 600 ssh/id_ed25519 # the container's userDropbox, Google Drive and other cloud storage
Section titled “Dropbox, Google Drive and other cloud storage”restic reaches them through rclone, which is part of the backup container. The first backup holds every archived PDF; later ones add only what changed, usually a few kilobytes.
-
Allow access, once, on a computer with a web browser (it does not need to be the server): install rclone 1.75 or newer (rclone.org/downloads, on a Mac
brew install rclone) and runTerminal window rclone authorize "dropbox"Log in to Dropbox in the browser that opens and allow access. The terminal then prints a token: one line starting with
{"access_token":. -
Hand the token to the backup container, on the server, in the Rhinvoice folder.
readkeeps the token out of the screen and the shell history:Terminal window read -rs TOKEN # paste the token, press Enterdocker compose run --rm --no-deps backup rclone config create dropbox dropbox \config_refresh_token false token "$TOKEN"unset TOKENThe configuration is kept, unencrypted, in the volume
backup-rclone; rclone renews the access there by itself. -
Choose the folder in
.envand restart (docker compose up -d):RESTIC_REPOSITORY=rclone:dropbox:Rhinvoice-Backup -
Try it:
docker compose exec backup rhinvoice-backup backup. The folderRhinvoice-Backupappears in your Dropbox; Settings → Backup shows the backup.
rclone’s own Dropbox app may access your whole Dropbox. For access to one folder only, create your own Dropbox app with “App folder” access (rclone.org/dropbox) and add its client_id and client_secret to both commands.
Google Drive works the same. Ask only for access to the files rclone creates itself (the scope must be chosen when authorizing):
rclone authorize "drive" --drive-scope drive.fileread -rs TOKENdocker compose run --rm --no-deps backup rclone config create gdrive drive \ scope drive.file config_refresh_token false token "$TOKEN"unset TOKENand RESTIC_REPOSITORY=rclone:gdrive:Rhinvoice-Backup.
For other providers (OneDrive, kDrive and other WebDAV storage) run docker compose run --rm --no-deps backup rclone config, answer “No” when asked whether to use a web browser automatically and follow the rclone documentation of the provider. Name the remote as you like and use it in RESTIC_REPOSITORY=rclone:<name>:<folder>.
A folder of this machine
Section titled “A folder of this machine”An iCloud or Nextcloud folder, the Dropbox app’s folder or a USB disk:
RESTIC_REPOSITORY=/repositoryBACKUP_LOCAL_DIR=/Users/me/Library/Mobile Documents/com~apple~CloudDocs/Rhinvoice-BackupThe container writes as user 10001; on Linux make the folder writable for it (sudo chown 10001 /path/to/folder). Without BACKUP_LOCAL_DIR the backups land in a Docker volume on the same disk: that protects against mistakes, not against a broken disk.
Checking
Section titled “Checking”docker compose logs backup # what the container doesdocker compose exec backup rhinvoice-backup snapshots # list the backupsdocker compose exec backup rhinvoice-backup check # verify the repositorydocker compose exec backup rhinvoice-backup backup # back up nowdocker compose exec backup rhinvoice-backup rclone lsd dropbox: # an rclone target is reachableRestoring
Section titled “Restoring”Restoring replaces the whole database with the state of a backup. It runs in one transaction: if anything fails, nothing changes.
docker compose exec backup rhinvoice-backup snapshots # pick a snapshot IDdocker compose stop app backupdocker compose run --rm --no-deps backup restore latest # or the ID, e.g. 52365e00docker compose start app backupFrom the source folder: make restore SNAPSHOT=latest.
On a new machine: install Rhinvoice as in Installation with the same RESTIC_REPOSITORY and RESTIC_PASSWORD. Start only the database first (docker compose up -d db), then restore as above and start everything (docker compose up -d).
Try a restore once after setting up, e.g. with a second installation next to the first (several installations on one computer). Give it the same RESTIC_REPOSITORY and RESTIC_PASSWORD only for restoring, and do not run its backup container with them (docker compose stop backup): two installations backing up to one repository would mix their backups. If you really want that, give each its own BACKUP_HOST.
Questions
Section titled “Questions”How often does Rhinvoice back up?
Daily, at 02:00 by default, and about two minutes after documents were issued or cancelled. Settings, Backup, Back up now asks for one at once.
How long are backups kept?
7 daily, 4 weekly, 12 monthly and every yearly backup. Yearly backups are never deleted, because invoices must be kept for ten years.
Can Rhinvoice back up to Dropbox or Google Drive?
Yes, through rclone, which is part of the backup container. The backups are encrypted before they leave the machine, so the cloud provider only stores unreadable blocks.
What happens if I lose the backup password?
Then nobody can restore the backups, not even you. Keep RESTIC_PASSWORD somewhere else too, for example in a password manager or printed in a safe.