Canton Network MainNet Validator Installation Guide
About Canton Network
Canton Network is the first public permissionless blockchain platform designed for institutional finance, combining privacy, interoperability, and scalability.
Key Features:
- Privacy-preserving architecture
- Atomic cross-domain transactions
- BFT consensus
- Institutional-grade security
Network Details:
- Network: MainNet
- Version: 0.7.5 (verified 2026-09-18)
- Migration ID: 4
- Purpose: Production network
Never trust a version number written in a guide, including this one. Read it
from the network before installing or upgrading:
curl -s https://docs.global.canton.network.sync.global/info | jq .
Participants:
Goldman Sachs, Deutsche Börse, BNP Paribas, Microsoft, Moody's, S&P Global, Digital Asset, and other institutional players.
Requirements
Hardware
| Component | Minimum | Recommended |
|---|
| CPU | 8 cores | 16 cores |
| RAM | 16 GB | 32 GB |
| Storage | 250 GB NVMe | 500 GB NVMe |
| Network | 1 Gbps | 10 Gbps |
Software
- Docker 20.10+
- Docker Compose 2.0+
- curl, jq
⚠️ Important:
- Unique dedicated IP required (cannot be shared with DevNet or TestNet)
- Corporate email required for validator application
- ~2 weeks approval process by Tokenomics Committee
Onboarding Process
1. Submit Validator Form
Fill out the validator request form:
https://sync.global/validator-request/
Requirements:
- Corporate email (not Gmail/Yahoo/etc.)
- Company information
- Dedicated IP address for MainNet
Expected approval time: ~2 weeks
2. IP Whitelist
- After approval, contact SV sponsor in Slack
- Provide your dedicated IP address for MainNet
- Wait 2-7 days for whitelisting (2/3 Super Validators must approve)
3. Verify IP Whitelist
bash -c 'CURL="curl -fsS -m 5 --connect-timeout 5"
for url in $($CURL https://scan.sv-1.global.canton.network.sync.global/api/scan/v0/scans | jq -r ".scans[].scans[].publicUrl"); do
echo -n "$url: "
$CURL "$url"/api/scan/version | jq -r ".version" 2>&1 || echo "TIMEOUT"
done'
All SVs should respond with version (not TIMEOUT) = IP is whitelisted ✅
4. Get Onboarding Secret
Request from your SV sponsor in Slack (valid for 48 hours).
Installation
Step-by-Step Installation
1. System Preparation
# Update system
apt update && apt upgrade -y
# Install dependencies
apt install -y curl iptables build-essential git wget jq make gcc \
nano tmux htop pkg-config libssl-dev tar clang ncdu unzip
# Install Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
apt update && apt install -y docker-ce
docker --version
# Install Docker Compose
curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version
2. Check Network Status
curl -s https://docs.global.canton.network.sync.global/info | jq .
{"network":"mainnet","sv":{"migration_id":4,"serial_id":5,"version":"0.7.5"},
"synchronizer":{"current":{"chain_id_suffix":"2","serial_id":5,"version":"0.7.5"},
"legacy":null,"successor":null}}
Note sv.version and sv.migration_id — you need both below. This endpoint is
public and needs no API key and no IP whitelisting, so it works before your
node exists.
Do not use https://lighthouse.cantonloop.com/api/stats for this. It now
returns 401 API key required. Any guide or script still polling it for the
network version is broken.
3. Download Canton Node
# Use the version from step 2
VERSION="0.5.9"
mkdir -p ~/.canton/${VERSION}
cd ~/.canton/${VERSION}
wget https://github.com/digital-asset/decentralized-canton-sync/releases/download/v${VERSION}/${VERSION}_splice-node.tar.gz
tar xzf ${VERSION}_splice-node.tar.gz
cd splice-node/docker-compose/validator
4. Start Validator
cd ~/.canton/${VERSION}/splice-node/docker-compose/validator
export IMAGE_TAG=${VERSION}
./start.sh \
-s "https://sv.sv-2.global.canton.network.digitalasset.com" \
-c "https://scan.sv-2.global.canton.network.digitalasset.com" \
-o "YOUR_ONBOARDING_SECRET_FROM_SV" \
-p "YOUR_VALIDATOR_NAME" \
-m "4" \
-w
⚠️ If sv-2 is unavailable, try sv-1 or specify scan separately with -c:
./start.sh \
-s "https://sv.sv-1.global.canton.network.digitalasset.com" \
-c "https://scan.sv-2.global.canton.network.digitalasset.com" \
-o "YOUR_ONBOARDING_SECRET_FROM_SV" \
-p "YOUR_VALIDATOR_NAME" \
-m "4" \
-w
Parameters:
-s - Sponsor SV URL (use sv-2 .digitalasset.com; sv-1 can be unstable)
-c - Scan address (use if SV scan is down but another SV's scan works)
-o - Onboarding secret from SV sponsor (use "" after first start)
-p - Party hint (validator name)
-m - Migration ID (4 for MainNet)
-w - Enable wallet
⚠️ SV Fallback: If sv-2 is unavailable, try other SVs:
https://sv.sv-2.global.canton.network.digitalasset.com (preferred)
https://sv.sv-1.global.canton.network.digitalasset.com
You can specify the scan address separately with -c flag if the SV endpoint works but its scan is down:
./start.sh \
-s "https://sv.sv-1.global.canton.network.digitalasset.com" \
-c "https://scan.sv-2.global.canton.network.digitalasset.com" \
-o "" -p "YOUR_VALIDATOR_NAME" -m "4" -w
Check SV health before starting:
curl -s --max-time 5 "https://scan.sv-2.global.canton.network.digitalasset.com/api/scan/version"
5. Check Status
# Container status
docker ps --filter "name=splice-validator"
# Logs
docker logs splice-validator-validator-1 -f --tail 100
# Health check
docker ps --filter "name=splice-validator-validator" --format "{{.Names}}: {{.Status}}"
# Should show: Up X minutes (healthy)
Unsafe Auth Mode (Disable Authentication)
If you need to disable authentication for local access (e.g. scripts, monitoring):
cd ~/.canton/${VERSION}/splice-node/docker-compose/validator
1. Add compose override to .env:
echo "COMPOSE_FILE=compose.yaml:compose-disable-auth.yaml" >> .env
2. Set required environment variables in .env:
Even with auth disabled, the Wallet UI requires valid URLs in its config — otherwise you get a Zod validation error (Invalid url for auth.authority / networkFaviconUrl).
Add these to .env:
AUTH_URL=https://unsafe.auth
SPLICE_APP_UI_NETWORK_FAVICON_URL=https://www.canton.network/hubfs/cn-favicon-05%201-1.png
SPLICE_APP_UI_NETWORK_NAME="Canton Network"
3. Restart:
./stop.sh && ./start.sh \
-s "https://sv.sv-2.global.canton.network.digitalasset.com" \
-o "" -p "YOUR_VALIDATOR_NAME" -m "4" -w
⚠️ Without valid AUTH_URL and SPLICE_APP_UI_NETWORK_FAVICON_URL, the Wallet UI will crash with:
Error when parsing config: ZodError — Invalid url for auth.authority / networkFaviconUrl
Accessing Wallet UI
The nginx proxy binds to 127.0.0.1:8888 (localhost only, not exposed externally).
Nginx uses virtual hosts and basic auth (.htpasswd). You cannot access it by IP — you need the correct Host header.
1. Set up SSH tunnel (from your local machine)
ssh -L 8888:127.0.0.1:8888 user@YOUR_SERVER_IP -N
2. Add to /etc/hosts on your local machine
127.0.0.1 wallet.localhost ans.localhost
3. Open in browser
- Wallet:
http://wallet.localhost:8888
- ANS:
http://ans.localhost:8888
The browser will prompt for basic auth credentials (login/password from .htpasswd).
Setting up .htpasswd
cd ~/.canton/${VERSION}/splice-node/docker-compose/validator/nginx
# Install htpasswd utility
apt install -y apache2-utils
# Create credentials
htpasswd -c .htpasswd YOUR_USERNAME
Management
Stop
cd ~/.canton/${VERSION}/splice-node/docker-compose/validator
./stop.sh
Restart
cd ~/.canton/${VERSION}/splice-node/docker-compose/validator
export IMAGE_TAG=${VERSION}
./start.sh \
-s "https://sv.sv-2.global.canton.network.digitalasset.com" \
-c "https://scan.sv-2.global.canton.network.digitalasset.com" \
-o "" \
-p "YOUR_VALIDATOR_NAME" \
-m "4" \
-w
View Logs
cd ~/.canton/${VERSION}/splice-node/docker-compose/validator
# All containers
docker compose logs -f
# Validator only
docker compose logs -f validator
# Last 100 lines
docker logs splice-validator-validator-1 --tail 100
Upgrade
⚠️ Important: Always backup before upgrading!
Process
# 1. Check the network version and migration ID
curl -s https://docs.global.canton.network.sync.global/info | jq .
# 2. Backup database
docker exec splice-validator-postgres-splice-1 pg_dump -U cnadmin validator | gzip > ~/mainnet_backup_$(date +%Y%m%d).sql.gz
# 3. Download new version
NEW_VERSION="X.Y.Z" # from step 1
mkdir -p ~/.canton/${NEW_VERSION}
cd ~/.canton/${NEW_VERSION}
wget https://github.com/digital-asset/decentralized-canton-sync/releases/download/v${NEW_VERSION}/${NEW_VERSION}_splice-node.tar.gz
tar xzf ${NEW_VERSION}_splice-node.tar.gz
cd splice-node/docker-compose/validator
# 4. Copy your .env and nginx config
cp ~/.canton/${CURRENT_VERSION}/splice-node/docker-compose/validator/.env .env
cp ~/.canton/${CURRENT_VERSION}/splice-node/docker-compose/validator/nginx.conf nginx.conf 2>/dev/null
cp -r ~/.canton/${CURRENT_VERSION}/splice-node/docker-compose/validator/nginx/ nginx/ 2>/dev/null
sed -i "s/IMAGE_TAG=.*/IMAGE_TAG=${NEW_VERSION}/" .env
# 5. Pre-pull images (while old version still running — minimizes downtime!)
export IMAGE_TAG=${NEW_VERSION}
docker compose --env-file .env pull
# 6. Stop current node
cd ~/.canton/${CURRENT_VERSION}/splice-node/docker-compose/validator
./stop.sh
# 7. Start new version (fast — images already cached)
cd ~/.canton/${NEW_VERSION}/splice-node/docker-compose/validator
export IMAGE_TAG=${NEW_VERSION}
./start.sh \
-s "https://sv.sv-2.global.canton.network.digitalasset.com" \
-c "https://scan.sv-2.global.canton.network.digitalasset.com" \
-o "" \
-p "YOUR_VALIDATOR_NAME" \
-m "4" \
-w
# 8. Check logs
docker compose logs -f validator
Backup & Recovery
Backup Identity
cd ~/.canton/${VERSION}/splice-node/docker-compose/validator
# Get token
TOKEN=$(python3 get-token.py administrator)
# Create backup
curl --fail -sS "http://localhost:5003/api/validator/v0/admin/participant/identities" \
-H "authorization: Bearer ${TOKEN}" \
-o ~/canton_mainnet_identity_$(date +%Y%m%d).json
Backup Database
# PostgreSQL dump (compressed)
docker exec splice-validator-postgres-splice-1 pg_dump -U cnadmin validator | gzip > ~/canton_mainnet_db_$(date +%Y%m%d).sql.gz
# Full volume backup
docker run --rm -v splice-validator_postgres-splice:/data -v $(pwd):/backup \
ubuntu tar czf /backup/mainnet_postgres_$(date +%Y%m%d).tar.gz /data
Automated Backups (Cron)
cat > /root/canton_mainnet_backup.sh << 'SCRIPT'
#!/bin/bash
BACKUP_DIR="/root/canton_mainnet_backups"
mkdir -p ${BACKUP_DIR}
DATE=$(date +%Y%m%d_%H%M%S)
# DB backup
docker exec splice-validator-postgres-splice-1 pg_dump -U cnadmin validator \
| gzip > ${BACKUP_DIR}/mainnet_db_${DATE}.sql.gz
# Remove old backups (>7 days)
find ${BACKUP_DIR} -name "mainnet_db_*.sql.gz" -mtime +7 -delete
SCRIPT
chmod +x /root/canton_mainnet_backup.sh
# Add to cron (every 6 hours)
(crontab -l 2>/dev/null; echo "0 */6 * * * /root/canton_mainnet_backup.sh") | crontab -
Monitoring
Prometheus Metrics
Canton exports metrics on port 10013. The validator image ships wget,
not curl — a curl exec fails with executable file not found in $PATH and
returns an empty body, which reads exactly like a dead metrics port:
docker exec splice-validator-validator-1 \
wget -q -O - --timeout=10 http://localhost:10013/metrics | head -20
The Monitoring tab covers which of those metrics actually indicate health, and
which obvious alert rule silently never fires.
Alerting
cat > /root/canton_mainnet_monitor.sh << 'SCRIPT'
#!/bin/bash
BOT_TOKEN="YOUR_BOT_TOKEN"
CHAT_ID="YOUR_CHAT_ID"
MONIKER="CANTON - POSTHUMAN-MainNet-Validator"
if ! docker ps --format '{{.Names}} {{.Status}}' | grep -q 'splice-validator-validator.*healthy'; then
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" \
-d text="🔴 ${MONIKER} DOWN - $(hostname)"
fi
SCRIPT
chmod +x /root/canton_mainnet_monitor.sh
# Add to cron (every 5 minutes)
(crontab -l 2>/dev/null; echo "*/5 * * * * /root/canton_mainnet_monitor.sh") | crontab -
Security
Essential Security Measures
- Firewall Configuration
A Canton validator has no external ingress requirements — Splice states it
does not need to whitelist any SVs or validators inbound. It needs egress on
443 to the Super Validators, which is usually allowed already. So the correct
policy admits nothing from the internet except your own SSH:
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp # restrict to your admin CIDR
ufw insert 1 allow out to 172.19.0.0/16 # Docker internal, if needed locally
ufw enable
Do not open 443 inbound. Nothing on a validator listens on it.
See the Security Hardening tab for the full treatment, including why a
published Docker port bypasses ufw entirely.
-
Wallet UI is localhost-only by default — nginx binds to 127.0.0.1:8888. Access via SSH tunnel only.
-
SSH Tunnel for UI Access
The Wallet UI nginx uses virtual hosts. You need to access it via wallet.localhost (not 127.0.0.1):
# From local machine — forward port
ssh -L 8888:127.0.0.1:8888 user@validator_ip -N
Add to /etc/hosts on your local machine (where the browser runs):
127.0.0.1 wallet.localhost ans.localhost
Then open in browser:
- Wallet:
http://wallet.localhost:8888 (will ask for basic auth login/password from .htpasswd)
- ANS:
http://ans.localhost:8888
- Recommendations
- Use SSH keys (disable password auth)
- Implement fail2ban
- Store secrets (onboarding secret, bot token, DB password) outside of plain
.env where possible
- Rotate credentials if exposed
Rewards
Validators earn Canton Coin (CC) for:
- Node uptime and liveness
- Traffic generation
- Featured app participation
Check balance: http://wallet.localhost:8888 (via SSH tunnel)
Useful Links
Troubleshooting
503 / Failed to fetch splice_instance_names
The SV endpoint is down. Try a different SV:
# Check which SVs are alive
for i in 1 2; do
echo -n "sv-$i digitalasset.com: "
curl -s --max-time 5 "https://scan.sv-$i.global.canton.network.digitalasset.com/api/scan/version" 2>&1 || echo "DOWN"
done
Use a working SV with -s flag, or specify scan separately with -c:
./start.sh \
-s "https://sv.sv-2.global.canton.network.digitalasset.com" \
-c "https://scan.sv-2.global.canton.network.digitalasset.com" \
-o "" -p "YOUR_VALIDATOR_NAME" -m "4" -w
Zod Validation Error (Wallet UI)
Error when parsing config: ZodError — Invalid url for auth.authority / networkFaviconUrl
Cause: Empty or missing AUTH_URL / SPLICE_APP_UI_NETWORK_FAVICON_URL in .env when using compose-disable-auth.yaml.
Fix: Add valid values to .env:
AUTH_URL=https://unsafe.auth
SPLICE_APP_UI_NETWORK_FAVICON_URL=https://www.canton.network/hubfs/cn-favicon-05%201-1.png
SPLICE_APP_UI_NETWORK_NAME="Canton Network"
Then restart.
401 Authorization Required (Wallet UI)
Cause: Nginx uses virtual hosts. Accessing by IP (127.0.0.1:8888) without the correct Host header hits basic auth.
Fix: Add 127.0.0.1 wallet.localhost to /etc/hosts on your local machine and access via http://wallet.localhost:8888.
IP Whitelist Verification Failed
curl -s https://scan.sv-1.global.canton.network.sync.global/api/scan/version
# Should return version, not error/timeout
Container Health Issues
docker logs splice-validator-validator-1 --tail 200
docker stats splice-validator-validator-1
Database Issues
docker exec splice-validator-postgres-splice-1 psql -U cnadmin -d validator -c "SELECT version();"
df -h
Created by POSTHUMAN validators
Website: https://posthuman.digital