Hetzner installation guide

Guide for installing Cradle CMS on Hetzner hosting provider.

Create Hetzner account

  1. Login or signup for a new Hetzner account here.
  2. Then enable two-factor authentication by navigating to "Administration" » "Settings" » "Two-factor authentication" in the left menu bar.

After that open Hetzner Cloud and go to Cloud projects via services menu 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.

Firewall

Setup a Firewall for the Hetzner project you created previously according to this table;

Source

Protocol

Port

Description

<YOUR_IP_ADDRESS>  TCP 22 Allow SSH
0.0.0.0/0  TCP 80 Allow HTTP
0.0.0.0/0 TCP 443 Allow HTTPS
You can find out your IP-address by using Hetzners IP lookup service.
curl -4 https://ip.hetzner.com

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 24.04 Linux.

You can also use Debian 12 and then install docker or podman manually.

Architecture

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 it up when needed. We'll go for the CAX11 having `2 shared vCPU:s` with `4GB RAM` and `40GB SSD` disk.

Network

For networking we only need to have a public `IPv4` address.

SSH key

Earlier we setup a firewall rule that accepts ssh connections from a single IP address. To be able to log in to your server using `ssh` you need to generate a new keypair.

You can generate a 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 <YOUR SERVER IP>
  IdentitiesOnly yes
  IdentityFile ~/.ssh/hetzner.key

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

Volume

Create a Hetzner 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).

Firewall

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.

On windows, unless running WSL, you need to install a different ssh utility like putty from https://putty.org.

Login

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

Start with some basic maintenance and update the server packages.

apt update
apt upgrade

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

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 the 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 using the updated fstab configuration.

mount -a

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

mount
df -H

Deployment

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 create and start a docker service for cradle-cms using the latest release, all in one go.

Start service with automatic certificates

To start cradle-cms with letsencrypt certificates you need to register and configure a domain name pointing its `A RECORD` to your server ip. Your domain name should be configured using the -e DOMAIN_NAME=<domain> option otherwise the server uses a wildcard `*`domain setting. More configuration options: site, frontend and admin.

docker service create --name cradle-cms --mount type=bind,source=/storage,destination=/storage --publish published=443,target=4040,mode=host -p 80:8080 --replicas 1 -e DOMAIN_NAME=your.site.domain -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 by using  -e ACME_DIRECTORY configuration option.

On a production server you should use docker secrets for the configuration.           

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.

docker service create --name cradle-cms --mount type=bind,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

You can run the container as a low privileged system user with the docker option --user . It requires that the user exists both on the docker host and in the container. You also need to change ownership of the /storage directory to the same user. Debian based Linux, such as Ubuntu, have a www-data user (with uid 33) that you may use.

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:///admin. Login with username admin and the password you configured with -e ADMIN_PASS.

Logs

The system log is written to standard out in json format so you can use tools such as jq to filter log messages. To see the log output you need to use docker logs as shown in the example.

docker logs -f <container id>

You can also subscribe to a log event stream using the nats client. 

nats subscribe "logs.>"
[#6] Received on "logs.frontend"
{"time":"2024-09-28T08:54:26.176Z","level":"INFO","service":"frontend","msg":"render","host":"localhost:5000","site":"17427f63-e498-4654-bcaa-a6f24afabeef","path":"/","type":"index","handle":"","lang":"en"}
Use the log stream if you want to store the log on another server or monitor it in real time.

References