diff --git a/configs/nym/Containerfile b/configs/nym/Containerfile index 3f4f504..4956efd 100644 --- a/configs/nym/Containerfile +++ b/configs/nym/Containerfile @@ -1,26 +1,34 @@ # koopa-nym — nym-node (nym.com mixnet / NymVPN network) # Fetch binary on host first (see scripts/nym/build.sh), then: # podman build -t localhost/koopa-nym:latest -f Containerfile . +# +# Process runs as uid/gid 1000 (not root). With rootless podman use +# userns=keep-id so host ./data owned by hernani stays writable (see compose.yml). FROM docker.io/library/debian:bookworm-slim ENV DEBIAN_FRONTEND=noninteractive \ NYM_HOME=/var/lib/nym \ - PATH=/usr/local/bin:$PATH + PATH=/usr/local/bin:$PATH \ + HOME=/var/lib/nym RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates libssl3 \ && rm -rf /var/lib/apt/lists/* \ - && mkdir -p /var/lib/nym /usr/local/bin + && groupadd --gid 1000 nym \ + && useradd --uid 1000 --gid 1000 --home-dir /var/lib/nym --shell /usr/sbin/nologin nym \ + && mkdir -p /var/lib/nym /usr/local/bin \ + && chown -R nym:nym /var/lib/nym # Pre-downloaded on host into build context as ./nym-node COPY nym-node /usr/local/bin/nym-node -RUN chmod +x /usr/local/bin/nym-node \ +RUN chmod 755 /usr/local/bin/nym-node \ && /usr/local/bin/nym-node --version || true COPY entrypoint.sh /usr/local/bin/nym-entrypoint -RUN chmod +x /usr/local/bin/nym-entrypoint +RUN chmod 755 /usr/local/bin/nym-entrypoint EXPOSE 1789/udp 1789/tcp 1790 8080 9000 51822/udp WORKDIR /var/lib/nym +USER nym:nym ENTRYPOINT ["/usr/local/bin/nym-entrypoint"] diff --git a/configs/nym/README.md b/configs/nym/README.md index 3b3c01d..7f1f486 100644 --- a/configs/nym/README.md +++ b/configs/nym/README.md @@ -9,6 +9,7 @@ Mirror in this repo: `configs/nym/`. |---------|--------| | Container | `koopa-nym` | | Image | `localhost/koopa-nym:latest` | +| Process user | **non-root** `nym` **uid/gid 1000** (`USER` + compose `userns_mode: keep-id`) | | Default mode | **`mixnode`** (safest on a home host; no open-internet exit) | | Optional modes | `entry-gateway`, `exit-gateway` (+ WireGuard for dVPN) — see env | | Local ID | `koopa-nym` | @@ -45,12 +46,28 @@ before enabling. ```bash cd ~/koopa-nym # or this mirror cp .env.example .env # edit PUBLIC_IPS, LOCATION, MODE +# host data must be writable by uid 1000 (hernani) +mkdir -p data && chown -R "$(id -u):$(id -g)" data +# sync compose + entrypoint from admin-log if this tree is a copy podman build -t localhost/koopa-nym:latest -f Containerfile . -podman compose up -d # or podman run … +# IMPORTANT: port maps only apply on create — not on plain podman start +podman compose down +podman compose up -d --force-recreate --build +podman exec koopa-nym id # expect uid=1000(nym) +podman port koopa-nym # must list 1789/tcp+udp and 1790/tcp +ss -lntp | grep -E '1789|1790|9080' # bonding: use Nym wallet / harbourmaster; node must accept operator T&Cs curl -sS http://127.0.0.1:9080/api/v1/roles | jq . ``` +### If WAN `1790` is “connection refused” but `1789` works + +Almost always **container publish/bind**, not VeciGate: + +1. Old container created without a solid `1790/tcp` map → **recreate** (above). +2. Process bound only on `[::]:1790` while host proxy expects IPv4 → defaults are now **`0.0.0.0:1790`**. +3. Confirm: `podman port koopa-nym` shows `1790/tcp -> 0.0.0.0:1790`, then `nc -vz WAN 1790`. + Secrets layout (values in **koopa-admin-secrets**): | Live | Secrets mirror | diff --git a/configs/nym/compose.yml b/configs/nym/compose.yml index f639fce..ccb6c91 100644 --- a/configs/nym/compose.yml +++ b/configs/nym/compose.yml @@ -10,6 +10,9 @@ services: image: localhost/koopa-nym:latest container_name: koopa-nym restart: unless-stopped + # Non-root (image USER nym = 1000). keep-id → host ./data owned by hernani works. + user: "1000:1000" + userns_mode: keep-id env_file: - .env environment: @@ -21,22 +24,25 @@ services: NYMNODE_HOSTNAME: ${NYMNODE_HOSTNAME:-} NYMNODE_WG_ENABLED: ${NYMNODE_WG_ENABLED:-false} NYMNODE_ACCEPT_OPERATOR_TERMS: ${NYMNODE_ACCEPT_OPERATOR_TERMS:-true} - NYMNODE_HTTP_BIND_ADDRESS: "[::]:8080" - NYMNODE_MIXNET_BIND_ADDRESS: "[::]:1789" - NYMNODE_VERLOC_BIND_ADDRESS: "[::]:1790" - NYMNODE_ENTRY_BIND_ADDRESS: "[::]:9000" + # IPv4 binds: rootless podman port-proxy is reliable with 0.0.0.0 + # ([::] can leave verloc without a host IPv4 listener → WAN "connection refused") + NYMNODE_HTTP_BIND_ADDRESS: ${NYMNODE_HTTP_BIND_ADDRESS:-0.0.0.0:8080} + NYMNODE_MIXNET_BIND_ADDRESS: ${NYMNODE_MIXNET_BIND_ADDRESS:-0.0.0.0:1789} + NYMNODE_VERLOC_BIND_ADDRESS: ${NYMNODE_VERLOC_BIND_ADDRESS:-0.0.0.0:1790} + NYMNODE_ENTRY_BIND_ADDRESS: ${NYMNODE_ENTRY_BIND_ADDRESS:-0.0.0.0:9000} NYMNODE_EXTRA_ARGS: ${NYMNODE_EXTRA_ARGS:-} volumes: # identity + config.toml (bond keys live here — back up) - ./data:/var/lib/nym ports: - - "9080:8080" # HTTP API / swagger - - "1789:1789/tcp" # mixnet - - "1789:1789/udp" - - "1790:1790" # verloc + # Host publish must be recreated if ports change (podman start ≠ re-map). + - "0.0.0.0:9080:8080/tcp" # HTTP API / swagger (local/LAN) + - "0.0.0.0:1789:1789/tcp" # mixnet + - "0.0.0.0:1789:1789/udp" + - "0.0.0.0:1790:1790/tcp" # verloc (was missing/unreliable with bare "1790:1790") # gateway / WG — uncomment when mode needs them: - # - "19000:9000" # entry client websocket - # - "51822:51822/udp" # WireGuard + # - "0.0.0.0:19000:9000/tcp" # entry client websocket + # - "0.0.0.0:51822:51822/udp" # WireGuard labels: org.hacktivism.service: nym org.hacktivism.container: koopa-nym diff --git a/configs/nym/entrypoint.sh b/configs/nym/entrypoint.sh index 374e90c..a2fdee0 100755 --- a/configs/nym/entrypoint.sh +++ b/configs/nym/entrypoint.sh @@ -9,10 +9,11 @@ PUBLIC_IPS="${NYMNODE_PUBLIC_IPS:-}" LOCATION="${NYMNODE_LOCATION:-}" HOSTNAME_OPT="${NYMNODE_HOSTNAME:-}" WG="${NYMNODE_WG_ENABLED:-false}" -HTTP_BIND="${NYMNODE_HTTP_BIND_ADDRESS:-[::]:8080}" -MIX_BIND="${NYMNODE_MIXNET_BIND_ADDRESS:-[::]:1789}" -VERLOC_BIND="${NYMNODE_VERLOC_BIND_ADDRESS:-[::]:1790}" -ENTRY_BIND="${NYMNODE_ENTRY_BIND_ADDRESS:-[::]:9000}" +# Prefer 0.0.0.0 for rootless podman host port publishing (IPv4 WAN / DNAT). +HTTP_BIND="${NYMNODE_HTTP_BIND_ADDRESS:-0.0.0.0:8080}" +MIX_BIND="${NYMNODE_MIXNET_BIND_ADDRESS:-0.0.0.0:1789}" +VERLOC_BIND="${NYMNODE_VERLOC_BIND_ADDRESS:-0.0.0.0:1790}" +ENTRY_BIND="${NYMNODE_ENTRY_BIND_ADDRESS:-0.0.0.0:9000}" ACCEPT_TC="${NYMNODE_ACCEPT_OPERATOR_TERMS:-true}" ARGS=(run --id "$ID" --mode "$MODE")