Deployment
Server Setup
Minimal host preparation for Kamal and accessories.
Goal
Prepare one Hetzner server so Kamal can run app, Postgres, Redis, and backup containers.
Step 0: Provision resources in Hetzner
Before host configuration, provision required infrastructure in Hetzner Cloud:
- Create and pay for at least one server in your target region.
- Provision a Volume if you need persistent app/database storage.
- Provision Object Storage and create a bucket if you plan to store uploads or database backups.
Step 1: Base host setup
Run on server:
apt update && apt upgrade -y
apt install -y docker.io curl gitAfter base updates, disable SSH password authentication and keep SSH key authentication only.
Edit /etc/ssh/sshd_config and set PasswordAuthentication no (or uncomment the line and change it to no).
Step 2: Prepare persistent volume mount
Use your Hetzner volume and mount it, for example to /mnt/main-volume.
Preferred option (automatic):
- Use Hetzner Cloud Console and attach/mount the volume with automatic configuration.
- This is the safest default for most teams.
Manual option:
- If you configure manually, you must:
- format the volume filesystem
- mount the volume to your target path
- add persistent mount entry in
/etc/fstab
- Follow Hetzner guide: Creating and mounting a volume
This guide uses paths:
/mnt/main-volume/example-app/postgres-data/mnt/main-volume/example-app/redis-data
Create directories:
mkdir -p /mnt/main-volume/example-app/postgres-data
mkdir -p /mnt/main-volume/example-app/redis-dataStep 3: Open required ports
22for SSH80and443for Kamal proxy
Configure this in Hetzner Cloud UI in the server Firewall tab.
Allow inbound TCP only for ports 22, 80, and 443.
Notes
- This page is intentionally short. You can expand hardening and monitoring later.
- In this example, accessory data is mapped to
/mnt/main-volume/...inconfig/deploy.yml.
Verify
- Docker is running:
docker ps - Mount exists:
df -h | grep /mnt/main-volume - Data directories exist:
ls -la /mnt/main-volume/example-app