Files
universe/compose.yml
T
zeekayandHanzo AI 15131f6af4
CI/CD / render (push) Waiting to run
chain letters are lowercase
The primary-network chains answer to either case; one spelling beats two.
/v1/chain/c/rpc, /v1/chain/p, /v1/chain/x across the estate.

Co-authored-by: Hanzo AI <[email protected]>
2026-09-08 15:23:20 -07:00

982 lines
30 KiB
YAML

# Lux Universe - Production Mainnet Stack
# Full 5-node validator network with explorers, indexers, and graph node
#
# Usage:
# docker compose up -d # Start mainnet (5 validators)
# docker compose --profile testnet up -d # Start testnet configuration
# docker compose --profile graph up -d # Add subgraph indexing
# docker compose --profile indexers up -d # Add P/X chain indexers
# docker compose --profile bridge up -d # Add bridge infrastructure
# docker compose --profile ui up -d # Add frontend UIs
# docker compose down # Stop all services
#
# Mainnet Ports:
# 9630: Node 1 HTTP 4010: LUX Explorer
# 9660: Node 2 HTTP 4011: Zoo Explorer
# 9670: Node 3 HTTP 4012: Hanzo Explorer
# 9680: Node 4 HTTP 8000: Graph Node
# 9690: Node 5 HTTP 5001: IPFS
# 8085: Pricing API
#
# Network: lux-network (172.30.0.0/16)
networks:
lux-network:
driver: bridge
ipam:
config:
- subnet: 172.30.0.0/16
volumes:
postgres-data:
ipfs-data:
graph-data:
node1-data:
node2-data:
node3-data:
node4-data:
node5-data:
bridge-nats-data:
bridge-consul-data:
redis-data:
iam-data:
vm-plugins:
# ==============================================================================
# INFRASTRUCTURE SERVICES
# ==============================================================================
services:
# PostgreSQL 15 - Shared database for all services
postgres:
image: ghcr.io/hanzoai/sql:0.1.0
container_name: lux-postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
volumes:
- postgres-data:/var/lib/postgresql/data
- ./docker/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
ports:
- "${POSTGRES_PORT:-5432}:5432"
networks:
- lux-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
interval: 10s
timeout: 5s
retries: 5
# Redis Cache
redis:
image: ghcr.io/hanzoai/kv:0.1.0
container_name: lux-redis
restart: unless-stopped
command: redis-server --appendonly yes --maxmemory 2gb --maxmemory-policy allkeys-lru
ports:
- "${REDIS_PORT:-6380}:6379"
volumes:
- redis-data:/data
networks:
- lux-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# Pricing API - CoinGecko price cache
# ghcr.io/luxfi/price, the same image deploy/lux-cloud/price.yaml pins. The
# old `ghcr.io/luxfi/pricing:0.1.0` was dead twice over: that tag 404s, and
# `build: ./pricing` named a directory that does not exist in this repo.
price:
image: ghcr.io/luxfi/price:v1.0.0
container_name: lux-price
restart: unless-stopped
environment:
# Optional. The service falls back to the anonymous CoinGecko endpoint
# and logs that it did; `:?` refused to start without a key it never
# required.
- COINGECKO_API_KEY=${COINGECKO_API_KEY:-}
- PORT=8080
ports:
- "${PRICING_PORT:-8085}:8080"
networks:
- lux-network
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
# IPFS - Decentralized storage
ipfs:
image: ipfs/kubo:latest
container_name: lux-ipfs
restart: unless-stopped
environment:
IPFS_PROFILE: server
volumes:
- ipfs-data:/data/ipfs
ports:
- "${IPFS_API_PORT:-5001}:5001"
- "${IPFS_GATEWAY_PORT:-8080}:8080"
- "${IPFS_SWARM_PORT:-4001}:4001"
networks:
- lux-network
command: daemon --migrate=true --enable-pubsub-experiment
healthcheck:
test: ["CMD-SHELL", "ipfs id || exit 1"]
interval: 30s
timeout: 10s
retries: 3
# ==============================================================================
# VM PLUGINS — fetches plugin binaries into shared volume
# Built by luxfi/chains CI, copied into vm-plugins volume at startup.
# Nodes mount this volume at /plugins and use --plugin-dir=/plugins.
# ==============================================================================
vm-plugins:
image: ghcr.io/luxfi/chains/evm:${PLUGIN_VERSION:-latest}
container_name: lux-vm-plugins
entrypoint: ["/bin/sh", "-c"]
command:
- |
mkdir -p /plugins
# Copy EVM plugin (from this image)
cp /plugin /plugins/evm 2>/dev/null || true
echo "VM plugins installed"
# Keep running so dependent services can start
sleep infinity
volumes:
- vm-plugins:/plugins
networks:
- lux-network
# ==============================================================================
# LUX VALIDATOR NODES (5 nodes - mainnet minimum)
# NodeIDs from genesis: ~/work/lux/mainnet/genesis_mainnet.json
# ==============================================================================
# Node 1 - Bootstrap node (NodeID-FrtEjhat6RUqjEWCJgYZKqBaxY2Woyy5G)
lux-node-1:
image: ghcr.io/luxfi/node:${NODE_VERSION:-latest}
container_name: lux-node-1
restart: unless-stopped
volumes:
- node1-data:/app/data
- ~/.lux/keys/node0:/app/keys:ro
- ../genesis/configs/mainnet:/app/genesis:ro
- vm-plugins:/app/plugins:ro
ports:
- "${NODE1_HTTP_PORT:-9630}:9630"
- "${NODE1_STAKING_PORT:-9631}:9631"
networks:
lux-network:
ipv4_address: 172.30.0.10
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
NETWORK_ID: ${NETWORK_ID:-1}
command: >
--network-id=${NETWORK_ID:-1}
--http-host=0.0.0.0
--http-port=9630
--staking-port=9631
--staking-host=0.0.0.0
--network-allow-private-ips=true
--genesis-file=/app/genesis/pchain.json
--chain-config-dir=/app/configs
--staking-tls-cert-file=/app/keys/staking/staker.crt
--staking-tls-key-file=/app/keys/staking/staker.key
--staking-signer-key-file=/app/keys/bls/private.key
--index-enabled
--api-admin-enabled
--plugin-dir=/app/plugins
--data-dir=/app/data
--log-level=${LOG_LEVEL:-info}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9630/v1/health"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
depends_on:
postgres:
condition: service_healthy
vm-plugins:
condition: service_started
# Node 2 (NodeID-9hq49qGVZN7M7tXxdpF3AqptQGdmPCFnQ)
lux-node-2:
image: ghcr.io/luxfi/node:${NODE_VERSION:-latest}
container_name: lux-node-2
restart: unless-stopped
volumes:
- node2-data:/app/data
- ~/.lux/keys/node1:/app/keys:ro
- ../genesis/configs/mainnet:/app/genesis:ro
- vm-plugins:/app/plugins:ro
ports:
- "${NODE2_HTTP_PORT:-9660}:9630"
- "${NODE2_STAKING_PORT:-9661}:9631"
networks:
lux-network:
ipv4_address: 172.30.0.11
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
NETWORK_ID: ${NETWORK_ID:-1}
command: >
--network-id=${NETWORK_ID:-1}
--http-host=0.0.0.0
--http-port=9630
--staking-port=9631
--staking-host=0.0.0.0
--network-allow-private-ips=true
--staking-tls-cert-file=/app/keys/staking/staker.crt
--staking-tls-key-file=/app/keys/staking/staker.key
--staking-signer-key-file=/app/keys/bls/private.key
--bootstrap-ips=172.30.0.10:9631
--bootstrap-ids=NodeID-FrtEjhat6RUqjEWCJgYZKqBaxY2Woyy5G
--plugin-dir=/app/plugins
--data-dir=/app/data
--log-level=${LOG_LEVEL:-info}
depends_on:
- lux-node-1
- vm-plugins
# Node 3 (NodeID-8osEnSC4LQFdG1LMit12CBsE6BfKGHNAw)
lux-node-3:
image: ghcr.io/luxfi/node:${NODE_VERSION:-latest}
container_name: lux-node-3
restart: unless-stopped
volumes:
- node3-data:/app/data
- ~/.lux/keys/node2:/app/keys:ro
- ../genesis/configs/mainnet:/app/genesis:ro
- vm-plugins:/app/plugins:ro
ports:
- "${NODE3_HTTP_PORT:-9670}:9630"
- "${NODE3_STAKING_PORT:-9671}:9631"
networks:
lux-network:
ipv4_address: 172.30.0.12
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
NETWORK_ID: ${NETWORK_ID:-1}
command: >
--network-id=${NETWORK_ID:-1}
--http-host=0.0.0.0
--http-port=9630
--staking-port=9631
--staking-host=0.0.0.0
--network-allow-private-ips=true
--staking-tls-cert-file=/app/keys/staking/staker.crt
--staking-tls-key-file=/app/keys/staking/staker.key
--staking-signer-key-file=/app/keys/bls/private.key
--bootstrap-ips=172.30.0.10:9631
--bootstrap-ids=NodeID-FrtEjhat6RUqjEWCJgYZKqBaxY2Woyy5G
--plugin-dir=/app/plugins
--data-dir=/app/data
--log-level=${LOG_LEVEL:-info}
depends_on:
- lux-node-1
- vm-plugins
# Node 4 (NodeID-MrdgTgPuddyo7anomKr4akMcoKzVKcgbG)
lux-node-4:
image: ghcr.io/luxfi/node:${NODE_VERSION:-latest}
container_name: lux-node-4
restart: unless-stopped
volumes:
- node4-data:/app/data
- ~/.lux/keys/node3:/app/keys:ro
- ../genesis/configs/mainnet:/app/genesis:ro
- vm-plugins:/app/plugins:ro
ports:
- "${NODE4_HTTP_PORT:-9680}:9630"
- "${NODE4_STAKING_PORT:-9681}:9631"
networks:
lux-network:
ipv4_address: 172.30.0.13
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
NETWORK_ID: ${NETWORK_ID:-1}
command: >
--network-id=${NETWORK_ID:-1}
--http-host=0.0.0.0
--http-port=9630
--staking-port=9631
--staking-host=0.0.0.0
--network-allow-private-ips=true
--staking-tls-cert-file=/app/keys/staking/staker.crt
--staking-tls-key-file=/app/keys/staking/staker.key
--staking-signer-key-file=/app/keys/bls/private.key
--bootstrap-ips=172.30.0.10:9631
--bootstrap-ids=NodeID-FrtEjhat6RUqjEWCJgYZKqBaxY2Woyy5G
--plugin-dir=/app/plugins
--data-dir=/app/data
--log-level=${LOG_LEVEL:-info}
depends_on:
- lux-node-1
- vm-plugins
# Node 5 (NodeID-Mgd5yHs4pe6qRjkBcW5Y7oqHA51j4afcC)
lux-node-5:
image: ghcr.io/luxfi/node:${NODE_VERSION:-latest}
container_name: lux-node-5
restart: unless-stopped
volumes:
- node5-data:/app/data
- ~/.lux/keys/node4:/app/keys:ro
- ../genesis/configs/mainnet:/app/genesis:ro
- vm-plugins:/app/plugins:ro
ports:
- "${NODE5_HTTP_PORT:-9690}:9630"
- "${NODE5_STAKING_PORT:-9691}:9631"
networks:
lux-network:
ipv4_address: 172.30.0.14
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
NETWORK_ID: ${NETWORK_ID:-1}
command: >
--network-id=${NETWORK_ID:-1}
--http-host=0.0.0.0
--http-port=9630
--staking-port=9631
--staking-host=0.0.0.0
--network-allow-private-ips=true
--staking-tls-cert-file=/app/keys/staking/staker.crt
--staking-tls-key-file=/app/keys/staking/staker.key
--staking-signer-key-file=/app/keys/bls/private.key
--bootstrap-ips=172.30.0.10:9631
--bootstrap-ids=NodeID-FrtEjhat6RUqjEWCJgYZKqBaxY2Woyy5G
--plugin-dir=/app/plugins
--data-dir=/app/data
--log-level=${LOG_LEVEL:-info}
depends_on:
- lux-node-1
- vm-plugins
# ==============================================================================
# BLOCKSCOUT EXPLORERS
# ==============================================================================
# LUX C-Chain Explorer (Chain ID: 96369)
lux-explorer:
image: ghcr.io/luxfi/explorer:0.1.0
container_name: lux-explorer
restart: unless-stopped
command: sh -c "bin/blockscout eval 'Elixir.Explorer.ReleaseTasks.create_and_migrate()' && bin/blockscout start"
environment:
ETHEREUM_JSONRPC_VARIANT: geth
ETHEREUM_JSONRPC_HTTP_URL: http://lux-node-1:9630/v1/chain/c/rpc
ETHEREUM_JSONRPC_TRACE_URL: http://lux-node-1:9630/v1/chain/c/rpc
ETHEREUM_JSONRPC_WS_URL: ws://lux-node-1:9630/v1/chain/c/ws
DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/explorer_lux
NETWORK: LUX
SUBNETWORK: C-Chain
COIN: LUX
COIN_NAME: LUX
CHAIN_ID: ${LUX_CHAIN_ID:-96369}
POOL_SIZE: 50
ECTO_USE_SSL: "false"
HEART_BEAT_TIMEOUT: 30
BLOCKSCOUT_HOST: localhost
BLOCKSCOUT_PROTOCOL: http
DISABLE_EXCHANGE_RATES: "true"
CHECKSUM_FUNCTION: eth
SECRET_KEY_BASE: ${SECRET_KEY_BASE:-change-me-in-production}
ports:
- "${LUX_EXPLORER_PORT:-4010}:4000"
networks:
- lux-network
depends_on:
postgres:
condition: service_healthy
lux-node-1:
condition: service_healthy
# Zoo Mainnet Explorer (Chain ID: 200200)
zoo-explorer:
image: ghcr.io/luxfi/explorer:0.1.0
container_name: zoo-explorer
restart: unless-stopped
profiles:
- explorers
command: sh -c "bin/blockscout eval 'Elixir.Explorer.ReleaseTasks.create_and_migrate()' && bin/blockscout start"
environment:
ETHEREUM_JSONRPC_VARIANT: geth
ETHEREUM_JSONRPC_HTTP_URL: http://lux-node-1:9630/v1/chain/${ZOO_BLOCKCHAIN_ID:-zoo}/rpc
ETHEREUM_JSONRPC_TRACE_URL: http://lux-node-1:9630/v1/chain/${ZOO_BLOCKCHAIN_ID:-zoo}/rpc
ETHEREUM_JSONRPC_WS_URL: ws://lux-node-1:9630/v1/chain/${ZOO_BLOCKCHAIN_ID:-zoo}/ws
DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/explorer_zoo
NETWORK: Zoo
SUBNETWORK: Zoo Network
COIN: ZOO
COIN_NAME: ZOO
CHAIN_ID: ${ZOO_CHAIN_ID:-200200}
POOL_SIZE: 50
ECTO_USE_SSL: "false"
HEART_BEAT_TIMEOUT: 30
BLOCKSCOUT_HOST: localhost
BLOCKSCOUT_PROTOCOL: http
DISABLE_EXCHANGE_RATES: "true"
CHECKSUM_FUNCTION: eth
SECRET_KEY_BASE: ${SECRET_KEY_BASE:-change-me-in-production}
ports:
- "${ZOO_EXPLORER_PORT:-4011}:4000"
networks:
- lux-network
depends_on:
postgres:
condition: service_healthy
lux-node-1:
condition: service_healthy
# Hanzo AI Chain Explorer (Chain ID: 36963)
hanzo-explorer:
image: ghcr.io/luxfi/explorer:0.1.0
container_name: hanzo-explorer
restart: unless-stopped
profiles:
- explorers
command: sh -c "bin/blockscout eval 'Elixir.Explorer.ReleaseTasks.create_and_migrate()' && bin/blockscout start"
environment:
ETHEREUM_JSONRPC_VARIANT: geth
ETHEREUM_JSONRPC_HTTP_URL: http://lux-node-1:9630/v1/chain/${HANZO_BLOCKCHAIN_ID:-hanzo}/rpc
ETHEREUM_JSONRPC_TRACE_URL: http://lux-node-1:9630/v1/chain/${HANZO_BLOCKCHAIN_ID:-hanzo}/rpc
ETHEREUM_JSONRPC_WS_URL: ws://lux-node-1:9630/v1/chain/${HANZO_BLOCKCHAIN_ID:-hanzo}/ws
DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/explorer_hanzo
NETWORK: Hanzo
SUBNETWORK: AI Chain
COIN: HANZO
COIN_NAME: HANZO
CHAIN_ID: ${HANZO_CHAIN_ID:-36963}
POOL_SIZE: 50
ECTO_USE_SSL: "false"
HEART_BEAT_TIMEOUT: 30
BLOCKSCOUT_HOST: localhost
BLOCKSCOUT_PROTOCOL: http
DISABLE_EXCHANGE_RATES: "true"
CHECKSUM_FUNCTION: eth
SECRET_KEY_BASE: ${SECRET_KEY_BASE:-change-me-in-production}
ports:
- "${HANZO_EXPLORER_PORT:-4012}:4000"
networks:
- lux-network
depends_on:
postgres:
condition: service_healthy
lux-node-1:
condition: service_healthy
# ==============================================================================
# GRAPH-NODE (for subgraphs)
# ==============================================================================
graph-node:
image: graphprotocol/graph-node:latest
container_name: lux-graph-node
restart: unless-stopped
profiles:
- graph
environment:
postgres_host: postgres
postgres_port: 5432
postgres_user: ${POSTGRES_USER:-postgres}
postgres_pass: ${POSTGRES_PASSWORD:-postgres}
postgres_db: graph_node
ipfs: ipfs:5001
ethereum: "lux:http://lux-node-1:9630/v1/chain/c/rpc"
GRAPH_LOG: ${GRAPH_LOG:-info}
GRAPH_ETHEREUM_CLEANUP_BLOCKS: "true"
ports:
- "${GRAPH_HTTP_PORT:-8000}:8000"
- "${GRAPH_WS_PORT:-8001}:8001"
- "${GRAPH_ADMIN_PORT:-8020}:8020"
- "${GRAPH_METRICS_PORT:-8040}:8040"
networks:
- lux-network
depends_on:
postgres:
condition: service_healthy
ipfs:
condition: service_healthy
lux-node-1:
condition: service_healthy
# ==============================================================================
# CHAIN INDEXERS (P, X chains)
# ==============================================================================
# P-Chain Indexer (Platform - Validators, Staking)
pchain-indexer:
build:
context: ../indexer
dockerfile: Dockerfile
container_name: lux-pchain-indexer
restart: unless-stopped
profiles:
- indexers
command: ["-chain", "pchain", "-port", "4000"]
environment:
RPC_ENDPOINT: http://lux-node-1:9630/v1/chain/p
DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/explorer_pchain?sslmode=disable
HTTP_PORT: 4000
ports:
- "${PCHAIN_INDEXER_PORT:-4100}:4000"
networks:
- lux-network
depends_on:
postgres:
condition: service_healthy
lux-node-1:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4000/health"]
interval: 30s
timeout: 10s
retries: 3
# X-Chain Indexer (Exchange - Assets, UTXOs)
xchain-indexer:
build:
context: ../indexer
dockerfile: Dockerfile
container_name: lux-xchain-indexer
restart: unless-stopped
profiles:
- indexers
command: ["-chain", "xchain", "-port", "4000"]
environment:
RPC_ENDPOINT: http://lux-node-1:9630/v1/chain/x
DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/explorer_xchain?sslmode=disable
HTTP_PORT: 4000
ports:
- "${XCHAIN_INDEXER_PORT:-4200}:4000"
networks:
- lux-network
depends_on:
postgres:
condition: service_healthy
lux-node-1:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4000/health"]
interval: 30s
timeout: 10s
retries: 3
# ==============================================================================
# BRIDGE SERVICES (optional profile)
# ==============================================================================
# Bridge NATS messaging
bridge-nats:
image: nats:2.10-alpine
container_name: lux-bridge-nats
restart: unless-stopped
profiles:
- bridge
ports:
- "${BRIDGE_NATS_PORT:-4223}:4222"
- "${BRIDGE_NATS_MONITOR:-8223}:8222"
command: "-js -m 8222 --store_dir /data"
volumes:
- bridge-nats-data:/data
networks:
- lux-network
healthcheck:
test: ["CMD", "nc", "-z", "localhost", "4222"]
interval: 5s
timeout: 3s
retries: 5
# Bridge Consul service discovery
bridge-consul:
image: hashicorp/consul:1.17
container_name: lux-bridge-consul
restart: unless-stopped
profiles:
- bridge
ports:
- "${BRIDGE_CONSUL_PORT:-8501}:8500"
command: "agent -server -bootstrap-expect=1 -ui -client=0.0.0.0"
volumes:
- bridge-consul-data:/consul/data
networks:
- lux-network
environment:
CONSUL_BIND_INTERFACE: eth0
healthcheck:
test: ["CMD", "consul", "members"]
interval: 5s
timeout: 3s
retries: 5
# Bridge KMS (Vault)
bridge-kms:
image: hashicorp/vault:1.15
container_name: lux-bridge-kms
restart: unless-stopped
profiles:
- bridge
ports:
- "${BRIDGE_KMS_PORT:-8200}:8200"
environment:
VAULT_DEV_ROOT_TOKEN_ID: ${VAULT_DEV_TOKEN:-devroot}
VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200
cap_add:
- IPC_LOCK
networks:
- lux-network
healthcheck:
test: ["CMD", "vault", "status"]
interval: 5s
timeout: 3s
retries: 5
# ==============================================================================
# FRONTEND UIs (optional profile)
# ==============================================================================
# LUX Explorer Frontend
lux-frontend:
image: ghcr.io/luxfi/explore:0.1.0
container_name: lux-frontend
restart: unless-stopped
profiles:
- ui
ports:
- "${LUX_FRONTEND_PORT:-3100}:3000"
environment:
NEXT_PUBLIC_NETWORK_NAME: LUX Network
NEXT_PUBLIC_NETWORK_SHORT_NAME: LUX
NEXT_PUBLIC_NETWORK_ID: ${NETWORK_ID:-1}
NEXT_PUBLIC_NETWORK_CURRENCY_NAME: LUX
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL: LUX
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS: 18
NEXT_PUBLIC_COLOR_THEME_DEFAULT: dark
NEXT_PUBLIC_API_HOST: localhost:${LUX_EXPLORER_PORT:-4010}
NEXT_PUBLIC_API_PROTOCOL: http
NEXT_PUBLIC_API_BASE_PATH: /
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL: ws
NEXT_PUBLIC_APP_HOST: localhost:${LUX_FRONTEND_PORT:-3100}
NEXT_PUBLIC_APP_PROTOCOL: http
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED: "true"
networks:
- lux-network
depends_on:
lux-explorer:
condition: service_started
# LUX Exchange UI (DEX)
lux-exchange:
image: ghcr.io/luxfi/exchange:0.1.0
container_name: lux-exchange
restart: unless-stopped
profiles:
- ui
ports:
- "${LUX_EXCHANGE_PORT:-3200}:3000"
environment:
NODE_ENV: production
NEXT_PUBLIC_CHAIN_ID: ${LUX_CHAIN_ID:-96369}
NEXT_PUBLIC_NETWORK_URL: http://lux-node-1:9630/v1/chain/c/rpc
NEXT_PUBLIC_EXPLORER_URL: http://localhost:${LUX_EXPLORER_PORT:-4010}
networks:
- lux-network
depends_on:
lux-node-1:
condition: service_healthy
# LXD Gateway (DEX API for AMM + Orderbook)
lxd-gateway:
build:
context: ../dex
dockerfile: Dockerfile
image: lxd-gateway:latest
container_name: lxd-gateway
restart: unless-stopped
profiles:
- ui
ports:
- "${LXD_GATEWAY_PORT:-8080}:8080"
environment:
LUX_RPC_URL: http://lux-node-1:9630/v1/chain/c/rpc
ZOO_RPC_URL: http://lux-node-1:9630/v1/chain/Zoo/rpc
LOG_LEVEL: info
networks:
- lux-network
depends_on:
lux-node-1:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
# LUX Wallet
lux-wallet:
image: ghcr.io/luxfi/wallet:0.1.0
container_name: lux-wallet
restart: unless-stopped
profiles:
- ui
ports:
- "${LUX_WALLET_PORT:-3300}:3000"
environment:
NODE_ENV: production
NEXT_PUBLIC_CHAIN_ID: ${LUX_CHAIN_ID:-96369}
NEXT_PUBLIC_RPC_URL: http://localhost:${NODE1_HTTP_PORT:-9630}/v1/chain/c/rpc
NEXT_PUBLIC_EXPLORER_URL: http://localhost:${LUX_EXPLORER_PORT:-4010}
networks:
- lux-network
depends_on:
lux-node-1:
condition: service_healthy
# LUX Bridge UI
lux-bridge:
image: ghcr.io/luxfi/bridge:0.1.0
container_name: lux-bridge-ui
restart: unless-stopped
profiles:
- ui
ports:
- "${LUX_BRIDGE_PORT:-3400}:3000"
environment:
NODE_ENV: production
NEXT_PUBLIC_CHAIN_ID: ${LUX_CHAIN_ID:-96369}
NEXT_PUBLIC_RPC_URL: http://localhost:${NODE1_HTTP_PORT:-9630}/v1/chain/c/rpc
networks:
- lux-network
depends_on:
lux-node-1:
condition: service_healthy
# ==============================================================================
# DEVELOPMENT TOOLS (optional profile)
# ==============================================================================
# Database Admin UI
adminer:
image: adminer:latest
container_name: lux-adminer
restart: unless-stopped
profiles:
- dev
ports:
- "${ADMINER_PORT:-8082}:8080"
networks:
- lux-network
environment:
ADMINER_DEFAULT_SERVER: postgres
ADMINER_DESIGN: pepa-linha-dark
# Redis UI
redis-commander:
image: rediscommander/redis-commander:latest
container_name: lux-redis-commander
restart: unless-stopped
profiles:
- dev
ports:
- "${REDIS_COMMANDER_PORT:-8083}:8081"
networks:
- lux-network
environment:
REDIS_HOSTS: "local:redis:6379"
# ==============================================================================
# IAM SERVICES (uses shared Hanzo IAM)
# ==============================================================================
# Hanzo IAM - Unified Identity & Access Management
# Provides lux.id login that routes to iam.hanzo.ai backend
iam:
image: ghcr.io/hanzoai/iam:0.1.0
container_name: lux-iam
restart: unless-stopped
profiles:
- iam
environment:
# Database (uses shared postgres)
- DATABASE_URL=postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/iam?sslmode=disable
# Redis
- REDIS_URL=redis://redis:6379
# IAM Config
- CASDOOR_ORIGIN=${CASDOOR_ORIGIN:-https://lux.id}
- CASDOOR_APP_NAME=lux-iam
# Multi-tenant (routes to shared Hanzo IAM)
- ENABLE_MULTI_TENANT=true
- ALLOWED_ORIGINS=lux.id,lux.network,wallet.lux.network,bridge.lux.network
# Security
- ENCRYPTION_KEY=${IAM_ENCRYPTION_KEY}
volumes:
- ./iam/init_data.json:/app/init_data.json:ro
- iam-data:/app/data
ports:
- "${IAM_PORT:-8001}:8000"
networks:
- lux-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
labels:
- "traefik.enable=true"
- "traefik.http.routers.lux-id.rule=Host(`lux.id`)"
- "traefik.http.routers.lux-id.tls=true"
- "traefik.http.routers.lux-id.middlewares=org-lux"
- "traefik.http.middlewares.org-lux.headers.customrequestheaders.X-Org-Name=lux"
# ==============================================================================
# LUX BANK (lux.financial) - B2B Stablecoin Infrastructure
# ==============================================================================
# Bank API - Backend services
bank-api:
build:
context: ./bank
dockerfile: app/api/Dockerfile
image: ghcr.io/luxfi/bank-api:0.1.0
container_name: lux-bank-api
restart: unless-stopped
profiles:
- bank
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/bank?sslmode=disable
- REDIS_URL=redis://redis:6379
- JWT_SECRET=${BANK_JWT_SECRET}
- CURRENCY_CLOUD_LOGIN_ID=${CURRENCY_CLOUD_LOGIN_ID}
- CURRENCY_CLOUD_API_KEY=${CURRENCY_CLOUD_API_KEY}
- SENDGRID_API_KEY=${SENDGRID_API_KEY}
- AUTH0_DOMAIN=${AUTH0_DOMAIN}
- AUTH0_CLIENT_ID=${AUTH0_CLIENT_ID}
- AUTH0_CLIENT_SECRET=${AUTH0_CLIENT_SECRET}
ports:
- "${BANK_API_PORT:-4000}:4000"
networks:
- lux-network
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4000/health"]
interval: 30s
timeout: 10s
retries: 3
labels:
- "traefik.enable=true"
- "traefik.http.routers.bank-api.rule=Host(`api.lux.financial`)"
- "traefik.http.routers.bank-api.tls=true"
# Bank Dashboard - Client portal
bank-dash:
build:
context: ./bank
dockerfile: app/dash/Dockerfile
image: ghcr.io/luxfi/bank-dash:0.1.0
container_name: lux-bank-dash
restart: unless-stopped
profiles:
- bank
environment:
- NODE_ENV=production
- NEXT_PUBLIC_BASE_URL=https://api.lux.financial
ports:
- "${BANK_DASH_PORT:-3500}:3000"
networks:
- lux-network
depends_on:
- bank-api
labels:
- "traefik.enable=true"
- "traefik.http.routers.bank-dash.rule=Host(`app.lux.financial`)"
- "traefik.http.routers.bank-dash.tls=true"
# Bank Marketing Site
bank-site:
build:
context: ./bank
dockerfile: app/site/Dockerfile
image: ghcr.io/luxfi/bank-site:0.1.0
container_name: lux-bank-site
restart: unless-stopped
profiles:
- bank
environment:
- NODE_ENV=production
ports:
- "${BANK_SITE_PORT:-3501}:3000"
networks:
- lux-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.bank-site.rule=Host(`lux.financial`)"
- "traefik.http.routers.bank-site.tls=true"
# Bank Admin Dashboard
bank-admin:
build:
context: ./bank
dockerfile: app/admin/Dockerfile
image: ghcr.io/luxfi/bank-admin:0.1.0
container_name: lux-bank-admin
restart: unless-stopped
profiles:
- bank
environment:
- NODE_ENV=production
- NEXT_PUBLIC_BASE_URL=https://api.lux.financial
ports:
- "${BANK_ADMIN_PORT:-3502}:3000"
networks:
- lux-network
depends_on:
- bank-api
labels:
- "traefik.enable=true"
- "traefik.http.routers.bank-admin.rule=Host(`admin.lux.financial`)"
- "traefik.http.routers.bank-admin.tls=true"
# Bank Documentation Site
bank-docs:
build:
context: ./bank
dockerfile: app/docs/Dockerfile
image: ghcr.io/luxfi/bank-docs:0.1.0
container_name: lux-bank-docs
restart: unless-stopped
profiles:
- bank
environment:
- NODE_ENV=production
ports:
- "${BANK_DOCS_PORT:-3503}:3000"
networks:
- lux-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.bank-docs.rule=Host(`docs.lux.financial`)"
- "traefik.http.routers.bank-docs.tls=true"