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
36 changes: 29 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This project packages the official PulseChain clients in Docker Compose with a s

## Quick start

**Requirements:** Linux (Ubuntu 22.04 / 24.04 or Debian recommended; amd64 or arm64), `sudo`, outbound internet, and a large SSD mounted where `/blockchain` will live.
**Requirements:** Linux (Ubuntu 22.04 / 24.04, Debian, or [Omarchy](https://omarchy.org); amd64 or arm64), `sudo`, outbound internet, and a large SSD mounted where `/blockchain` will live.

```bash
git clone https://github.com/DavidFeder/pulsechain-rpc-node.git
Expand All @@ -26,10 +26,11 @@ chmod +x install.sh

The installer will:

1. Install Docker Engine and the Compose plugin if they are missing (Ubuntu/Debian)
2. Create `/blockchain` (with `execution` / `consensus` subdirs) and generate a JWT secret if needed
3. Pull the official images and start both containers
4. Print your LAN IP and wallet connection settings
1. Install Docker Engine and the Compose plugin if they are missing (Ubuntu/Debian via Docker CE; Omarchy/Arch via `omarchy-pkg-add` or pacman)
2. Enable Docker to start on boot (needed so the node comes back after reboot; Omarchy otherwise only socket-activates Docker)
3. Create `/blockchain` (with `execution` / `consensus` subdirs) and generate a JWT secret if needed
4. Pull the official images and start both containers
5. Print your LAN IP and wallet connection settings

---

Expand Down Expand Up @@ -85,11 +86,32 @@ LAN binding is intentional so phones and other machines on the same network can

---

## Omarchy Linux

[Omarchy](https://omarchy.org) is Arch-based and already ships Docker, Compose, and UFW on typical installs. `./install.sh` detects it even when `/etc/os-release` still says `ID=arch`.

What the installer does on Omarchy:

- Installs `docker`, `docker-compose`, `docker-buildx`, and `openssl` if missing, using `omarchy-pkg-add` when that command exists (otherwise `pacman -S --needed`). It does **not** run `pacman -Syu`, which Omarchy blocks in favor of `omarchy update`.
- Enables `docker.service` on boot. Omarchy’s default is `docker.socket` only; without a running daemon, `restart: unless-stopped` containers would not return after a reboot.
- Adds UFW rules for P2P (open) and wallet RPC (private ranges). Omarchy’s first-run firewall is deny-incoming, so those P2P rules are what allow inbound peers.

```bash
git clone https://github.com/DavidFeder/pulsechain-rpc-node.git
cd pulsechain-rpc-node
chmod +x *.sh
./install.sh
```

If Docker was just added to your user group, log out and back in (or reboot) before using `./status.sh` without sudo.

---

## Installation

### Prerequisites

- Linux host (Ubuntu 22.04 / 24.04 or Debian recommended; **amd64 or arm64**)
- Linux host (Ubuntu 22.04 / 24.04, Debian, or [Omarchy](https://omarchy.org); **amd64 or arm64**). Vanilla Arch works with the same pacman path.
- `sudo` privileges
- Sufficient free space for `/blockchain`
- Outbound connectivity to pull images and sync with the network
Expand Down Expand Up @@ -334,7 +356,7 @@ Optional variables (`DATA_DIR`, ports, image pins) are documented in `.env.examp

| Issue | Suggested action |
|-------|------------------|
| Docker permission denied | Log out and back in after install (docker group membership), or prefix commands with `sudo` |
| Docker permission denied | Log out and back in after install (docker group membership), or prefix commands with `sudo`. On Omarchy this is common until the session picks up the `docker` group. |
| `address already in use` / crash loop | Another node is using ports 8545, 8546, 3500, 4000, or 8551. Stop the other process or change ports in `docker-compose.yml` |
| Beacon cannot find execution client | Confirm both containers are running and that `/blockchain/jwt.hex` exists and is shared by both |
| JWT / `401 Unauthorized` to execution | Ensure only one execution client is on port 8551 and both services use the same `/blockchain/jwt.hex`. The file must be 64 hex characters with **no newline**. Keep the host clock in sync (NTP / `timedatectl`); JWT `iat` skew also returns 401. |
Expand Down
33 changes: 33 additions & 0 deletions common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,36 @@ confirm_yes() {
*) return 1 ;;
esac
}

os_is_debian_family() {
local os_id="${1:-}"
case "${os_id}" in
ubuntu|debian|linuxmint|pop) return 0 ;;
*) return 1 ;;
esac
}

# Omarchy (https://omarchy.org) is Arch-based. Stock images still report ID=arch,
# so also look for Omarchy tools and install paths.
os_is_omarchy() {
local os_id="${1:-}"
[[ "${os_id}" == "omarchy" ]] && return 0
command -v omarchy-pkg-add >/dev/null 2>&1 && return 0
command -v omarchy >/dev/null 2>&1 && return 0
[[ -f /etc/profile.d/omarchy.sh ]] && return 0
[[ -d /usr/share/omarchy ]] && return 0
[[ -d "${HOME}/.local/share/omarchy" ]] && return 0
[[ -n "${OMARCHY_PATH:-}" && -e "${OMARCHY_PATH}" ]] && return 0
return 1
}

