logos-storage-nim/tools/storage-test/SETUP_STORAGE_NODE.md

9.9 KiB

Logos Storage Node Machine Setup Recipe

This recipe describes how to prepare a fresh machine to run a headless Logos Storage node. It is written for a human operator or an AI agent that can SSH into the target machine and execute administrative commands.

The first section is system-independent. The second section gives the concrete Ubuntu 24.04 setup used for the Linode test node.

Goal

Set up a machine that:

  • Runs Logos Storage as a non-root service user.
  • Keeps the REST API bound to localhost only.
  • Exposes only the P2P and discovery ports publicly.
  • Can be administered over SSH using key-based login.
  • Starts the node automatically on boot using the host service manager.

Target Runtime Shape

Purpose Default Used Here Protocol Exposure
SSH 22 TCP Restricted to operator IP
P2P listen 8070 TCP Public
Discovery 8090 UDP Public
REST API 8080 TCP Localhost only

The storage node command should look conceptually like:

storage \
  --data-dir=<data-dir> \
  --listen-port=8070 \
  --disc-port=8090

Do not pass --api-bindaddr=0.0.0.0 unless there is a deliberate reason to expose the API. The default API bind address is 127.0.0.1.

Generic Setup Steps

  1. Provision a machine.

Choose a machine with enough resources for the intended workload. For running the node, a small machine can work. For compiling on the machine, prefer at least 2 vCPU and 2-4 GB RAM. A 1 vCPU / 1 GB RAM machine can build, but slowly and may need extra swap.

  1. Configure firewall rules.

Inbound rules:

Purpose Protocol Port Source
SSH TCP 22 Operator IP only, if possible
Storage P2P TCP 8070 Public IPv4/IPv6 as needed
Storage Discovery UDP 8090 Public IPv4/IPv6 as needed

Do not open 8080/TCP publicly. Access the API over SSH tunneling.

  1. Create a non-root service user.

Create a dedicated user, for example storage. The node process should run as this user, not as root.

  1. Configure SSH access.

Install the operator public SSH key for the service/admin user. Verify login works before disabling root login. Then harden SSH:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
  1. Install build/runtime prerequisites.

Install a C/C++ toolchain, git, cmake, curl, make, bash, and runtime libraries required by the build. If building from source, install Nim 2.2.10, preferably through choosenim.

  1. Clone and build Logos Storage.

Clone https://github.com/logos-storage/logos-storage-nim.git, initialize submodules, and build:

make update
make NIMFLAGS="-d:disableMarchNative"

Use low parallelism on small machines:

make -j1 NIMFLAGS="-d:disableMarchNative"

-d:disableMarchNative is recommended for Linux amd64 release/test artifacts to avoid leaking build-machine CPU choices into the binary and to avoid known GCC/secp256k1 x86_64 asm failures.

  1. Install the binary.

Install the built binary somewhere stable, for example:

/opt/logos-storage/storage

Keep source checkout and runtime data separate.

  1. Create the data directory.

Use a dedicated persistent data directory owned by the service user, for example:

/var/lib/logos-storage
  1. Create a service.

Use the platform service manager to run the node as the non-root service user, restart on failure, and start on boot.

  1. Verify.

Verify:

  • Service is running.
  • TCP 8070 listens on all addresses.
  • UDP 8090 listens on all addresses.
  • TCP 8080 listens only on 127.0.0.1.
  • GET http://127.0.0.1:8080/api/storage/v1/peerid returns a peer ID locally.
  • External TCP connectivity to 8070 works.

Ubuntu 24.04 Example

This example assumes:

  • Ubuntu 24.04 LTS.
  • Initial SSH access as root.
  • Desired user: storage.
  • Public IP: replace SERVER_IP with the host IP.
  • Repository branch: master.

1. Update The System

apt-get update
DEBIAN_FRONTEND=noninteractive apt-get -y upgrade
DEBIAN_FRONTEND=noninteractive apt-get -y full-upgrade
reboot

Reconnect after reboot and verify:

apt list --upgradable
test ! -f /var/run/reboot-required

2. Create The storage User

adduser --disabled-password --gecos "" storage
usermod -aG sudo storage
install -d -m 700 -o storage -g storage /home/storage/.ssh
install -m 600 -o storage -g storage /root/.ssh/authorized_keys /home/storage/.ssh/authorized_keys

Optional passwordless sudo for bootstrap/admin work:

printf 'storage ALL=(ALL) NOPASSWD:ALL\n' > /etc/sudoers.d/90-storage-user
chmod 440 /etc/sudoers.d/90-storage-user
visudo -cf /etc/sudoers.d/90-storage-user

From the operator machine, verify:

ssh storage@SERVER_IP 'whoami; id; sudo -n true'

3. Harden SSH

Create a drop-in:

install -d -m 755 /etc/ssh/sshd_config.d
cat > /etc/ssh/sshd_config.d/99-logos-storage-hardening.conf <<'EOF'
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
EOF
sshd -t
systemctl restart ssh || systemctl restart sshd

