Chain ID:atomone-testnet-1
Block Height:—
RPC Status:Checking...
Node Version:—

Installation

Step-by-step installation guide for AtomOne - Cosmovisor (recommended) or manual setup, your choice below. Looking for a faster option? Check the auto-install scripts further down.

Recommended for most operators. Cosmovisor automatically switches binaries at scheduled on-chain upgrade heights and preserves previous versions for rollback if needed.

Core Setup

1

Setup Server & Dependencies

Update the system and install all packages required to build the node.

bash
sudo apt update && sudo apt upgrade -y && sudo apt install curl tar wget jq build-essential git chrony lz4 -y
2

Install Go

Go version

Only change this if the chain requires a different minimum Go version than our default.

bash
ver="1.21.2"
cd $HOME
wget "https://golang.org/dl/go$ver.linux-amd64.tar.gz"
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go$ver.linux-amd64.tar.gz"
rm "go$ver.linux-amd64.tar.gz"
echo "export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin" >> ~/.bash_profile
source ~/.bash_profile
go version
3

Clone & Build Binary

Version tag to build

Defaults to the last known-good tag from our config.

bash
if [ ! -d "atomone" ]; then
  git clone https://github.com/atomone-hub/atomone.git
else
  echo "atomone already exists, skipping clone."
fi
cd atomone
git checkout v4.1.0
make install
atomoned version --long
4

Install & Initialize Cosmovisor

Installs Cosmovisor and sets up its genesis/ and upgrades/ folder structure around the binary you just built.

Install Cosmovisor

bash
if ! command -v cosmovisor &> /dev/null; then
  go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@latest
else
  echo "Cosmovisor already installed, skipping."
fi

Initialize

bash
export DAEMON_NAME=atomoned
export DAEMON_HOME=$HOME/.atomone
cosmovisor init $(which atomoned)

Node Configuration

5

Initialize Node

Set your moniker

Your moniker is your node's public display name on the network.

bash
atomoned init $(hostname) --chain-id atomone-testnet-1
6

Custom Port

optional

Only needed if you're running multiple nodes on the same server and need to avoid port conflicts. Comes before Configure App below, since that step needs to point at whatever port you set here.

Shift default ports

bash
CUSTOM_PORT=26
sed -i.bak -e "s%^proxy_app = \"tcp://127.0.0.1:26658\"%proxy_app = \"tcp://127.0.0.1:${CUSTOM_PORT}658\"%; s%^proxy_app = \"tcp://localhost:26658\"%proxy_app = \"tcp://localhost:${CUSTOM_PORT}658\"%; s%^laddr = \"tcp://127.0.0.1:26657\"%laddr = \"tcp://127.0.0.1:${CUSTOM_PORT}657\"%; s%^laddr = \"tcp://localhost:26657\"%laddr = \"tcp://localhost:${CUSTOM_PORT}657\"%; s%^laddr = \"tcp://0.0.0.0:26656\"%laddr = \"tcp://0.0.0.0:${CUSTOM_PORT}656\"%; s%^pprof_laddr = \"localhost:6060\"%pprof_laddr = \"localhost:${CUSTOM_PORT}060\"%; s%^pprof_laddr = \"127.0.0.1:6060\"%pprof_laddr = \"127.0.0.1:${CUSTOM_PORT}060\"%; s%^prometheus_listen_addr = \":26660\"%prometheus_listen_addr = \":${CUSTOM_PORT}660\"%" $HOME/.atomone/config/config.toml
sed -i.bak -e "s%^address = \"tcp://0.0.0.0:1317\"%address = \"tcp://0.0.0.0:${CUSTOM_PORT}317\"%; s%^address = \"tcp://localhost:1317\"%address = \"tcp://localhost:${CUSTOM_PORT}317\"%; s%^address = \"0.0.0.0:9090\"%address = \"0.0.0.0:${CUSTOM_PORT}090\"%; s%^address = \"localhost:9090\"%address = \"localhost:${CUSTOM_PORT}090\"%; s%^address = \"0.0.0.0:9091\"%address = \"0.0.0.0:${CUSTOM_PORT}091\"%; s%^address = \"localhost:9091\"%address = \"localhost:${CUSTOM_PORT}091\"%; s%^address = \":8080\"%address = \":${CUSTOM_PORT}080\"%" $HOME/.atomone/config/app.toml
7

Configure App

Point the CLI to this chain's ID, keyring backend, and local node.

bash
atomoned config chain-id atomone-testnet-1
atomoned config keyring-backend file
atomoned config node tcp://localhost:26657
8

Set Minimum Gas Price & Node Defaults

Set minimum gas price, enable Prometheus, and disable / enable indexing.

bash
# set minimum gas price, enable prometheus and disable indexing
sed -i 's|minimum-gas-prices =.*|minimum-gas-prices = "0.3uphoton"|g' $HOME/.atomone/config/app.toml
sed -i -e "s/prometheus = false/prometheus = true/" $HOME/.atomone/config/config.toml
sed -i -e "s/^indexer *=.*/indexer = \"null\"/" $HOME/.atomone/config/config.toml
9

Download Genesis & Addrbook

bash
wget -O $HOME/.atomone/config/genesis.json "<genesis-url>"
wget -O $HOME/.atomone/config/addrbook.json "<addrbook-url>"
10

Set Seeds & Peers

Loading peers…

Finishing Touches

11

Configure Pruning

These defaults are suited for a regular RPC/full node. Use 'nothing' for an archive node, or 'everything' to minimize disk usage.

Pruning strategy

