Appearance
Run a Validator
Bringing a Zink validator online is mostly standard Agave / Solana operator work with one extra reality: the cluster is currently permissioned. A good new operator should be able to use this page to self-qualify, prepare a host, generate the correct keys, and know exactly which values still need to come from the Zink network team.
Zink-specific
Zink Testnet validator participation currently requires coordination with the network team. Treat this page as both a self-service preparation guide and the runbook to execute once you receive the current cluster bootstrap bundle.
What success looks like
By the end of this guide, you should have:
- a trusted workstation with the Solana CLI and validator key material
- a remote Linux host with separated NVMe storage and system tuning applied
- a systemd-managed
agave-validatorlaunch command ready to run - a checklist of values to request from the Zink team before first join
- a verification sequence that proves the node is visible, catching up, and ready to vote
What you prepare vs. what Zink provides
You prepare
- validator-class hardware that meets System Requirements
- a publicly reachable host with the intended dynamic port range open
- validator identity, vote-account, and withdraw-authority keys
- mounted ledger and accounts volumes
- the Linux user, startup script, and systemd service you will run in production
The Zink network team provides or confirms
- current cluster entrypoints
- current known-validator pubkeys
- expected genesis hash
- required Agave / Solana version or release tag
- vote-account policy for the target cluster (self-create vs. operator-provided)
- any cluster-specific flags or admission requirements
- confirmation that your identity and vote account are approved for the validator set
Zink recommendation
If you do not yet have current entrypoints, known validators, expected genesis hash, and version guidance, you are not blocked from preparing the machine — but you are blocked from safely joining the live cluster. Finish host prep first, then request the current bootstrap bundle.
Operator handoff checklist
Before or during onboarding, expect to exchange these values.
Send these to the network team
- validator identity pubkey
- vote account pubkey
- public IP address or hostname
- cloud/provider region
- intended
--dynamic-port-range - whether the host will expose RPC publicly, privately, or not at all
- an operator contact for incident follow-up
Ask for these back
- entrypoints for the target cluster
- known validators for snapshot / gossip trust
- expected genesis hash
- recommended validator version
- whether the vote account should be created by you or pre-provisioned by the team
- any cluster-specific allowlisting or approval step after the node is online
Preferred bootstrap bundle format
Ask the Zink network team to send the live join parameters in a copy-pasteable bundle, not as prose scattered across chat.
text
cluster_name=Zink Testnet
validator_version=<AGAVE_OR_SOLANA_VERSION>
entrypoints=<HOST:PORT>,<HOST:PORT>
known_validators=<PUBKEY>,<PUBKEY>
expected_genesis_hash=<GENESIS_HASH>
dynamic_port_range=8000-10000
vote_account_policy=self-create | operator-provided
additional_flags=...
approval_contact=<TEAM_OR_PERSON>That format makes it much harder to misread one value and spend an hour debugging the wrong problem.
1. Prepare a trusted workstation
Do the key-generation and vote-account work on a trusted machine, not on the remote validator host.
Install the CLI
bash
sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"
export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"
solana --version
agave-validator --versionIf the Zink team tells you to match a specific release, pin it explicitly:
bash
solana-install init <VERSION>Point the CLI at the right cluster
For the currently published public Zink Testnet endpoint:
bash
solana config set --url https://testnet-rpc.z.ink
solana config getFor an unpublished or operator-only environment, use the URL provided during onboarding.
Generate validator keys
bash
mkdir -p ~/zink-validator
chmod 700 ~/zink-validator
solana-keygen new --outfile ~/zink-validator/identity.json
solana-keygen new --outfile ~/zink-validator/vote-account.json
solana-keygen new --outfile ~/zink-validator/withdrawer.jsonRecord the public keys you will share with the network team:
bash
solana-keygen pubkey ~/zink-validator/identity.json
solana-keygen pubkey ~/zink-validator/vote-account.json
solana-keygen pubkey ~/zink-validator/withdrawer.jsonZink recommendation
Treat the withdrawer key as the most sensitive key in this flow. Keep it under stronger custody than the validator host. Do not leave the withdrawer key on the validator machine.
Create or confirm the vote account
If onboarding expects you to create your own vote account, the standard command shape is:
bash
solana create-vote-account \
~/zink-validator/vote-account.json \
~/zink-validator/identity.json \
~/zink-validator/withdrawer.jsonThen verify it:
bash
solana vote-account $(solana-keygen pubkey ~/zink-validator/vote-account.json)If the vote account is operator-provided instead, do not improvise. Use the exact vote account and authority arrangement supplied during onboarding.
2. Prepare the validator host
Base OS and operator user
Use Ubuntu 22.04 or 24.04. Start with a clean, fully updated host.
bash
sudo apt update
sudo apt upgrade -y
sudo adduser solRunning the validator as a dedicated non-root user keeps the setup boring in the best possible way.
Create mount points and log paths
bash
sudo mkdir -p /mnt/ledger /mnt/accounts /var/log/zink-validator /home/sol/bin /home/sol/zink-validator
sudo chown -R sol:sol /mnt/ledger /mnt/accounts /var/log/zink-validator /home/sol/bin /home/sol/zink-validatorMount storage
Use separate high-performance NVMe devices for ledger and accounts. If you are formatting new disks, the shape is typically:
bash
# Example only — replace with your actual device names
sudo mkfs.ext4 /dev/nvme0n1
sudo mkfs.ext4 /dev/nvme1n1
sudo mount /dev/nvme0n1 /mnt/ledger
sudo mount /dev/nvme1n1 /mnt/accountsVerify the layout:
bash
lsblk
df -h /mnt/ledger /mnt/accountsApply Linux tuning
Apply the tuning from System Requirements before first boot. At minimum, ensure:
vm.max_map_count = 1000000fs.nr_open = 1000000net.core.rmem_max = 134217728net.core.wmem_max = 134217728- systemd
LimitNOFILEandLimitMEMLOCKare raised
3. Copy only the keys the host actually needs
The validator host needs the identity key. It does not need the withdrawer key.
If you created the vote account already, the launch command can use the vote-account pubkey instead of storing the vote-account keypair on the host.
Example copy step:
bash
scp ~/zink-validator/identity.json sol@<server>:/home/sol/zink-validator/If you still need the vote-account keypair on-box for your own workflow, copy it intentionally and remove it later once no longer needed.
4. Install Agave on the validator host
As the sol user:
bash
sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"
export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"
solana --version
agave-validator --versionIf Zink operator guidance specifies a particular release, pin that exact version here too.
5. Open ports and confirm reachability
At minimum, your validator needs its dynamic port range reachable.
Example UFW rules
bash
sudo ufw allow 8000:10000/tcp
sudo ufw allow 8000:10000/udpIf you intentionally expose RPC:
bash
sudo ufw allow 8899/tcp
sudo ufw allow 8900/tcpZink-specific
A node that starts cleanly but is not reachable on the configured dynamic port range will often fail the real goal: appearing in gossip and catching up. Port reachability is not a cosmetic check.
6. Create the validator launch script
Create /home/sol/bin/validator.sh:
bash
cat >/home/sol/bin/validator.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
exec /home/sol/.local/share/solana/install/active_release/bin/agave-validator \
--identity /home/sol/zink-validator/identity.json \
--vote-account <VOTE_ACCOUNT_PUBKEY> \
--ledger /mnt/ledger \
--accounts /mnt/accounts \
--log /var/log/zink-validator/validator.log \
--entrypoint <ZINK_ENTRYPOINT_1> \
--entrypoint <ZINK_ENTRYPOINT_2> \
--known-validator <KNOWN_VALIDATOR_PUBKEY_1> \
--known-validator <KNOWN_VALIDATOR_PUBKEY_2> \
--only-known-rpc \
--expected-genesis-hash <ZINK_GENESIS_HASH> \
--dynamic-port-range 8000-10000 \
--wal-recovery-mode skip_any_corrupted_record \
--limit-ledger-size
EOF
chmod +x /home/sol/bin/validator.shImportant notes:
--vote-accountcan be the vote-account pubkey; it does not need to be a keypair file once the account exists.- Keep the real cluster values in this script or a sourced env file, not in a chat message or a scratchpad.
- Add any extra cluster-specific flags supplied by the network team exactly as provided.
- Do not reach for
--no-port-checkunless you have a very specific networking reason and understand the tradeoff.
Optional RPC flags
If the validator will also answer RPC for internal use, you may add:
bash
--rpc-port 8899 \
--private-rpcFor a pure consensus validator, keep RPC exposure minimal.
7. Run it once in the foreground
Before you daemonize it, do one clean foreground boot.
bash
sudo -iu sol /home/sol/bin/validator.shLook for the good early signs:
- the process stays up
- a snapshot begins loading or replay advances
- there is no immediate genesis-hash or key mismatch failure
- logs do not show repeated bind failures or panic loops
Stop the foreground run with Ctrl+C once you are satisfied it is basically healthy.
8. Create a systemd service
Create /etc/systemd/system/zink-validator.service:
ini
[Unit]
Description=Zink Validator
After=network-online.target
Wants=network-online.target
[Service]
User=sol
LimitNOFILE=1000000
LimitMEMLOCK=2000000000
Restart=always
RestartSec=3
ExecStart=/home/sol/bin/validator.sh
[Install]
WantedBy=multi-user.targetThen enable and start it:
bash
sudo systemctl daemon-reload
sudo systemctl enable --now zink-validator9. Verify the node after first boot
Process and logs
bash
pgrep -af agave-validator
journalctl -u zink-validator -fGossip visibility
bash
solana gossip | grep <IDENTITY_PUBKEY>Validator-set visibility
bash
solana validators | grep <IDENTITY_PUBKEY>
solana validators | grep <VOTE_ACCOUNT_PUBKEY>Catchup progress
bash
solana catchup <IDENTITY_PUBKEY>Vote-account health
bash
solana vote-account <VOTE_ACCOUNT_PUBKEY>Healthy early signs:
- the node appears in gossip
solana catchupshows progress toward cluster head- the vote account resolves correctly
- logs show snapshot load and replay rather than repeated crash loops
10. Final activation checklist for Zink Testnet
Before calling the node ready, confirm all of these are true:
- the host is visible in
solana gossip - catchup is converging instead of drifting away
- the vote account is the expected one
- the validator version matches the cluster guidance
- the network team has confirmed the identity / vote account are admitted to the permissioned set
- firewall rules match the actual
--dynamic-port-range
If the node is healthy but not yet voting, the remaining blocker is usually onboarding state, not host prep.
Common first-join failures
- Wrong cluster bundle — stale entrypoints, stale genesis hash, or wrong software version
- Closed UDP/TCP ports — process is running, but the rest of the cluster cannot really talk to it
- Underpowered storage — replay never catches up because ledger/accounts I/O is saturated
- Vote-account mismatch — correct host, wrong vote account or wrong authorities
- Key custody mistakes — identity missing on host, withdrawer accidentally copied to host, wrong file permissions
- Clock drift — host time is bad, causing weird network behavior and misleading symptoms