Skip to content

Harden installer ops, localhost beacon APIs, and digest pins - #2

Merged
DavidFeder merged 1 commit into
mainfrom
cursor/harden-rpc-node-ops-d98a
Aug 28, 2026
Merged

Harden installer ops, localhost beacon APIs, and digest pins#2
DavidFeder merged 1 commit into
mainfrom
cursor/harden-rpc-node-ops-d98a

Conversation

@DavidFeder

Copy link
Copy Markdown
Owner

Follow-up to the repo bug check: operational fixes, a few security defaults that do not change LAN wallet RPC (8545/8546 still bind 0.0.0.0), and tighter tests/CI.

Behavior that stays the same

  • Wallet HTTP/WS RPC remains LAN-visible (0.0.0.0:8545 / 8546) for MetaMask / Internet Money on the home network.
  • Engine API stays 127.0.0.1:8551.
  • Host networking, checkpoint sync URL, and pinned Go-Pulse v3.3.0 / Prysm-Pulse v2.3.0 tags.

Fixes

  • restart.sh actually restarts. It now runs docker compose up -d --force-recreate --remove-orphans. Plain up -d was a no-op when the config hash had not changed.
  • ./update.sh --latest sticks. It writes GETH_IMAGE / BEACON_IMAGE into .env so a later ./restart.sh or ./start.sh does not silently roll back to the digest pin.
  • Idempotent install. Re-running ./install.sh no longer treats this stack’s own listeners as foreign port conflicts. Existing jwt.hex is validated (64 hex, newline stripped or backed up). After up -d, both containers must still be running or install fails.
  • Docker install. Distro docker.io / containerd packages are removed before Docker CE, then the script waits for the daemon. PULSE_ALLOW_PORT_CONFLICTS=1 covers non-interactive port conflicts (same pattern as PULSE_ALLOW_PUBLIC_RPC=1).
  • UFW reporting. Failed ufw allow is no longer reported as success.
  • User / permissions. Uses id -un / SUDO_USER instead of $USER, and sudo ls so an unreadable datadir cannot look empty and trigger a recursive chown of multi-TB chain data.
  • Port check. Uses ss -H -ltn sport = :port instead of grepping ss columns.

Hardening (intentional default changes)

  • Beacon HTTP/gRPC default to 127.0.0.1. MetaMask does not need them. Set BEACON_HTTP_HOST=0.0.0.0 and BEACON_GRPC_HOST=0.0.0.0 in .env if you want them on the LAN.
  • Geth --ipcdisable so admin APIs are not on /blockchain/execution/geth.ipc.
  • Images pinned by digest (currently the same as :latest):
    • go-pulse:v3.3.0@sha256:d2f5959…
    • beacon-chain:v2.3.0@sha256:31b4401…
  • Container nofile ulimit 65535.
  • Tunable GETH_CACHE (default 1024).

Docs / status

  • ./status.sh prints the wallet RPC URL using the default-route source address (not hostname -I / docker0).
  • README: arm64, NTP/JWT troubleshooting, VPC vs home LAN on 10.0.0.0/8, checkpoint weak-subjectivity note, how to expose beacon APIs.

Tests / CI

  • Expanded tests/test_common.sh (dotenv, JWT, CGNAT, upsert, installer contracts).
  • Compose/README contracts updated for localhost beacon, --ipcdisable, digest pins.
  • New tests/test_image_pins.sh checks compose ↔ common.sh pins and that GitLab’s v3.3.0 / v2.3.0 tags still match those digests (:latest drift is a note, not a failure).
  • CI runs shellcheck plus the three test scripts.

How to verify

bash tests/test_common.sh
bash tests/test_beacon_flags.sh
bash tests/test_image_pins.sh
shellcheck -x common.sh install.sh start.sh stop.sh restart.sh logs.sh update.sh status.sh tests/*.sh

On a real node (not run in this environment): ./install.sh twice should refresh the stack instead of aborting on ports; ./restart.sh should bounce containers; beacon 3500/4000 should listen on localhost only.

Open in Web Open in Cursor 

Fix restart.sh so it actually recreates containers, persist ./update.sh
--latest into .env, and make install.sh idempotent (ignore our own
ports, validate existing JWTs, wait for Docker, verify containers).

Bind beacon HTTP/gRPC to localhost by default, disable geth IPC, pin
client images by digest, and tighten UFW/user/port handling plus tests.

Co-authored-by: David Feder <DavidFeder@users.noreply.github.com>
@DavidFeder
DavidFeder marked this pull request as ready for review August 28, 2026 06:07
@DavidFeder
DavidFeder merged commit d9275ca into main Aug 28, 2026
1 check passed
@DavidFeder
DavidFeder deleted the cursor/harden-rpc-node-ops-d98a branch August 28, 2026 06:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants