1. Run the read node
Step 1 installs a Snapchain read node on the host in node.env, waits until it has caught up
with the network, and opens an SSH tunnel so http://127.0.0.1:3381 on your machine reaches the
node’s HTTP API.
./scripts/1-node.shWhat it does on the host
Section titled “What it does on the host”-
Waits until the host answers SSH. A new server needs to boot and run cloud-init first; the script tries 60 times, 5 seconds apart.
-
Waits for cloud-init to finish, if the host uses it.
-
Checks the host and prints one row per check:
Check Needs ram15 GiB (Snapchain asks for 16 GB; the kernel keeps some) disk1.8 TiB free in the data directory, skipped once ~/snapchain/.rocksexistsdockera Docker server the SSH user can talk to composeDocker Compose 2.24.4 or newer, which the override below needs ports3381 to 3383 free; shown, never fails, since on a rerun the node holds them clockwithin 60 seconds of your machine’s clock A
noin any row stops the run with exit code 5. -
Writes
~/snapchain/.envwithAGREE_NO_REWARDS_FOR_ME=true,HUB_OPERATOR_FID(your--fid, 0 by default),SKIP_CRONTAB=trueunless you pass--autoupgrade, one random Grafana password asGRAFANA_CREDS(which Snapchain’s own script reads) andGRAFANA_PASSWORD(which the override gives Grafana), andSTATSD_PUBLISHandSTATSD_ADMIN_PUBLISHset to the host’s loopback, where the compose file publishes statsd. It only adds keys the file does not have yet, and never changes a value that is already there. -
Downloads
docker-compose.mainnet.yml(saved asdocker-compose.yml),validators.toml, Grafana’sgrafana.iniand the Snapchain dashboard from the Snapchain repository at the@latesttag, or atv<version>with--release. -
Writes
docker-compose.override.yml, which Docker Compose merges over the downloaded file and which Snapchain upgrades never replace. It publishes Grafana on the host’s loopback only, gives it the password from.envand its datasource and dashboard, and, with--block-retention, sets block pruning. -
Starts the
snapchainandstatsdservices withdocker compose up -d. -
Waits for the sync, up to
--timeoutseconds (12 hours by default). -
Opens the tunnel, unless you pass
--no-tunnel.
Steps 4 to 7 are the non-interactive parts of Snapchain’s own snapchain.sh upgrade; the
node guide describes the .env keys and
the override file.
Waiting for the sync
Section titled “Waiting for the sync”The first start downloads a snapshot of several hundred GB, then syncs the blocks since that snapshot. Expect hours. The script prints the full status once:
snapchain <version>, synced: noshard 0 height <n> behind <s>s size <x> GiB mempool n/ashard 1 height <n> behind <s>s size <x> GiB mempool n/ashard 2 height <n> behind <s>s size <x> GiB mempool n/athen one line per check, with the time, how far behind the slowest shard is, and an estimate from the rate since the first check:
<HH:MM> <hours>h <minutes>m behind, ETA <estimate>The checks start 10 seconds apart and back off to one a minute. The node counts as synced when
every shard is less than 10 seconds behind; the full status is printed again then. behind is
the blockDelay the node reports in /v1/info. Read nodes report no mempool size for some
shards, which shows as n/a.
Pressing Ctrl-C ends only the wait. The node keeps syncing on the host;
./scripts/1-node.sh status --wait watches it from where it is. Running ./scripts/1-node.sh again
works too, but repeats every step, downloading the compose file again (the latest release’s
unless you pass the same --release).
The tunnel
Section titled “The tunnel”./scripts/1-node.sh tunnel # forward 127.0.0.1:3381 and :3383 to the node./scripts/1-node.sh tunnel --stop # close itThe tunnel is an ssh -N process in the background, found and stopped through its control
socket in ~/.ssh. It does not come back by itself after the connection drops or your machine
restarts: run tunnel again. If something else
already listens on local port 3381 or 3383, the tunnel does not come up and the script says so.
Other commands
Section titled “Other commands”| Command | What it does |
|---|---|
status |
the sync status once; exit code 0 when synced, 1 otherwise |
status --wait |
poll until synced, as up does |
logs |
follow the snapchain container’s logs; logs casty the page’s |
upgrade |
fetch the latest release’s compose file, or --release’s, then pull and restart |
serve |
run casty on the host behind HTTPS, with --domain or --tailscale: From any network |
down |
stop the node, and casty if it serves; the database stays on the volume |
status asks the node over SSH, so port 3381 never has to be public for it.
Pinning a release and upgrades
Section titled “Pinning a release and upgrades”The compose file of every Snapchain release names the image farcasterxyz/snapchain:latest.
--release 0.14.3 downloads the v0.14.3 files and rewrites that line to
farcasterxyz/snapchain:0.14.3; if the file no longer names :latest, the script stops rather
than run something else. ./scripts/1-node.sh upgrade without --release goes back to the latest
release.
--autoupgrade --fid <fid> installs snapchain.sh’s weekly upgrade job instead, on a weekday
derived from your fid the way snapchain.sh derives it. That job runs
docker system prune --volumes -f, which affects every Docker project on the host, not only
Snapchain. --release and --autoupgrade cannot be combined, and --release removes an upgrade
job it finds, since the job would replace the pinned version.
Block retention
Section titled “Block retention”--block-retention <n> sets SNAPCHAIN_PRUNING__BLOCK_RETENTION so the node prunes blocks older
than n days. Snapchain allows this on read nodes only and leaves it off by default. The value
is a duration, read as humantime by Snapchain’s config, so the <n>d casty writes is 30d for
30 days.
Grafana
Section titled “Grafana”Snapchain’s compose file includes Grafana. casty starts only snapchain and statsd, but
prepares Grafana so that one command starts it with the Snapchain dashboard in place: on the
host, run docker compose up -d grafana in ~/snapchain. The override publishes it on the
host’s loopback, so reach it through SSH:
ssh -L 3000:127.0.0.1:3000 <user>@<node ip> # then open http://127.0.0.1:3000The dashboard opens without a login (Snapchain’s grafana.ini lets anyone view); to edit, log
in as admin with the password GRAFANA_PASSWORD in ~/snapchain/.env holds. Grafana reads
that password on its first start only: if you set GRAFANA_CREDS yourself before casty ran,
set GRAFANA_PASSWORD to match it.
Options
Section titled “Options”Usage: 1-node.sh [up|status|logs|tunnel|upgrade|serve|down] [options]
(no command) up, wait for sync, then open the tunnel up check the host, write ~/snapchain, start the node, wait for sync status [--wait] sync progress per shard; --wait polls until synced logs [casty] follow the node's logs, or the casty service's tunnel [--stop] forward local ports 3381 and 3383 to the node over SSH upgrade fetch the latest release's compose file (or --release) and restart serve run casty on the host, reached over HTTPS from any network: needs --domain <name> (Caddy gets the certificate; open 80 and 443 with 0-provision.sh --https) or --tailscale (tailscale serve on the host) down stop the node, and casty if it serves
--fid <fid> your fid, recorded as HUB_OPERATOR_FID (default: 0) --autoupgrade install snapchain.sh's weekly auto-upgrade (needs --fid). It runs docker system prune --volumes -f on the whole host. --block-retention <n> prune blocks older than n days (read nodes only) --release <version> run this Snapchain release, such as 0.14.3, instead of the latest --no-tunnel do not open the tunnel after sync --timeout <seconds> how long status --wait waits (default: 43200, 12 hours) --env <file> node.env from step 0 (default: node.env) --dry-run print the ssh commands instead of running them serve: --domain <name> the name the page is reached at; must point at the host --tailscale reach it as the host's name on your tailnet instead --read-only a page that reads only: no app key or passphrase leaves this machine --config <dir> casty's config directory here (default: $XDG_CONFIG_HOME/casty)
Exit codes: 0 ok, 1 not synced or the node did not answer, 2 bad arguments, 3 missing prerequisite,4 no ssh connection or download failed, 5 preflight failed.Next: 2. Install the client.