Before you start
Choose the server
Plans and prices change, so pick by what the node needs rather than by name. Dedicated vCPUs keep it from falling behind when neighbours get busy.
- Image
- Ubuntu 24.04
- CPU
- 8 dedicated vCPUs or more
- Memory
- 16 GB or more, 32 GB is comfortable
- Volume
- 700 GB or more, mounted automatically
- Location
- Any; a less crowded provider or region scores more for hosting
On Hetzner Cloud, add the volume under Volumes while creating the server and leave its mount option on Automatic. On DigitalOcean, add it under Add Storage and keep Automatically Format & Mount.
Paste the setup file
This file sets the server up on its first boot: Docker, kaspad, the firewall and time sync.
On Hetzner, paste it into Cloud config near the end of the create page. On DigitalOcean, open Advanced Options, tick Add Initialization scripts and paste it there. Then create the server.
#cloud-config
# A public Kaspa node: kaspad in Docker on Ubuntu 24.04. From https://kasnodes.com/run/cloud
# Progress: /var/log/kaspad-setup.log
package_update: true
packages:
- docker.io
- docker-compose-v2
- ufw
write_files:
- path: /opt/kaspad/docker-compose.yml
content: |
services:
kaspad:
image: kaspanet/rusty-kaspad:latest
container_name: kaspad
restart: unless-stopped
ports:
- "16111:16111" # P2P, for other nodes
- "127.0.0.1:16110:16110" # RPC, from this server only
volumes:
- kaspad-data:/app/data
env_file:
- claim.env
command:
- kaspad
- --yes
- --nologfiles
- --disable-upnp
- --utxoindex
- --rpclisten=0.0.0.0:16110
logging:
options:
max-size: "50m"
max-file: "3"
volumes:
kaspad-data:
- path: /opt/kaspad/claim.env
content: |
# To claim this node on KasNodes, put your code after the = and remove the #, then run
# cd /opt/kaspad && docker compose up -d
# KASPAD_USER_AGENT_COMMENTS=
- path: /opt/kaspad/setup.sh
permissions: "0755"
content: |
#!/bin/bash
set -euo pipefail
exec >>/var/log/kaspad-setup.log 2>&1
echo "Setup started $(date -u)"
# The chain needs about 640 GB: use an attached volume (mounted under /mnt) when there is one.
data=""
for _ in $(seq 60); do
data=$(findmnt -rn -o TARGET | grep -m1 '^/mnt/' || true)
[ -n "$data" ] && break
udevadm trigger || true
sleep 5
done
if [ -n "$data" ]; then
echo "Keeping the chain on the volume at $data"
systemctl stop docker docker.socket
mkdir -p "$data/docker"
printf '{"data-root": "%s/docker"}\n' "$data" > /etc/docker/daemon.json
else
echo "No volume under /mnt after 5 minutes: keeping the chain on the server's own disk"
fi
systemctl enable --now docker
ufw allow OpenSSH
ufw allow 16111/tcp
ufw --force enable
timedatectl set-ntp true || true
cd /opt/kaspad
docker compose up -d
echo "kaspad is running. Follow it with: cd /opt/kaspad && docker compose logs -f kaspad"
runcmd:
- [bash, /opt/kaspad/setup.sh]
Or download it. It runs kaspad in Docker exactly as the Docker guide does, keeps the chain on the volume, opens port 16111 to other nodes and nothing else but SSH.
Watch it start
Setup takes a few minutes after the server boots. Log in with your SSH key and follow it.
ssh root@YOUR-SERVER-IP
tail -f /var/log/kaspad-setup.log
cd /opt/kaspad && docker compose logs -f kaspad- The setup log ends with kaspad is running
- It says the chain is kept on the volume
- kaspad's log shows peers connecting and blocks downloading
No volume found? The log says so if none was mounted within five minutes, and the chain then fills the server's own disk. Attach and mount a volume, then recreate the server with the same file.
Check it from outside
The first sync takes one to two hours. It accepts other nodes from the start, so you can check it right away.
Put the server's address into the node doctor: it should accept connections, run the newest kaspad and, once synced, be in step with the network and have a correct clock.
- The node doctor shows it accepts connections
- kaspad's log shows inbound peers
- It appears on KasNodes after a crawl or two
Claim it
Once it is listed, claim it so your name goes on its row. Start a claim from its page to get a one-time code.
- Find the node on KasNodes and choose Claim this node.
- Copy the code you are given.
- Run this on the server, with your code in place of YOUR-CODE:
echo 'KASPAD_USER_AGENT_COMMENTS=YOUR-CODE' | sudo tee /opt/kaspad/claim.env
cd /opt/kaspad && sudo docker compose up -dThat restarts kaspad with the code in its name tag; the claim confirms within a minute or two. Leave the code in place: it does no harm.
Day-to-day commands
Run these in /opt/kaspad.
- Follow the log
docker compose logs -f kaspad- Update to the newest version
docker compose pull docker compose up -d- Restart
docker compose up -d --force-recreate- Disk use
df -h /mnt/*- Resource use
docker stats kaspad
Troubleshooting
The usual problems and what fixes them.
The setup log is empty or missing
The file did not run. Check it starts with #cloud-config on its first line, and read /var/log/cloud-init-output.log for the reason.
The node doctor can't connect
Check the provider's own firewall, if you added one: it must allow TCP 16111 inbound. The server's firewall is already open for it.
It falls behind or restarts
The server is short of memory or CPU. Resize it to a larger plan; the volume keeps the chain, so it carries on where it stopped.
The volume is filling up
Grow it in the provider's console, then grow its filesystem with sudo resize2fs and the device findmnt shows for it. Keep at least 100 GB free.
Running? Put your name on it.
Once the node shows up in a crawl you can claim it, pick a public name and follow its rank.