> ## Documentation Index
> Fetch the complete documentation index at: https://docs.autheo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-hosting guide

> End-to-end guide for running an Autheo Chain validator node on your own infrastructure using Docker or systemd, including network configuration, sync methods, key management, and validator registration.

This guide covers running an Autheo node from scratch. Two deployment methods are provided: **Method A — systemd** (build from source) and **Method B — Docker** (official GHCR image).

<Note>
  **Before you begin:** This guide assumes you have already bridged your Sovereign license NFT from Arbitrum One to Autheo Mainnet. Complete that step first.

  Make sure you are bridging to the address you intend to use for creating the validator. That address must have enough THEO tokens for self-delegation and signing transactions. If you do not have a wallet yet, see [Key management](#7-key-management) to create one and obtain its address before bridging.

  See: [Bridging your Sovereign license NFT to Autheo Mainnet](https://hyper.autheo.com)
  [https://docs.autheo.com/web-apps/bridge/overview](https://docs.autheo.com/web-apps/bridge/overview)
</Note>

## 1. Chain reference

| Property         | Value                     |
| ---------------- | ------------------------- |
| Binary           | `autheod`                 |
| Cosmos chain ID  | `autheo_2127-1` (mainnet) |
| EVM chain ID     | `2127` (`0x84f`)          |
| Native denom     | `aauth`                   |
| Denom decimals   | 18 (1 THEO = 10^18 aauth) |
| Default home dir | `$HOME/.autheo`           |
| Key algorithm    | `eth_secp256k1`           |
| Block time       | \~5 seconds               |
| Block max gas    | `30000000`                |
| Min gas prices   | `10000000000000aauth`     |

**Ports (single node defaults):**

| Port    | Protocol | Purpose       |
| ------- | -------- | ------------- |
| `26656` | TCP      | CometBFT P2P  |
| `26657` | TCP      | CometBFT RPC  |
| `9090`  | TCP      | gRPC          |
| `1317`  | TCP      | REST API      |
| `8545`  | TCP      | EVM JSON-RPC  |
| `8546`  | TCP      | EVM WebSocket |

## 2. Infrastructure requirements

Size your server to meet the following minimums before proceeding. Under-provisioned nodes are more likely to miss blocks and get jailed.

| Resource | Minimum          | Recommended      |
| -------- | ---------------- | ---------------- |
| CPU      | 8 vCPU           | 16 vCPU          |
| RAM      | 32 GB            | 64 GB            |
| Storage  | 1 TB NVMe SSD    | 2 TB NVMe SSD    |
| Network  | 1 Gbps           | 10 Gbps          |
| OS       | Ubuntu 22.04 LTS | Ubuntu 22.04 LTS |

***

## 3. Method A: systemd

### 3.1 Prerequisites

```bash theme={null}
# Ubuntu / Debian
sudo apt update && sudo apt install -y \
  git make gcc build-essential \
  jq curl wget

# Go (must match go.mod — verify exact version at https://go.dev/dl/)
GO_VERSION=1.25.0
wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >> ~/.bashrc
source ~/.bashrc

go version
```

### 3.2 Build the binary

```bash theme={null}
git clone https://github.com/autheo-blockchain/autheo-chain-core
cd autheo-chain-core

make build
```

Install to PATH:

```bash theme={null}
sudo cp ./build/autheod /usr/local/bin/autheod
autheod --help
```

### 3.3 Join the network

All official configuration files are in the [autheo-blockchain/networks](https://github.com/autheo-blockchain/networks) repository.

```bash theme={null}
# 1. Clone the networks repo
git clone https://github.com/autheo-blockchain/networks

# 2. Initialize the node
autheod init <moniker> \
  --chain-id $(cat networks/mainnet/chain-id) \
  --home $HOME/.autheo

# 3. Copy the official genesis
cp networks/mainnet/genesis.json $HOME/.autheo/config/genesis.json

# 4. Set persistent peers
CONFIG=$HOME/.autheo/config/config.toml
sed -i "s|^persistent_peers = .*|persistent_peers = \"$(cat networks/mainnet/persistent_peers.txt)\"|" $CONFIG

# 5. Set minimum gas prices
APP=$HOME/.autheo/config/app.toml
sed -i 's|^minimum-gas-prices = .*|minimum-gas-prices = "10000000000000aauth"|' $APP
```

Then choose a sync method from [section 5](#5-sync-methods).

### 3.4 Configure the node

**`$HOME/.autheo/config/config.toml`**

```bash theme={null}
CONFIG=$HOME/.autheo/config/config.toml

# Expose RPC to all interfaces (default is 127.0.0.1)
sed -i 's|laddr = "tcp://127.0.0.1:26657"|laddr = "tcp://0.0.0.0:26657"|' $CONFIG
```

**`$HOME/.autheo/config/app.toml`**

```bash theme={null}
APP=$HOME/.autheo/config/app.toml

# Enable REST API (disabled by default)
sed -i '/^\[api\]/,/^\[/{s/^enable = false/enable = true/}' $APP
sed -i 's|address = "tcp://localhost:1317"|address = "tcp://0.0.0.0:1317"|' $APP

# Expose EVM JSON-RPC (enabled by default, bound to 127.0.0.1)
sed -i 's|address = "127.0.0.1:8545"|address = "0.0.0.0:8545"|' $APP
sed -i 's|ws-address = "127.0.0.1:8546"|ws-address = "0.0.0.0:8546"|' $APP

# Add debug and txpool namespaces
sed -i 's|api = "eth,net,web3"|api = "eth,net,web3,debug,txpool"|' $APP

# Expose gRPC (default is localhost:9090)
sed -i 's|address = "localhost:9090"|address = "0.0.0.0:9090"|' $APP
```

**`$HOME/.autheo/config/client.toml`**

```bash theme={null}
CLIENT=$HOME/.autheo/config/client.toml

sed -i 's|^keyring-backend = .*|keyring-backend = "file"|' $CLIENT
```

### 3.5 Start with systemd

Create `/etc/systemd/system/autheod.service`, adjusting `User`, `WorkingDirectory`, and `ExecStart` for your system user:

```ini theme={null}
[Unit]
Description=Autheo Chain Node
After=network-online.target
Wants=network-online.target

[Service]
User=autheo
WorkingDirectory=/home/autheo
ExecStart=/usr/local/bin/autheod start --home /home/autheo/.autheo
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
StandardOutput=journal
StandardError=journal
SyslogIdentifier=autheod

[Install]
WantedBy=multi-user.target
```

```bash theme={null}
sudo systemctl daemon-reload
sudo systemctl enable autheod
sudo systemctl start autheod
sudo systemctl status autheod
sudo journalctl -u autheod -f
```

***

## 4. Method B: Docker

The official image is published at `ghcr.io/autheo-blockchain/autheod`.

**Available tags:**

| Tag             | Use                     |
| --------------- | ----------------------- |
| `latest`        | Current mainnet release |
| `testnet`       | Current testnet release |
| `X.Y.Z`         | Pinned mainnet release  |
| `X.Y.Z-testnet` | Pinned testnet release  |

<Note>
  For production validators, pin to a specific release tag rather than `latest` so that container restarts do not pull an unexpected upgrade. Find release tags on the [GHCR package page](https://github.com/autheo-blockchain/autheod/pkgs/container/autheod).
</Note>

### 4.1 Pull the image

```bash theme={null}
docker pull ghcr.io/autheo-blockchain/autheod:latest
```

### 4.2 Prepare the data directory

The node home inside the container is `/root/.autheo`. Mount a host directory to persist state across container restarts.

```bash theme={null}
mkdir -p $HOME/.autheo
```

<Note>
  All `autheod` commands inside the container must use `--home /root/.autheo`. To run commands against a running container from the host, use `docker exec autheo-node autheod <command> --home /root/.autheo`.
</Note>

### 4.3 Join the network

```bash theme={null}
# 1. Clone the networks repo (on the host)
git clone https://github.com/autheo-blockchain/networks

# 2. Initialize the node
docker run --rm \
  -v $HOME/.autheo:/root/.autheo \
  ghcr.io/autheo-blockchain/autheod:latest \
  autheod init <moniker> --chain-id autheo_2127-1 --home /root/.autheo

# 3. Copy the official genesis
cp networks/mainnet/genesis.json $HOME/.autheo/config/genesis.json

# 4. Set persistent peers
CONFIG=$HOME/.autheo/config/config.toml
sed -i "s|^persistent_peers = .*|persistent_peers = \"$(cat networks/mainnet/persistent_peers.txt)\"|" $CONFIG

# 5. Set minimum gas prices
APP=$HOME/.autheo/config/app.toml
sed -i 's|^minimum-gas-prices = .*|minimum-gas-prices = "10000000000000aauth"|' $APP
```

Then apply the sync method of your choice from [section 5](#5-sync-methods) using the host-side config files.

### 4.4 Configure the node

Apply config changes directly to the host-side directory. Use the same `sed` commands from [section 3.4](#34-configure-the-node) — they operate on `$HOME/.autheo/config/` which is mounted into the container.

### 4.5 Run the container

```bash theme={null}
docker run -d \
  --name autheo-node \
  --restart unless-stopped \
  -v $HOME/.autheo:/root/.autheo \
  -p 26656:26656 \
  -p 26657:26657 \
  -p 9090:9090 \
  -p 1317:1317 \
  -p 8545:8545 \
  -p 8546:8546 \
  ghcr.io/autheo-blockchain/autheod:latest \
  autheod start --home /root/.autheo
```

**View logs:**

```bash theme={null}
docker logs -f autheo-node
```

**Stop and restart:**

```bash theme={null}
docker stop autheo-node
docker start autheo-node
```

***

## 5. Sync methods

After completing the join and configure steps for your chosen method, select one of the following sync strategies.

### Option A: State sync (recommended)

Downloads a recent snapshot from a live sentry and syncs only the remaining blocks.

```bash theme={null}
TRUST_HEIGHT=$(curl -s https://sentry1.autheo.com/block | jq -r '(.result.block.header.height | tonumber / 1000 | floor * 1000)')
TRUST_HASH=$(curl -s "https://sentry1.autheo.com/block?height=$TRUST_HEIGHT" | jq -r '.result.block_id.hash')

CONFIG=$HOME/.autheo/config/config.toml
sed -i '/^\[statesync\]/,/^\[/{s/^enable = false/enable = true/}' $CONFIG
sed -i "s|^rpc_servers = .*|rpc_servers = \"https://sentry1.autheo.com,https://sentry2.autheo.com,https://sentry3.autheo.com\"|" $CONFIG
sed -i "s|^trust_height = .*|trust_height = $TRUST_HEIGHT|" $CONFIG
sed -i "s|^trust_hash = .*|trust_hash = \"$TRUST_HASH\"|" $CONFIG
sed -i 's|^trust_period = .*|trust_period = "336h"|' $CONFIG
```

<Note>
  State sync does not retain historical data before the snapshot height. If you need a full archive node, use genesis sync instead.
</Note>

### Option B: Genesis sync

Replays every block from block 1. Required only for a full archive node.

<Note>
  The chain has had no governance upgrades since genesis — no additional setup is needed for current genesis sync.
</Note>

If governance upgrades occur in the future, genesis sync will require **cosmovisor** to manage binary swaps at each upgrade height. Historical upgrade plan names, heights, and binaries will be listed in `mainnet/upgrades.json` in the networks repo, following this structure:

```json theme={null}
[
  {
    "plan_name": "v1.7",
    "height": 1000000,
    "binary_version": "v1.7.0",
    "binary_url": "https://github.com/autheo-blockchain/autheo-chain-core/releases/download/v1.7.0/autheod_linux_amd64"
  }
]
```

`plan_name` is the exact string used in `MsgSoftwareUpgrade`. For each entry, create a matching cosmovisor directory with the corresponding binary.

```bash theme={null}
go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@latest

export DAEMON_NAME=autheod
export DAEMON_HOME=$HOME/.autheo

mkdir -p $DAEMON_HOME/cosmovisor/genesis/bin
cp <genesis-binary> $DAEMON_HOME/cosmovisor/genesis/bin/autheod

# For each upgrade in mainnet/upgrades.json:
#   mkdir -p $DAEMON_HOME/cosmovisor/upgrades/<plan_name>/bin
#   cp <binary> $DAEMON_HOME/cosmovisor/upgrades/<plan_name>/bin/autheod
# The directory name must exactly match the plan_name field.
```

***

## 6. Verify the node

**Sync status — `catching_up` must be `false` when fully synced:**

```bash theme={null}
# systemd
autheod status --node http://localhost:26657 | jq '.sync_info'

# Docker
docker exec autheo-node autheod status --node http://localhost:26657 | jq '.sync_info'
```

**EVM and REST checks — run from the host for both methods:**

```bash theme={null}
# EVM - result must be "0x84f" (2127)
curl -s -X POST http://localhost:8545 \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}'

# EVM - block number
curl -s -X POST http://localhost:8545 \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'

# REST API
curl -s http://localhost:1317/cosmos/base/tendermint/v1beta1/blocks/latest | jq '.block.header.height'
```

***

## 7. Key management

This chain uses **`eth_secp256k1`** keys.

**Create a new key:**

```bash theme={null}
# systemd
autheod keys add <key_name> \
  --keyring-backend file \
  --algo eth_secp256k1 \
  --home $HOME/.autheo

# Docker
docker exec -it autheo-node autheod keys add <key_name> \
  --keyring-backend file \
  --algo eth_secp256k1 \
  --home /root/.autheo
```

After creating the key, get its hex address for bridging:

```bash theme={null}
# systemd - run as two steps
# Step 1 - get Bech32 address
autheod keys show <key_name> -a --keyring-backend file --home $HOME/.autheo
# Step 2 - convert to hex
autheod debug addr <bech32_address>

# Docker - run as two steps
# Step 1 - get Bech32 address
docker exec -it autheo-node autheod keys show <key_name> -a --keyring-backend file --home /root/.autheo
# Step 2 - convert to hex
docker exec autheo-node autheod debug addr <bech32_address>
```

Use the `Address (hex)` value (prefixed with `0x`) when bridging your Sovereign license NFT and transferring THEO tokens to this address. Complete both steps before proceeding.

Keyring backends:

| Backend | Storage                | Use case                                                     |
| ------- | ---------------------- | ------------------------------------------------------------ |
| `file`  | Encrypted file on disk | Recommended for production — passphrase required on each use |
| `os`    | OS keychain            | macOS Keychain / Linux Secret Service                        |
| `test`  | Plaintext on disk      | Development only — never use in production                   |

**Import an existing key:**

If you already have a wallet (MetaMask, Keplr, or any BIP-39 compatible wallet), import it using its mnemonic. The imported address must be the same one you bridged the Sovereign license NFT to and that holds enough THEO for self-delegation. Only do this if you understand the risk: entering a mnemonic on a server exposes it to that environment.

```bash theme={null}
# systemd
autheod keys add <key_name> \
  --recover \
  --keyring-backend file \
  --algo eth_secp256k1 \
  --home $HOME/.autheo

# Docker
docker exec -it autheo-node autheod keys add <key_name> \
  --recover \
  --keyring-backend file \
  --algo eth_secp256k1 \
  --home /root/.autheo
```

**Show address:**

```bash theme={null}
# systemd
autheod keys show <key_name> -a \
  --keyring-backend file \
  --home $HOME/.autheo

# Docker
docker exec -it autheo-node autheod keys show <key_name> -a \
  --keyring-backend file \
  --home /root/.autheo
```

**List keys:**

```bash theme={null}
# systemd
autheod keys list \
  --keyring-backend file \
  --home $HOME/.autheo

# Docker
docker exec -it autheo-node autheod keys list \
  --keyring-backend file \
  --home /root/.autheo
```

**Show validator consensus public key:**

```bash theme={null}
# systemd
autheod tendermint show-validator --home $HOME/.autheo

# Docker
docker exec autheo-node autheod tendermint show-validator --home /root/.autheo
```

**Get your Autheo address from a hex address:**

Autheo Chain uses a Bech32 address format (`autheo...`). All on-chain transactions must use this address, not the `0x` hex form. Convert your EVM hex address (without the `0x` prefix) using:

```bash theme={null}
# systemd
autheod debug addr <hex_address_without_0x>

# Docker
docker exec autheo-node autheod debug addr <hex_address_without_0x>
```

Use the `Bech32 Acc` value from the output for all Autheo chain transactions.

***

## 8. Create a validator

Requirements:

* Node is fully synced (`catching_up: false`)
* Sufficient `aauth` balance for self-delegation and fees
* A Sovereign license owned by this account and bound to this validator address in **BOUND** status

The `x/licensedstaking` module enforces at the `MsgCreateValidator` level that a Sovereign license in BOUND status exists on the validator address. The transaction is rejected if this condition is not met.

**Step 1 — Verify your Sovereign license is BOUND:**

```bash theme={null}
# systemd

# Query licenses owned by your account
autheod query license licenses-by-owner <your_autheo_address> \
  --node http://localhost:26657 --output json

# Get your validator address (will prompt for passphrase)
autheod keys show <key_name> --bech val -a \
  --keyring-backend file \
  --home $HOME/.autheo

# Query license bound to your validator
autheod query license license-by-validator <validator_address> \
  --node http://localhost:26657 --output json

# Docker

# Query licenses owned by your account
docker exec autheo-node autheod query license licenses-by-owner <your_autheo_address> \
  --node http://localhost:26657 --output json

# Get your validator address (will prompt for passphrase)
docker exec -it autheo-node autheod keys show <key_name> --bech val -a \
  --keyring-backend file \
  --home /root/.autheo

# Query license bound to your validator
docker exec autheo-node autheod query license license-by-validator <validator_address> \
  --node http://localhost:26657 --output json
```

If your Sovereign license is in ISSUED status (not yet bound), bind it first:

```bash theme={null}
# systemd
autheod tx license bind <license_id> \
  --from <key_name> \
  --keyring-backend file \
  --chain-id autheo_2127-1 \
  --gas auto \
  --gas-adjustment 1.5 \
  --gas-prices 10000000000000aauth \
  --home $HOME/.autheo \
  --yes

# Docker
docker exec -it autheo-node autheod tx license bind <license_id> \
  --from <key_name> \
  --keyring-backend file \
  --chain-id autheo_2127-1 \
  --gas auto \
  --gas-adjustment 1.5 \
  --gas-prices 10000000000000aauth \
  --home /root/.autheo \
  --yes
```

Confirm the license is now BOUND before proceeding:

```bash theme={null}
# systemd
autheod query license license <license_id> \
  --node http://localhost:26657 --output json

# Docker
docker exec autheo-node autheod query license license <license_id> \
  --node http://localhost:26657 --output json
```

**Step 2 — Create the validator:**

<Warning>
  Do not submit `create-validator` more than once with the same consensus key. Double-signing results in permanent tombstoning — the validator cannot be recovered. Verify you have only one running instance before submitting.
</Warning>

```bash theme={null}
# systemd
VALIDATOR_PUBKEY=$(autheod tendermint show-validator --home $HOME/.autheo)

autheod tx staking create-validator \
  --pubkey "$VALIDATOR_PUBKEY" \
  --value 500000000000000000000aauth \
  --description '{"moniker":"<your_moniker>"}' \
  --commission '{"rate":"100000000000000000","max_rate":"200000000000000000","max_change_rate":"10000000000000000"}' \
  --min-self-delegation "1" \
  --from <key_name> \
  --keyring-backend file \
  --chain-id autheo_2127-1 \
  --home $HOME/.autheo \
  --gas auto \
  --gas-adjustment 1.5 \
  --gas-prices 10000000000000aauth \
  --yes

# Docker
VALIDATOR_PUBKEY=$(docker exec autheo-node autheod tendermint show-validator --home /root/.autheo)

docker exec -it autheo-node autheod tx staking create-validator \
  --pubkey "$VALIDATOR_PUBKEY" \
  --value 500000000000000000000aauth \
  --description '{"moniker":"<your_moniker>"}' \
  --commission '{"rate":"100000000000000000","max_rate":"200000000000000000","max_change_rate":"10000000000000000"}' \
  --min-self-delegation "1" \
  --from <key_name> \
  --keyring-backend file \
  --chain-id autheo_2127-1 \
  --home /root/.autheo \
  --gas auto \
  --gas-adjustment 1.5 \
  --gas-prices 10000000000000aauth \
  --yes
```

The self-delegation inside `create-validator` triggers the BOUND→ACTIVE license transition automatically.

**Step 3 — Verify the validator and license are active:**

```bash theme={null}
# systemd
# Step 1 - get validator address (will prompt for passphrase)
autheod keys show <key_name> --bech val -a \
  --keyring-backend file \
  --home $HOME/.autheo

# Step 2 - use the output from above
autheod query staking validator <validator_address> \
  --node http://localhost:26657 --output json

# Step 3 - get the license ID bound to this validator
autheod query license license-by-validator <validator_address> \
  --node http://localhost:26657 --output json

# Step 4 - check license status using the license ID from above, it must be ACTIVE
autheod query license license <license_id> \
  --node http://localhost:26657 --output json

# Docker
# Step 1 - get validator address (will prompt for passphrase)
docker exec -it autheo-node autheod keys show <key_name> --bech val -a \
  --keyring-backend file \
  --home /root/.autheo

# Step 2 - use the output from above
docker exec autheo-node autheod query staking validator <validator_address> \
  --node http://localhost:26657 --output json

# Step 3 - get the license ID bound to this validator
docker exec autheo-node autheod query license license-by-validator <validator_address> \
  --node http://localhost:26657 --output json

# Step 4 - check license status using the license ID from above, it must be ACTIVE
docker exec autheo-node autheod query license license <license_id> \
  --node http://localhost:26657 --output json
```

***

## 9. Troubleshooting

### Cannot connect to EVM JSON-RPC

Confirm the JSON-RPC server is enabled and bound correctly in `app.toml`:

```bash theme={null}
# Both methods — config is on the host-mounted directory
grep -A5 '\[json-rpc\]' $HOME/.autheo/config/app.toml
```

### Node not producing blocks / stuck

**systemd:**

```bash theme={null}
# Check peer count
curl -s http://localhost:26657/net_info | jq '.result.n_peers'

# Check sync status
autheod status --node http://localhost:26657 | jq '.sync_info.catching_up'

# Check logs
sudo journalctl -u autheod -n 100 --no-pager
```

**Docker:**

```bash theme={null}
# Check peer count
curl -s http://localhost:26657/net_info | jq '.result.n_peers'

# Check sync status
docker exec autheo-node autheod status --node http://localhost:26657 | jq '.sync_info.catching_up'

# Check logs
docker logs --tail 100 autheo-node
```
