Repository navigation
FreeBSD
This page is the complete guide to running the URnetwork provider on FreeBSD (amd64 and arm64): install, the rc.d service, updates, the required sysctl tuning, and the platform differences you will run into. For the other platforms and the general installer, see the Installation Guide.
The provider runs as an rc.d service named urnetwork under an unprivileged user. There is no hosted one-line installer for FreeBSD: you fetch the installer script and run it, and it downloads the release for your architecture.
The base system has no jq and no python3. The installer works without them, but they change one thing: they are what lets it verify and install the Go urnet-tools binary (see What the installer does). Install curl, sudo and, recommended, jq:
pkg install -y curl sudo jqRun the installer as the account the provider should run as, with sudo, or as root with an explicit account (see Service user).
curl -fsSL https://raw.githubusercontent.com/full-bars/urnetwork-3.23-fix/refs/heads/main/scripts/Provider_Install_FreeBSD.sh -o urnet-install.sh
sudo sh urnet-install.sh installTo install a specific release instead of the latest:
sudo sh urnet-install.sh install v3.23.0-fix.32.7The installer takes latest by default, resolves the tag through the GitHub API, and falls back to https://dl.fullbars.xyz/latest-version when the API is rate limited. It supports amd64 and arm64; any other architecture stops the install.
The provider must not run as root, and the installer refuses to set that up. It picks the account in this order:
-
SERVICE_USER_OVERRIDE, if set. -
SUDO_USER, the account that ransudo. -
logname, the owner of the login session, unless it isroot. -
id -un, the current user.
If the result is root (a genuine root login with none of the above), the install stops before downloading anything:
refusing to install a service that runs as root
From a root shell, name the account:
SERVICE_USER_OVERRIDE=urnet sh urnet-install.sh installThe account must already exist. Create one with pw useradd urnet -m -s /bin/sh if you want a dedicated user. All paths below come from that user's home directory, read from the passwd database (getent passwd, then pw usershow), not from $HOME, which under sudo can still be root's.
| What | Where |
|---|---|
| Provider binary |
~/.local/share/urnetwork-provider/bin/urnetwork (service user's home) |
| Installed version tag | ~/.local/share/urnetwork-provider/version |
urnet-tools |
~/.local/share/urnetwork-provider/bin/urnet-tools |
| State, including the login token |
~/.urnetwork (service user's home) |
rc.d script |
/usr/local/etc/rc.d/urnetwork |
| Service output | /var/log/urnetwork/stdout.log |
| PID file | /var/run/urnetwork.pid |
The steps, in order:
- Downloads
urnetwork-provider-<tag>.tar.gzfromdl.fullbars.xyz, and from the GitHub release if that fails, and extractsfreebsd/<arch>/providerfrom it. - Installs the binary by staging it beside the target and renaming it, so an update over a running provider never fails with "Text file busy".
- Installs
urnet-tools. It downloads theurnet-tools-freebsd-<arch>release asset and installs it only if its SHA-256 matches the digest GitHub publishes for the asset (read withjq, or withpython3whenjqis absent).sha256(1)from the base system does the check, withopensslas a fallback. If there is no digest to compare (neitherjqnorpython3), the download fails, or the sum does not match, it installs the installer script itself as a shellurnet-toolsinstead. The shell version coversstart,stop,restart,status,update,version,hot-restart,self-heal,session,proxy refresh|remove-dead|summary,authandlogs. Installjqand re-runupdateto get the full Go tool. - Writes the
rc.dscript and, withsysrc, setsurnetwork_enable=YESandurnetwork_user=<service user>only if they are not already set, so an operator's choice survives every update. - Starts the service. On a fresh install it always starts; on
updateit restarts only a service that was already running, so a provider you stopped on purpose is not resurrected by an unattended update. - Adds the install
bindirectory to the service user's shell profile once (.profile,.zshrc,.bash_profileor.cshrc, by the user's login shell).
When the installer is run as an ordinary user, the rc.d and sysrc steps go through sudo; without sudo it prints the commands to finish by hand.
The login token has to land in the service user's ~/.urnetwork. Get an auth code from https://ur.io and run the authentication as the service user:
su -l urnet -c '$HOME/.local/share/urnetwork-provider/bin/urnetwork auth <code>'If you installed as your own account with sudo, that account is the service user and you can run urnet-tools auth <code> directly. Restart the service so the provider picks up the token:
sudo service urnetwork restartAuth codes are single-use, so fetch a new one if a code was already submitted.
urnet-tools start|stop|restart|status run the rc.d service for you, through sudo when you are not root. You can also drive it yourself:
service urnetwork start
service urnetwork stop
service urnetwork restart
service urnetwork statusThe script does not use rc.subr's own process tracking, which keys off procname and command and would report "not running" for this service. It manages a pidfile directly:
-
start launches the provider through
daemon(8)and returns. If the pidfile points at a live process it printsurnetwork is already running as pid <pid>; not starting a second copy.and does nothing, so a double start cannot create two providers. -
stop sends
SIGTERMto the pid and pollskill -0once a second for up to 30 seconds. If the provider is still alive after that it sendsSIGKILL, then removes the pidfile. The 30 seconds covers the provider's connection drain. -
status (
status_cmd) printsurnetwork is running as pid <pid>.and exits 0, orurnetwork is not running.and exits 1.
kill -0 on a process owned by another user fails with EPERM, so the installer's own status check runs through sudo. Run service urnetwork status as root, or through sudo, when you are not the service user.
Boot start is controlled by rc.conf:
sysrc urnetwork_enable=YES # start at boot
sysrc urnetwork_enable=NO # do not start at boot
sysrc urnetwork_user # show the service user
sysrc urnetwork_flags="..." # extra flags passed to `provider provide`urnet-tools auto-start on|off sets urnetwork_enable for you, and refuses if the rc.d script is not installed.
tail -f /var/log/urnetwork/stdout.logdaemon(8) is started with -f -t urnetwork -p /var/run/urnetwork.pid -o /var/log/urnetwork/stdout.log -u <user>:
-
-owith no-msends both stdout and stderr to the file.-m 0would discard the provider's output, which is why the script omits it. -
-pwrites the pid of the provider (the child), not of thedaemonprocess, sostopandstatusact on the provider itself. -
-uruns the child as the service user and sets itsHOME,USERandSHELL, which is why the state directory lands in that user's home.
The log directory is created and handed to the service user on every start.
urnet-tools updateUpdate re-runs the install for the latest release (or urnet-tools update <tag>), keeps your rc.conf choices and shell profile, and restarts the service only if it was running. The installer's update is a plain service restart; HotSwap is a systemd feature.
Turn on a schedule:
urnet-tools auto-update weeklyThe interval is daily, weekly or monthly, and off removes it. On FreeBSD it is a line in the invoking user's crontab, not a systemd timer, and the times are fixed:
| Interval | Cron spec |
|---|---|
daily |
17 3 * * * (every day, 03:17) |
weekly |
17 3 * * 0 (Sundays, 03:17) |
monthly |
17 3 1 * * (the 1st, 03:17) |
The line runs urnet-tools update -f and appends its output to ~/.urnetwork/auto-update.log in that user's home. It ends in the marker comment # urnet-tools auto-update urnetwork, which is how a later change replaces or removes only its own line and leaves the rest of the crontab alone. Changing the interval never leaves two schedules.
Two things differ from a systemd timer:
-
No catch-up.
crondoes not run a missed job. A box that was off at 03:17 waits for the next scheduled time. -
Restarting needs privilege. The update restarts the service through
sudo serviceunless the crontab belongs to root. For unattended updates, schedule it from root's crontab (sudo urnet-tools auto-update weekly), or allow the user passwordlesssudoforservice, since cron has no terminal to ask for a password.
Run the tuner as root:
sudo urnet-tools optimizeIt sets these keys, in this order:
| Key | Target | Why |
|---|---|---|
kern.ipc.maxsockbuf |
16777216 |
Socket buffer ceiling. Must be raised first. |
net.inet.tcp.recvspace |
4194304 |
Default TCP receive buffer. |
net.inet.tcp.sendspace |
4194304 |
Default TCP send buffer. |
kern.maxfiles |
200000 |
System-wide descriptors; one socket per proxied connection. |
kern.maxfilesperproc |
100000 |
Per-process descriptors. |
Important
Raise kern.ipc.maxsockbuf first. Creating a TCP socket reserves the default send and receive space, and the kernel refuses a reservation above about 0.889 of kern.ipc.maxsockbuf (the cluster-to-mbuf ratio, 2048 / (256 + 2048)). Set the TCP buffers to 4 MiB while maxsockbuf is still at its default of about 2 MiB, and every new TCP socket fails with ENOBUFS. Size maxsockbuf to at least about 1.15 times the largest TCP buffer you set; 16 MiB covers the 4 MiB defaults with room to spare. Persisted, this failure survives a reboot.
If you tune by hand, apply them in the same order:
sysctl kern.ipc.maxsockbuf=16777216
sysctl net.inet.tcp.recvspace=4194304
sysctl net.inet.tcp.sendspace=4194304
sysctl kern.maxfiles=200000
sysctl kern.maxfilesperproc=100000Behavior of urnet-tools optimize:
-
Never lowers a value. Each key is applied as the larger of the current value and the target, so a site that already runs
kern.maxfiles=500000keeps it. -
All or nothing. It reads every key first and aborts before changing anything if one cannot be read. If a live write or the file write fails, it rolls the live values and
/etc/sysctl.confback to what they were. -
Persists in
/etc/sysctl.conf. Existing assignments to these keys are replaced in place; new ones go in a block between# --- urnet-tools optimize (managed block) ---and# --- end urnet-tools optimize ---. The file is rewritten through a temporary file and a rename.
To persist by hand, put key=value lines in /etc/sysctl.conf:
cat >> /etc/sysctl.conf <<'EOF'
kern.ipc.maxsockbuf=16777216
net.inet.tcp.recvspace=4194304
net.inet.tcp.sendspace=4194304
kern.maxfiles=200000
kern.maxfilesperproc=100000
EOFWarning
Never persist a sysctl with sysrc. sysrc edits /etc/rc.conf, whose entries are shell variable assignments, and a dotted MIB such as net.inet.tcp.recvspace is not a valid shell variable name. The line is written, nothing consumes it, and the setting silently reverts at the next boot. /etc/sysctl.conf is the file /etc/rc.d/sysctl applies at boot.
optimize does not set a conntrack-style limit: FreeBSD has no nf_conntrack, and pf table sizes are set per ruleset, not with a global sysctl.
-
No
jqorpython3in the base system. Installjqfor the installer's digest check (see step 3 above). -
User database fields differ. The installer reads home and shell with
getent passwdand falls back topw usershow, whose fields are numbered differently (home is field 9 and shell field 10, against 6 and 7 forgetent). Use whichever your tooling expects. -
Swap comes from
swapinfo -k. The provider's memory-pressure checks read swap usage by runningswapinfo -k, because FreeBSD does not expose a swap-used sysctl. -
ZFS ARC understates available memory. The host's available memory is estimated from the free, inactive, cache and laundry page counters (
vm.stats.vm.v_*_count). Memory held by the ZFS ARC is wired and is not counted, so on a ZFS hosttopcan show plenty of reclaimable memory while the provider sees less. Cap the ARC withvfs.zfs.arc_maxin/boot/loader.confif memory headroom matters on a small box. -
Jails. Provider discovery uses
procstat(1)and makes no jail distinction; a provider in a jail is not specially recognized. -
daemon(8)and the pidfile. The pidfile holds the provider's pid, sokill -0 $(cat /var/run/urnetwork.pid)is a valid liveness check from a root shell.
Each release publishes, for both amd64 and arm64:
| Asset | Contents |
|---|---|
urnetwork-provider-<tag>.tar.gz |
The universal tarball. The FreeBSD provider is at freebsd/<arch>/provider. The installer reads it from here. |
urnet-tools-freebsd-<arch> |
The Go urnet-tools binary, verified by SHA-256 at install. |
urnetwork-provider-<tag>-freebsd-<arch>.tar.gz |
A flat per-platform tarball with provider and the installer script as urnet-tools. |
If the installer reports FreeBSD/<arch> binary not found in release tarball, the release it fetched has no FreeBSD build; install a newer tag.
There is no hosted uninstall script for FreeBSD. As the service user and root:
sudo service urnetwork stop
sudo sysrc -x urnetwork_enable urnetwork_user
sudo rm -f /usr/local/etc/rc.d/urnetwork
urnet-tools auto-update off
rm -rf ~/.local/share/urnetwork-provider
sudo rm -rf /var/log/urnetwork~/.urnetwork holds the login token and proxy state; delete it too only if you do not intend to reinstall.
- Configuration Reference
- Node Identity
- HotSwap
- urnet-tools (Go)
- urnet-docker
- Proxy Management
- Proxy URL Sources
- Proxy Hot Reload
- Proxy Admission Pipeline
- High-Volume Tuning
- Bittensor Operations (Subnet 25)