Complete overview of all Integra servers, the mainnet/testnet coexistence model, and the full state of deployment readiness.
This document represents months of infrastructure work: a custom Cosmos EVM chain fork, 4 servers across 4 cloud providers, a live testnet running in parallel on shared servers, an air-gapped key management architecture where both the treasury AND all four validator operator keys live on a disconnected Windows laptop, a non-zero gas fee model from block 0, non-reproducible Go binaries requiring manual checksum verification across every server, and a genesis ceremony that requires physical USB transfers for every single cryptographic operation.
Last updated: 2026-03-09 (MAINNET LIVE — all 4 validators bonded, blocks producing)
| # | Name | IP | Provider | Specs | Cost | SSH | Status |
|---|---|---|---|---|---|---|---|
| 1 | mainnet-gateway | 89.167.88.24 |
Hetzner | 16C/32T, 128GB RAM, 2x3.84TB NVMe | $21.99/mo | ssh -i ~/.ssh/integra root@89.167.88.24 |
Ready — genesis, systemd, Caddy, Docker, UFW |
| 2 | testnet-gateway | 46.225.231.81 |
Hetzner | 8 vCPU, 16GB RAM, 320GB + 20GB vol | $21.99/mo | ssh -i ~/.ssh/integra root@46.225.231.81 |
Active (testnet + Blockscout + Portal) |
| 3 | signer-1 | 45.77.139.208 |
Vultr | 4 vCPU, 8GB RAM, 160GB | $40/mo | ssh -i ~/.ssh/integra root@45.77.139.208 |
Ready — testnet running, mainnet configured |
| 4 | signer-2 | 159.223.206.94 |
DigitalOcean | 4 vCPU, 8GB RAM, 200GB | $48/mo | ssh -i ~/.ssh/integra root@159.223.206.94 |
Ready — testnet running, mainnet configured |
| 5 | archive | 3.208.92.57 |
AWS us-east-1 | 4 vCPU, 32GB RAM, 1TB gp3 | ~$120/mo | ssh -i ~/.ssh/integra-validator-key.pem ubuntu@3.208.92.57 |
Ready — binary verified, systemd, UFW |
Total monthly cost: ~$252/mo (excludes Adam's personal validator on separate AWS EC2)
Every item below required individual SSH sessions across 4 providers with 3 different OS user models, 2 different SSH keys, and careful coordination to avoid disrupting the live testnet running on shared servers.
- Codebase audit — forked Cosmos EVM SDK, replaced all upstream
aatom/262144defaults withairl/26217, fixed 4 bugs, all 30 tests passing, CI fully green - Binary built from commit
0e6a388(Go 1.23.8, Cosmos SDK v0.53.5) — Go produces non-reproducible builds across environments, so the reference binary was physically copied to ensure identical executables. MD59f9c240e0e9f12a04990034410625b84verified on all 5 servers - Nodes initialized on all 4 mainnet servers — consensus keys generated per server
- Genesis created — 5 accounts, 100B IRL total supply, 5000 gwei base fee, 40+ parameters configured and cross-verified
- Genesis SHA-256 verified identical on all 4 servers:
4338fc44...14e2a10 - Persistent peers — full mesh topology, every server peers with every other
- Port offsets — systematic +10000 on all mainnet ports for shared servers (verified zero collisions across 11 port pairs per server)
- Config audit — every setting verified line-by-line across all 4 servers (gas prices, chain IDs, API enables, proxy_app ports, pruning modes, client configs)
- Systemd services created and enabled on all 4 mainnet servers
- Docker v29.3.0 installed on gateway, signing image built (306MB → 75MB .tar.gz) — this image is how Piyush runs signing commands on his air-gapped Windows laptop
- Caddy + TLS on gateway with path-routed reverse proxy, HTTPS auto-provisioned
- UFW hardened on all 4 mainnet servers (found 2 servers with no firewall at all, fixed)
- Consensus pubkeys collected and packaged as JSON
- Signing package hosted for download at
https://mainnet.integralayer.com/downloads/
Every step below requires physical interaction with the air-gapped Windows laptop. Files are downloaded from the gateway, transferred via USB stick to the air-gapped machine, processed, and the output makes the return journey via USB → Telegram to Adam.
This architecture — where not just the treasury but all four validator operator keys live on the air-gapped machine — means that every single validator operation (creation, delegation, governance vote) follows this physical transfer ceremony. No remote signing, no automation, no shortcuts.
- Download signing package from gateway (3 files)
- Transfer to air-gapped machine via USB
- Verify all 5 operator keys accessible in Docker keyring
- Sign 4 gentxs — one per validator, each referencing a different consensus pubkey, each a separate Docker command
- Transfer 4 signed gentx files back via email to Adam (2026-03-06)
- (Adam) Collect gentxs, finalize genesis, distribute, verify hash on all 4 — SHA-256:
de47657c531fcf81bf830800191539c697edbf16da494334a6d8631fdb6a228d - (Adam) Chain start — all 4 nodes started via systemctl, blocks producing (2026-03-09)
- (Adam) Verification — all 4 validators BONDED, EVM chain ID 0x6669, gas price ~5000 gwei, treasury 99.996B IRL
- Treasury delegations — same USB round-trip: 4 unsigned txs → sign with incrementing sequence → broadcast in order
Hosted on the mainnet gateway via HTTPS. Piyush downloads these on his internet-connected machine, then transfers to USB for the air-gapped laptop.
| File | Size | Download |
|---|---|---|
| Docker signing image | 75 MB | curl -O https://mainnet.integralayer.com/downloads/integra-signer.tar.gz |
| Genesis (pre-gentx) | 38 KB | curl -O https://mainnet.integralayer.com/downloads/genesis-pregentx.json |
| Consensus pubkeys | 850 B | curl -O https://mainnet.integralayer.com/downloads/consensus-pubkeys.json |
Or download all three at once:
mkdir integra-signing-package && cd integra-signing-package
curl -O https://mainnet.integralayer.com/downloads/integra-signer.tar.gz
curl -O https://mainnet.integralayer.com/downloads/genesis-pregentx.json
curl -O https://mainnet.integralayer.com/downloads/consensus-pubkeys.jsonNote
These will be removed from the gateway after genesis is finalized. The download endpoint is temporary.
A full audit of all servers revealed gaps that would have caused launch failures. Each server required individual SSH access, verification, and fixes — across 4 different providers, 3 different OS user models, and 2 different SSH keys. Nothing can be scripted when every server is its own snowflake.
Warning
Archive node's binary was 59KB larger than the reference despite identical source code and Go version. Different build environments produce non-reproducible binaries. For a Cosmos BFT chain, binary differences can cause consensus divergence — validators disagree on state transitions, the chain halts, and recovery requires coordinated intervention across all operators.
Fixed by physically copying the reference binary from gateway via SCP. The testnet gateway was also running a Feb 26 build while signer-1 and signer-2 (which share a single binary between testnet and mainnet) were already on the new one. Updating required stopping the testnet validator (can't overwrite a running binary on Linux), replacing, and restarting — brief testnet downtime even though the fix was for mainnet.
| Server | MD5 | Status |
|---|---|---|
| Gateway | 9f9c240e0e9f12a04990034410625b84 |
Reference |
| Signer-1 | 9f9c240e0e9f12a04990034410625b84 |
Match |
| Signer-2 | 9f9c240e0e9f12a04990034410625b84 |
Match |
| Archive | 9f9c240e0e9f12a04990034410625b84 |
Fixed (was mismatch) |
| Testnet GW | 9f9c240e0e9f12a04990034410625b84 |
Fixed (was older build) |
Caution
Two servers were running with no firewall at all. On signer-2, which runs both testnet and mainnet with validator keys on it, every port was exposed to the internet.
| Server | Before | After |
|---|---|---|
| Gateway | Missing EVM/REST/gRPC ports | Added 8545, 8546, 1317, 9090 |
| Signer-1 | Missing mainnet RPC | Added 36657 |
| Signer-2 | UFW completely inactive | Enabled: SSH, testnet (26656/26657), mainnet (36656/36657) |
| Archive | UFW completely inactive | Enabled: SSH, P2P, RPC, EVM, REST, gRPC |
- Gateway & Archive: No systemd service files existed — nodes were initialized and configured but literally could not start. Created services with appropriate flags.
- Archive: Pruning was set to
"default"instead of"nothing"— an archive node that prunes history defeats the entire purpose. Fixed in both app.toml and systemd. - Gateway: No Docker installed — needed to build the signing image for the air-gapped workflow.
These are the server-side consensus keys (Ed25519), auto-generated by intgd init. They sign blocks. They are NOT Piyush's operator keys (secp256k1).
| Server | Node ID | Consensus Pubkey |
|---|---|---|
| gateway | 837a39f482a80b56f491737055fe52199006f1fd |
O1JktAT8EVm+EEs1TphuwUwsBw+w/grbYeL4cj/cSq0= |
| signer-1 | adeaabdac580df25d3766d6f1950e30c1aba2f1c |
k95WNbsJQecxhavFluaJje5QMzIQEd9s8WJs/jauB1g= |
| signer-2 | 91d0540496a97bf071d7fd44458b1c00a2515af3 |
TxScDU+iPQkiTnjnsiCaCmUafrOXm2IyhPaR2cTiLes= |
| archive | 9c953486b7e73d0028ef63589605926213471ef3 |
Lym3RlyQMhhW6PTcTISlmzpE6W39QEosOW2Ynp5qUh4= |
Every setting verified line-by-line on all 4 servers. Each shared server (signer-1, signer-2) has two complete config sets — one for testnet (default home), one for mainnet (offset home). Every port, path, and flag was individually checked.
| Setting | Gateway | Signer-1 | Signer-2 | Archive |
|---|---|---|---|---|
| minimum-gas-prices | 5000000000000airl |
same | same | same |
| evm-chain-id | 26217 |
same | same | same |
| chain_id (genesis) | integra-1 |
same | same | same |
| api.enable | true |
false (OK) |
false (OK) |
false (OK) |
| json-rpc.enable | true |
false (OK) |
false (OK) |
false (OK) |
| proxy_app | 26658 | 36658 | 36658 | 26658 |
| P2P port | 26656 | 36656 | 36656 | 26656 |
| RPC port | 26657 | 36657 | 36657 | 26657 |
| pruning | default |
default |
default |
nothing |
Note
API and JSON-RPC are disabled in config on signers but the systemd services override this with explicit --api.address and --json-rpc.address flags binding to offset ports.
Signer-1 and signer-2 run both networks simultaneously on the same physical server. They share a single intgd binary at /usr/local/bin/intgd. Everything else is isolated — but this coupling creates operational complexity:
- Binary updates affect both networks. You can't overwrite a running executable on Linux (
Text file busy), so updating the mainnet binary requires stopping the testnet service too. - One wrong
--homeflag and you're operating on the wrong chain. No warning, no error. Commands silently target testnet instead of mainnet. - Firewall rules must cover both. Opening mainnet ports without breaking testnet requires careful per-port UFW configuration.
| Service | Testnet (default) | Mainnet (+10000 offset) |
|---|---|---|
| P2P | 26656 | 36656 |
| RPC | 26657 | 36657 |
| proxy_app | 26658 | 36658 |
| EVM JSON-RPC | 8545 | 18545 |
| WebSocket | 8546 | 18546 |
| REST API | 1317 | 11317 |
| gRPC | 9090 | 19090 |
| pprof | 6060 | 16060 |
| prometheus | 26660 | 36660 |
| Aspect | Testnet | Mainnet |
|---|---|---|
| Chain ID | integra-testnet-1 (EVM: 26218) |
integra-1 (EVM: 26217) |
| Home directory | ~/.intgd (default) |
/root/.intgd-mainnet |
| Systemd service | intgd.service |
intgd-mainnet.service |
MAINNET (integra-1, EVM 26217)
══════════════════════════════
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ mainnet-gateway│ │ signer-1 │ │ signer-2 │
│ 89.167.88.24 │◄───►│ 45.77.139.208 │◄───►│159.223.206.94 │
│ P2P: 26656 │ │ P2P: 36656 │ │ P2P: 36656 │
└───────┬────────┘ └───────┬────────┘ └───────┬────────┘
│ │ │
└──────────┬───────────┴──────────────────────┘
│
┌──────▼─────────┐
│ archive │
│ 3.208.92.57 │
│ P2P: 26656 │
└────────────────┘
| Account | IRL Amount | airl Amount |
|---|---|---|
| Treasury | 99,996,000,000 | 99996000000000000000000000000 |
| Gateway validator | 1,000,000 | 1000000000000000000000000 |
| Signer-1 validator | 1,000,000 | 1000000000000000000000000 |
| Signer-2 validator | 1,000,000 | 1000000000000000000000000 |
| Archive validator | 1,000,000 | 1000000000000000000000000 |
| Total supply | 100,000,000,000 | 100000000000000000000000000000 |
| Parameter | Value | Notes |
|---|---|---|
| Chain ID | integra-1 |
|
| EVM Chain ID | 26217 (0x6669) |
|
| Base fee | 5000000000000 (5000 gwei) |
~0.000005 IRL per gas unit |
| Min gas price | 5000000000000 |
Matches base fee |
| Inflation | 3% fixed | min = max = 0.03, rate_change = 0 |
| Unbonding | 21 days (1,814,400s) | |
| Max validators | 100 | |
| Voting period | 7 days | Expedited: 3 days |
| Min deposit | 100,000,000 IRL | Expedited: 500,000,000 IRL |
| Quorum | 33.4% | |
| Community tax | 0% | Initially zero |
| Slash (double-sign) | 5% | Permanent tombstoning |
| Slash (downtime) | 0.01% | 10min jail |
| ERC20 registration | Governance only | permissionless_registration = false |
| goal_bonded | 0.01 | Must be >0 — SDK silently rejects 0.0 |
| Endpoint | URL |
|---|---|
| RPC | https://mainnet.integralayer.com/rpc |
| REST API | https://mainnet.integralayer.com/api |
| EVM JSON-RPC | https://mainnet.integralayer.com/evm |
| WebSocket | wss://mainnet.integralayer.com/ws |
| Endpoint | URL |
|---|---|
| RPC | https://testnet.integralayer.com/rpc |
| REST API | https://testnet.integralayer.com/api |
| EVM JSON-RPC | https://testnet.integralayer.com/evm |
| WebSocket | wss://testnet.integralayer.com/ws |
# Mainnet gateway (Hetzner, dedicated)
ssh -i ~/.ssh/integra root@89.167.88.24
# Testnet gateway (Hetzner, dedicated)
ssh -i ~/.ssh/integra root@46.225.231.81
# Signer-1 (Vultr, shared — testnet + mainnet)
ssh -i ~/.ssh/integra root@45.77.139.208
# Signer-2 (DigitalOcean, shared — testnet + mainnet)
ssh -i ~/.ssh/integra root@159.223.206.94
# Archive (AWS — different SSH key, different user)
ssh -i ~/.ssh/integra-validator-key.pem ubuntu@3.208.92.57| Item | Value |
|---|---|
| Mainnet Chain ID | integra-1 |
| Mainnet EVM Chain ID | 26217 |
| Testnet Chain ID | integra-testnet-1 |
| Testnet EVM Chain ID | 26218 |
| Token | IRL / airl (18 decimals) |
| Bech32 Prefix | integra |
| Binary | intgd (commit 0e6a388) |
| Binary MD5 | 9f9c240e0e9f12a04990034410625b84 |
| Go version | 1.23.8 linux/amd64 |
| Cosmos SDK | v0.53.5 |
| Repo | github.com/Integra-layer/integra-chain |
| Genesis SHA-256 | 4338fc44d971a677d84bc23e6d053d58a9fe7e9bff00136f3027ee18f14e2a10 |
Each gentx links one of Piyush's operator keys to the corresponding server's consensus key. Four validators = four separate signing ceremonies on the air-gapped machine, each output file transferred to USB, each verified, each sent back individually.
intgd genesis gentx <key-name> <STAKE_AMOUNT>airl \
--chain-id integra-1 \
--moniker "<validator-name>" \
--commission-rate 0.05 \
--commission-max-rate 0.20 \
--commission-max-change-rate 0.01 \
--gas-prices 5000000000000airl \
--gas 200000 \
--pubkey '<consensus-pubkey-json>' \
--keyring-backend fileWarning
--gas-prices 5000000000000airl is mandatory. The genesis has a non-zero base fee by design — no free transactions from block 0. Without this flag, the gentx silently fails DeliverTx validation.
Note
Each validator has 1,000,000 IRL in genesis. The stake amount should leave some IRL in the account for gas fees. Example: staking 999,000 IRL leaves 1,000 IRL for operations.