The bootstrap document
The install asks nothing it does not have to. Everything it is not told it installs with a sensible default, and all of it can be finished in the console afterwards. To decide something in advance instead - the server's name, the mail profile, the addresses that may reach the API - write a bootstrap document before you run the installer.
The document is optional, and so is every key in it: no hostname means the machine's own name, no
registry means anonymous pulls, no smtp or geoip means unconfigured until you reach the
console.
Write it
The file is /etc/antelao/bootstrap.json, and it has to be there before the installer runs:
# On a brand-new server /etc/antelao does not exist yet. The installer creates it later, but this
# file has to be there before the installer runs.
sudo install -d -m 0755 /etc/antelao
sudo tee /etc/antelao/bootstrap.json > /dev/null <<'EOF'
{
"hostname": "pelmo.example.com",
"acceptLicense": true,
// null installs at the unregistered tier; upload the license later under License.
// To have the host born licensed, copy your .lic to the server and name it here. A repair
// never touches a license already on the host.
"licensePath": null,
"geoip": { "maxMindAccountId": "123456", "maxMindLicenseKey": "AbCdEf..." },
"smtp": {
"host": "mail.example.com",
"port": 587,
"username": "notifier@example.com",
"password": "s3cret",
"sender": "odoo@example.com",
"senderName": "Odoo Host Manager",
"to": ["ops@example.com", "admin@example.com"]
},
// null trusts no proxy: every connection's own address is the visitor.
"trustedProxies": null,
// The addresses that may reach the host agent (HTTPS on 5202); its key is the protection. null
// admits this server and the apiAllow addresses below; ["0.0.0.0/0", "::/0"] admits every address.
"agentAllow": null,
// Addresses the management API on 5312 admits beside this server's own network. A fresh
// install closes the API to the outside: name the console that manages this server here.
"apiAllow": null,
// The proxy this server reaches the Internet through, when it has no direct way out.
// null is none. See "The outbound proxy" in the configuration reference.
"outboundProxy": null,
// Instances created without a host name are named <id>.pelmo.example.com. Point the
// wildcard *.pelmo.example.com at this server. Leave the key out for <id>.localhost.
"provisioningDomain": "pelmo.example.com",
// The built-in admin account's password (at least 12 characters) and its two-factor seed
// (base32). Either may be given alone. Leave the section out for a generated password.
"administrator": {
"password": "a-long-passphrase-of-your-own",
"totpSeed": "JBSWY3DPEHPK3PXPJBSWY3DPEHPK3PXP"
}
}
EOF
sudo chmod 0600 /etc/antelao/bootstrap.json
Comments are allowed in the file.
Every key
| Key | What it decides | Left out |
|---|---|---|
hostname | The name the server answers to: the console, the API and the agent, and the name on the management certificate | The machine's own name |
acceptLicense | true accepts the license agreement for this installation on behalf of whoever wrote the file, as --accept-license does. See The license agreement | No acceptance for the installation. Run from a terminal, the installer then shows the agreement and asks |
licensePath | A *.lic file already on this server, placed during the install | The unregistered tier, until you install a license under License |
registry | url, username and password of a self-hosted registry that needs a credential. Give both the user name and the password, or neither | Anonymous pulls: the product's own images need no credential |
geoip | maxMindAccountId and maxMindLicenseKey: the MaxMind account the GeoIP service downloads the GeoLite2 databases with, which location rules match against | No GeoIP account until you add one under Security > GeoIP |
smtp | The mail profile: host, port, username, password, sender, senderName, the recipient lists to, cc and bcc, and fromFilter, the sender addresses allowed. Saved enabled, and the Postfix relay comes up with it | No mail profile |
outboundProxy | url, and optionally username, password and a noProxy list. See The outbound proxy | No proxy |
trustedProxies | The exact addresses of a reverse proxy or load balancer in front of nginx | No proxy is trusted |
agentAllow | The addresses or ranges that may reach the host agent on 5202. The loopback address is always admitted | With no apiAllow either, every address, the agent's key being the protection. With apiAllow, this server and those addresses |
apiAllow | The addresses or ranges the management API admits beside this server's own network: the console that manages this server, and your own address if you administer it remotely. See First, let your address in | The API answers this server and the private ranges only |
provisioningDomain | The domain instances created without a host name of their own are named under. See The provisioning domain | Such instances are named under localhost |
administrator | password and totpSeed of the built-in admin account. See The administrator's credentials | A generated password, and two-factor left to the person |
workstation | true makes this machine a developer workstation, as ohm install --workstation does | An ordinary server |
workstationUser | On a workstation, the developer's own account | The account that ran sudo |
allowUnencryptedDisk | On a workstation, true goes ahead on a disk the installer cannot prove is encrypted | An unencrypted disk is a refusal |
ide | On a workstation, the editor new profiles default to: vscode, pycharm or both | vscode |
A provisioning console or an Odoo Management Plane that writes the document
for a server it sets up adds keys of its own (provisionedBy, acceptedBy, managedBy). Leave
those to the tool that writes them.
Set it only when a reverse proxy or load balancer stands in front of nginx, and list exactly its
addresses - ["10.0.0.8"], never ["10.0.0.0/8"]. A whole range lets anything inside it, the
instance containers included, forge visitor addresses to the firewall, the bans and the logs.
null is right for a server that is its own edge. Editable later under
Configuration > Network edge.
It is checked before anything is installed
The file is validated before anything is installed. An unknown key, a bad value or malformed JSON stops the installer with every problem named at once, and nothing on the host is touched. A misspelt key is therefore a refusal you see straight away, not a setting that is quietly ignored.
Its secrets are stored encrypted during the install, and the whole file is overwritten and then deleted once the install succeeds. A later repair ignores it entirely - by then the server's own settings are authoritative, and a stale file must never reshape or block anything.
Environment variables (ANTELAO_INSTALL_*) override the file for one run.
The license agreement
The installer asks one question at most, and it is this one. Run from a terminal, it shows the
license agreement and asks you to accept it before it changes anything on the host; a no stops
it and leaves the host as it was. "acceptLicense": true answers the question in advance, as do
--accept-license and ANTELAO_INSTALL_ACCEPT_LICENSE=yes, and the acceptance is recorded for the
installation.
With no terminal and no answer - a cloud-init run, a machine image's first boot - the installer asks nothing and goes ahead without an acceptance for the installation, and says so.
Either way, the console still asks every person to accept the agreement the first time they sign
in, and again whenever a release carries a new version. acceptLicense does not answer that for
anyone. See Sign in and finish the setup.
The outbound proxy
An outboundProxy section (url, and optionally username, password and a noProxy list) is
saved and applied with the rest, so the server sends its Internet traffic through that proxy from
its first minute:
"outboundProxy": {
"url": "http://proxy.example.com:3128",
"username": "ohm",
"password": "s3cret",
"noProxy": ["intranet.example.com", "10.0.0.0/8"]
}
The package and the first images are downloaded before the server can apply it. On a host with no direct way out, give the package manager and Docker the proxy before you run the installer - see Installing behind a proxy.
The provisioning domain
provisioningDomain is the server's
provisioning domain: an instance created
without a host name of its own is named <id>.pelmo.example.com instead of <id>.localhost. The
installer's --provisioning-domain option and ANTELAO_INSTALL_PROVISIONING_DOMAIN set it too.
Cloudflare Turnstile
ANTELAO_INSTALL_TURNSTILE_SITE_KEY and ANTELAO_INSTALL_TURNSTILE_SECRET_KEY, both together, switch
on the console's Cloudflare Turnstile at install. They are read from the
environment only; the document has no key for them.
The administrator's credentials
By default the install creates the built-in admin account with a generated password, printed once
in the hand-off. To have the server start with credentials you already hold - a provisioned server
above all - give them in the bootstrap document's administrator section:
password, at least 12 characters, is set as the account's password.totpSeed, a base32 two-factor seed of at least 16 bytes (26 characters), switches two-factor on and makes it required, so the account cannot go on without a second factor. Load the same seed into your authenticator app.
Either may be given alone: a seed alone keeps the generated password, and a password alone leaves
two-factor to the person. A document with an administrator section must be readable by root
only - the chmod 0600 above - or the installer refuses it before anything is installed.
ohm install can read them from files instead, which keeps them out of the document altogether:
sudo ohm install --admin-password-file /root/admin-password --admin-totp-file /root/admin-totp
Each file holds the value on its first line and must be readable by its owner only (chmod 600);
a file that is missing, empty, readable by others or holding an unusable value stops the installer
with the file named, and nothing is installed. The files win over the document. The one-line
installer passes no options, so give these to ohm install itself, on a host where the
antelao-ohm package is installed. Unlike the document, they work on a
repair too: --admin-password-file sets a new password on the
existing account, and --admin-totp-file sets a new seed and requires two-factor.
Neither value is ever printed, logged or written into the audit trail; the audit entry says only where each came from. The hand-off then shows where the password came from instead of the password, and says two-factor is on and required when a seed was given.
Provisioning many servers
The bootstrap document is the same file a remote provisioner writes before running the one-line
installer, so setting up a fleet is the ordinary install, repeated. Write the document, run the
installer, and the host comes up configured - narrowed agent included, if you set agentAllow, its
API open to the console that manages it, if you set apiAllow, its instances named under
provisioningDomain, and with an administrator section, signed in with credentials you already
hold and two-factor required from the first minute.