# How to Set Up an Amadeus Protocol Node: Complete Installation Guide

> Easily set up an Amadeus Protocol node. Follow our guide to build the Docker image, compile the release, and launch for local development or production.

- Repository: [Amadeus Protocol/node](https://github.com/amadeusprotocol/node)
- Tags: how-to-guide
- Published: 2026-08-20

---

**Set up an Amadeus Protocol node by building a Docker image with Erlang/OTP and RocksDB, compiling the release with [`./build.sh`](https://github.com/amadeusprotocol/node/blob/main/./build.sh), and launching with `TESTNET=true` for local development or configuring systemd with `AUTOUPDATE=true` for production.**

This guide walks you through deploying an Amadeus Protocol node, an Elixir/Erlang OTP application that powers a high-performance, UDP-based blockchain engine. The node manages networking, persistent storage, and JSON-RPC handling through supervised GenServer processes, with support for WebAssembly contracts written in AssemblyScript or Rust.

## Prerequisites for Amadeus Protocol Node Setup

Before building the node, ensure your system meets these requirements:

| Requirement | Purpose | Installation |
|-------------|---------|--------------|
| **Docker or Podman** | Containerized build environment | `sudo apt install podman` or `sudo apt install docker.io` |
| **Erlang OTP 26+ / Elixir 1.16+** | BEAM VM runtime for the node | Included in Docker image; optional local install for development |
| **Rust toolchain** (optional) | Compile Rust contracts to WebAssembly | `curl https://sh.rustup.rs -sSf \| sh` |
| **Node.js 20+** (optional) | Build AssemblyScript contracts | `sudo apt install nodejs` |
| **High file descriptor limits** | Support many UDP sockets and open files | Apply sysctl and limits.conf settings (see Production Deployment section) |

The node runs as a single OS process inside the **BEAM virtual machine**, using message-passing between components for fault tolerance and low latency.

## Architecture Overview

Understanding the core components helps troubleshoot issues and optimize performance:

| Component | File Path | Function |
|-----------|-----------|----------|
| **OTP Supervision Tree** | [`ex/lib/node/node_gen.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/node/node_gen.ex) | Creates the main supervision hierarchy managing socket, reassembly, net-guard, and RPC processes |
| **UDP Socket Layer** | [`ex/lib/node/node_gen_socket_gen.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/node/node_gen_socket_gen.ex), [`ex/lib/node/node_gen_netguard.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/node/node_gen_netguard.ex) | Handles raw UDP packets, NAT traversal, and packet size enforcement |
| **RocksDB Storage** | [`ex/lib/misc/rocksdb.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/misc/rocksdb.ex) | Persistent key/value store for blocks, state, and contract data |
| **STUN/NAT Helper** | [`ex/lib/misc/stun.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/misc/stun.ex) | Discovers public IP/port for peer-to-peer communication |
| **RPC API** | [`ex/lib/api/rpc_api.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/api/rpc_api.ex) | Exposes JSON-RPC endpoint for browsers, wallets, and CLI tools |
| **Contract Loader** | [`ex/lib/ex_bakeware.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/ex_bakeware.ex) | Loads WebAssembly contracts and routes RPC calls to them |

All components are supervised, meaning failures in one process trigger automatic restarts without stopping the entire node.

## Building the Amadeus Protocol Node

### Step 1: Build the Docker Image

The `build.Dockerfile` provides a reproducible environment with Erlang/Elixir, RocksDB native libraries, and optional Rust tooling:

```bash

# Build the Erlang/Elixir base image with RocksDB

podman build --tag erlang_builder -f build.Dockerfile

# Compile the production release

./build.sh

```

The [`build.sh`](https://github.com/amadeusprotocol/node/blob/main/build.sh) script produces a BEAM release at `_build/prod/rel/amadeusd` and copies the executable `amadeusd` to your repository root.

### Step 2: Verify the Build

Check that the binary exists and is executable:

```bash
ls -la ./amadeusd
file ./amadeusd

```

## Running a Local Testnet Node

The fastest way to set up an Amadeus Protocol node is **testnet mode**, which starts a single-node network with an in-process RPC server:

```bash

# Start testnet with HTTP RPC on localhost port 80

TESTNET=true WORKFOLDER=/tmp/testnet HTTP_IPV4=127.0.0.1 HTTP_PORT=80 ./amadeusd

```

Environment variables control the node behavior:

| Variable | Description | Example |
|----------|-------------|---------|
| `TESTNET=true` | Enable single-node testnet mode | Required for local development |
| `WORKFOLDER` | Data directory for blocks and state | `/tmp/testnet` |
| `HTTP_IPV4` | IP address to bind RPC server | `127.0.0.1` |
| `HTTP_PORT` | Port for JSON-RPC endpoint | `80` |

### Interacting with the Running Node

Once started, connect via the Elixir REPL (`iex`) or direct HTTP calls:

**Using the REPL:**

```elixir
iex -S mix

# Load trainer keys (pre-funded in testnet)

iex> pk = Application.fetch_env!(:ama, :trainer_pk)
iex> sk = Application.fetch_env!(:ama, :trainer_sk)

# Transfer AMA tokens

iex> Testnet.call(sk, "Coin", "transfer", [pk, "5", "AMA"])

# Deploy a WebAssembly contract

iex> Testnet.deploy "/path/to/node/contract_samples/assemblyscript/counter.wasm"

# Call contract methods

iex> Testnet.call(sk, pk, "get", [])
iex> Testnet.call(sk, pk, "increment", ["2"])

```

**Using curl (external clients):**

```bash
curl -X POST http://127.0.0.1:80/rpc \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"call","params":["<sk>","Coin","balance",["<pk>"]],"id":1}'

```

## Deploying Custom WebAssembly Contracts

The Amadeus Protocol node executes contracts compiled to WebAssembly. Two toolchains are supported:

### AssemblyScript Contracts

```bash
cd contract_samples/assemblyscript

# Compile and validate

./build_and_validate.sh my_contract.ts

# Output: my_contract.wasm ready for deployment

```

Upload via `Testnet.deploy` in the REPL or through the RPC API.

### Rust Contracts

Follow [`contract_samples/rust/README.md`](https://github.com/amadeusprotocol/node/blob/main/contract_samples/rust/README.md) for project setup, then:

```bash
cargo build --release --target wasm32-unknown-unknown

```

**Critical:** Use `wasm32-unknown-unknown` target only. Other targets produce invalid WASM for the node runtime.

## Production Deployment with Systemd

For persistent, auto-updating nodes, configure systemd with optimized kernel parameters.

### System Limits Configuration

Apply UDP buffer sizes and security settings (referenced in README.md lines 49–62):

```bash
cat <<'EOF' | sudo tee /etc/sysctl.d/99-amadeusd.conf
net.core.wmem_max = 268435456
net.core.rmem_max = 268435456
net.ipv4.udp_mem = 3060432 4080578 6120864
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
EOF

sudo sysctl --system

```

Set file descriptor and process limits (README.md lines 65–78):

```bash
cat <<'EOF' | sudo tee /etc/security/limits.d/99-amadeusd.conf
*    hard    nofile    1048576
*    soft    nofile    1048576
*    hard    nproc     unlimited
*    soft    nproc     unlimited
*    hard    memlock   unlimited
*    soft    memlock   unlimited
EOF

```

### Systemd Service File

Create the service unit (adapted from README.md lines 98–115):

```bash
cat <<'EOF' | sudo tee /etc/systemd/system/amadeusd.service
[Unit]
Description=AmadeusD Node
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
LimitNOFILE=1048576
KillMode=control-group
Restart=always
RestartSec=3
User=root
WorkingDirectory=/root
Environment="AUTOUPDATE=true"
ExecStart=/usr/bin/screen -UdmS amadeusd bash -c './amadeusd'

[Install]
WantedBy=multi-user.target
EOF

```

Enable and start:

```bash
sudo systemctl daemon-reload
sudo systemctl enable amadeusd
sudo systemctl start amadeusd

```

For **non-root deployment**, modify `User` and `WorkingDirectory` as shown in README.md lines 124–128.

## Troubleshooting Common Issues

| Symptom | Root Cause | Solution |
|---------|-----------|----------|
| `EADDRINUSE` on port 80/443 | Privileged port restrictions | Run `sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80` (README line 27) |
| Browser CORS errors | Cross-origin security policy | Launch Chrome with `--ignore-certificate-errors --disable-web-security` (README line 23) |
| Node crashes under load | Insufficient `nofile`/`memlock` limits | Apply limits.conf settings from production section |
| "Invalid wasm" on contract upload | Wrong compilation target | Verify `wasm32-unknown-unknown` for Rust, or use provided AssemblyScript build script |
| STUN/NAT traversal failures | Firewall blocking UDP | Open UDP ports used by [`node_gen_socket_gen.ex`](https://github.com/amadeusprotocol/node/blob/main/node_gen_socket_gen.ex) and verify [`stun.ex`](https://github.com/amadeusprotocol/node/blob/main/stun.ex) can reach public STUN servers |

## Summary

- **Build process:** Use `build.Dockerfile` and [`./build.sh`](https://github.com/amadeusprotocol/node/blob/main/./build.sh) to compile the `amadeusd` binary with all native dependencies
- **Local development:** Launch with `TESTNET=true` for immediate RPC access via REPL or HTTP
- **Contract support:** Compile AssemblyScript with [`build_and_validate.sh`](https://github.com/amadeusprotocol/node/blob/main/build_and_validate.sh) or Rust with `wasm32-unknown-unknown` target
- **Production readiness:** Configure systemd with `AUTOUPDATE=true`, apply kernel tuning for UDP buffers, and set high file descriptor limits
- **Core files:** Reference [`ex/lib/node/node_gen.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/node/node_gen.ex) for supervision tree, [`ex/lib/api/rpc_api.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/api/rpc_api.ex) for RPC handling, and [`ex/lib/misc/rocksdb.ex`](https://github.com/amadeusprotocol/node/blob/main/ex/lib/misc/rocksdb.ex) for storage implementation

## Frequently Asked Questions

### What hardware is required to run an Amadeus Protocol node?

A node runs on modest hardware: 2+ CPU cores, 4GB RAM, and SSD storage for RocksDB. The critical requirement is **network capacity**—the UDP-heavy architecture in [`node_gen_socket_gen.ex`](https://github.com/amadeusprotocol/node/blob/main/node_gen_socket_gen.ex) benefits from low-latency connections and sufficient kernel buffer sizes (`rmem_max`/`wmem_max`).

### How does the node handle software updates?

Set `AUTOUPDATE=true` in the environment to enable the built-in updater. The node checks for releases and applies them automatically while maintaining state in the `WORKFOLDER` directory. For manual control, run without this flag and replace the `amadeusd` binary directly.

### Can I run multiple nodes on the same machine?

Yes. Specify distinct `WORKFOLDER`, `HTTP_PORT`, and UDP port ranges for each instance. The [`node_gen.ex`](https://github.com/amadeusprotocol/node/blob/main/node_gen.ex) supervision tree isolates processes within each BEAM VM, though you must ensure sufficient file descriptors (`nofile` limits) for the combined socket count.

### Is there a difference between testnet and mainnet binaries?

No. The same `amadeusd` binary serves both modes. Testnet behavior is activated solely by the `TESTNET=true` environment variable, which modifies the genesis block and consensus rules in [`node_gen.ex`](https://github.com/amadeusprotocol/node/blob/main/node_gen.ex) without requiring a separate build.