Configuration
Configuration
All configuration options for the XE node and its deployment environment.
Node flags
The xe binary takes these flags on its node subcommand (xe node [flags]). Go's flag package accepts either -flag or --flag. The version string is printed by the separate xe version subcommand, not by a flag.
General
| Flag | Default | Description |
|---|---|---|
-port | 9000 | libp2p TCP listen port |
-dial | (none) | Bootstrap peer multiaddr(s), comma-separated |
-data | ./data | Data directory: ledger database, identity keys, Lima VM state |
-max-conns-per-ip | 8 | Max inbound libp2p connections per source IP (raise for multi-node-per-host setups) |
HTTP API
| Flag | Default | Description |
|---|---|---|
-api | true | Enable the HTTP API server |
-api-port | 8080 | HTTP API listen port |
-api-bind | 127.0.0.1 | API bind address |
-cors-origin | (empty) | Allowed CORS origin for API responses. Empty falls back to http://localhost:3000. |
Embedded web UI
The explorer and wallet ship inside the node binary as plain HTML and ES modules (core/web) — there is no separate build step. The UI server reverse-proxies its own /api/* to the API server, so -ui requires -api; starting with -ui and -api=false is a fatal error.
| Flag | Default | Description |
|---|---|---|
-ui | false | Enable the embedded web UI server |
-ui-port | 8000 | Web UI listen port |
-ui-bind | 127.0.0.1 | Web UI bind address |
-ui-dir | (embedded) | Serve the UI from this directory instead of the embedded filesystem (development) |
-wallet | true | Expose /wallet/ in the UI; -wallet=false serves 404 for /wallet/* |
Provider mode
| Flag | Default | Description |
|---|---|---|
-provide | false | Enable compute provider mode |
-vcpus | 2 | vCPUs to offer for leasing |
-memory | 2048 | Memory in MB to offer for leasing |
-disk | 20 | Disk in GB to offer for leasing |
-ssh-port | 0 | SSH gateway listen port (0 = disabled) |
-limactl-path | (empty) | Path to the limactl binary; empty resolves limactl from PATH |
Provider auto-accept policy
Optional local filters applied before the stake, resource, and certificate gates. A zero or unset value means "no constraint", so the default policy is permissive. Inverted ranges (min above max) are rejected at startup.
| Flag | Default | Description |
|---|---|---|
-min-lease-duration | (none) | Reject leases shorter than this (Go duration, e.g. 1h) |
-max-lease-duration | (none) | Reject leases longer than this (e.g. 720h) |
-min-lease-cost | 0 | Reject leases whose cost is below this value (0 = no minimum) |
-max-lease-cost | 0 | Reject leases whose cost is above this value (0 = no maximum) |
-max-concurrent-leases | 0 | Cap on active leases, running plus provisioning (0 = bounded only by capacity) |
-price-multiplier | 1000 | Provider price multiplier ×1000 (1000 = baseline, 2500 = 2.5×) |
[!WARNING] Non-baseline price multipliers are simulation-only Values other than
1000are for simulation today; they require anti-cheat gates before production use.
Examples
Minimal standalone node:
xe nodeProduction node with bootstrap peers:
xe node \
-port 9000 \
-api-port 8080 \
-api-bind 0.0.0.0 \
-data /var/lib/xe-node \
-dial /ip4/203.0.113.10/tcp/9000/p2p/12D3KooW...Provider node with SSH gateway:
xe node \
-provide \
-vcpus 4 \
-memory 8192 \
-disk 100 \
-ssh-port 2222 \
-data /var/lib/xe-node \
-dial /ip4/203.0.113.10/tcp/9000/p2p/12D3KooW...[!WARNING] API bind address The default
-api-bind 127.0.0.1only allows local connections, which is all a same-host reverse proxy needs. Only widen it to0.0.0.0if something off-host must reach the API directly, and never expose the API to the internet without a reverse proxy in front of it. The same applies to-ui-bind.
Environment variables
Read by the node process
| Variable | Description |
|---|---|
XE_API_ADMIN_TOKEN | Bearer token for operator-only API endpoints (those that spend or sign as the node, such as POST /lease/request). Unset leaves them disabled. |
Read by the xe CLI
| Variable | Default | Description |
|---|---|---|
XE_NODE | https://ldn.core.test.network | Node API URL the CLI talks to |
XE_FAUCET | https://faucet.test.network | Faucet service URL used by xe faucet. Testnet only, and the default host is not currently deployed. |
XE_WALLET | ~/.xe/wallet.seed | Wallet seed file |
XE_SEED | (none) | Signing seed for xe sign-block (the only supported way to supply it) |
XE_SSH_HOST | ldn.test.network | SSH gateway host used by xe ssh |
XE_SSH_PORT | 2222 | SSH gateway port used by xe ssh |
Deployment .env
Used by the pm2/Caddy deployment on the test network, at /opt/xe/deploy/.env:
| Variable | Description | Example |
|---|---|---|
DOMAIN | Primary domain for Caddy TLS and routing | ldn.test.network |
CORE_DOMAIN | Domain for direct API access | ldn.core.test.network |
NODE_FLAGS | Arguments passed to the xe-node binary — the node subcommand first, then flags | node -port 9000 -api-port 8080 ... |
The ecosystem.config.js reads NODE_FLAGS from the .env file and passes it as command-line arguments to the xe-node binary, so the value must start with node: the binary dispatches on its first argument and exits with unknown command if it sees a flag there. Caddy reads DOMAIN and CORE_DOMAIN via --envfile.
Data directory
The -data flag points to a directory containing all persistent state:
| Path | Content | Notes |
|---|---|---|
ledger/ | BadgerDB database files | WAL, value log, manifest — all blocks, chains, leases, state chain |
host.key | libp2p identity private key | Ed25519, determines peer ID. Persisted across restarts. |
node.key | Node account private key | Ed25519, used for signing blocks and attestations |
ssh_host_key | SSH gateway host key | Ed25519, generated on first SSH gateway start |
lima/ | Lima VM state (LIMA_HOME) | Per-VM directories with disk images, sockets, logs |
lima-templates/ | Lima YAML templates | Per-VM config files used during limactl create |
images/ | VM base images | ubuntu-24.04-x86_64.img (~600 MB), auto-downloaded on first provider startup |
[!NOTE] Identity persistence The
host.keyfile determines the node's peer ID on the network. If this file is deleted, the node generates a new identity and all other nodes'-dialflags must be updated. Back up this file if peer identity continuity matters.
Data directory sizing
BadgerDB stores all blocks, chains, pending sends, votes, conflicts, leases, and state chain data. For a test network, 1 GB is sufficient. Lima VMs consume additional disk for QCOW2 images (typically the lease's disk_gb value per VM).
Port summary
| Port | Protocol | Service | Exposed |
|---|---|---|---|
| 9000 | TCP | libp2p (peer-to-peer) | Yes (firewall open) |
| 8080 | TCP | HTTP API (-api-port) | No (localhost only, via Caddy) |
| 8000 | TCP | Embedded web UI (-ui-port, off unless -ui is set) | No (localhost only, via Caddy) |
| 80 | TCP | Caddy (HTTP, ACME challenges) | Yes (firewall open) |
| 443 | TCP | Caddy (HTTPS, TLS termination) | Yes (firewall open) |
| 2222 | TCP | SSH gateway (if -ssh-port set) | Optional (firewall open if used) |
Process management
On the bootstrap nodes the node is managed by pm2 with the config at /opt/xe/deploy/ecosystem.config.js. The binary is installed as /usr/local/bin/xe-node and started with the node subcommand plus NODE_FLAGS.
| Process | Binary | User | Description |
|---|---|---|---|
xe-node | /usr/local/bin/xe-node | xe | Core node (non-root for Lima compatibility) |
caddy | /usr/bin/caddy | root | Reverse proxy and TLS terminator |
Common pm2 commands:
pm2 list # Show process status
pm2 logs xe-node # Stream node logs
pm2 restart xe-node # Restart the node
pm2 restart caddy # Restart Caddy
pm2 delete xe-node # Remove from pm2 (for config reload)
pm2 start ecosystem.config.js --only xe-node # Start from config
pm2 save # Persist process list across reboots[!TIP] Config reload
pm2 restartdoes not reload the ecosystem.config.js. To pick up newNODE_FLAGSfrom.env, you mustpm2 delete xe-nodeand thenpm2 start ecosystem.config.js --only xe-node.
Provider nodes are managed by systemd instead — see Provider Node Setup.
State chain genesis
The state chain genesis block (statechain/genesis.json) is embedded in the binary at compile time. It configures:
| Key | Description |
|---|---|
sys.dao_keyset | DAO governance keys and threshold |
sys.network_id | Network identifier (e.g. testnet). Included in all block hashes. |
sys.timekeepers | Trusted timekeeper keys + threshold. Required for lease operations. |
sys.oracle | Oracle keyset allowed to write epoch.* keys |
sys.minter | Keys authorised to issue XUSD mint blocks |
sys.phase | Settlement split phase |
sys.tokenomics | Emission curve parameters (R bounds, price tiers, Hermite cap) |
[!DANGER] Timekeepers must be in genesis Provider nodes refuse to start without
sys.timekeepersconfigured. Timekeeper attestations are mandatory for lease acceptance and settlement — there is no fallback to self-reported timestamps.
The genesis is produced by the gen-genesis script in the core repo. -canonical regenerates the committed placeholder (deterministic keys, network_id of testnet) that lets a fresh clone build and test; a real deploy passes the live bootstrap node key seeds instead, which also mints a fresh random network ID so blocks from previous networks are rejected:
go run ./scripts/gen-genesis -canonical
go run ./scripts/gen-genesis -ldn-seed <hex> -ffm-seed <hex> -nyc-seed <hex>[!NOTE] Ledger genesis is separate
statechain/genesis.jsonabove is the state chain genesis. The ledger genesis block — the one that mints the 42,000,000 XE launch supply — is a different embedded file and carries its own optional lease-timing pins.
See also
- Node CLI -- the
xecommand surface - Bootstrap Node Setup -- host preparation and initial deployment
- System Constants -- hard-coded system constants