Hetzner installation guide

Hetzner account

  1. Login or signup for a new Hetzner account at https://accounts.hetzner.com/login
  2. Enable two factor authentication which you can find in your user account settings (under the top right profile icon).

Then go to Cloud projects which you find by clicking the services on the top right next to the user profile icon.

Create a new project (or use the existing one) where to deploy the cradle-cms service.


First we create a Firewall to be used for the service we are going to create. Setup a Firewall in the Hetzner project you created.

Create inbound rules.

  • Add a rule ssh management allowing TCP on port 22 from your own public IP-address.

NOTE: if you don't know your public IP search for what is my ip on the web or curl ipinfo.io.

  • Add rules for http with TCP on port 80 and https with TCP on port 443 from anywhere.

Add server

Click Add server to start configuring a new cloud server.

Operating system

Click the Apps tab and select the Docker CE which is based on Ubuntu 22.04 Linux.

NOTE: You can also use Debian 12 and then install docker or podman manually as it's needed for the deployment later.


Select server architecture Amd64 or Arm64 according to your own preference. In this guide we selected Arm64 Ampere.

Then you can select the smallest possible CPU size and scale up when required. We'll go for the CAX11 having 2 shared vCPU:s with 4GB RAM and 40GB SSD disk.


For networking we only need a public IPv4 address for now.

SSH key

For SSH access you can use your own or a Hetzner generated key. Earlier we setup a firewall rule that accepts ssh connections from a single IP address.

You can create a new hetzner.key using the ssh-keygen utility.

cd ~/.ssh
ssh-keygen -t rsa -b 4096 -f hetzner.key

Open or create the file ~/.ssh/config and add configuration for accessing the server with the hetzner key.

Host <server-hostname-or-ip-address>
  IdentitiesOnly yes
  IdentityFile ~/.ssh/hetzner.key

Copy the public key part hetzner.key.pub to the clipboard and paste it into the Hetzner cloud SSH-key dialog.


Create a Volume for persistent storage with the smallest available size 10GB and select XFS as a file system which can be utilised for backup purposes later (XFS snapshots).


Select the Firewall you created earlier.

You can leave rest of the cloud options unselected i.e backup, placement, groups, labels etc.

On the right side you can review the whole setup and also see a monthly cost of around €4 per month.

Click on Create and buy and wait for the server to spin up.

Login to server

When the server is up and running you should be able to login using ssh.

NOTE: On windows you might need to install a different utility like putty from https://putty.org.


ssh root@<server-hostname-or-ip-address>

Start with some basic maintenance and update the server packages.

apt update
apt upgrade

NOTE: For good measure you can reboot the server and login using ssh after it has restarted. Take a note of the information displayed when you login.

Configure storage

On the server create a /storage directory where the cradle-cms files are going to be persisted.

mkdir /storage

Then edit the /etc/fstab configuration and point Volume to the /storage directory.

vi /etc/fstab

NOTE: If you don't know how to edit using vi (or Vim) it's good to learn as it's installed per default on most linux distributions. See https://vimsheet.com

Now edit the line containing the Volume and change the mount point to our /storage directory.

before any changes, yours might look a bit different.

/dev/disk/by-id/scsi-0HC_Volume_100701234 /mnt/HC_Volume_100701234 xfs discard,nofail,defaults 0 0

after where we changed mount point to /storage

/dev/disk/by-id/scsi-0HC_Volume_100701234 /storage xfs discard,nofail,defaults 0 0

Then save the file and re-mount the file system with the changed fstab configuration.

mount -a

Validate using the mount command, you should see that /storage has been mounted. Also check with df -g that the Volume size in GB is correct.

df -g


Login to the cradle registry with podman or docker cli using your cradle-cms license-key as username and your account password.

docker login registry.cradlecms.com

Initialise a docker swarm, even though we're using a single server, it simplifies deployment and updates later on.

docker swarm init

Download the latest cradle-cms image.

docker pull registry.cradlecms.com/cradle-cms:latest

Then we configure, create and start a docker service for cradle-cms using the latest release, all in one go.

start service (without letsencrypt)

To start cradle-cms without a domain name we use the -e ACME=false environment option. It disables automatic letsencrypt certificates and defaults to a self-signed certificate. However, you can install your own default certificate in /storage/certs/cert.pem if you want.

docker service create --name cradle-cms --mount type=volume,source=storage,destination=/storage --publish published=443,target=4040,mode=host -p 80:8080 --replicas 1 -e ACME=false -e ADMIN_PASS=your-password registry.cradlecms.com/cradle-cms

NOTE: You should run the container as a low privileged system user with the docker option --user <uid>. But it requires some additional configuration which we'll skip for now.

Now you can check the docker service logs.

docker service logs cradle-cms

When the service is up and running you can reach the admin web interface at https://<your-server-ip>/admin. Login with username admin and the password you configured with -e ADMIN_PASS.

start service with automatic certificates

To start cradle-cms with letsencrypt certificates you need to register and configure a domain name and pointing it to your server ip.

When you create the docker service you also need to specify the domain name using the -e DOMAIN_NAME=<your.domain.name> option.

docker service create --name cradle-cms --mount type=volume,source=storage,destination=/storage --publish published=443,target=4040,mode=host -p 80:8080 --replicas 1 -e DOMAIN_NAME=<your.domain.name> -e ADMIN_PASS=your-password registry.cradlecms.com/cradle-cms

When you browse the server using the domain name, cradle-cms negotiates a certificate from letsencrypt. You can also get certificates from other ACME compatible providers using the -e ACME_DIRECTORY=<https://other.acme.provider/directory> option.

NOTE: On a production server you should use docker secrets for configuration. There are many more server options you can configure, this covers only the most basic setup.