Skip to content

Every script, setting, port and endpoint, with defaults.

ScriptRuns onDoes
provision.shyour machineCreates the firewall, volume and server on Hetzner with hcloud. Checks the price first. Prints the IPv4 address
node.shVM (ssh … bash -s < node.sh)all (default): checks, Docker, disk helpers on small disks, official bootstrap, wait for sync, health check. Also wait, health, helpers
deploy-client.shyour machineBuilds the app on your computer, copies it and Caddy to /opt/snapchain-client
teardown.shyour machineDeletes the server, volume and firewall; lists what is left. Safe to run twice
watchdog.shyour machineRuns teardown.sh before the bill reaches MAX_USD, after MAX_WALL_SECS, or after HANG_SECS with no progress
disk-guard.shVM (systemd timer; node.sh installs it)install, check, status, uninstall. Stops the node at 90% disk
snapshot-space-saver.shVM (systemd; node.sh installs it)install, run, once, uninstall. Deletes snapshot files the node has finished with; stops when the restore is done

provision.sh, node.sh, deploy-client.sh, teardown.sh and the two VM helpers take DRY_RUN=1: they print what they would do and change nothing. watchdog.sh does not. Tokens come from the environment and are never printed.

VariableScriptDefaultNotes
HCLOUD_TOKENprovision, teardown, watchdog(required)Hetzner API token, read/write
SSH_KEYprovision(required)Name or ID of an SSH key in your Hetzner project
SERVER_TYPEprovisioncx43Tested with cax31. Empty = auto-pick from SERVER_TYPE_CANDIDATES. If it isn’t available to rent in LOCATION, the error lists what is, cheapest first
SERVER_TYPE_CANDIDATESprovisioncx43 cax31 cpx42 ccx23Cheapest first
VOLUME_GBprovision2000 (REQUIRED_DISK_GB)1000 fits a new account’s quota
LOCATIONprovisionfsn1fsn1, nbg1, hel1, ash, hil or sin. Server and volume share it
MAX_USDprovision, watchdog8Price limit for the check before creating anything; the watchdog deletes everything at it. In your Hetzner account’s currency
EXPECTED_HOURSprovision24Hours the price check multiplies by. Our cax31 sync took 14 h 06 m
WATCHDOGprovision10 = no watchdog; the server runs until you delete it. The Full run uses 0
ESTIMATE_ONLYprovision01 = price check only, creates nothing
SSH_SOURCE_CIDRSprovision0.0.0.0/0,::/0Set to "$MY_IP/32" (from curl -4 -s https://ifconfig.me)
NODE_API_CIDRSprovisionemptyAddresses allowed to reach 3381 and 3383. Empty keeps both closed
PORT_PROFILEprovisiondocsreadme also opens the README’s TCP+UDP superset
NAMEprovision, teardown, watchdogsnapchain-read-nodeVolume $NAME-data, firewall $NAME-fw. The Full run exports it, so every step and teardown.sh use the same name
REUSEprovision0If the server $NAME, the volume $NAME-data or an applied firewall $NAME-fw already exists, provision.sh stops before it creates or changes anything. 1 continues with them (your own earlier run)
VOLUME_QUOTA_GBprovision1024Account-wide volume limit (new Hetzner accounts: 1024 GB across all projects). Before creating anything, provision.sh adds the volumes in this project to VOLUME_GB and stops if the sum is over it. Volumes in other projects are not visible, so Hetzner can still refuse. Set it if Hetzner raised your limit
WATCHDOG_MAX_WALL_SECSprovision86400Time limit provision.sh passes to the watchdog (as MAX_WALL_SECS; MAX_WALL_SECS on provision.sh works too). 172800 = 48 hours
CONFIRMteardown(prompt)Must equal NAME
OTHER_SERVER_OKteardown0teardown.sh stops and deletes nothing if the server named $NAME has a different ID from the one provision.sh recorded in .provision-state/server-$NAME.id. 1 deletes it anyway
SNAPCHAIN_AGREE_NO_REWARDSnode.sh(prompt)yes records the no-rewards agreement
OPERATOR_FIDnode.shunsetEnables the weekly auto-upgrade cron; unset = SKIP_CRONTAB=true
MIN_FREE_GBnode.sh1500900 for a 1000 GB volume
SYNC_TIMEOUT_SECSnode.sh8640024 hours; our cax31 sync took 14 h 06 m
DISK_HELPERSnode.shautoauto installs disk-guard and the space saver when the disk is under DISK_HELPERS_BELOW_GB; 1 always; 0 never
DISK_HELPERS_BELOW_GBnode.sh1500
SPACE_SAVER_WAIT_SECSnode.sh7200How long the space saver waits for the snapshot folder to appear
SNAPSHOT_REPAIRnode.shautoIf a shard’s snapshot download fails with no upstream retry, restore only that shard. 0 only prints the command
REPAIR_ATTEMPTS / REPAIR_PARALLELnode.sh3 / 4Fresh snapshot lists per repair; parallel chunk downloads
SYNC_MAX_BLOCK_DELAY / SYNC_STABLE_CHECKS / SYNC_POLL_SECSnode.sh10 / 3 / 60Sync criterion
NODE_UPGRADEnode.sh01 re-runs the official bootstrap (upgrade)
SSH_OPTSdeploy-clientemptyExtra ssh/scp options, e.g. -i key
LIMIT_PCTdisk-guard90
HANG_SECS / MAX_WALL_SECSwatchdog7200 / 86400No-progress limit; total time limit. When provision.sh starts the watchdog, set the time limit with WATCHDOG_MAX_WALL_SECS
SSH_KEY_FILEwatchdogemptyPrivate key for the progress check. Empty turns the check off
PROGRESS_MIN_BYTESwatchdog1048576Database growth that counts as progress; any block height increase also counts
UNREACHABLE_IS_HANGwatchdog01 counts lost SSH as no progress
PortPurposeOpen in the firewall
3381/tcpSnapchain HTTP APINo, unless you set NODE_API_CIDRS. Caddy reaches it on 127.0.0.1
3382/udpGossip (libp2p QUIC)Yes
3383/tcpSnapchain gRPC APINo, unless you set NODE_API_CIDRS
80/tcp, 443/tcpCaddy: Let’s Encrypt and the HTTPS clientYes
22/tcpSSHYes, limit with SSH_SOURCE_CIDRS
3000/tcpGrafana (default admin:admin)No. Keep it closed
8125/udp, 8126/tcpstatsdNo

Docker publishes 3381, 3383, 3000 and the statsd ports on every interface of the server, so the Hetzner firewall is what keeps them private. The app reaches the node through Caddy on 443. To read the API from your computer, use https://<name>/v1/... or ssh -N -L 3381:127.0.0.1:3381 root@$IP.

/v1/info, /v1/castsByFid, /v1/castById, /v1/linksByFid, /v1/linkById, /v1/reactionById, /v1/userDataByFid, /v1/signersByFid, /v1/signer, /v1/onChainIdRegistryEventByAddress, POST /v1/submitMessage. Reference: HTTP API.

PathWhat
client/The web app: Vite and TypeScript, @farcaster/core 0.20.0
deploy/Caddyfile, Caddy compose file, Hetzner firewall rules
test/, e2e/Tests for the scripts; browser tests against a mock node and the live node
site/This site (Astro Starlight)
MEASUREMENTS.md, run-log.mdNumbers and log from the mainnet run
DOCS_ISSUES.md, SOURCES.mdProblems found in the official docs; the source for each fact
SECURITY.md, VOUCHER.mdHow keys are handled; the checklist for vouching