Creating an instance
Creating an instance is one request: you describe the instance, its certificate and its first database, and the server then builds it - an image, a container, an nginx site and a certificate - and creates the database once the instance is installed.
In the console
Instances > New opens the New instance wizard. It has five tabs - Basics, Database, Certificate, Advanced and Review + create - and every tab is reachable at any time, with Previous, Next, Review + create (Create on the last tab) and Cancel at the top of each tab. The draft lives in the page until you press Create: nothing is created before Create, and Cancel leaves without a trace.
- Basics. Start from - New, Restore from backup or Clone an existing instance
(see Starting from a backup or another instance).
Then the FQDN(s) (comma-separated, the first is the main one; optional, see
Host names and DNS), the Version (the newest offered is preselected),
the Image source and Odoo build,
the Edition, the Role, the Classification and the Description. A new instance
starts on Production on a server and on Development on a
developer workstation. An Enterprise instance asks for a GitHub
token with access to
odoo/enterprisehere, because it cannot be installed without one. - Database. Create and activate a database is on by default: the database is created once
the instance is installed, and the instance serves it. Choose A blank database or Restore an
uploaded Odoo backup (a
.zipas Odoo's database manager writes it, uploaded when you press Create). A blank database takes a Name (derived from the instance when left empty), an Admin login (adminby default) and an Admin password - leave it empty and a strong one is generated and shown once on the database's page - a Country, and Demo data. The country is preselected from your browser's time zone or language, and the wizard says so; change it if it guessed wrong. The country sets up the company, its currency and the time zone. - Certificate. Self-signed or Let's Encrypt. Until you choose, the certificate follows
the Role: Let's Encrypt for Production, Self-signed otherwise. Let's Encrypt uses the http-01
challenge and needs an FQDN that is not a
localhostname; it asks for no e-mail address. The DNS check on this tab says whether every name points at this server and whether ports 80 and 443 answer. Another challenge or a custom certificate is set on the instance's Certificate tab once it exists. - Advanced. Custom modules / add-ons, off by default: switch it on to add git providers with their credentials and workspaces, and enable their repositories as modules. They are added with Create, before the instance is installed, so the installation clones them. The Tuning card sizes the workers from the workload (see Tuning), and the Installation card holds Install now and Start (both on), the Filestore location of a blank database, and Let's Encrypt staging.
- Review + create. The server checks the whole request again every time the tab opens - a malformed FQDN, or one another instance already uses, is caught here rather than after Create. Until every problem is put right, Create waits, and each problem has an Edit button that opens the tab it belongs to. The DNS check runs again here: when a name does not resolve to this server, switch Create anyway on to go ahead (with Let's Encrypt, the instance then falls back to Self-signed until the name points here). The Summary has a copy button for every value and a Copy all, and each line an Edit.
Create instance sends the request. The server queues the creation, then the custom add-ons, the installation and the database, each only once the one before it succeeded, and you follow them on the page and on the Jobs page.
A new instance starts with its backups Disabled and no backup target, so nothing backs it up - not the server-wide schedule either. Once it is installed, give it a target and switch its backups on, as Schedule nightly backups describes.
Starting from a backup or another instance
Restore from backup restores an instance backup archive (.zip) as a new instance: its
configuration, its custom add-ons and every database in it. Restore from backup on the
Instances page opens the wizard on it. Upload the archive from your computer or name one already
on the server; an uploaded archive goes to the server as soon as it is chosen, so the wizard can
fill its tabs in from it, and one that is not restored is removed after a day by the
Staged upload cleanup. The Database tab then offers Keep the
archive's databases. Choose the Environment preset - see Restoring for
what Production keeps.
Clone an existing instance backs up one of this server's instances and restores it as a new one, under names of its own. It is what an instance's Duplicate button opens; see Duplicate and import.
On the command line
The same request, with its certificate and a blank database:
pelmo$ ohm instance create --fqdn fanes.example.com --country BEThe options follow the wizard. Left out, --role is Production on a server and Development on a
workstation, --certificate follows the Role (LetsEncrypt for Production, SelfSigned
otherwise), --fqdn gives the instance a generated name, and --odoo-version is the newest version
offered. The database administrator's login is --admin-login (admin by default); its
password is read from --admin-password-file or a masked prompt with --admin-password-prompt,
never from the command line, and without either one is generated and printed once at the end. An
Enterprise instance reads its GitHub token the same way, with --github-token-file or
--github-token-prompt. --no-database creates no database, --no-install only the
configuration.
The server checks the request first, the same check as the Review tab, and prints every problem per field. Then the command follows the creation, the installation and the database job by job.
Everything after that has a command of its own:
pelmo$ ohm instance install --instance fanespelmo$ ohm instance database init --instance fanes --country BE-i, --instance accepts an id, a name, an HTTP port or a description. Omit it and the CLI shows a
picker rather than guessing. -c, --country is required on database init: it is the two-letter
ISO code Odoo initialises the database's localisation with.
A whole instance can also arrive from elsewhere without the wizard: Import configuration on the
instance list builds one from a configuration exported on another server, and
ohm server manifest apply carries a whole server's worth at once. See
Duplicate and import.
Choosing a version and edition
Antelao hosts Odoo 15.0, 16.0, 17.0, 18.0, 19.0 and 20.0, the newest on PostgreSQL 16 or 17. Both editions are supported, and instances of different versions run side by side against the same PostgreSQL server.
Removing Enterprise addons from an instance is not gated. An unregistered server can always undo an Enterprise install; it just cannot perform one.
When the license stops carrying Odoo Enterprise - an unregistered server does not carry it, so this includes a subscription that ended - every Enterprise instance is switched to the Community edition and its Enterprise add-ons are removed. A database with Enterprise modules installed loses those modules' code. This does not come back by itself: once a license carries Enterprise again, switch the edition back on the instance's Configuration tab. See When the license changes.
Two separate warnings can appear under the version. One says Odoo no longer supports that version: Odoo publishes no more fixes for it, security fixes included. The other says Odoo no longer maintains the Docker image for it: its image is built from the last recipe Odoo published, on a base system Odoo no longer updates. A version can carry either without the other, and neither stops you creating an instance.
Where the image comes from
Every instance runs an image built for it on the server, and the Image source decides what that image starts from:
- Pre-built (Docker Hub) is the default: Odoo's own image from Docker Hub, as Odoo publishes it for the version.
- Built on this server builds the image here from Odoo's own recipe, the same one Odoo publishes its images from. It is how a version Odoo has not published an image for yet is installed at all - Odoo 20.0, for now - and the first build of a version takes several minutes.
When Docker Hub has no image for the chosen version, the wizard says so under the Image source and asks you to choose Built on this server. It never switches the source for you.
A pre-built image has two choices. The Image version chooses which Docker Hub image the instance starts from: Latest follows the newest image Docker Hub publishes for the version, and a date pins one of the dated images Docker Hub publishes. The Odoo build chooses which Odoo runs in it - always a nightly build of the instance's own version from nightly.odoo.com, and never another version:
| Image source | Default | A date |
|---|---|---|
| Pre-built | The image's own build: the Odoo build Odoo put in the Docker Hub image, nothing installed | That build is installed into the Docker Hub image during the build, checked against Odoo's own checksum |
| Built on this server | Newest: the newest nightly build, looked up at each build | Odoo's recipe installs that build |
Installing a build into a pre-built image makes every build of it several minutes longer and the image larger. The build fails if the image ends up with any other Odoo than the one chosen. The instance keeps the choices, so every later rebuild installs the same build; the instance's Docker image card on its Configuration page changes them later.
A pinned Image version is always one Docker Hub publishes. A pin it does not publish - one a restored backup brought along, for example - moves at the instance's next image build to the first later build Docker Hub publishes, never to an older one, and the build's job log says so in a warning naming both builds. When Docker Hub has no later build, the image build is refused: choose Latest and pick that build as the Odoo build to install it into the image, or choose Built on this server.
Host names and DNS
The host names you give the instance are what nginx serves it on, and what a certificate will be requested for. There are two shapes, and which one you choose says what the instance is for.
A name of its own
fanes.example.com, with its own A record pointing at the server. This is what a real instance
gets. The DNS record is a deliberate act: somebody decided this name belongs to this workload, and
the name outlives the server it happens to be on today.
Check it resolves before you install, because a certificate request that fails for DNS looks exactly like one that fails for any other reason:
pelmo$ ohm server config validate-dnsA name under the server's wildcard
test1.pelmo.example.com, where a wildcard record such as *.pelmo.example.com points at the
server. An instance under that wildcard needs no DNS work of its own - the record already exists
and covers every name beneath it.
That is the whole point of it. Standing up a throwaway instance to try an upgrade, reproduce a customer's bug or hand a developer a copy of production is a one-minute job, and waiting on a DNS change would be the slowest part of it. So the wildcard is the fast path, and a name under it is a useful signal to everyone who sees it later: this one was spun up in a hurry and was probably meant to be temporary.
No name at all
Leave FQDN(s) empty and the instance is named after its generated id, under the server's
provisioning domain: with
pelmo.example.com set under Configuration > Network, the instance is named
<id>.pelmo.example.com and is reachable at once through the wildcard. Without a provisioning
domain it is named <id>.localhost, which only the server itself can reach. The wizard's note under
the field shows which one applies.
Adding *.pelmo.example.com alongside the server's own record, and making pelmo.example.com the
provisioning domain, costs nothing and is what makes the fast path available later. See
Install the server.
What installing actually builds
| Step | Result |
|---|---|
| Image | A per-instance Odoo image for the chosen version and Odoo build, from Docker Hub or built here, with the Python packages that version needs |
| Container | ohm-<12 hex>, attached to the managed Docker networks |
| nginx site | A server block for the instance's host names on the shared ohm-nginx container |
| Certificate | A trusted certificate if it can be obtained, otherwise a self-signed one |
| Data tree | The instance's directories under the instance root |
Nothing is shared between instances except PostgreSQL, nginx and the host itself.
Quotas
| Instances | Unregistered | Community | Developer | Professional | Provider |
|---|---|---|---|---|---|
| Limit | 1 | 2 | Unlimited | 5 | Unlimited |
Creating an instance above the limit is refused, and so are a duplicate, an import of an instance backup and a move in from another server; duplicates started side by side count together, so two of them cannot both take the last free place. When a license allows fewer instances than run, those above the limit are stopped - Production kept running first, then Staging, then Development, the oldest first within each - and started again by themselves when a license allows them. See When the license changes.