os_is_arch_family() {
local os_id="${1:-}"
local id_like="${2:-}"
case "${os_id}" in
arch|omarchy) return 0 ;;
esac
[[ "${id_like}" == *arch* ]] && return 0
[[ -f /etc/arch-release ]] && return 0
return 1
}
108 changes: 76 additions & 32 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,41 @@ else
fi

# ---------------------------------------------------------------------------
# 2. Detect OS (Ubuntu/Debian focused)
# 2. Detect OS (Ubuntu/Debian, Omarchy, Arch)
# ---------------------------------------------------------------------------
if [[ -f /etc/os-release ]]; then
# shellcheck source=/dev/null
. /etc/os-release
OS_ID="${ID:-unknown}"
OS_ID_LIKE="${ID_LIKE:-}"
else
OS_ID="unknown"
OS_ID_LIKE=""
fi

case "${OS_ID}" in
ubuntu|debian|linuxmint|pop)
ok "Detected Debian-family OS: ${OS_ID}"
;;
*)
warn "OS '${OS_ID}' is not Ubuntu/Debian. Docker install may need to be done manually."
warn "If Docker + Compose are already installed, the rest of this script should still work."
;;
esac
if os_is_omarchy "${OS_ID}"; then
ok "Detected Omarchy Linux (Arch-based)"
elif os_is_debian_family "${OS_ID}"; then
ok "Detected Debian-family OS: ${OS_ID}"
elif os_is_arch_family "${OS_ID}" "${OS_ID_LIKE}"; then
ok "Detected Arch-based OS: ${OS_ID}"
else
warn "OS '${OS_ID}' is not Ubuntu/Debian or Omarchy/Arch. Docker install may need to be done manually."
warn "If Docker + Compose are already installed, the rest of this script should still work."
fi

install_arch_packages() {
if command -v omarchy-pkg-add >/dev/null 2>&1; then
# Official Omarchy helper; avoids -Syu so the ALPM update-guard is not tripped.
omarchy-pkg-add "$@" || die "omarchy-pkg-add failed for: $*"
return 0
fi
if ! command -v pacman >/dev/null 2>&1; then
die "pacman not found. Install Docker and openssl manually, then re-run."
fi
# Install only (no -Syu). Omarchy blocks unattended system upgrades via ALPM guard.
$SUDO pacman -S --noconfirm --needed "$@" || die "pacman failed to install: $*"
}

# ---------------------------------------------------------------------------
# 3. Install Docker + Compose plugin if missing
Expand All @@ -91,8 +107,7 @@ fi

if [[ "${need_docker_install}" == true ]]; then
info "Installing Docker Engine + Compose plugin..."
case "${OS_ID}" in
ubuntu|debian|linuxmint|pop)
if os_is_debian_family "${OS_ID}"; then
$SUDO apt-get update -y
# Distro docker.io / containerd packages conflict with Docker CE.
$SUDO apt-get remove -y docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc || true
Expand Down Expand Up @@ -125,27 +140,47 @@ if [[ "${need_docker_install}" == true ]]; then
else
die "Docker was installed but the daemon is not responding. Try: sudo systemctl status docker"
fi
;;
*)
die "Automatic Docker install is only supported on Ubuntu/Debian. Install Docker manually: https://docs.docker.com/engine/install/ then re-run this script."
;;
esac
elif os_is_omarchy "${OS_ID}" || os_is_arch_family "${OS_ID}" "${OS_ID_LIKE}"; then
# Arch packages: docker-compose is the v2 CLI plugin (`docker compose`).
# Do not use pacman -Syu — Omarchy's ALPM guard aborts unattended sysupgrades.
install_arch_packages docker docker-compose docker-buildx openssl
# Omarchy enables docker.socket (on-demand). A node needs dockerd at boot
# so unless-stopped containers come back after reboot.
$SUDO systemctl enable docker.socket 2>/dev/null || true
$SUDO systemctl enable --now docker
info "Waiting for the Docker daemon..."
if wait_for_docker; then
ok "Docker installed (Omarchy/Arch packages)."
else
die "Docker was installed but the daemon is not responding. Try: sudo systemctl status docker"
fi
else
die "Automatic Docker install is only supported on Ubuntu/Debian and Omarchy/Arch. Install Docker manually: https://docs.docker.com/engine/install/ then re-run this script."
fi
else
ok "Docker and Compose plugin already available."
fi

# Full nodes must start Docker on boot (Omarchy defaults to socket-activation only).
if command -v systemctl >/dev/null 2>&1; then
$SUDO systemctl enable docker.socket 2>/dev/null || true
$SUDO systemctl enable docker 2>/dev/null || true
if ! $SUDO systemctl is-active --quiet docker 2>/dev/null; then
$SUDO systemctl start docker 2>/dev/null || true
fi
fi

