Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Hetzner

Preparing SSH

First we rebuild the image from Ubuntu 24.04.

We reset the root password using Rescue -> Reset root password. I recommend then changing it to a new password once inside again (through passwd root).

Login using the console GUI.

Go to /etc/ssh and change the SSH server settings sshd_config:

PermitRootLogin no
PasswordAuthentication no

Then we create a new user (-m creates home directory, then we add them to sudo group):

useradd -m backend
adduser backend sudo

Then do passwd backend and set up a password.

Switch to the user using su backend.

The default shell might not be bash (for example if your prompt starts with only ‘$’), in that case run:

chsh --shell /bin/bash

Create a new directory mkdir /home/backend/.ssh. Enter this directory (using cd) and then do nano authorized_keys to open/create a new file there.

Paste in your SSH public key (generate one using ssh-keygen -t ed25519 -C "your_email@example.com") (the public key looks something like ssh-ed25519 .... tiptenbrink@tipc) and save the file (Ctrl-X). If copy-paste is not working, maybe try a different browser and make sure you’re not in GUI mode or similar.

Then, ensure the file has the correct permissions:

chmod 700 /home/backend/.ssh && chmod 600 /home/backend/.ssh/authorized_keys

Then you can log in with ssh backend@<ip address here> (make sure it uses the proper private key, so you might have to use the -i option).

Note that it’s often had to find out what’s going on when it’s not working. Be sure that the string in authorized_keys precisely matches your public key. Note that sometimes copy-pasting can not work correctly and some characters are changed (like = to -, or _ to -) or maybe you missed one character at the beginning or end. It really needs to match!

SSH niceties

Install “xauth” (while logged in as root)

apt install xauth

If you’re using a nice terminal emulator, you might have to add some xterm files. Consult the documentation of your terminal for details.

From this point on we never need to be logged in as root anymore! Always log in via ssh from your terminal

Dependencies

Update packages

sudo apt update
sudo apt upgrade

You might have to reboot after this: reboot.

Install basic C compiler and other useful packages

sudo apt install unzip build-essential

Install NodeJS

Using fnm:

curl -o- https://fnm.vercel.app/install | bash

Be sure to re-login/start new terminal.

Set-up NodeJS 24:

fnm use 24

Verify with node -v, should return something starting with v24.

Install Python (with uv)

First, we install uv:

curl -LsSf https://astral.sh/uv/install.sh | sh

Then install Python (free-threading build) with:

uv python install 3.14t

Install Go

Go here to get the latest version (for linux and amd64/x64):

https://go.dev/doc/install

Currently that would be go1.25.5.linux-amd64. Then download it like:

curl -OL https://go.dev/dl/go1.25.5.linux-amd64.tar.gz

Then put it in the install location with:

sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.25.5.linux-amd64.tar.gz

Finally, add go to your path by appending the following to the end of ~/.profile:

export PATH="$PATH:/usr/local/go/bin"

Install backend (and frontend)

We did not strictly need to install NodeJS and the frontend as we will not host the frontend ourselves. However, I will explain how to here, since that can be useful as a demo.

Frontend

First, let’s clone the frontend to the home directory.

git clone https://github.com/DSAV-Dodeka/DSAV-Dodeka.github.io.git frontend --filter=blob:none

Set up reverse proxy

Installing Caddy

We will install Caddy. Go to their docs for the precise command (the one with stable and containing sudo apt update among other things).

Caddyfile

Permissions

The Caddy server runs as the caddy user and if you want to run the demo using a file server, you will have to give it permission to access the files you generate when building the frontend. Therefore, we will create a new group and add both the backend and caddy users to it and give it access to the frontend build output.

The following snippets shows all commands you have to run.

# Create a shared group called "webdata"
sudo groupadd webdata
# groupadd: creates a new group
# webdata: the name of the group to create

# Add both users to the webdata group
sudo usermod -aG webdata backend
sudo usermod -aG webdata caddy
# usermod: modify a user account
# -a: append (add to group without removing from other groups)
# -G: specify supplementary group(s) to add the user to
# webdata: the group to add them to
# backend/caddy: the username to modify

# Change ownership of the client folder
sudo chown -R backend:webdata /home/backend/frontend/build/client
# chown: change file owner and group
# -R: recursive (apply to all files and subdirectories)
# backend:webdata: set owner to "backend" and group to "webdata"
# /home/...: the target directory

# Set permissions: owner full, group read+execute
sudo chmod -R 750 /home/backend/frontend/build/client
# chmod: change file mode/permissions
# -R: recursive
# 750: octal permission code
#   7 (owner): read(4) + write(2) + execute(1) = full access
#   5 (group): read(4) + execute(1) = can read and traverse
#   0 (others): no access

# Make new files inherit the group (setgid bit)
sudo chmod g+s /home/backend/frontend/build/client
# g+s: set the setgid bit on the directory
# This means new files/folders created inside will inherit
# the "webdata" group instead of the creator's primary group

# Ensure parent directories are traversable
chmod 755 /home/backend
chmod 755 /home/backend/frontend
chmod 755 /home/backend/frontend/build
# 755: 
#   7 (owner): full access
#   5 (group): read + execute
#   5 (others): read + execute
# "execute" on a directory means permission to traverse/enter it

# Restart caddy to pick up the new group membership
sudo systemctl restart caddy
# systemctl: control the systemd service manager
# restart: stop and start the service
# caddy: the service name

# Log out and back in (or run `newgrp webdata`) for backend user to pick up the new group
# newgrp webdata: starts a new shell with webdata as the active group

Backup volume creation

When you create a volume in the Hetzner Cloud Console and attach it to a server, it gets mounted with an auto-generated name like /mnt/HC_Volume_104307139. This guide shows how to rename the mount point to /mnt/backup.

Ensure you have a Hetzner Cloud volume attached to the server!

Step 1: Identify Your Volume

ls -l /dev/disk/by-id/

Look for something like scsi-0HC_Volume_XXXXXXXX.

Step 2: Unmount the Volume

sudo umount /mnt/HC_Volume_XXXXXXXX

Step 3: Create New Mount Point

sudo mkdir /mnt/backup

Step 4: Update /etc/fstab

Edit fstab:

sudo nano /etc/fstab

Remove the old auto-generated line, then add:

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

Step 5: Mount and Set Ownership

sudo mount /mnt/backup
sudo chown backend:backend /mnt/backup

Step 6: Verify

df -Th /mnt/backup
ls -la /mnt/backup

Step 7: Clean Up Old Mount Point

sudo rmdir /mnt/HC_Volume_XXXXXXXX

Step 8: Test Persistence

Reboot and confirm the volume mounts correctly:

sudo reboot
# after reboot:
lsblk

Restic

Installation

Download and install restic v0.18.1:

curl -L https://github.com/restic/restic/releases/download/v0.18.1/restic_0.18.1_linux_amd64.bz2 | bunzip2 > /home/backend/.local/bin/restic && chmod +x /home/backend/.local/bin/restic

After installing, you can update to the latest version with:

restic self-update

Note: Check the Restic GitHub releases page to verify you’re getting the latest version, as v0.18.1 may no longer be current.

Initialize Repository

First, create a password file (be sure to replace it with an actual randomly generated password!):

echo "your-secure-password-here" > /mnt/backup/.restic-password
chmod 600 /mnt/backup/.restic-password

Then initialize the repository:

restic init --repo /mnt/backup/restic --password-file /mnt/backup/.restic-password

The backup cron job and log rotation are set up automatically by install-services.sh (see Environments).