Hetzner Cloud
Hetzner Cloud has no marketplace listing for the Odoo Host Manager and no way to import a disk image. The simple route needs neither: create a server from Hetzner's own Debian 13 image and paste a Cloud config that runs the one-line installer on its first boot. Nothing to download, nothing to upload, and the server is ready about 10 minutes after you create it.
The ready-made image can be brought to Hetzner too, as a snapshot made with a community tool. That route is described below for those who want it, but it needs a Linux machine, a larger server type and two workarounds, and it ends in the same server.
Before you start
- A Hetzner Cloud project in which you may create servers and firewalls.
- A server type with 2 vCPU, 4 GB of memory and 40 GB of disk or more, as Hardware describes: CX23 or larger. Choose an x86 (Intel/AMD) type. The Arm types (CAX) cannot run the product, and the installer refuses them.
- Your SSH public key, added to the project under Security > SSH keys, or added while you create the server.
- A DNS name you can point at the server's public address later, for publicly trusted certificates on your Odoo instances. Optional at this point.
The Cloud config
This is the whole of it. Copy it as it is:
#cloud-config
# Antelao Odoo Host Manager: install on the first boot of a stock Debian 13 server.
# The administrator's first password goes to /root/antelao-ohm-handoff.json (root only),
# never to the cloud-init log.
package_update: true
package_upgrade: true
runcmd:
- curl -fsSL https://packages.antelao.io/raw/antelao-ohm-installer.sh | ANTELAO_INSTALL_RESULT=/root/antelao-ohm-handoff.json ANTELAO_INSTALL_NO_REGISTRATION_KEY=yes bash
- The first line must be exactly
#cloud-config. package_updateandpackage_upgradebring Debian up to date before the install.ANTELAO_INSTALL_RESULTwrites the hand-off - the console's address, the useradminand its generated password - to/root/antelao-ohm-handoff.json, readable by root only, instead of printing it. The cloud-init log,/var/log/cloud-init-output.log, then says the hand-off was written to that file and carries no password.ANTELAO_INSTALL_NO_REGISTRATION_KEY=yesleaves out the registration key. Writing the hand-off to a file otherwise also issues an API key, the registration key, for a console that registers the new server as an environment; with nobody to collect it, it would only be a credential lying in a file. A ready-made image's first boot leaves it out too.
Without the two variables the install still works, but the password is then shown nowhere and you
set a new one on the server with sudo ohm user password-reset admin.
To decide things up front - the server's DNS name, the mail profile, the provisioning domain - add
a write_files entry that writes the
bootstrap document
to /etc/antelao/bootstrap.json with permissions: '0600', as
Microsoft Azure shows. Hetzner keeps the
Cloud config with the server, so leave passwords out of it unless that is acceptable.
Create the firewall
Once per project. In the Hetzner Console, open your project:
- In the left menu, Firewalls > Create Firewall.
- Name:
odoo-host-manager. - Inbound rules: TCP 22, TCP 80 and TCP 443, each from Any IPv4 and Any IPv6. ICMP is optional. Add nothing for 5322 or the other management ports.
- Outbound rules: leave them empty, which allows everything out.
- Create Firewall.
This firewall is what keeps the management ports closed. The console (5322), the API (5312) and the agent (5202) listen on every address of the server, as the installation page warns, so do not create the server without it.
Create the server
- Servers > Add Server.
- Location: Falkenstein, Nuremberg or Helsinki. The CX types are offered in Hetzner's European locations only.
- Image: OS Images > Debian > 13.
- Type: Shared vCPU > x86 (Intel/AMD) > CX23, or larger.
- Networking: Public IPv4 and Public IPv6, as proposed.
- SSH keys: select your key, or Add SSH key. With a key selected Hetzner sets no root password.
- Firewalls: tick
odoo-host-manager. - Cloud config: paste the Cloud config.
- Name: for example
pelmo. It becomes the server's host name and the name on the console's certificate, until you give the server a DNS name. - Create & Buy now.
With the hcloud CLI
The same, from the hcloud command-line tool with your
project's API token set up. Save the Cloud config as cloud-config.yaml, and the firewall's rules as
firewall-rules.json:
[
{"direction": "in", "protocol": "tcp", "port": "22", "source_ips": ["0.0.0.0/0", "::/0"]},
{"direction": "in", "protocol": "tcp", "port": "80", "source_ips": ["0.0.0.0/0", "::/0"]},
{"direction": "in", "protocol": "tcp", "port": "443", "source_ips": ["0.0.0.0/0", "::/0"]},
{"direction": "in", "protocol": "icmp", "source_ips": ["0.0.0.0/0", "::/0"]}
]
Then:
hcloud firewall create --name odoo-host-manager --rules-file firewall-rules.json
hcloud server create --name pelmo --type cx23 --location fsn1 --image debian-13 \
--ssh-key <your key's name> --firewall odoo-host-manager \
--user-data-from-file cloud-config.yaml
Wait for the install
The server is running within a minute. The Cloud config then upgrades Debian, which takes about two minutes, and the installer lays the server, which takes about six or seven more: about 10 minutes in all.
Sign in as root with your key and follow it:
ssh root@203.0.113.10
cloud-init status --wait # says "status: done" when the install is finished
tail -f /var/log/cloud-init-output.log # or follow it as it goes
Reach the console
Once cloud-init is done, read the administrator's first password:
sudo cat /root/antelao-ohm-handoff.json
The user is admin, and the password is the file's administratorPassword. Delete the file after
your first sign-in to the console.
Then open the console through an SSH tunnel from your own computer, which opens no port on the firewall:
ssh -N -L 5322:127.0.0.1:5322 root@203.0.113.10
Browse to https://localhost:5322/ and accept the self-signed certificate once; it is made out to
the server's name and to localhost. Point your DNS name at the server's public addresses, then
carry on with the installation page:
Install your license in the console under Server > License; see Installing a license.
The ready-made image as a snapshot (advanced)
Hetzner Cloud cannot import a disk image. The way around it is hcloud-upload-image, a community tool: it rents a temporary server, starts its rescue system, writes the image to its disk over SSH, takes a snapshot of it and deletes the server again. Hetzner does not support or endorse this tool. What it buys is time per server: once the snapshot exists, a server made from it is ready in about 4 minutes instead of 10.
Two things differ from the Before you start list:
- The server type needs an 80 GB disk: CX33 or larger. The image's disk is 40 GB in the binary
sense (40 GiB), and a CX23's "40 GB" disk is a little smaller than that, so Hetzner refuses a CX23
with
image disk is bigger than server type disk. The snapshot needs an 80 GB disk for the same reason, and so does every server made from it. - A Linux machine (
x86_64) to prepare the image on, withqemu-img,zstdandhcloud-upload-image, and about 12 GB of free disk. A small Debian server at Hetzner does well.
Make the snapshot
Download the qcow2, antelao-ohm-<version>-amd64.qcow2, from the
table on the overview page, and check it in the folder you
downloaded it to:
curl -fsSLO https://packages.antelao.io/raw/cosign.pub
sha256sum cosign.pub
curl -fsSLO https://images.antelao.io/ohm/stable/0.23.0/SHA256SUMS
curl -fsSLO https://images.antelao.io/ohm/stable/0.23.0/SHA256SUMS.sig
cosign verify-blob --key cosign.pub --signature SHA256SUMS.sig \
--insecure-ignore-tlog=true SHA256SUMS
sha256sum --check --ignore-missing SHA256SUMS
Install the tools. On Debian:
sudo apt-get install -y qemu-utils zstd
and hcloud-upload-image from its
releases page.
The tool cannot take the qcow2 as it is: it converts a qcow2 in the rescue system's memory, which is
too small for this image, and the upload stops with No space left on device. Convert it to a raw
disk and compress that instead; a raw image is written straight to the disk:
qemu-img convert -O raw antelao-ohm-<version>-amd64.qcow2 antelao-ohm-<version>-amd64.raw
zstd -T0 antelao-ohm-<version>-amd64.raw -o antelao-ohm-<version>-amd64.raw.zst
Create an API token with Read & Write permission under your project's Security > API tokens, and upload:
export HCLOUD_TOKEN=<your API token>
hcloud-upload-image upload --image-path antelao-ohm-<version>-amd64.raw.zst --compression zstd \
--server-type cx33 --location nbg1 \
--description "Antelao Odoo Host Manager <version>"
Converting and compressing take a few minutes, the upload about three more. The tool ends with
Successfully uploaded the image! and the snapshot's id, and removes its temporary server and SSH
key itself.
error during placement: the location had no CX33 free at that moment. Try again a little later, or with another--location. A snapshot can be used in every location, whichever one made it.- An interrupted upload can leave its temporary server behind.
hcloud-upload-image cleanupremoves it. - The snapshot shows under Snapshots with the operating system Ubuntu 24.04, a leftover of the tool's temporary server. It is Debian 13.
Create a server from it
Create the firewall as above, if the project does not have it yet. Then:
-
Servers > Add Server, and any Location.
-
Image: the Snapshots tab >
Antelao Odoo Host Manager <version>. -
Type: CX33, or any type with an 80 GB disk or more. CX23 is refused.
-
SSH keys: select your key.
-
Firewalls: tick
odoo-host-manager. -
Cloud config: paste this, so your key may sign in as
root:#cloud-config# Antelao Odoo Host Manager snapshot on Hetzner: let the SSH key you selected sign in as root.disable_root: false -
Name, then Create & Buy now.
With the CLI:
hcloud server create --name pelmo --type cx33 --location nbg1 --image <snapshot id> \
--ssh-key <your key's name> --firewall odoo-host-manager \
--user-data-from-file cloud-config.yaml
The disable_root: false line is not optional. Without it, a server made with your key refuses
root with Please login as the user "root" rather than the user "root", and there is no other
user to sign in as. The image installs itself on its first boot, as every
ready-made image does, so the Cloud config
here carries no installer.
Without an SSH key, Hetzner sets a root password, shows it once and mails it, and SSH accepts it. The password has expired: the first sign-in asks for it once more, then for a new one twice, and disconnects. Sign in again with the new password. Rescue > Reset root password on the server's page also works. The install runs either way.
Sign in as root while the first boot runs and the login message says so and shows how to follow
it; when it is done, the message shows the console's address and the tunnel command. From there,
Reach the console is the same as for the simple route.
Platform notes and troubleshooting
- The type is greyed out or refused. The simple route needs a 40 GB disk, the snapshot an 80 GB
one. Arm types (CAX) are never offered for the product: it is
amd64only. - SSH times out. Check that the
odoo-host-managerfirewall is applied to the server and allows port 22, and that you use the server's public address. - SSH refuses the key. Sign in as
root. On a server from the snapshot, check that the Cloud config helddisable_root: false; it is read at the first boot only, so create the server again if it did not. - The install is not finished after 15 minutes.
tail /var/log/cloud-init-output.logshows where it stopped, and If the install stops part-way what to look at;sudo ohm installrepairs whatever it finds. On a server from the snapshot, see What the first boot does instead. - The management ports. Keep 5322, 5312 and the other management ports out of the Hetzner firewall, or open them to your own addresses only. For a second line on the server itself, see Restricting the management ports.
- The DNS name. Without one, the server is named after the Hetzner server. Point an A record, and an AAAA record for the IPv6 address, at it, then rename the server as Renaming the server shows.