# Ensure openssl for JWT generation
if ! command -v openssl >/dev/null 2>&1; then
info "Installing openssl..."
case "${OS_ID}" in
ubuntu|debian|linuxmint|pop)
if os_is_debian_family "${OS_ID}"; then
$SUDO apt-get update -y
$SUDO apt-get install -y openssl || die "Please install openssl and re-run."
;;
*)
elif os_is_omarchy "${OS_ID}" || os_is_arch_family "${OS_ID}" "${OS_ID_LIKE}"; then
install_arch_packages openssl
else
die "openssl is required. Please install it and re-run."
;;
esac
fi
fi

# Allow the invoking user to run docker without sudo (best-effort; needs re-login)
Expand Down Expand Up @@ -375,15 +410,24 @@ if command -v ufw >/dev/null 2>&1; then
warn "If UFW is not enabled yet, the rules are stored and apply after: sudo ufw enable"
fi
echo ""
warn "IMPORTANT about UFW:"
warn " The rules have been added, but UFW may still be inactive."
warn " To enable the firewall safely (after confirming SSH still works):"
warn " sudo ufw allow OpenSSH"
warn " sudo ufw enable"
warn " Then check: sudo ufw status numbered"
warn " If your home network uses a different subnet, edit the rules accordingly."
warn " IPv4 rules do not cover IPv6 — if the host has global IPv6, add matching rules or disable it."
warn " 10.0.0.0/8 on a cloud VPC is the VPC, not a home LAN — tighten that range on VPS hosts."
if ufw_is_active; then
ok "UFW is already active — new PulseChain rules apply immediately."
if os_is_omarchy "${OS_ID}"; then
info "Omarchy defaults to deny-incoming; inbound P2P (30303/13000/12000) is now allowed."
fi
warn "If your LAN uses a different subnet than 10/8, 172.16/12, or 192.168/16, edit the RPC rules."
warn "IPv4 rules do not cover IPv6 — if the host has global IPv6, add matching rules or disable it."
else
warn "IMPORTANT about UFW:"
warn " The rules have been added, but UFW may still be inactive."
warn " To enable the firewall safely (after confirming SSH still works):"
warn " sudo ufw allow OpenSSH"
warn " sudo ufw enable"
warn " Then check: sudo ufw status numbered"
warn " If your home network uses a different subnet, edit the rules accordingly."
warn " IPv4 rules do not cover IPv6 — if the host has global IPv6, add matching rules or disable it."
warn " 10.0.0.0/8 on a cloud VPC is the VPC, not a home LAN — tighten that range on VPS hosts."
fi
else
info "UFW not found — assuming no software firewall (or it is managed elsewhere). Skipping firewall rules."
fi
Expand Down
48 changes: 48 additions & 0 deletions tests/test_common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,54 @@ if grep -q 'effective_install_user' "${ROOT}/install.sh"; then
else
fail "install.sh should not rely on possibly-empty USER"
fi
if grep -q 'omarchy-pkg-add' "${ROOT}/install.sh" && grep -q 'os_is_omarchy' "${ROOT}/install.sh"; then
pass "install.sh has an Omarchy/Arch package path"
else
fail "install.sh should install Docker via omarchy-pkg-add or pacman"
fi
if grep -q 'systemctl enable docker' "${ROOT}/install.sh"; then
pass "install.sh enables docker.service on boot"
else
fail "install.sh should enable docker.service so Omarchy nodes survive reboot"
fi
if grep -E '^[[:space:]]*[^#[:space:]].*pacman[[:space:]].*-Syu' "${ROOT}/install.sh"; then
fail "install.sh must not run pacman -Syu (Omarchy ALPM guard)"
else
pass "install.sh does not run pacman -Syu"
fi

# Distro detection helpers
if os_is_debian_family ubuntu && os_is_debian_family debian && os_is_debian_family linuxmint && os_is_debian_family pop; then
pass "os_is_debian_family accepts Ubuntu/Debian/Mint/Pop"
else
fail "os_is_debian_family rejected a Debian-family id"
fi
if os_is_debian_family arch || os_is_debian_family omarchy; then
fail "os_is_debian_family accepted an Arch id"
else
pass "os_is_debian_family rejects arch/omarchy"
fi
if os_is_omarchy omarchy; then
pass "os_is_omarchy accepts ID=omarchy"
else
fail "os_is_omarchy rejected ID=omarchy"
fi
if os_is_arch_family arch "" && os_is_arch_family omarchy "" && os_is_arch_family cachyos "arch"; then
pass "os_is_arch_family accepts arch, omarchy, and ID_LIKE=arch"
else
fail "os_is_arch_family rejected an Arch-family id"
fi
if os_is_arch_family ubuntu ""; then
fail "os_is_arch_family accepted ubuntu"
else
pass "os_is_arch_family rejects ubuntu"
fi

if grep -q 'Omarchy' "${ROOT}/README.md"; then
pass "README documents Omarchy Linux"
else
fail "README should document Omarchy support"
fi

# status.sh prints wallet URL via detect_lan_ip
if grep -q 'detect_lan_ip' "${ROOT}/status.sh"; then
Expand Down
Loading