bash
pruning="custom"
pruning_keep_recent="100"
pruning_keep_every="0"
pruning_interval="10"
sed -i -e "s/^pruning *=.*/pruning = \"$pruning\"/" $HOME/.atomone/config/app.toml
sed -i -e "s/^pruning-keep-recent *=.*/pruning-keep-recent = \"$pruning_keep_recent\"/" $HOME/.atomone/config/app.toml
sed -i -e "s/^pruning-keep-every *=.*/pruning-keep-every = \"$pruning_keep_every\"/" $HOME/.atomone/config/app.toml
sed -i -e "s/^pruning-interval *=.*/pruning-interval = \"$pruning_interval\"/" $HOME/.atomone/config/app.toml
12

Create Service & Start

This creates a systemd service that runs the node through Cosmovisor, so it restarts automatically on crash/reboot AND swaps binaries automatically at upgrade height.

bash
sudo tee /etc/systemd/system/atomoned.service > /dev/null << EOF
[Unit]
Description=atomoned (via cosmovisor)
After=network-online.target

[Service]
User=$USER
Environment="DAEMON_NAME=atomoned"
Environment="DAEMON_HOME=$HOME/.atomone"
Environment="DAEMON_ALLOW_DOWNLOAD_BINARIES=false"
Environment="DAEMON_RESTART_AFTER_UPGRADE=true"
ExecStart=$(which cosmovisor) run start --home $HOME/.atomone
Restart=on-failure
RestartSec=3
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable atomoned
sudo systemctl restart atomoned && sudo journalctl -fu atomoned -o cat

A few basic hardening steps worth doing on any fresh server - not specific to this chain, and not required for the node to run. Read each command before running it and do them one at a time, not chained together - the SSH steps in particular can lock you out if a key isn't already working.

1. Create a non-root admin user

Most fresh servers only have root SSH access - do this before disabling root login below, or you'll have nothing left to log in as. First, generate an SSH key on your own computer (skip this if you already have one):

bash
ssh-keygen -t ed25519

Print the public key and copy it - you'll paste it into the next command:

bash
cat ~/.ssh/id_ed25519.pub

Then, on the server, create the user and install that key:

bash
sudo adduser admin --disabled-password -q
sudo mkdir -p /home/admin/.ssh
echo "PASTE_YOUR_PUBLIC_KEY_HERE" | sudo tee -a /home/admin/.ssh/authorized_keys
sudo chown -R admin: /home/admin/.ssh
echo "admin ALL=(ALL) NOPASSWD:ALL" | sudo tee -a /etc/sudoers

NOPASSWD is a deliberate trade-off, not an oversight - this account has no password at all (login is key-only), so sudo has nothing to prompt for. Log out and back in as admin@your-server-ip and confirm it works before moving on.

2. SSH: key-only login, no root

Make sure you can already log in as the admin user above before running this - it disables password login and root login entirely.

bash
sudo sed -i.bak -e 's/^#*PermitRootLogin.*/PermitRootLogin no/' \
  -e 's/^#*ChallengeResponseAuthentication.*/ChallengeResponseAuthentication no/' \
  -e 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' \
  -e 's/^#*PermitEmptyPasswords.*/PermitEmptyPasswords no/' \
  -e 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo systemctl restart sshd
3. Firewall

Default-deny inbound, only open SSH and this node's P2P port. RPC/API are left closed here on purpose - only open 26657/26317 if you actually want them reachable directly from the internet; otherwise keep them on localhost and put a reverse proxy (with rate limiting) in front instead.

bash
sudo apt-get install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 26656/tcp comment 'P2P'
sudo ufw enable
4. Ban repeated SSH login failures

fail2ban automatically firewalls off an IP after too many failed SSH attempts.

bash
sudo apt-get install -y fail2ban
sudo systemctl enable --now fail2ban
5. Security updates: now and automatic

Applies any patches already outstanding, then sets up automatic security updates going forward so you don't need to remember to check again.

bash
sudo apt update && sudo apt upgrade -y
sudo apt-get install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
6. Lock down the validator key file

Only needed if this node is (or will become) a validator - restricts priv_validator_key.json so only the account running the node can read it.

bash
chmod 600 ~/.atomone/config/priv_validator_key.json

Once the service is running, this polls your node's own height against AtomOne's live network height every 5s and reports how many blocks are left - stops on its own once caught up.

bash
#!/bin/bash
# Compares this node's local height against a live network RPC to track sync progress.
trap 'exit 0' INT

while true; do
  local_status=$(curl -s "localhost:26657/status")
  local_height=$(echo "$local_status" | jq -r '.result.sync_info.latest_block_height // empty')
  catching_up=$(echo "$local_status" | jq -r '.result.sync_info.catching_up // empty')
  network_height=$(curl -s "https://atomone-testnet-rpc.kynraze.com/status" | jq -r '.result.sync_info.latest_block_height // empty')

  if [[ -z "$local_height" || -z "$network_height" ]]; then
    echo "Could not read a height from the local or network RPC - retrying..."
    sleep 5
    continue
  fi

  blocks_left=$((network_height - local_height))

  if [[ "$catching_up" == "false" ]]; then
    echo "Synced - local height $local_height (network $network_height)."
    break
  fi

  echo "Local: $local_height | Network: $network_height | Blocks left: $blocks_left"
  sleep 5
done

Contact Us

Questions about staking, delegation, or running a validator with us? Reach out directly or use the form.

Kynraze
Kynraze
Validator operator

Questions about delegating, commission, or a specific chain? Email us or send a message through the form, and we'll get back to you.