#!/bin/sh # HulyNet for testers, from https://8dgx2h0f.nothing.md/ (published there as install.sh by # scripts/testers/server-setup.sh: the stable channel at the server's root, the unstable # one under /unstable): downloads the release for this computer, checks # it, installs it with this server's configuration, which the archive carries, and, given # the wave's invite code, registers the computer and attaches it to our routers (ADR # 0034, stage 5): a new computer, one still in a network of its own from before (it # moves), and one attached already (a fresh ticket) alike. Every computer attaches: a # network of one's own per tester ended on 2026-11-10, and the registrar answers 410 to # an older line's registration, which asked for one. # # curl -fsSL https://8dgx2h0f.nothing.md/install.sh | sudo sh -s -- [--name ] # curl -fsSL https://8dgx2h0f.nothing.md/install.sh | sudo sh -s -- --uninstall [--purge] # curl -fsSL https://8dgx2h0f.nothing.md/install.sh | sh -s -- --uninstall [--purge] # # a Mac's proxy-mode installation from before, # # without sudo: it can only be removed # # Without a code it only installs. Running it again is safe: an installed computer is # upgraded, and a registered one keeps its name. A computer that is in its network or # attached already keeps its configuration (`attach` changes it, or nothing does), and # whatever goes wrong after the programs are replaced (the registrar's answer is not 200, # `attach` fails) leaves it as it was, saying so. # # Everything is in a function that runs on the last line: `curl | sh` reads the script # as it goes, and a cut-off download must not run half of it. set -eu main() { invite="" name="" pass="" while [ $# -gt 0 ]; do case $1 in --name) [ $# -ge 2 ] || die "--name needs a name" name=$2 shift 2 ;; --uninstall | --purge) pass="$pass $1" && shift ;; -*) die "unknown option $1" ;; *) [ -z "$invite" ] || die "one invite code, please (two were given: $invite, $1)" invite=$1 shift ;; esac done case $pass in *--purge*) case $pass in *--uninstall*) ;; *) die "--purge goes with --uninstall" ;; esac ;; esac base=https://8dgx2h0f.nothing.md/downloads case $(uname -s) in Linux) case $(uname -m) in x86_64 | amd64) file=hulyscale-linux-x86_64.tar.gz ;; aarch64 | arm64) file=hulyscale-linux-aarch64.tar.gz ;; *) die "HulyNet runs on 64-bit PCs (x86_64 or ARM64), not on $(uname -m)" ;; esac [ "$(id -u)" = 0 ] || die "it needs administrator rights: curl -fsSL https://8dgx2h0f.nothing.md/install.sh | sudo sh -s -- $invite" mode="" cli=/usr/bin/hulyscale config=/etc/hulyscale/hulyscale.toml ;; Darwin) file=hulyscale-macos.tar.gz # With sudo, for the whole Mac. Without it there was proxy mode for this user # (ADR 0020), which cannot attach and ended for the testers on 2026-11-10: the line # without sudo only removes such an installation now. if [ "$(id -u)" = 0 ]; then mode=--system cli=/usr/local/bin/hulyscale config="/Library/Application Support/hulyscale/hulyscale.toml" elif [ -n "$pass" ]; then mode="" cli=$HOME/.local/bin/hulyscale config="" else die "it needs administrator rights: curl -fsSL https://8dgx2h0f.nothing.md/install.sh | sudo sh -s -- $invite If this Mac has HulyNet from before without them (as a proxy), remove that one first, and turn the SOCKS proxy off in System Settings: curl -fsSL https://8dgx2h0f.nothing.md/install.sh | sh -s -- --uninstall --purge" fi ;; *) die "HulyNet runs on Linux and macOS" ;; esac command -v curl >/dev/null 2>&1 || die "curl is missing" tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT echo "Downloading HulyNet ($file)..." curl -fL --progress-bar -o "$tmp/$file" "$base/$file" || die "the download failed: check the connection and try again" curl -fsSL -o "$tmp/SHA256SUMS" "$base/SHA256SUMS" || die "the download failed: check the connection and try again" expected=$(sed -n "s/^\([0-9a-f]*\) $file\$/\1/p" "$tmp/SHA256SUMS") if command -v sha256sum >/dev/null 2>&1; then actual=$(sha256sum "$tmp/$file" | cut -d' ' -f1) else actual=$(shasum -a 256 "$tmp/$file" | cut -d' ' -f1) fi [ -n "$expected" ] && [ "$expected" = "$actual" ] || die "the download is damaged: try again" tar -C "$tmp" -xzf "$tmp/$file" if [ -n "$invite" ] && [ -z "$pass" ]; then # The installer need not ask the tester to send us their ID: we attach below. HULYSCALE_JOINS=1 export HULYSCALE_JOINS fi # What the computer is before the programs are replaced: in a network of its own # (its daemon says so), attached ([access] in its configuration), or neither; and the # router it prefers, which its ticket then names first (`hulyscale exit`: the first # word of its answer is the member or router that carries by its choice, "exit" or, # once a tester chose it, "entry"). was="" first="" if [ -n "$invite" ] && [ -z "$pass" ]; then if [ -f "$config" ] && grep '^\[access\]' "$config" >/dev/null 2>&1; then was=attached elif [ -x "$cli" ]; then case $("$cli" status 2>/dev/null | sed -n 's/^network *//p') in none* | "") ;; *) was=member ;; esac fi # The first line's first word: sed prints the line whether or not it had more. if [ -x "$cli" ]; then case $("$cli" exit 2>/dev/null | sed -n '1{s/[^a-z0-9-].*//;p;}') in entry) first="entry" ;; exit) first="exit" ;; esac fi fi # Its configuration stays when it has one we must not lose: `attach` makes the change, # and keeps the old one in place if it fails. if [ -n "$was" ]; then rm -f "$tmp/hulyscale/server.toml"; fi # sh, not the file itself: /tmp may not let programs run. # shellcheck disable=SC2086 # $mode and $pass are words or nothing. sh "$tmp/hulyscale/install.sh" $mode $pass /dev/null | sed -n 's/^endpoint *//p') [ -z "$endpoint" ] || break sleep 1 done [ -n "$endpoint" ] || die "HulyNet did not start; please send us its log (see the page)" } # register …: POSTs the invite code, this computer's ID, the name if one was # asked for, and the fields (`--data` words) to the registrar; the answer in $tmp/reply. # Anything but 200 is said as the registrar said it (one line), and nothing more is done. register() { echo "Registering this computer..." if [ -n "$name" ]; then set -- "$@" --data-urlencode "name=$name"; fi status=$(curl -sS -o "$tmp/reply" -w '%{http_code}' --data-urlencode "invite=$invite" \ --data-urlencode "endpoint=$endpoint" "$@" https://8dgx2h0f.nothing.md/register) || die "the server cannot be reached: try again" if [ "$status" != 200 ]; then said=$(head -n 1 "$tmp/reply") die "${said:-the server answered $status: try again in a minute}" fi } # A computer that already sends everything through HulyNet reaches nothing, this server # included, while the daemon this line has just installed starts: it stays closed until # it is carried again (a few seconds). Waits up to a minute for the server to answer; # after that the registration itself says what is wrong. reach_server() { for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do if curl -fsS -m 2 -o /dev/null https://8dgx2h0f.nothing.md/VERSION 2>/dev/null; then return 0; fi sleep 1 done return 0 } # Registers this computer as one that attaches (ADR 0034), and attaches it to our routers # with the ticket it gets: `hulyscale attach` writes [access] and restarts HulyNet, and # moves a computer out of its own network. attach() { echo wait_endpoint reach_server if [ -n "$first" ]; then register --data access=1 --data "first=$first" else register --data access=1 fi ticket=$(sed -n 's/^access //p' "$tmp/reply") named=$(sed -n 's/^name //p' "$tmp/reply") [ -n "$ticket" ] || die "the server's answer has no ticket: try again, or write to us" # The registrar the daemon asks for its ticket again (ADR 0036, stage 2): this server, # given to a CLI that takes it (an earlier release's, which a way back installs, does # not). if "$cli" attach --help 2>/dev/null | grep -e --registrar >/dev/null 2>&1; then set -- --registrar "https://8dgx2h0f.nothing.md" else set -- fi if ! "$cli" attach "$ticket" "$@" "$tmp/attach" 2>&1; then case $was in member) kept="This computer is still in its own network, as before." ;; attached) kept="This computer is still attached, as before." ;; *) kept="This computer's own connection is as it was." ;; esac die "attaching failed: $(tail -n 1 "$tmp/attach"). $kept Please send us this message and what sudo hulyscale report --private prints." fi attached="" for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30; do attached=$("$cli" status 2>/dev/null | sed -n '/^attached[[:space:]]\{1,\}to /p') [ -z "$attached" ] || break sleep 1 done [ -n "$attached" ] || die "HulyNet took the ticket but does not say it is attached yet: run hulyscale status in a minute; if no line begins \"attached\", please send us what it prints." echo echo "Done: this computer is \"$named\" on HulyNet, and its traffic goes through it." echo "To check: curl https://ifconfig.me; echo" } die() { echo "HulyNet: $*" >&2 exit 1 } main "$@"