Installation
Prerequisites
A machine with:
- OS: Linux (Ubuntu 22.04 LTS / Debian 12 / RHEL 9 or compatible). macOS works for development.
- CPU: x86_64 or aarch64; at least 4 cores for a relay, 8 for a block producer.
- RAM: 16 GB minimum, 32 GB recommended for mainnet block production.
- Storage: 500 GB SSD (NVMe preferred). The mainnet immutable + volatile chain currently grows at roughly 8–12 GB per month.
- Network: stable IPv4 (or IPv4 + IPv6) with at least 25 Mbit/s symmetric.
- Time: NTP synchronised to within ±100 ms of UTC. Drifting clocks cause
BlockFromFuturerejection of valid peer blocks.
Software:
- A C toolchain and
pkg-config(build-essentialon Debian/Ubuntu). git,curl.- The Rust toolchain — installed below.
Install Rust
Yggdrasil pins the Rust toolchain version in rust-toolchain.toml. Currently 1.95.0 (Edition 2024).
If you do not have rustup:
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
$ source "$HOME/.cargo/env"
rustup will read rust-toolchain.toml automatically when you build the workspace and download the pinned compiler if missing. You do not need to run rustup install manually.
Make cargo available in non-interactive shells
The rustup installer adds $HOME/.cargo/bin to your interactive
shell’s PATH via ~/.bashrc / ~/.zshrc. Non-interactive shells
(CI runners on WSL, editor terminals, scripted Bash subprocesses,
agent harnesses) typically don’t source those files, so cargo
won’t be found.
Two robust fixes:
-
Symlink the rustup binaries into
~/.local/bin/(which is on every shell’sPATHby default on Debian/Ubuntu):$ mkdir -p ~/.local/bin $ for bin in cargo rustc rustup rustdoc rustfmt clippy-driver \ cargo-clippy cargo-fmt cargo-nextest cargo-deny just; do ln -sf "$HOME/.cargo/bin/$bin" "$HOME/.local/bin/$bin" done -
Or install Rust system-wide via your distribution’s packaging (
apt-get install rustc cargoon Debian/Ubuntu). The pinned1.95.0toolchain still gets downloaded byrustup-via-rustcwhen you build, but the dispatch binaries are in/usr/bin.
The devcontainer (.devcontainer/devcontainer.json) uses the
ghcr.io/devcontainers/features/rust:1 feature which handles this
automatically — system-wide install with cargo on PATH for every
shell mode. The two fixes above only apply when running on a local
host (WSL, bare-metal Linux).
Verify:
$ rustc --version
rustc 1.95.0 (...)
Clone the repository
$ git clone https://github.com/yggdrasil-node/Cardano-node.git yggdrasil
$ cd yggdrasil
The default branch is main and is always at a green-gates commit.
Build a release binary
$ cargo build --release --bin yggdrasil-node
First build will fetch and compile dependencies; expect 5–15 minutes on a typical server. Subsequent rebuilds are incremental and finish in seconds.
The binary lands at target/release/yggdrasil-node. It is statically linked against everything except glibc/libc, so you can copy it between machines of the same architecture.
Verify the build
Run the test suite:
$ cargo test-all
The full workspace runs 4.7K+ tests across all crates. Failure-free output from cargo test-all, together with cargo check-all and cargo lint, is the green-gates baseline.
For a faster smoke check before shipping the binary:
$ ./target/release/yggdrasil-node --version
yggdrasil-node 0.2.0
$ ./target/release/yggdrasil-node default-config | head -20
Install the binary system-wide
For convenience:
# cp target/release/yggdrasil-node /usr/local/bin/
# chmod 755 /usr/local/bin/yggdrasil-node
Or run directly from the build directory if you prefer not to install globally.
Create a system user (production)
Recommended for any production deployment:
# useradd --system --create-home --home-dir /var/lib/yggdrasil --shell /usr/sbin/nologin yggdrasil
# mkdir -p /var/lib/yggdrasil/db /var/lib/yggdrasil/config
# chown -R yggdrasil:yggdrasil /var/lib/yggdrasil
The node will write its chain database under --database-path (default: current working directory). Pointing it at /var/lib/yggdrasil/db keeps mutable state out of the system root.
Open firewall ports
A relay needs:
- 3001/tcp inbound for peer-to-peer (or whatever you set
--portto). - The metrics port (default disabled; if enabled with
--metrics-port, bound to127.0.0.1only — open it only on your monitoring network if you want external Prometheus scraping).
A block producer should not accept inbound connections from the public internet. Only its own relays should connect.
Example with ufw:
# ufw allow 3001/tcp
# ufw reload
Sanity-check the configuration before first run
$ yggdrasil-node validate-config --network mainnet --database-path /var/lib/yggdrasil/db
This runs the operator preflight: it loads the configuration, verifies vendored genesis hashes, checks the storage state, validates KES/Praos invariants if credentials are configured, and reports warnings (storage uninitialized on a fresh setup is expected).
Where to go next
You have a working binary. Continue to Quick Start to sync your first node.