Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@
# and a `git add -A` sweeps them into a public repo.
.DS_Store
**/.DS_Store
# graphify knowledge-graph output (graph.json, graph.html, report, cache).
# Built locally per machine; not part of the project.
/graphify-out/
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,43 @@ Anything that changes what a miner is paid, or what an operator has to tell
their miners, is called out explicitly — those are the changes that cost
somebody money if they go unread.

## Unreleased

### Operators: the dashboard now listens on loopback by default

`dashboard/server.js` binds `DASHBOARD_BIND`, default `127.0.0.1`, where it
used to bind every interface. Behind nginx nothing changes. **If you reach the
dashboard directly on `:8081`, add `Environment=DASHBOARD_BIND=0.0.0.0` to its
systemd drop-in before upgrading**, or it stops answering there. `install.sh`
sets it for you: loopback with nginx, all interfaces with `--no-nginx`. The
Docker image sets `0.0.0.0` inside the container.

### Miners on pplns-thunder / pplns-btc: small blocks are no longer short-changed

When a block's operator fee came to less than the 546-sat dust limit, the
coinbase (correctly) paid no fee output and the pool wallet received the whole
reward — but the distributor still took `fee_bps` off before crediting miners,
so the difference sat in the pool wallet credited to nobody. The distributor
now applies the coinbase's dust rule. Only blocks worth less than roughly
`546 × 10000 / fee_bps` sats are affected (54,600 sats at 1%).

### Config: an eighth `listener` line is refused

The server has room for `listen_port` plus seven extra ports. An eighth
`listener` used to load cleanly and then silently not be bound; it is now a
config error naming the limit.

### Smaller fixes

- `install.sh --help` no longer claims `--pps-sats-per-diff` defaults to 1000
— it defaults to unset (derived per template) — and the installer warns if
you pass it.
- `schema.sql` documents the unique index on `blocks_found(hash)` that the
proxy creates at startup, and why it is not created there.
- `docs/simplepool.html` is now a full reference: every config key and
environment variable, the stratum protocol, the coinbase layout, every API,
the schema and the hard limits.

## 0.4.0 — three PPLNS modes, and coinbase-direct payouts

The headline is that a pool no longer has to hold miners' money to run PPLNS.
Expand Down
7 changes: 5 additions & 2 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -656,8 +656,11 @@ scripted one-liner in [OPERATOR_GUIDE.md](OPERATOR_GUIDE.md#rotating-the-admin-p

### Reverse proxy (recommended)

The dashboard binds `0.0.0.0:8081` — reachable directly. In
production you probably want nginx / caddy in front of it. Solo
The dashboard binds `127.0.0.1:8081` by default (`DASHBOARD_BIND`), so it
is reachable only through a reverse proxy on the same host. To serve it
directly, set `Environment=DASHBOARD_BIND=0.0.0.0` in its drop-in — and then
put TLS in front of `/admin` some other way. In production you want nginx /
caddy in front of it. Solo
`deploy/nginx/simplepool.conf` has a working template.

Do NOT expose `/admin` on plain HTTP over the internet without at
Expand Down
6 changes: 6 additions & 0 deletions OPERATOR_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ tracked by git.
| SSH | `root@<pool-host>` | `<ssh-key>` |
| Everything from the shell | `simplepoolctl status` / `doctor` / `logs -f` | root for `restart`, `upgrade`, `uninstall` |

The `:8081` URLs assume the dashboard listens publicly. Since it defaults to
loopback (`DASHBOARD_BIND=127.0.0.1`), that needs
`Environment=DASHBOARD_BIND=0.0.0.0` in
`/etc/systemd/system/simplepool-dashboard.service.d/local.conf`; behind nginx,
use `https://<your-domain>/` instead and leave it on loopback.

The admin password is stashed at `/root/simplepool-admin-cred.txt` on the
box (root-only). To rotate, edit
`/etc/systemd/system/simplepool-dashboard.service.d/pps-thunder.conf`
Expand Down
3 changes: 2 additions & 1 deletion dashboard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ npm start # production
npm run dev # auto-restart on file change
```

Defaults: `PORT=8081`, `PROXY_DB_PATH=../data/shares.snapshot.db`.
Defaults: `PORT=8081`, `DASHBOARD_BIND=127.0.0.1` (set `0.0.0.0` to serve it
without a reverse proxy), `PROXY_DB_PATH=../data/shares.snapshot.db`.

If the snapshot file doesn't exist yet, the dashboard starts anyway and
displays "no data yet" until the first `.backup` produces it. You can also
Expand Down
9 changes: 7 additions & 2 deletions dashboard/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ import { createAdminRouter } from './lib/admin-router.js';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PORT = parseInt(process.env.PORT || '8081', 10);
// Loopback by default, like the payout and slipstream services: the
// dashboard is meant to be published through nginx, and /admin speaks HTTP
// Basic auth, which must not be reachable in the clear on a public
// interface. Set DASHBOARD_BIND=0.0.0.0 (or ::) to serve it directly.
const BIND = process.env.DASHBOARD_BIND || '127.0.0.1';
const DB_PATH = process.env.PROXY_DB_PATH || '../data/shares.db';

const app = express();
Expand Down Expand Up @@ -296,6 +301,6 @@ app.use('/admin',

app.use((_req, res) => res.status(404).render('404', { what: 'page' }));

app.listen(PORT, () => {
console.log(`simplepool dashboard on :${PORT} (db: ${db.path})`);
app.listen(PORT, BIND, () => {
console.log(`simplepool dashboard on ${BIND}:${PORT} (db: ${db.path})`);
});
2 changes: 2 additions & 0 deletions deploy/docker/Dockerfile.dashboard
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,7 @@ WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY dashboard/ ./
USER node
# Inside a container loopback is unreachable from the published port.
ENV DASHBOARD_BIND=0.0.0.0
EXPOSE 8081
ENTRYPOINT ["/usr/bin/tini", "--", "node", "server.js"]
1 change: 1 addition & 0 deletions deploy/docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ services:
- "${DASHBOARD_PORT:-8081}:8081"
environment:
PORT: "8081"
DASHBOARD_BIND: 0.0.0.0
PROXY_DB_PATH: /data/shares.db
PUBLIC_STRATUM_URL: ${PUBLIC_STRATUM_URL:-stratum+tcp://<pool-host>:3334}
THUNDER_RPC_URL: ${THUNDER_RPC_URL:-http://host.docker.internal:6009}
Expand Down
3 changes: 3 additions & 0 deletions deploy/systemd/simplepool-dashboard.service
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ User=@USER@
Group=@USER@
WorkingDirectory=@ROOT@/dashboard
Environment=PORT=8081
# Loopback: nginx publishes the dashboard. Set 0.0.0.0 only to serve it
# directly, and then only behind a firewall or TLS -- /admin uses Basic auth.
Environment=DASHBOARD_BIND=127.0.0.1
Environment=PROXY_DB_PATH=@ROOT@/data/shares.db
# Rendered on the public "Connect a miner" card. Set to the actual
# host miners should point their ASIC at. Leave unset to show
Expand Down
Loading
Loading