Self-hosting on Hetzner VPS
Deploy Savannah Cloud to a Hetzner VPS — production instance at 178.105.152.34.
Production instance: 178.105.152.34 · App directory: /opt/riftcloud
Prerequisites
- A Hetzner Cloud VPS (Ubuntu 24.04 recommended)
- SSH access as
root - All required environment variables ready
Initial Server Setup
ssh root@YOUR_SERVER_IP
apt update && apt install -y docker.io docker-compose-plugin git
git clone https://github.com/Mbuthia71/distributed-task-queue.git /opt/riftcloud
cd /opt/riftcloud
# Create .env with all required variables
nano .env
# Build and start all 5 services
docker compose up -d --buildServices will be available at:
| Service | URL |
|---|---|
| API | http://YOUR_SERVER_IP:8080 |
| Dashboard | http://YOUR_SERVER_IP:80 |
| Health | http://YOUR_SERVER_IP:8080/health |
Updating After Code Changes
ssh -i ~/.ssh/id_ed25519 root@178.105.152.34
cd /opt/riftcloud
git pull
docker compose up -d --build app dashboardDo NOT use --build without specifying services. Always use --build app dashboard to avoid rebuilding the postgres container and wiping data.
If Postgres Auth Fails After Rebuild
cd /opt/riftcloud
bash fix_scram.shThis resets the SCRAM-SHA-256 password hash and restarts the app. The pg_hba.conf in the repo uses trust for Docker's 172.x.x.x network — auth failures should not recur. See Postgres Auth Notes.
Monitoring
# API health — checks postgres + redis
curl http://178.105.152.34:8080/health
# → {"status":"ok","postgres":"ok","redis":"ok"}
# Prometheus metrics
curl http://178.105.152.34:8080/metrics
# Live logs
docker compose logs -f app
# All container statuses
docker compose psFirewall Recommendations
| Port | Purpose |
|---|---|
22 | SSH |
80 | Dashboard (React + Nginx) |
8080 | Go API |
53 | PowerDNS (custom domain DNS) |
Keep ports 5432 (Postgres), 6379 (Redis), and 8081 (PowerDNS API) closed to external traffic — they should only be accessible within the Docker network.
Running Tests
go test ./... -v
go test -run TestPushJob -v
go test -race ./...