342 lines
11 KiB
Bash
342 lines
11 KiB
Bash
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
echo -e "\n* * * Ensuring ~/nym-binaries exists * * *"
|
|
mkdir -p "$HOME/nym-binaries"
|
|
|
|
# load env.sh via absolute path if provided, else try ./env.sh
|
|
if [[ -n "${ENV_FILE:-}" && -f "${ENV_FILE}" ]]; then
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
. "${ENV_FILE}"
|
|
set +a
|
|
elif [[ -f "./env.sh" ]]; then
|
|
set -a
|
|
# shellcheck disable=SC1091
|
|
. ./env.sh
|
|
set +a
|
|
fi
|
|
|
|
# check for existing node config and optionally reset
|
|
NODE_CONFIG_DIR="$HOME/.nym/nym-nodes/default-nym-node"
|
|
|
|
check_existing_config() {
|
|
# proceed only if dir exists AND has any entries inside
|
|
if [[ -d "$NODE_CONFIG_DIR" ]] && find "$NODE_CONFIG_DIR" -mindepth 1 -maxdepth 1 | read -r _; then
|
|
echo
|
|
echo "Nym node configuration already exist at $NODE_CONFIG_DIR"
|
|
echo
|
|
echo "Initialising nym-node again will NOT overwrite your existing private keys, only adjust your preferences (like mode, wireguard optionality etc)."
|
|
echo
|
|
echo "If you want to remove your current node configuration and all data files including nodes keys type 'RESET' and press enter."
|
|
echo
|
|
read -r -p "To keep your existing node and just change its preferences press enter: " resp
|
|
|
|
if [[ "${resp}" =~ ^([Rr][Ee][Ss][Ee][Tt])$ ]]; then
|
|
echo
|
|
echo "We are going to remove the existing node with configuration $NODE_CONFIG_DIR and replace it with a fresh one."
|
|
read -r -p "back up the old one first? (Y/n) " backup_ans
|
|
if [[ -z "${backup_ans}" || "${backup_ans}" =~ ^[Yy]$ ]]; then
|
|
ts="$(date +%Y%m%d-%H%M%S)"
|
|
backup_dir="$HOME/.nym/backup/$(basename "$NODE_CONFIG_DIR")-$ts"
|
|
echo "Backing up to: $backup_dir"
|
|
mkdir -p "$(dirname "$backup_dir")"
|
|
cp -a "$NODE_CONFIG_DIR" "$backup_dir"
|
|
fi
|
|
echo "Removing $NODE_CONFIG_DIR ..."
|
|
rm -rf "$NODE_CONFIG_DIR"
|
|
echo "Old node removed. Proceeding with fresh initialization..."
|
|
else
|
|
echo "Keeping existing node configuration. Proceeding to re-configure."
|
|
export ASK_WG="1"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# run the check before any initialization
|
|
check_existing_config
|
|
|
|
# downloader for nym-node: probes platform-specific assets; if none exist,
|
|
# asks user for a direct downloadable URL and validates it.
|
|
download_nym_node() {
|
|
local latest_tag_url="$1" # e.g. "https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.13-emmental"
|
|
local dest_path="$2" # e.g. "$HOME/nym-binaries/nym-node"
|
|
local base_download_url
|
|
local os arch exe_ext=""
|
|
local candidates=()
|
|
local found_url=""
|
|
local http_code=""
|
|
|
|
if [[ -z "$latest_tag_url" || "$latest_tag_url" != *"/releases/tag/"* ]]; then
|
|
echo "ERROR: Invalid latest tag URL: $latest_tag_url" >&2
|
|
return 1
|
|
fi
|
|
|
|
base_download_url="${latest_tag_url/tag/download}"
|
|
|
|
# detect OS / ARCH
|
|
case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
|
|
linux*) os="linux" ;;
|
|
darwin*) os="darwin" ;;
|
|
msys*|cygwin*|mingw*) os="windows"; exe_ext=".exe" ;;
|
|
*) echo "WARNING: Unknown OS; defaulting to linux." ; os="linux" ;;
|
|
esac
|
|
|
|
case "$(uname -m)" in
|
|
x86_64|amd64) arch="x86_64" ;;
|
|
aarch64|arm64) arch="aarch64" ;;
|
|
armv7*|armv6*|armv5*) arch="arm" ;;
|
|
*) arch="$(uname -m)";;
|
|
esac
|
|
|
|
# candidate asset names to probe (no assumptions about compression)
|
|
if [[ "$os" == "linux" ]]; then
|
|
candidates+=(
|
|
"nym-node"
|
|
"nym-node-${arch}-unknown-linux-gnu"
|
|
"nym-node-${arch}-unknown-linux-musl"
|
|
)
|
|
elif [[ "$os" == "darwin" ]]; then
|
|
candidates+=(
|
|
"nym-node-${arch}-apple-darwin"
|
|
"nym-node"
|
|
)
|
|
elif [[ "$os" == "windows" ]]; then
|
|
candidates+=(
|
|
"nym-node-${arch}-pc-windows-msvc${exe_ext}"
|
|
"nym-node${exe_ext}"
|
|
)
|
|
fi
|
|
|
|
# return 0 if URL exists (HTTP 200)
|
|
url_exists() {
|
|
local url="$1"
|
|
http_code="$(curl -sI -L -o /dev/null -w '%{http_code}' "$url")"
|
|
[[ "$http_code" == "200" ]]
|
|
}
|
|
|
|
echo -e "\n* * * Probing release assets for your platform ($os/$arch) * * *"
|
|
|
|
# try candidate assets in order
|
|
for name in "${candidates[@]}"; do
|
|
local try_url="${base_download_url}/${name}"
|
|
if url_exists "$try_url"; then
|
|
found_url="$try_url"
|
|
break
|
|
fi
|
|
done
|
|
|
|
# if nothing found, prompt the user for a URL
|
|
if [[ -z "$found_url" ]]; then
|
|
echo
|
|
echo "Could not find a 'nym-node' asset for your platform in the latest release:"
|
|
echo " $latest_tag_url"
|
|
echo
|
|
echo "HTTP check for first candidate (${base_download_url}/${candidates[0]}): ${http_code:-n/a}"
|
|
echo
|
|
echo "Please paste a direct, downloadable URL for the 'nym-node' binary for your platform."
|
|
echo "Tip: Open the GitHub release page, right-click the correct asset, and copy link address."
|
|
read -r -p "Custom download URL: " user_url
|
|
|
|
if [[ -z "${user_url// }" ]]; then
|
|
echo "ERROR: No URL provided. Aborting."
|
|
return 1
|
|
fi
|
|
if ! url_exists "$user_url"; then
|
|
echo "ERROR: The provided URL does not appear downloadable (HTTP $http_code). Aborting."
|
|
return 1
|
|
fi
|
|
found_url="$user_url"
|
|
fi
|
|
|
|
echo -e "\n* * * Downloading nym-node from: $found_url * * *"
|
|
mkdir -p "$(dirname "$dest_path")"
|
|
|
|
# remove any existing file to avoid 'text file busy'
|
|
if [[ -e "$dest_path" ]]; then
|
|
echo "Removing existing binary at $dest_path ..."
|
|
rm -f "$dest_path"
|
|
fi
|
|
|
|
if ! curl -fL "$found_url" -o "$dest_path"; then
|
|
echo "ERROR: Download failed from $found_url" >&2
|
|
return 1
|
|
fi
|
|
|
|
chmod +x "$dest_path" 2>/dev/null || true
|
|
|
|
echo "---------------------------------------------------"
|
|
echo "Nym node binary downloaded to: $dest_path"
|
|
"$dest_path" --version || true
|
|
echo "---------------------------------------------------"
|
|
}
|
|
|
|
echo -e "\n* * * Resolving latest release tag URL * * *"
|
|
LATEST_TAG_URL="$(curl -sI -L -o /dev/null -w '%{url_effective}' https://github.com/nymtech/nym/releases/latest)"
|
|
# expected example: https://github.com/nymtech/nym/releases/tag/nym-binaries-v2025.13-emmental
|
|
|
|
if [[ -z "${LATEST_TAG_URL}" || "${LATEST_TAG_URL}" != *"/releases/tag/"* ]]; then
|
|
echo "ERROR: Could not resolve latest tag URL from GitHub." >&2
|
|
exit 1
|
|
fi
|
|
|
|
NYM_NODE="$HOME/nym-binaries/nym-node"
|
|
|
|
# if binary already exists, ask to overwrite; if yes, remove first; if no, skip download
|
|
if [[ -e "${NYM_NODE}" ]]; then
|
|
echo
|
|
echo -e "\n* * * A nym-node binary already exists at: ${NYM_NODE}"
|
|
read -r -p "Overwrite with the latest release? (Y/n): " ow_ans
|
|
|
|
if [[ -z "${ow_ans}" || "${ow_ans}" =~ ^[Yy]$ ]]; then
|
|
echo "Removing existing binary..."
|
|
rm -f "${NYM_NODE}"
|
|
download_nym_node "$LATEST_TAG_URL" "$NYM_NODE"
|
|
else
|
|
echo "Keeping existing binary. Skipping download."
|
|
fi
|
|
|
|
else
|
|
# binary does not exist → must download
|
|
download_nym_node "$LATEST_TAG_URL" "$NYM_NODE"
|
|
fi
|
|
|
|
echo -e "\n * * * Making binary executable * * *"
|
|
chmod +x "${NYM_NODE}"
|
|
echo "---------------------------------------------------"
|
|
echo "Nym node binary downloaded:"
|
|
"${NYM_NODE}" --version || true
|
|
echo "---------------------------------------------------"
|
|
|
|
# check that MODE is set (after sourcing env.sh or other scripts)
|
|
if [[ -z "${MODE:-}" ]]; then
|
|
echo "ERROR: Environment variable MODE is not set."
|
|
echo "Please export MODE as one of: mixnode, entry-gateway, exit-gateway"
|
|
exit 1
|
|
fi
|
|
|
|
# determine public IP (fallback if ifconfig.me fails)
|
|
echo -e "\n* * * Discovering public IP (IPv4) * * *"
|
|
if ! PUBLIC_IP="$(curl -fsS -4 https://ifconfig.me)"; then
|
|
PUBLIC_IP="$(curl -fsS https://api.ipify.org || echo '')"
|
|
fi
|
|
if [[ -z "${PUBLIC_IP}" ]]; then
|
|
echo "WARNING: Could not determine public IP automatically."
|
|
fi
|
|
|
|
# respect existing WIREGUARD; for gateways: prompt if unset OR if we kept config and ASK_WG=1
|
|
WIREGUARD="${WIREGUARD:-}"
|
|
if [[ ( "$MODE" == "entry-gateway" || "$MODE" == "exit-gateway" ) && ( -n "${ASK_WG:-}" || -z "$WIREGUARD" ) ]]; then
|
|
echo
|
|
echo "Gateways can also route WireGuard in NymVPN."
|
|
def_hint=""
|
|
[[ -n "${WIREGUARD}" ]] && def_hint=" [current: ${WIREGUARD}]"
|
|
|
|
read -r -p "Enable WireGuard support? (Y/n)${def_hint}: " answer || true
|
|
|
|
if [[ -z "${answer}" || "${answer}" =~ ^[Yy]$ ]]; then
|
|
WIREGUARD="true"
|
|
elif [[ "${answer}" =~ ^[Nn]$ ]]; then
|
|
WIREGUARD="false"
|
|
fi
|
|
fi
|
|
|
|
# final default only if still empty
|
|
WIREGUARD="${WIREGUARD:-false}"
|
|
|
|
# persist WIREGUARD to the same env file Python CLI uses
|
|
ENV_PATH="${ENV_FILE:-./env.sh}"
|
|
if [[ -n "$ENV_PATH" ]]; then
|
|
mkdir -p "$(dirname "$ENV_PATH")"
|
|
if [[ -f "$ENV_PATH" ]]; then
|
|
# replace existing export or append
|
|
if grep -qE '^[[:space:]]*export[[:space:]]+WIREGUARD=' "$ENV_PATH"; then
|
|
sed -i -E 's|^[[:space:]]*export[[:space:]]+WIREGUARD=.*$|export WIREGUARD="'"$WIREGUARD"'"|' "$ENV_PATH"
|
|
else
|
|
printf '\nexport WIREGUARD="%s"\n' "$WIREGUARD" >> "$ENV_PATH"
|
|
fi
|
|
else
|
|
printf 'export WIREGUARD="%s"\n' "$WIREGUARD" > "$ENV_PATH"
|
|
fi
|
|
echo "WIREGUARD=${WIREGUARD} persisted to $ENV_PATH"
|
|
fi
|
|
|
|
# helpers: ensure optional env vars exist (avoid -u issues)
|
|
HOSTNAME="${HOSTNAME:-}"
|
|
LOCATION="${LOCATION:-}"
|
|
EMAIL="${EMAIL:-}"
|
|
MONIKER="${MONIKER:-}"
|
|
DESCRIPTION="${DESCRIPTION:-}"
|
|
|
|
# initialize node config
|
|
case "${MODE}" in
|
|
mixnode)
|
|
echo -e "\n* * * Initialising nym-node in mode: mixnode * * *"
|
|
"${NYM_NODE}" run \
|
|
--mode mixnode \
|
|
${PUBLIC_IP:+--public-ips "$PUBLIC_IP"} \
|
|
${HOSTNAME:+--hostname "$HOSTNAME"} \
|
|
${LOCATION:+--location "$LOCATION"} \
|
|
-w \
|
|
--init-only
|
|
;;
|
|
entry-gateway)
|
|
echo -e "\n* * * Initialising nym-node in mode: entry-gateway * * *"
|
|
"${NYM_NODE}" run \
|
|
--mode entry-gateway \
|
|
${PUBLIC_IP:+--public-ips "$PUBLIC_IP"} \
|
|
${HOSTNAME:+--hostname "$HOSTNAME"} \
|
|
${LOCATION:+--location "$LOCATION"} \
|
|
--wireguard-enabled "${WIREGUARD}" \
|
|
${HOSTNAME:+--landing-page-assets-path "/var/www/${HOSTNAME}"} \
|
|
-w \
|
|
--init-only
|
|
;;
|
|
exit-gateway)
|
|
echo -e "\n* * * Initialising nym-node in mode: exit-gateway * * *"
|
|
if [[ -z "${HOSTNAME:-}" || -z "${LOCATION:-}" ]]; then
|
|
echo "ERROR: HOSTNAME and LOCATION must be exported for exit-gateway."
|
|
exit 1
|
|
fi
|
|
"${NYM_NODE}" run \
|
|
--mode exit-gateway \
|
|
${PUBLIC_IP:+--public-ips "$PUBLIC_IP"} \
|
|
--hostname "$HOSTNAME" \
|
|
--location "$LOCATION" \
|
|
--wireguard-enabled "${WIREGUARD:-false}" \
|
|
--announce-wss-port 9001 \
|
|
--landing-page-assets-path "/var/www/${HOSTNAME}" \
|
|
-w \
|
|
--init-only
|
|
;;
|
|
*)
|
|
echo "ERROR: Unsupported MODE: '${MODE}'"
|
|
echo "Valid values: mixnode, entry-gateway, exit-gateway"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
echo
|
|
echo "* * * nym-node initialised. Config path should be:"
|
|
echo " $HOME/.nym/nym-nodes/default-nym-node/"
|
|
|
|
# setup description.toml (if init created the dir)
|
|
DESC_DIR="$HOME/.nym/nym-nodes/default-nym-node/data"
|
|
DESC_FILE="$DESC_DIR/description.toml"
|
|
|
|
if [[ -d "$DESC_DIR" ]]; then
|
|
echo -e "\n* * * Writing node description: $DESC_FILE * * *"
|
|
mkdir -p "$DESC_DIR"
|
|
cat > "$DESC_FILE" <<EOF
|
|
moniker = "${MONIKER}"
|
|
website = "${HOSTNAME}"
|
|
security_contact = "${EMAIL}"
|
|
details = "${DESCRIPTION}"
|
|
EOF
|
|
echo "* * * Node description saved * * *"
|
|
echo "You can edit it later at: $DESC_FILE (restart node to apply)."
|
|
else
|
|
echo "NOTE: Description directory not found yet ($DESC_DIR)."
|
|
echo " It will exist after a full init; you can create the file later."
|
|
fi
|