Installation¶
Nexo is distributed as two static binaries, nexo (server with the embedded web console) and nexoctl
(CLI), and as multi-arch Docker images. The mode (single drive, multiple drives, cluster) does not depend
on the package but on the arguments of nexo server: see Deployment modes.
| Platform | nexo |
nexoctl |
|---|---|---|
| Linux amd64, arm64 | ✅ | ✅ |
| macOS amd64, arm64 | ✅ | ✅ |
| Windows amd64 | ✅ | ✅ |
| Windows arm64 | — | ✅ |
Every release contains archives, .deb/.rpm packages, a checksums.txt signed with cosign (keyless) and
an SPDX SBOM per archive. Verifying the signatures is described in
docs/08 §8.7.
Binaries (archives)¶
VERSION=1.0.0
curl -LO https://github.com/R3n3r0/Nexo/releases/download/v$VERSION/nexo_${VERSION}_linux_amd64.tar.gz
curl -LO https://github.com/R3n3r0/Nexo/releases/download/v$VERSION/nexoctl_${VERSION}_linux_amd64.tar.gz
curl -LO https://github.com/R3n3r0/Nexo/releases/download/v$VERSION/checksums.txt
sha256sum --ignore-missing -c checksums.txt
tar xzf nexo_${VERSION}_linux_amd64.tar.gz
tar xzf nexoctl_${VERSION}_linux_amd64.tar.gz
sudo install -m 0755 nexo nexoctl /usr/local/bin/
nexo version
nexoctl --version
- The
nexoarchive also containssystemd/nexo.service,systemd/nexo.env.exampleand their README (see systemd). - The
nexoctlarchive contains the shell completions incompletions/; they can also be generated withnexoctl completion bash|zsh|fish|powershell(seenexoctl completion). - On Windows the archives are
.zipfiles.
deb and rpm packages¶
# Debian, Ubuntu
sudo apt install ./nexo_1.0.0_amd64.deb ./nexoctl_1.0.0_amd64.deb
# Fedora, RHEL, openSUSE
sudo dnf install ./nexo-1.0.0-1.x86_64.rpm ./nexoctl-1.0.0-1.x86_64.rpm
The nexo package:
- installs
/usr/bin/nexoand the unit/usr/lib/systemd/system/nexo.service; - creates the
nexosystem user and group and the directory/var/lib/nexo/data(default drive); - installs
/etc/default/nexo(ownerroot:nexo, mode 0640) with an empty root password: the service refuses to start until you set it; - never enables, starts or restarts the service on its own; removing the package stops the service and keeps the data.
The nexoctl package installs the binary and the bash, zsh and fish completions. After the installation:
sudoedit /etc/default/nexo # NEXO_ROOT_PASSWORD, NEXO_ENDPOINTS
sudo systemctl enable --now nexo
journalctl -u nexo -f
Homebrew¶
brew install r3n3r0/tap/nexoctl
brew install r3n3r0/tap/nexo
The casks install the macOS and Linux binaries; the macOS binaries are signed with cosign but not notarized by Apple (the cask removes the quarantine attribute).
Docker¶
| Image | Contents |
|---|---|
paolor/nexo |
/nexo and /nexoctl, distroless base, non-root user (UID 65532), VOLUME /data, ports 9000 and 9001, HEALTHCHECK with nexo healthcheck |
paolor/nexoctl |
the CLI only, for CI pipelines and use from containers |
Tags: vX.Y.Z, plus vX.Y and latest for final releases. The images are multi-arch (linux/amd64,
linux/arm64), signed with cosign and carry SBOM and provenance attestations.
The images are published on Docker Hub only (docker.io/paolor/nexo and docker.io/paolor/nexoctl; paolor/nexo
is the short form):
docker pull paolor/nexo:latest
docker run -d --name nexo -p 9000:9000 -p 9001:9001 \
-e NEXO_ROOT_USER=admin -e NEXO_ROOT_PASSWORD=supersecret \
-v nexo-data:/data paolor/nexo:latest server /data
- Secrets:
NEXO_ROOT_USER_FILEandNEXO_ROOT_PASSWORD_FILEread the credentials from files (Docker or Swarm secrets); the_FILEvariable wins over the plain one. The same holds forNEXO_KMS_SECRET_KEY_FILEand for theNEXO_SECRET_<NAME>_FILEsecrets. - Host volumes: the container runs as UID 65532, so a mounted directory must belong to it:
sudo chown 65532:65532 /srv/nexobefore-v /srv/nexo:/data. Named volumes need nothing. - Multiple drives: one volume per drive and ellipses in the arguments:
-v /mnt/d1:/data1 … -v /mnt/d4:/data4 paolor/nexo server /data{1...4}. - TLS: mount the certificates directory and set
NEXO_CERTS_DIR; the healthcheck switches to HTTPS as well (see TLS and certificates). - CLI from a container:
docker run --rm -it --network host -v nexoctl-config:/home/nonroot/.nexoctl paolor/nexoctl ls local.
To build the images from source: make docker and make docker-nexoctl.
Docker Compose¶
The files in deploy/docker cover every
mode; you always start from nexo.env:
cd deploy/docker
cp nexo.env.example nexo.env # set NEXO_ROOT_USER and NEXO_ROOT_PASSWORD
docker compose -f compose.single.yml up -d
| File | Deployment |
|---|---|
compose.single.yml |
SNSD, one named volume (plus a /cache volume for the distributions cache) |
compose.snmd.yml |
SNMD with 4 volumes (server /data{1...4}) |
compose.cluster.yml + nginx.conf |
Cluster of 4 nodes × 2 drives behind an nginx on 9000 and 9001 |
compose.cluster-tls.yml + nginx-tls.conf |
The same cluster with TLS (./certs mounted on /certs; development certificates with gen-dev-certs.sh) |
compose.multi-proxy.yml + multi-proxy/ |
Cluster behind two proxies (nginx and HAProxy) with different domains and origin secrets |
compose.observability.yml |
Prometheus and Grafana with the Nexo dashboard, to layer on top of the other files |
The published ports are changed with NEXO_S3_PORT and NEXO_CONSOLE_PORT, the image with NEXO_IMAGE
(in the shell or in a .env next to the files). The README of the directory describes each variant.
Kubernetes (Helm)¶
The chart deploy/helm/nexo (Kubernetes
≥ 1.27) has two modes:
The packaged chart nexo-X.Y.Z.tgz is attached to every
GitHub release, signed with cosign (nexo-X.Y.Z.tgz.sigstore.json,
see Verifying a release); Helm installs it
straight from the URL:
TAG=v1.0.0
CHART="https://github.com/R3n3r0/Nexo/releases/download/$TAG/nexo-${TAG#v}.tgz"
# standalone: one Deployment, one PVC per drive (1 drive = SNSD, more drives = SNMD)
helm install nexo "$CHART" -n storage --create-namespace
# distributed: StatefulSet of 4 pods × 4 drives of 100 GiB, one pod per Kubernetes node
helm install nexo "$CHART" -n storage --create-namespace \
--set mode=distributed --set distributed.replicas=4 --set distributed.drivesPerNode=4 \
--set persistence.size=100Gi --set podAntiAffinity=hard
helm test nexo -n storage # cluster health and S3 round trip
- An empty root password is generated at install time and kept across upgrades (the chart's Secret,
auth.rootPasswordorauth.existingSecret). - The chart generates the endpoints with ellipses, one argument per pool (
distributed.pools), and rejects combinations that do not form valid erasure sets. - TLS from a
kubernetes.io/tlsSecret (tls.enabled,tls.secretName), hot-reloaded on renewal; KMS fromkms.secretKey/kms.existingSecretor KES (kms.kes.*). serviceMonitor.enabledcreates a Prometheus Operator ServiceMonitor; three optional Ingresses (S3, console, distributions).- An image upgrade proceeds one pod at a time; the PodDisruptionBudget (
maxUnavailable: 1) protects the quorum while nodes are drained. Adding a pool, or changing the root credentials or TLS, requires restarting all the pods together.
All the values are documented in values.yaml and validated by values.schema.json.
systemd¶
The unit deploy/systemd/nexo.service
is the same for every mode and every node: it reads the environment from /etc/default/nexo and the endpoints
from NEXO_ENDPOINTS. It runs nexo server --dry-run before starting and runs as the nexo user in a
sandbox (ProtectSystem=strict, no capabilities; systemd-analyze security rates it 1.5 "OK").
Manual installation from an archive:
sudo install -m 0755 nexo nexoctl /usr/local/bin/
sudo useradd --system --home-dir /var/lib/nexo --shell /usr/sbin/nologin nexo
sudo install -d -m 0750 -g nexo /etc/nexo
sudo install -m 0640 -g nexo systemd/nexo.env.example /etc/default/nexo # then edit it
sudo install -m 0644 systemd/nexo.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now nexo
The file system is read-only for the service, except /var/lib/nexo and /var/cache/nexo. Drives in
other paths need a drop-in and the right owner:
sudo install -d -o nexo -g nexo -m 0750 /mnt/disk1 /mnt/disk2 /mnt/disk3 /mnt/disk4
sudo systemctl edit nexo
# [Service]
# ReadWritePaths=/mnt/disk1 /mnt/disk2 /mnt/disk3 /mnt/disk4
# in /etc/default/nexo: NEXO_ENDPOINTS=/mnt/disk{1...4}
sudo systemctl restart nexo
systemctl reload nexosendsSIGHUP: it reloads the TLS certificates without dropping connections.- The unit is
Type=exec: to wait until the node is ready usenexo healthcheck --ready. - Ports below 1024 (
NEXO_WEB_ADDRESS=:80) needAmbientCapabilities=CAP_NET_BIND_SERVICEandCapabilityBoundingSet=CAP_NET_BIND_SERVICEin a drop-in.
Docker Swarm¶
The stack deploy/swarm/stack.yml starts a cluster
of 4 nodes × 2 drives with two nginx instances, the credentials as Docker secrets and upgrades one node at a time:
docker node update --label-add nexo.node=1 swarm-a # … up to nexo.node=4
printf admin | docker secret create nexo_root_user -
openssl rand -base64 30 | tr -d '\n' | docker secret create nexo_root_password -
NEXO_TAG=v1.0.0 docker stack deploy -c stack.yml nexo
From source¶
You need Go ≥ 1.27.2 (with GOTOOLCHAIN=auto, the default, an older toolchain downloads the one in go.mod
by itself), Node.js 22 with npm, and make:
git clone https://github.com/R3n3r0/Nexo.git && cd Nexo
make build # React console + bin/nexo (console embedded) + bin/nexoctl
bin/nexo version
make build-go builds the two binaries without the console (useful for backend development: on port 9001
the Admin API works, and a "console not included" page takes the place of the console). make help lists
all the targets.
Verifying the installation¶
nexo version
# checks configuration, topology, drive permissions, ports and certificates without starting anything
NEXO_ROOT_USER=admin NEXO_ROOT_PASSWORD=supersecret nexo server --dry-run /srv/nexo
# configuration OK: mode=snsd s3=:9000 console=:9001 endpoints=/srv/nexo
# node: local (1 node(s))
# pool 1: 1 erasure set(s) of 1 drive(s), parity 0
# local drives: 1 writable, 0 formatted
--dry-run does not write to the drives and exits with a non-zero code (and the list of problems) if the
configuration is not valid.