Fresh PIR Setup
Use Automatic for the supported one-command install. Switch to
Manual when you need to download, verify, configure, and start
nf-server yourself without running
start_pir.sh.
-
Provision A Dedicated PIR Host
Minimum production requirement: run PIR on its own machine with at least this capacity.
- Platform
- Linux amd64
- CPU
- 4 vCPU + AVX-512
- Memory
- 32 GB RAM
- Storage
- 65 GB free SSD
More CPU and storage are recommended when available to keep query serving and future snapshot growth comfortable.
The production
linux-amd64binary requires AVX-512. If the host does not expose AVX-512, the service will crash before binding port3000, usually withstatus=4/ILLin systemd logs. -
Run The PIR Installer
Run this on the PIR host. It installs the verified
nf-serverrelease, writes the systemd service, startsnullifier-query-server, and bootstraps the active PIR snapshot from Valar-hosted object storage.curl -fsSL https://vote.fra1.digitaloceanspaces.com/start_pir.sh | sudo bashThe installer targets Linux hosts with systemd and must run as root because it writes under
/optand/etc. -
Expose HTTPS To The Local Service
nf-serverserves plaintext HTTP on local port3000. Set up your own Caddy, nginx, or load balancer so the public URL uses HTTPS and proxies to127.0.0.1:3000. Do not expose the raw port directly to clients.pir.example.org { reverse_proxy 127.0.0.1:3000 @debug path /tier1/row/* /tier2/row/* handle @debug { respond 403 } }Replace
pir.example.orgwith your hostname. The public endpoint should look likehttps://pir.example.org. -
Publish The PIR Endpoint
Add the public HTTPS URL to
pir_endpoints[]indynamic-voting-config.json. Add one JSON object withurlandlabel, then open a PR from GitHub's edit flow. Edit voting config.{ "url": "https://pir.example.org", "label": "Example PIR" }
-
Provision A Dedicated PIR Host
Minimum production requirement: run PIR on its own machine with at least this capacity.
- Platform
- Linux amd64
- CPU
- 4 vCPU + AVX-512
- Memory
- 32 GB RAM
- Storage
- 65 GB free SSD
More CPU and storage are recommended when available to keep query serving and future snapshot growth comfortable.
The production
linux-amd64binary requires AVX-512. If the host does not expose AVX-512, the service will crash before binding port3000, usually withstatus=4/ILLin systemd logs. -
Install Host Requirements
Install the shell tools used by the manual download, checksum, and local service checks.
sudo apt-get update sudo apt-get install -y curl ca-certificates jq command -v systemctl >/dev/null -
Download And Verify The Release
Pin
TAGif you need a specific release. By default this downloads the latest GitHub release, prefers Valar-hosted object storage for the binary and checksum, and falls back to GitHub release assets.set -euo pipefail REPO="valargroup/vote-nullifier-pir" BINARY_BASE_URL="${BINARY_BASE_URL:-https://vote.fra1.digitaloceanspaces.com/binaries/vote-pir}" TAG="${TAG:-$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" | jq -r '.tag_name')}" WORKDIR="${WORKDIR:-/tmp/pir-manual-install}" case "$(uname -m)" in x86_64) PLATFORM=linux-amd64 ;; aarch64|arm64) PLATFORM=linux-arm64 ;; *) echo "Unsupported CPU architecture: $(uname -m)" >&2; exit 1 ;; esac rm -rf "$WORKDIR" mkdir -p "$WORKDIR" curl -fsSL --retry 3 --retry-delay 2 -o "${WORKDIR}/nf-server-${PLATFORM}" \ "${BINARY_BASE_URL}/nf-server-${TAG}-${PLATFORM}" \ || curl -fsSL --retry 3 --retry-delay 2 -o "${WORKDIR}/nf-server-${PLATFORM}" \ "https://github.com/${REPO}/releases/download/${TAG}/nf-server-${PLATFORM}" curl -fsSL --retry 3 --retry-delay 2 -o "${WORKDIR}/SHA256SUMS" \ "${BINARY_BASE_URL}/SHA256SUMS-${TAG}" \ || curl -fsSL --retry 3 --retry-delay 2 -o "${WORKDIR}/SHA256SUMS" \ "https://github.com/${REPO}/releases/download/${TAG}/SHA256SUMS" curl -fsSL --retry 3 --retry-delay 2 -o "${WORKDIR}/nullifier-query-server.service" \ "https://github.com/${REPO}/releases/download/${TAG}/nullifier-query-server.service" grep -q " nf-server-${PLATFORM}$" "${WORKDIR}/SHA256SUMS" grep -q " nullifier-query-server.service$" "${WORKDIR}/SHA256SUMS" (cd "$WORKDIR" && sha256sum -c SHA256SUMS --ignore-missing) -
Install The Binary And Service Files
This installs the verified release under
/opt/nf-ingest, exposesnf-serveronPATH, and writes the same environment defaults the installer writes.set -euo pipefail WORKDIR="${WORKDIR:-/tmp/pir-manual-install}" case "$(uname -m)" in x86_64) PLATFORM=linux-amd64 ;; aarch64|arm64) PLATFORM=linux-arm64 ;; *) echo "Unsupported CPU architecture: $(uname -m)" >&2; exit 1 ;; esac sudo install -d /opt/nf-ingest /opt/nf-ingest/pir-data sudo install -m 0755 "${WORKDIR}/nf-server-${PLATFORM}" /opt/nf-ingest/nf-server sudo install -m 0644 "${WORKDIR}/nullifier-query-server.service" /etc/systemd/system/nullifier-query-server.service sudo ln -sf /opt/nf-ingest/nf-server /usr/local/bin/nf-server sudo tee /etc/default/nf-server >/dev/null <<'EOF' SVOTE_PIR_VOTING_CONFIG_URL=https://valargroup.github.io/token-holder-voting-config/voting-config.json SVOTE_PIR_PRECOMPUTED_BASE_URL=https://vote.fra1.digitaloceanspaces.com EOF /opt/nf-ingest/nf-server --version /opt/nf-ingest/nf-server doctor --pir-data-dir /opt/nf-ingest/pir-dataOptional: write
SENTRY_DSN=...to/opt/nf-ingest/.env; the service reads that file when present. -
Start And Bootstrap The Service
On first start,
nf-server serveresolves the active voting snapshot height from the voting config and downloads the matching PIR tiers from Valar-hosted object storage before serving local port3000.sudo systemctl daemon-reload sudo systemctl enable --now nullifier-query-server sudo systemctl status nullifier-query-server curl -fsS http://127.0.0.1:3000/readyIf no active round exists on a fresh host, set
SVOTE_PIR_BOOTSTRAP_SNAPSHOT_HEIGHTin/etc/default/nf-serverto a published snapshot height, then restart the service. -
Expose HTTPS To The Local Service
Proxy public HTTPS traffic to
127.0.0.1:3000and block debug row routes. SetPIR_URLto the public URL you will publish for wallets.PIR_DOMAIN="pir.example.org" PIR_URL="https://${PIR_DOMAIN}" sudo apt-get install -y caddy sudo tee /etc/caddy/Caddyfile >/dev/null <<EOF ${PIR_DOMAIN} { reverse_proxy 127.0.0.1:3000 @debug path /tier1/row/* /tier2/row/* handle @debug { respond 403 } } EOF sudo caddy validate --config /etc/caddy/Caddyfile sudo systemctl restart caddyIf TLS is handled upstream, skip the Caddy block and set
PIR_URLdirectly before publishing.PIR_URL="https://pir.example.org" -
Verify And Publish The PIR Endpoint
Confirm local readiness and public HTTPS access, then add the public URL to
pir_endpoints[]indynamic-voting-config.json.curl -fsS http://127.0.0.1:3000/ready curl -fsS http://127.0.0.1:3000/health | jq -r '.status' curl -fsS http://127.0.0.1:3000/root | jq '{height, pir_depth, num_ranges}' curl -fsS "${PIR_URL}/root" | jq '{height, pir_depth, num_ranges}'{ "url": "https://pir.example.org", "label": "Example PIR" }