Skip to content
Admin portal → Settings → Backup/admin/backup3 minCannot be undone

Backup and restore ​

Operator page

Developers and owners only. Restoring replaces everything. There is no undo.

The backup and restore screen
Export on the left, restore on the right.
The backup and restore screen

Click anywhere, or press Esc, to close.

Export ​

Press Download backup. You get a single file containing the whole production database. It is the same file whichever environment the console is showing.

When the server has a backup key, the button says Download encrypted backup (.dump.age) and the card names the key (age1…). That file opens only with the owner's private key, on their own computer. Without a key the card warns in red that copies leave the server unencrypted.

Keep the encryption key with the backup

Stored Stripe and Mailchimp keys inside the backup are encrypted. Without the application's encryption key the backup restores, but every connection in it is unreadable. The key is not in the file.

Restore ​

The restore card
If the database is not empty you must type REPLACE to continue.
The restore card

Click anywhere, or press Esc, to close.

Choose the file and press restore. It takes the plain .dump. An encrypted (.age) or zipped (.gz) copy is refused with the step that is missing: open it on your own computer first, as below. If the database already has data, FMS refuses and asks you to type REPLACE in full. That is the last thing standing between you and losing everything currently in the system.

A restore always replaces the production database. The card counts production's members, whichever environment is active. While a sandbox is active the card says so and the restore is refused with "Switch to production before restoring". Switch on Settings → Sandboxes first.

What comes back, and what does not ​

A restore brings back every member, plan, team and connection as the backup holds them. It also brings back the staff accounts, passwords, two-step set-ups and service keys of that day.

Changes to sign-ins made after the backup are put back by FMS straight after the restore:

Made after the backupAfter the restore
A colleague switched offStill switched off
A password changed, or a temporary password setThe newer password
Sign out my other sessionsThose sessions stay signed out
Two-step sign-in reset, or a new phoneThe newer set-up
A recovery code used, or a new set madeStill used, or the new set
A service key revoked, or a website switched offStill refused

FMS never switches off the last owner who can sign in. If the backup would leave nobody else, that owner stays on and is signed out everywhere. The success message names them. Check them on Settings → Staff.

A brand-new server starts without that record

Restoring onto a new server brings the backup's sign-ins back unchanged. Switch off colleagues and revoke keys again by hand if you did so after the backup.

A restore also ends every Claude connection the backup carried, so one that was ended since cannot come back. Colleagues who use Claude with FMS press Connect in Claude and sign in again (Connect Claude to FMS). The success message says any Claude connections in the backup were ended.

Two things can go wrong after the data is back, and they are reported apart. If FMS could not end the Claude connections, the restore shows an error: ask the technical team before you let anyone use Claude. If only the read-only access Claude uses could not be set up again, the restore succeeds and shows a warning: "Claude cannot read FMS until … run ops/ai-reader.sql or restart FMS". Nothing else is affected. Pass the warning to the technical team.

Off-site copies (Cloudflare R2) ​

The middle card sends a copy of the database to a Cloudflare R2 bucket every night and keeps the newest 7 daily and 12 weekly copies. You need four things from the Cloudflare dashboard: the account ID, the bucket name, and an API token's access key ID and secret (scoped to that bucket, Object Read & Write).

  1. Enter the four values and press **Connect bucket**. FMS checks them with Cloudflare first; a wrong token is refused and nothing is stored.
  2. Press **Upload snapshot now** once. The card shows the file name that landed and when.
  3. Leave it. Every night at the hour shown (03:00 UTC unless you change it) a new copy goes up. **Health** raises an alert if a night is missed.

Test connection lists what is in the bucket. Edit lets you change the schedule or rotate the token — leave the secret blank to keep the stored one. Remove forgets the target; nothing in the bucket is deleted.

One uploader per bucket

If the server's .env also has R2_* values for the separate backup container, blank them. Two uploaders pruning the same folder keep fewer copies than you think. Health turns the Off-site backup row amber while both are set.

If no target is set at all

On the live console, Health shows Off-site backup in amber with not configured. The only copies are then on the same server as the database. Connect a bucket here to clear it.

A custom endpoint must start with https://

The live console refuses an http:// endpoint. The upload holds every member's record. Plain http:// is only allowed on a test machine, or for a store on the server itself (localhost), where nothing crosses a network.

Encrypted copies ​

Every copy that leaves the server, the nightly R2 upload, the download and the separate backup container, is encrypted to a key pair the owner makes once. The server holds only the public half. Someone who takes over the server cannot read the copies, and nobody can restore one without the private half.

  1. On your own computer, install age and run age-keygen -o fms-backup-key.txt. It prints a line starting Public key: age1.
  2. Save fms-backup-key.txt in the password manager, and one copy offline. Tell a second person where it is.
  3. Whoever runs the server puts the public key in .env as BACKUP_AGE_RECIPIENT and restarts FMS.
  4. This page then names the key, and the download button says encrypted.

Lose the private key, lose the backups

An encrypted copy cannot be opened without fms-backup-key.txt. FMS never sees that file and cannot make a new one for old copies. Never put it on the server.

To open a copy before a restore, on your own computer:

bash
age -d -i fms-backup-key.txt frontier-backup-<date>.dump.age > backup.dump
age -d -i fms-backup-key.txt fms-<date>.dump.gz.age | gunzip > backup.dump   # from R2

Then upload backup.dump here. The server's restore script opens it by itself with --identity fms-backup-key.txt.

Test that a restore works ​

Do this every three months, and after any change to the backup set-up. It proves the newest copy can be fetched, that the private key opens it, and that it restores with the same contents. It never touches the live database: it restores into a scratch database and deletes it afterwards. Whoever runs the server follows §5.1 Restore drill in ops/RUNBOOK.md; the owner brings the private key file.

The retention rules are written up in ops/RUNBOOK.md §4.

Internal staff guide. Screenshots come from the rehearsal rig and never show real members. Project status (for developers and admins).