Verify from the operator machine:

ssh storage@SERVER_IP 'true'
ssh -o BatchMode=yes root@SERVER_IP 'true'

The root command should fail.

4. Install Packages

sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y \
  build-essential \
  cmake \
  git \
  curl \
  make \
  bash \
  lcov \
  libgomp1 \
  jq \
  ca-certificates \
  pkg-config

5. Add Swap On Small Machines

On very small machines, for example 1 GB RAM, add a swap file before building:

if [ ! -f /swapfile ]; then
  sudo fallocate -l 2G /swapfile || sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
  sudo chmod 600 /swapfile
  sudo mkswap /swapfile
  sudo swapon /swapfile
fi
grep -q '^/swapfile ' /etc/fstab || echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -h

6. Install Nim 2.2.10 With choosenim

Run as the storage user:

curl https://nim-lang.org/choosenim/init.sh -sSf | sh -s -- -y
export PATH="$HOME/.nimble/bin:$PATH"
choosenim 2.2.10
nim --version

Persist PATH:

grep -qxF 'export PATH=$HOME/.nimble/bin:$PATH' ~/.profile || \
  printf '\nexport PATH=$HOME/.nimble/bin:$PATH\n' >> ~/.profile

7. Clone And Build

Run as the storage user:

git clone https://github.com/logos-storage/logos-storage-nim.git ~/logos-storage-nim
cd ~/logos-storage-nim
make -j1 update
make -j1 NIMFLAGS="-d:disableMarchNative"
./build/storage --help >/dev/null

On larger machines, use higher parallelism, for example:

make -j"$(nproc)" update
make -j"$(nproc)" NIMFLAGS="-d:disableMarchNative"

8. Install Binary And Data Directory

sudo install -d -m 755 -o root -g root /opt/logos-storage
sudo install -m 755 -o root -g root ~/logos-storage-nim/build/storage /opt/logos-storage/storage
sudo install -d -m 700 -o storage -g storage /var/lib/logos-storage
/opt/logos-storage/storage --help >/dev/null

9. Create systemd Service

sudo tee /etc/systemd/system/logos-storage.service >/dev/null <<'EOF'
[Unit]
Description=Logos Storage Node
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=storage
Group=storage
WorkingDirectory=/var/lib/logos-storage
ExecStart=/opt/logos-storage/storage --data-dir=/var/lib/logos-storage --listen-port=8070 --disc-port=8090
Restart=on-failure
RestartSec=10
LimitNOFILE=1048576
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/var/lib/logos-storage

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now logos-storage.service

10. Verify Service And Ports

systemctl --no-pager --full status logos-storage.service
ss -lntup | grep -E ':(8070|8080|8090)\b'
curl -fsS http://127.0.0.1:8080/api/storage/v1/peerid
curl -fsS http://127.0.0.1:8080/api/storage/v1/spr
journalctl -u logos-storage.service --no-pager -n 80

Expected bindings:

udp 0.0.0.0:8090
tcp 127.0.0.1:8080
tcp 0.0.0.0:8070

From the operator machine, verify public TCP reachability:

timeout 10 bash -c 'cat < /dev/null > /dev/tcp/SERVER_IP/8070' && echo open

UDP reachability is harder to verify with a simple shell one-liner. Confirm the firewall rule exists and inspect node logs for discovery startup and advertised /udp/8090 addresses.

API Access From Operator Machine

Keep the API private and tunnel over SSH:

ssh -N -L 127.0.0.1:18080:127.0.0.1:8080 storage@SERVER_IP

Then use:

curl http://127.0.0.1:18080/api/storage/v1/peerid

In this repository, tools/storage-test/storage-test.sh manages this tunnel automatically for commands targeting remote.

Operational Commands

sudo systemctl start logos-storage.service
sudo systemctl stop logos-storage.service
sudo systemctl restart logos-storage.service
systemctl status logos-storage.service
journalctl -u logos-storage.service -f

Troubleshooting

SSH Hangs During Build

Symptoms:

Connection timed out during banner exchange

Likely cause: small VM overloaded by compilation. Use make -j1, add swap, or build on a larger machine and copy the binary.

REST API Is Unreachable Externally

This is expected. The REST API should bind to 127.0.0.1:8080. Use SSH tunneling.

Node Has No Peers

Check:

  • Firewall allows 8070/TCP and 8090/UDP.
  • Service logs show public IP in advertised addresses.
  • The machine has public internet access.
  • The network preset is the intended one, for example logos.test.

Data Directory Permissions Warning

The node may correct permissions on startup. Prefer setting the directory explicitly:

sudo chmod 700 /var/lib/logos-storage
sudo chown storage:storage /var/lib/logos-storage

Security Notes

  • Do not run the node as root.
  • Do not expose API port 8080 publicly.
  • Restrict SSH source IPs in the cloud firewall.
  • Keep outbound traffic allowed unless there is a specific network policy.
  • Treat the node private key in the data directory as sensitive.