Gno.land Test13 Docker Validator Setup
This guide deploys a Gno test13 node with Docker Compose. gnoland runs in a container and stores chain data under /data/gno/gnoland-data on the host. gnokey runs on the host, so the source build still installs both gnoland and gnokey.
The commands below assume a root shell. If you use a non-root user, prefix system package and firewall commands with sudo.
Variables
Set all operator-specific values once before running the guide:
export GNO_HOME=/data/gno
export GNO_REPO=${GNO_HOME}/gno
export GNO_DATA=${GNO_HOME}/gnoland-data
export GNO_CHAIN_ID=test-13
export GNO_IMAGE=gnoland:test13
export GNO_BRANCH=chain/test13
export GNO_GENESIS_URL=https://github.com/gnolang/gno/releases/download/chain/test13/genesis.json
export GNO_RPC=https://rpc.test13.testnets.gno.land:443
export GNO_P2P_PORT=26656
export GNO_RPC_PORT=26657
export GNO_KEY_NAME=operator
export GNO_PUBLIC_IP=$(curl -s https://ipinfo.io/ip)
export GNO_SEEDS=g1rrj6gvxp7ph8d4rsy9vegrhp8nx4lyxzgmc4ad@gnoland-testnet-seed.itrocket.net:54656
export GNO_PERSISTENT_PEERS=g1e3pftctakyx58mzapqs4syc4h0jcxwtnraq00c@185.248.24.16:47656,[email protected]:26656,[email protected]:32556,[email protected]:41656,[email protected]:26656,[email protected]:17656,[email protected]:26656,[email protected]:17656,[email protected]:26656,[email protected]:26656,[email protected]:26656,[email protected]:26656,[email protected]:26656,[email protected]:54656,[email protected]:22656,[email protected]:27656,[email protected]:26656,[email protected]:26656,[email protected]:26656,[email protected]:26656,[email protected]:26656,[email protected]:30800,[email protected]:37656,[email protected]:26656
The example key name operator is only a local keyring label. Choose a label that helps you recognize the wallet on the server.
System Requirements
| Component | Recommended |
|---|---|
| CPU | 4+ cores |
| Memory | 8GB+ RAM |
| Storage | 200GB+ NVMe SSD |
| OS | Ubuntu 22.04/24.04 LTS |
| Network | Public TCP 26656 for P2P; restrict RPC 26657 unless you intentionally expose it |
Install Dependencies
apt update
apt install -y git make build-essential curl wget jq lz4 ufw ca-certificates ripgrep
Install Go if it is not already available:
go version
Gno test13 builds with a recent Go toolchain. If go version is missing or too old, install Go from the official Go downloads page before continuing.
Install Docker Engine with the Compose plugin:
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${VERSION_CODENAME}") stable" \
> /etc/apt/sources.list.d/docker.list
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
docker --version
docker compose version
Build Gno and Host Binaries
mkdir -pv ${GNO_HOME}
cd ${GNO_HOME}
git clone https://github.com/gnolang/gno.git
cd ${GNO_REPO}
git checkout ${GNO_BRANCH}
make -C gno.land install.gnoland install.gnokey
docker build --target gnoland -t ${GNO_IMAGE} .
docker run --rm ${GNO_IMAGE} version
gnokey version
gnoland is built into the Docker image and node operations below use Docker or Docker Compose. gnokey is used directly on the host for keys and transactions.
Create Data Directories and Genesis
mkdir -pv ${GNO_DATA}/config ${GNO_DATA}/secrets
cd ${GNO_HOME}
wget -O ${GNO_DATA}/genesis.json ${GNO_GENESIS_URL}
shasum -a 256 ${GNO_DATA}/genesis.json
Compare the hash with the checksum published by the official test13 release notes before starting the node.
Create Docker Compose File
cat > ${GNO_HOME}/docker-compose.yaml << EOF
services:
gnoland:
image: ${GNO_IMAGE}
container_name: gnoland-test13
restart: unless-stopped
ports:
- "${GNO_P2P_PORT}:26656"
- "127.0.0.1:${GNO_RPC_PORT}:26657"
volumes:
- ${GNO_DATA}:/gnoland-data
command: >
start
-chainid ${GNO_CHAIN_ID}
-data-dir /gnoland-data
-genesis /gnoland-data/genesis.json
-skip-genesis-sig-verification=true
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "5"
EOF
RPC is bound to 127.0.0.1 in this example. Put a reverse proxy and access control in front of it if remote RPC access is required.
Initialize Config and Secrets
Run gnoland configuration commands through Docker Compose:
cd ${GNO_HOME}
docker compose run --rm gnoland config init -config-path /gnoland-data/config/config.toml
docker compose run --rm gnoland secrets init -data-dir /gnoland-data/secrets
Update the generated config with test13 networking values:
python3 - <<'PY'
import os
from pathlib import Path
path = Path(os.environ["GNO_DATA"]) / "config" / "config.toml"
text = path.read_text()
public_ip = os.environ["GNO_PUBLIC_IP"]
seeds = os.environ["GNO_SEEDS"]
persistent_peers = os.environ["GNO_PERSISTENT_PEERS"]
replacements = {
'db_backend = "lmdbdb"': 'db_backend = "pebbledb"',
'moniker = ""': 'moniker = "gno-test13-node"',
'prune_strategy = "everything"': 'prune_strategy = "syncable"',
'timeout_commit = "1s"': 'timeout_commit = "3s"',
'peer_gossip_sleep_duration = "100ms"': 'peer_gossip_sleep_duration = "10ms"',
'flush_throttle_timeout = "100ms"': 'flush_throttle_timeout = "10ms"',
'laddr = "tcp://127.0.0.1:26657"': 'laddr = "tcp://0.0.0.0:26657"',
'laddr = "tcp://127.0.0.1:26656"': 'laddr = "tcp://0.0.0.0:26656"',
'external_address = ""': f'external_address = "{public_ip}:26656"',
'seeds = ""': f'seeds = "{seeds}"',
'persistent_peers = ""': f'persistent_peers = "{persistent_peers}"',
}
for old, new in replacements.items():
text = text.replace(old, new)
path.write_text(text)
PY
Review peer settings before startup:
rg -n "moniker|external_address|seeds|persistent_peers|db_backend|laddr" ${GNO_DATA}/config/config.toml
Open P2P Port
ufw allow ${GNO_P2P_PORT}/tcp
ufw status
If your cloud provider has a separate firewall, allow TCP 26656 there as well.
Optional: Restore Snapshot
If you use a trusted snapshot, stop the node first and extract the snapshot into the mounted data directory:
cd ${GNO_HOME}
docker compose down
curl -L http://146.19.24.32:8000/gno_test13/gno-test13-snapshot.tar.lz4 \
| lz4 -c -d - \
| tar -x -C ${GNO_DATA} \
--exclude='./config' \
--exclude='./config/*' \
--exclude='./secrets' \
--exclude='./secrets/*' \
--exclude='./genesis.json'
Only restore snapshots from sources you trust. Keep config/, secrets/, and genesis.json intact.
Start the Node
cd ${GNO_HOME}
docker compose up -d
docker compose ps
docker compose logs -f
Check node status from the host:
curl -s http://127.0.0.1:${GNO_RPC_PORT}/status | jq
Wait until catching_up is false before sending validator registration transactions.
Create a Host Wallet
Run gnokey on the host:
gnokey add ${GNO_KEY_NAME}
gnokey list
Back up the mnemonic immediately. Fund the resulting Gno address with enough ugnot for registration and later operations.
Confirm the account is visible on test13:
gnokey query -remote "${GNO_RPC}" auth/accounts/$(gnokey list | awk '/address:/ {print $2; exit}')
Read Validator Key from the Container Data
The validator private key lives under the mounted /gnoland-data/secrets directory and is read through Docker Compose:
docker compose run --rm gnoland secrets get validator_key -data-dir /gnoland-data/secrets
Use the returned validator address and public key in the registration command below. Keep the key files under ${GNO_DATA}/secrets backed up and private.
Register the Validator
The registration transaction is a gnokey transaction from the host. The example below avoids separate placeholder variables for the public profile fields; replace the human-readable example strings inline.
gnokey maketx call \
--pkgpath gno.land/r/gnops/valopers \
--func Register \
--args "gno-test13-node" \
--args "Gno test13 validator running Docker Compose with host-side gnokey operations and Prometheus monitoring." \
--args "data-center" \
--args "g1examplevalidatoraddressxxxxxxxxxxxxxxxxxx" \
--args "gpub1examplevalidatorpublickeyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
--gas-fee 1000000ugnot \
--gas-wanted 50000000 \
--chainid ${GNO_CHAIN_ID} \
--remote ${GNO_RPC} \
--broadcast \
${GNO_KEY_NAME}
The first two --args are examples for the public profile shown in the valopers registry. The validator address and public key come from docker compose run --rm gnoland secrets get validator_key -data-dir /gnoland-data/secrets.
Maintenance Commands
cd ${GNO_HOME}
docker compose ps
docker compose logs --tail=100 gnoland
docker compose logs -f gnoland
docker compose restart gnoland
docker compose down
docker compose up -d
Check disk usage:
du -sh ${GNO_HOME} ${GNO_DATA} ${GNO_DATA}/*
df -h
Backup
Back up the key material and config before upgrades:
tar -czf ${GNO_HOME}/gno-test13-config-secrets-$(date +%Y%m%d).tar.gz \
-C ${GNO_DATA} \
config secrets genesis.json
Store the archive outside the validator host. Never publish secrets/ or wallet mnemonics.