Restoring
There are three kinds of restore, and they differ in what they replace:
| Restore | What it replaces | Where |
|---|---|---|
| As a new instance | Nothing: the archive becomes an instance of its own | Restore from backup in the New instance wizard, ohm instance import |
| Over an existing instance | That instance's databases, filestore and add-ons | The instance's Restore tab, ohm instance restore |
| A database | Nothing, when it is restored under a new name | ohm instance database restore |
When in doubt, restore beside what you have rather than over it: a new instance, or a database under a new name. Then the original is still there if the restored copy turns out to be wrong.
Restoring an instance
As a new instance
Restoring an instance backup archive as a new instance is a start of the New instance wizard: Restore from backup on the Instances page opens it, or choose Restore from backup under Start from on its Basics tab. Upload the archive from your computer or use one already on the server, and the wizard fills its tabs in from what the archive holds - the version, the edition, the names and the databases, which the Database tab offers to keep. An encrypted archive cannot be looked into before it is restored, so its tabs are yours to fill in.
The Environment preset decides the copy's identity. Production keeps the original instance and database identity; every other preset issues new ones and switches off what would let the copy act as the original (see What a preset other than Production switches off). A Production restore asks whether to keep the backup's database GUID or create a new one, and needs I understand the consequences of restoring with the Production preset switched on: if the source installation is still running anywhere, two systems reporting the same database GUID to Odoo is how an Odoo Enterprise license gets revoked. Keep the GUID only when the restore replaces the source, as in a move to another server.
With Test or Staging, Automatic git updates starts off; switch it on in the wizard if the
restored instance should follow its branch heads by itself. Restore instance on the Review tab
queues the restore. ohm instance import is the same restore from the command line, with
--git-auto-update for the switch:
pelmo$ ohm instance import --archive instance-backup-fanes.zip --preset stagingOn a server whose license does not carry restoring, Restore from backup and Clone an existing instance are disabled, with the edition named, and an upload is refused before it starts.
What a preset other than Production switches off
A copy restored, cloned or imported with Development, Test, Staging or Disaster
recovery (dr on the command line) is changed in every database before it runs, so that it
cannot send mail, charge customers or talk to the outside world as the original would:
- incoming and outgoing mail servers are switched off;
- every scheduled action is switched off;
- PrintNode, SMS, WhatsApp, Ponto, in-app purchases, Peppol and VoIP are switched off;
- on websites, search engines are told not to index (
robots.txt), the CDN is switched off and webhooks are disabled; - Cloudflare Turnstile is switched off by parking its keys;
- the database's Odoo subscription details are reset, so the copy is not counted as the original;
- a banner and a ribbon name the environment (DEVELOPMENT, TEST, STAGING or DR) on every page.
The copy also gets an instance id, a database GUID and an Odoo master password of its own, and its own backups start Disabled. A database cloned with one of these presets also goes through Odoo's own neutralisation, from Odoo 16.0 on. Production changes none of this and keeps the original's identity.
Restore over an existing instance
Restoring into an instance that already exists stops it and replaces its databases and filestore
with the archive's, and its Odoo version, edition, git setup and modules with the ones the archive
records. Whatever was written to the instance since that archive is gone. The archive and restore-source forms of ohm instance restore ask for no
confirmation. Take a backup of the instance first: it is the only way back.
The instance keeps its own id, its names and its own backup configuration. Restoring over an instance is refused while its restore Mode is Disabled, which is where a new Production instance starts: that mode is the latch that stops a restore landing on a production instance by mistake.
What it restores from:
| Command | Restores from |
|---|---|
ohm instance restore --instance fanes --archive <path> | An instance backup archive already on the server, in its backup directory |
ohm instance restore --instance fanes | Every enabled restore source on the instance's Restore tab, in turn: an Instance source first, then the storage providers, each restoring over the one before |
ohm instance restore --instance fanes --from-instance <id> | A fresh backup of another instance on this server. The source is not stopped or changed. Asks for confirmation unless --yes is given |
... with --from-server <environment> | The same, from an instance on another server registered as an environment. Needs the management API, so it runs over a connection |
With --from-instance, three options shape the copy:
--database-filterrestores only the source's databases whose names match a regular expression, for example--database-filter '^fanes$'. All of them by default.--copy-from LatestLocalBackupuses the source's newest backup on this server instead of taking a fresh one (FreshBackup, the default).--max-age-dayssays how old it may be, and--fallbackwhat happens when none is recent enough: take a fresh backup (FreshBackup, the default) or fail without touching the instance (Fail).
To restore over an instance:
-
Back the instance up, and wait for the job to succeed:
Remote or localagainstpelmo$ ohm instance backup --instance fanes -
Open the latch. Set the restore Mode to Manual on the instance's Restore tab, or:
Remote or localagainstpelmo$ ohm instance restore-config set --instance fanes --mode Manual -
Restore, from an archive or from another instance:
Remote or localagainstpelmo$ ohm instance restore --instance fanes --archive /var/lib/odoo/backup/7db76c35291f/instance-backup-fanes-20261011-020000.zipRemote or localagainstpelmo$ ohm instance restore --instance tissi --from-instance 7db76c35291f --database-filter '^fanes$' -
Check the instance: sign in to Odoo, open recent records and attachments, and run Check now on its Health tab.
-
Close the latch again for a production instance:
Remote or localagainstpelmo$ ohm instance restore-config set --instance fanes --mode Disabled
The way back is the backup from step 1, restored over the instance the same way.
What an Operator may restore from
A restore or a database load from a file on the server, started by an Operator or by an API key limited to some instances, reads only:
- that instance's own backups, in its backup folder, and its own files;
- an archive the same person, or the same key, uploaded for it.
Another instance's backups, the server's database dumps and every other shared folder are refused, and the instance is not touched. An Administrator, and a key that covers every instance, restore from anywhere on the server. An Operator who restored from an archive in a shared folder before 0.24.0 now has an Administrator restore it, or copies it into the instance's backup folder first.
Restoring from another instance (--from-instance, and an Instance source on the Restore
tab) is held to the instances the Operator is assigned, and to a key's own instances: a source on
this server outside them is answered as an instance that does not exist. An Instance source an Operator saved before 0.24.0 for an instance outside
their assignment stays in that instance's restore configuration until the next save, which refuses
it, so an Administrator should review the Instance sources on each instance's Restore tab.
What a restored instance brings with it
A restore or an import keeps the archive's own provider configurations - the storage hosts, the policy identifiers the backup sets are keyed on, and the credentials where the archive carries them in transport form. The exception is managed backup storage, and a restore into an instance that already exists keeps that instance's own backup configuration and takes none from the archive.
Applying an environment preset afterwards seeds its default providers; it does not replace imported ones wholesale. Replacing them would discard hostnames and re-mint the policy identifiers the storage side is keyed on, orphaning the very backup sets the restore was meant to inherit.
Managed backup storage stays with its instance
A target that Backup storage or an Odoo Management Plane bound to an instance (Managed by on the Backup tab) belongs to that instance, where it was bound. An instance that arrives from an archive keeps it only when both of these hold:
- the instance that arrives is the instance the target was bound to, restored or moved under its own identity; and
- the binding lives on this server: this server's Backup storage holds the container and has it assigned to this instance, or, for a target the Odoo Management Plane bound, the archive was written on this server.
Every other managed target is left out, and the job's result names each one: a copy, a duplicate and an import of another server's archive never back up into the source's container. Give the copy a container of its own with Make and bind under Managed storage on its Backup tab. Targets you typed yourself - local, FTP, Azure Blob and S3 - travel with the archive.
The certificate comes back with it
An instance backup carries the instance's certificate (see What a backup contains). Before the restore asks for a certificate, it puts the carried one back when all of these hold:
- it is valid for the names the restored instance answers on, and more than 30 days from expiry;
- it belongs to the instance's certificate mode, and in Let's Encrypt mode it was issued by Let's Encrypt;
- a self-signed one was issued by this server's own authority; one from another server's authority is issued again here, which costs nothing;
- its private key can be read: the archive was encrypted or written with portable credentials, or it is restored on the server that wrote it.
Then nothing is requested while it is valid - no new Let's Encrypt certificate, and no gap in HTTPS while DNS still points at the old server during a move - and the usual renewal replaces it when it is due. A certificate the instance already serves that lasts at least as long is kept. In every other case the restore requests a certificate as usual, and so does an archive that carries none.
Uploading an archive reports which of its credentials this server could not read, because they were protected under the key ring of the server that wrote them. That warning stays on screen past the job's verdict, so it is still there when you go looking for what to re-enter.
Restore configuration, like backup configuration, is per instance:
pelmo$ ohm instance restore-config show --instance fanespelmo$ ohm instance restore-config set --instance fanesRestoring a database
A database restore brings one database back from a database backup into an instance. The safe pattern for production is to restore alongside rather than over: restore under a new database name, check it, then switch the instance's active database to it. The instance serves only its active database, so the restored one waits unseen beside it until you activate it.
ohm instance database restore needs two options:
-a, --archive- the database backup, by its path on the server;-p, --preset- the environment preset the restored database is set up for:dev,test,staging,drorprod. Everything butprodswitches off what a preset other than Production switches off. Useprodfor a database that will replace the production one, anddrfor a standby copy that must not send mail or run scheduled actions until you decide it should.
And three that decide what comes back:
-n, --name- the name to restore under. Left out, the name from the archive is used, which is the live database's own name: give a new one to restore alongside.--restore-filestore- restores the database's filestore (its attachments) from the archive as well. Without it the filestore is not restored, and the restored database has no attachments.--keep-guid- keeps the database GUID from the backup instead of making a new one. Keep it when the restored database replaces the live one; leave it out for a copy that runs beside it.
-o, --overwrite replaces a database of the same name. Do not use it on the live database: restore
alongside instead.
To bring the production database back from a backup:
-
Back the live database up, so the state you are replacing can be had again:
Remote or localagainstpelmo$ ohm instance database backup --instance fanes --database fanes -
Restore alongside, under a new name, with its filestore:
Remote or localagainstpelmo$ ohm instance database restore --instance fanes --archive /var/lib/odoo/backup/7db76c35291f/fanes-20261011-020000.zip --name fanes_restored --preset prod --restore-filestore --keep-guid -
Check it before anybody uses it: it is listed beside the live one, and its size should be close to the live database's.
Remote or localagainstpelmo$ ohm instance database list --instance fanesRemote or localagainstpelmo$ ohm instance database size --instance fanes --database fanes_restored -
Activate it. From now on the instance serves the restored database:
Remote or localagainstpelmo$ ohm instance database activate --instance fanes --database fanes_restored -
Check it in Odoo: sign in, open the records you restored for and a few attachments.
The way back is the previous database, which is still there: activate it again with
ohm instance database activate --instance fanes --database fanes. Remove it only once the restored
one has proved itself, as Managing databases describes.
Restore sources
You can restore from any target that is configured for the instance, and from a file you supply.
A restore source the license does not carry is switched off with its backup target, and archives held there cannot be listed or fetched from here until a license carries it again. Local sources still are, and a backup file you hand over directly always works where restoring is licensed. If your only copy is in S3 and your license no longer carries S3, fetch the file with your own S3 client and restore it as a local file. See When the license changes.
Being told how it went
An instance's Restore tab can e-mail a report when a restore of that instance finishes, the same way its Backup tab does for a backup: a switch, the To, Cc and Bcc boxes with the server SMTP profile's own recipients listed under each, a check button per box, and a Minimum outcome. A restore either completes or fails, so the minimum is Info (every restore) or Error (only a restore that failed). It is off until you switch it on.
One restore sends one report, whatever it is made of: a restore from the instance's restore sources reads several of them in turn and still mails once. Every kind of restore reports - from an archive, from a provider's listing, from another instance, and the scheduled restore. A cancelled restore sends nothing.
Sending needs a working SMTP profile. Every restore is also an alert event - Restore completed or Restore failed - so it can go to a channel instead of, or as well as, this mail.
Large archives download without staging
An archive held by an FTP, S3 or Azure provider streams straight to your browser. A multi-gigabyte download therefore needs no free disk space on the server.
A provider that stops sending for two minutes fails the download rather than holding it open for ever.
Every database a restore may target is listed
Restore from a dump lists every database the restore could land on, the instances' own included, each named with its instance.
The analytics database is a system database, like master and
postgres: it carries the system badge, cannot be restored over, and has no delete action anywhere,
down to the host agent.
A disaster-recovery drill
A backup you have never restored is untested. Restore one once a quarter, the way you would after losing the server: from the copy that left the server, onto a server that is not the one it came from, as a new instance beside nothing it could disturb.
- Pick the archive. On the production instance's Backup tab, note the newest archive at your off-site target - FTP, S3, Azure or a managed container - by its name and date. Download it from there, not from the server's own disk: the drill is about the copy that survives the server. An encrypted archive needs the server's key file on the drill server (see Backup encryption).
- Restore it as a new instance on a second server, or on the same server when you have no other: Restore from backup on the Instances page, upload the archive and choose the Test preset. Never Production for a drill: Test gives the copy an identity of its own and switches off its mail and scheduled actions, so it cannot act as the original. Leave FQDN(s) empty or use a name under the server's wildcard; leave Automatic git updates off.
- Wait for the restore to succeed on the Jobs page, and read its result: it names any credential it could not read and any managed target it left out.
- Check what you would miss: sign in to Odoo and open recent invoices, recent attachments and the newest records you know were made before the archive's date.
- Write down the archive's date, how long the download and the restore took, and anything you had to put right. That time is what a real recovery costs.
- Remove the drill instance as Running and removing instances describes.
It catches what nothing else does: a backup that has been skipping its off-site target for months, an archive that does not open without a key nobody kept, and a filestore that is not in the backup you assumed covered it.
Rolling back a version upgrade
Roll back on the Updates page takes Antelao back one release when the update did not change the master database's schema. After a schema change it needs the master database from before the update. See Rolling back.