Servers: CLI and Docker
necter-miner is one binary: CLI, background daemon, local HTTP API and dashboard. Mining needs no inbound
port: everything is outbound HTTPS plus one outbound WebSocket.
Install
Section titled “Install”cargo build --release -p necter-miner && sudo install target/release/necter-miner /usr/local/bin/necter-miner init # asks "Open the web dashboard on this server's IP? [y/N]" on serversnecter-miner join --project 0x<project_id> --payout 0x<payout address>sudo necter-miner service install # systemd unit (User=necter-miner, ProtectSystem=strict, data in /var/lib/necter-miner)On a headless host without a keyring, the embedded wallet’s encryption key lives in <data_dir>/wallet.key
(0600) unless you pass --wallet-key-file. Data: ~/.local/share/necter-miner (service:
/var/lib/necter-miner).
cargo install --path cli # inside the necter-miner checkoutnecter-miner init # node key, embedded wallet (key in the macOS Keychain), confignecter-miner join --project 0x<project_id> --payout 0x<payout address>necter-miner ui # opens http://127.0.0.1:7878, already signed innecter-miner service install # launchd agent ~/Library/LaunchAgents/network.necter.miner.plistData: ~/Library/Application Support/network.necter.miner.
cargo build --release -p necter-miner.\target\release\necter-miner.exe init.\target\release\necter-miner.exe join --project 0x<project_id>.\target\release\necter-miner.exe service install # Windows service "NecterMiner" (elevated prompt)The wallet key is kept in Windows Credential Manager. Data: %LOCALAPPDATA%\Necter\Miner (service:
%PROGRAMDATA%\Necter\Miner).
# build context = the directory that holds necter-miner/ and the NDSR checkoutdocker buildx build --platform linux/amd64,linux/arm64 -f necter-miner/Dockerfile -t necter/miner .docker run -d --name necter-miner -v necter-data:/data necter/miner join --project 0x<project_id> --payout 0x<payout>docker exec necter-miner necter-miner statusThe image runs as uid 10001 with VOLUME /data. The dashboard stays on loopback inside the container unless
you pass --ui-public (then publish -p 7878:7878, see below).
join: one-step setup
Section titled “join: one-step setup”necter-miner join --project <id> does init + bind (embedded wallet) + faucet + subscribe + run:
| Flag | |
|---|---|
--project <id> |
the project to mine (its id from the store) |
--collateral <NECTA> |
decimal, e.g. 10 or 12.5; default: the project’s minimum |
--payout 0x… |
where rewards go (default: the owner wallet) |
--no-run |
do not start the daemon afterwards |
Find project ids in the store, or: curl -s https://testnet-rpc.necter.network/v1/projects.
A fresh init prints:
Data dir: /home/miner/.local/share/necter-minerNode ID: ndsr-f7f67866c5cfe55cWallet: 0x0414cceceab0d06f76db18c923afca75c672ceb4 (embedded)Dashboard: ssh -L 7878:127.0.0.1:7878 <user>@<host> then open http://127.0.0.1:7878and status:
State: stoppednode: ndsr-f7f67866c5cfe55cowner: (unbound)relay: disconnectedengine: nativeleases: 0 active, 0 today (0 units)(daemon not running; start it with `necter-miner start`)Everyday commands
Section titled “Everyday commands”necter-miner status [--json] # state, owner, relay, engine, leasesnecter-miner start | stop [--daemon] # stop mining; --daemon also exits the daemonnecter-miner subscriptions [--json]necter-miner claims [--submit] # show / claim rewards (gasless)necter-miner faucet # test NECTA for the owner walletnecter-miner leave --project <id> # unbond this device's subscriptionnecter-miner withdraw --project <id> # withdraw released collateral after unbondingnecter-miner payout set 0x… # change the payout address (gasless)necter-miner policy show | policy set max_cpu_pct=50 networks='["ethernet"]'necter-miner logs [-f] [--level warn]necter-miner bench # run the benchmark suitenecter-miner update [--check]Full list: necter-miner CLI.
The dashboard on a server
Section titled “The dashboard on a server”By default the dashboard listens only on 127.0.0.1:7878. Reach it through SSH:
ssh -L 7878:127.0.0.1:7878 user@host # then open http://127.0.0.1:7878To open it on the server’s IP (opt-in; password and TLS are mandatory):
-
Enable it interactively:
Terminal window necter-miner ui enable-remote # prompts for a password twice (min 12 chars)necter-miner ui enable-remote --domain miner.example.org # Let's Encrypt instead of self-signedor non-interactively:
Terminal window install -m 600 /dev/stdin /root/ui-pass <<< 'a-long-unique-password'necter-miner --ui-public --ui-password-file /root/ui-pass run -
Allow TCP 7878 in your firewall or security group.
-
Open
https://<server-ip>:7878. With the self-signed certificate, compare the SHA-256 fingerprint the CLI printed with the one your browser shows before accepting it.
How it is protected:
- The password is stored only as an argon2id hash in
miner.toml. The daemon refuses to start (exit 78) if the dashboard is bound to a non-loopback address without a password or without TLS. - TLS: a self-signed ECDSA P-256 certificate (397 days, renewed 30 days before expiry), or Let’s Encrypt with
--ui-domain(HTTP-01 on port 80, or TLS-ALPN-01 when the dashboard uses port 443). - 5 failed sign-ins per IP in 15 minutes → 15-minute lockout, doubling up to 24 hours; 60 attempts per minute
globally. Sessions are
Secure; HttpOnly; SameSite=Strictcookies (12 h, 1 h idle) with CSRF protection. - Payout changes, unbond, withdraw, wallet create/unlock and dashboard settings ask for the password again. Wallet import and export are never available remotely.
necter-miner ui status | disable-remote [--forget-password] | set-password | rotate-tokenwork on a running daemon.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
| 0 | ok |
| 1 | runtime error |
| 2 | usage error |
| 73 | cannot create the data directory or key |
| 75 | another instance holds miner.lock |
| 78 | configuration refused (e.g. remote dashboard without password/TLS) |
If the Hub is unreachable, the daemon keeps running, serves the dashboard, raises a hub_unreachable alert and
retries with backoff (1 s to 60 s).