Build and deploy Nowhere on native hosts and in containers.
Linux, macOS and Windows share one configuration model and the same Vector, Portal and Egress connection semantics. Platform-specific IPC and process identity checks follow the operating system's facilities.
Native validation follows Testing. A successful cross-build does not replace execution on the target platform.
| Platform | Architecture and toolchain | Archive |
|---|---|---|
| Linux | x86-64 and AArch64, GNU libc | .tar.gz |
| Linux | x86-64 and AArch64, musl | .tar.gz |
| FreeBSD | x86-64 and AArch64, cross-built | .tar.gz |
| macOS | Apple Silicon | .tar.gz |
| Windows | x86-64 MSVC | .zip |
The release workflow defines the packaged targets. FreeBSD packages are cross-built; the native CI matrix covers Linux, macOS and Windows.
The executable is nowhere on Unix hosts and nowhere.exe on Windows. Build
and test from the repository root:
cargo build --release --locked
cargo test --all-targets --lockedPortal binds one socket for every address selected by each declared carrier. The endpoint path therefore defines both process listeners and the firewall or container rules required around the process.
| Endpoint | Required inbound exposure |
|---|---|
*:2000 |
TCP 2000 and UDP 2000 |
*/tcp:2006 |
TCP 2006 |
*/udp:2017 |
UDP 2017 |
*/tcp:2006/udp:2017 |
TCP 2006 and UDP 2017 |
*/tcp4:2006/udp6:2017 |
IPv4 TCP 2006 and IPv6 UDP 2017 |
An unrestricted * carrier opens separate IPv4 and IPv6 wildcard sockets.
IPv6 sockets use V6ONLY on Linux, macOS, and Windows, so an IPv6 firewall
rule does not replace the corresponding IPv4 rule. If the operating system
does not support one family, only an unrestricted wildcard carrier may start
with the available family and a diagnostic on stderr. Explicit families and concrete bind
addresses fail startup when unavailable.
A hostname listener resolves once at startup and binds every matching address.
DNS changes take effect after a process restart. Vector and Egress resolve the
selected Portal carrier, filter by its 4 or 6 suffix and fail rather than
crossing the declared family boundary.
Build from the repository root:
docker build -t nowhere:local .Container builds support linux/amd64 and linux/arm64. The examples use
the local nowhere:local image.
The runtime image uses scratch. It contains the statically linked executable
and a CA bundle for default client certificate verification, with no shell,
package manager, or dynamic libraries.
Start a Portal with its generated certificate:
docker run -d --rm --name nowhere-portal \
-p 2000:2000/tcp \
-p 2000:2000/udp \
nowhere:local \
"portal://<generated-key>@*:2000"Publish separate carrier ports when the endpoint uses an explicit path:
docker run -d --rm --name nowhere-portal \
-p 2006:2006/tcp \
-p 2017:2017/udp \
nowhere:local \
"portal://<generated-key>@*/tcp:2006/udp:2017"Docker publication is transport-specific. Publishing 2006/udp does not
expose the TCP carrier, and publishing 2017/tcp does not expose QUIC. For an
IPv4-only or IPv6-only carrier, align the Docker host binding and host firewall
with the endpoint suffix.
For tls=2, mount the CA-issued PEM certificate chain and private key:
docker run -d --rm --name nowhere-portal \
-p 2000:2000/tcp \
-p 2000:2000/udp \
-v /path/fullchain.pem:/cert.pem:ro \
-v /path/private-key.pem:/key.pem:ro \
nowhere:local \
"portal://<generated-key>@*:2000?tls=2&crt=/cert.pem&key=/key.pem"crt is the full certificate chain and key is its private key. A Vector
verifies the endpoint host by default; sni=relay.example can override that name.
The image CA bundle trusts public CAs. For a private CA, mount its root
certificate and set SSL_CERT_FILE to the mounted path.
Run status inside the same container as the service:
docker exec nowhere-portal /nowhere statusThe relay and collector must use the same UID and system temporary directory. Telemetry uses a private Unix socket, not a published network port. Run third-party collectors inside the same container. Host-to-container, sidecar and cross-container observation are outside the supported contract; do not share telemetry directories across PID or user namespaces.
The image supplies /tmp with mode 1777 and does not force a user. A non-root
UID can create its own mode-0700 directory. Mounted certificates and keys must
also be readable by that UID. Read-only containers need writable temporary storage:
docker run -d --rm --name nowhere-portal \
--user 10001:10001 --read-only \
--tmpfs /tmp:rw,noexec,nosuid,nodev,size=16m,mode=1777 \
-p 2000:2000/tcp -p 2000:2000/udp \
nowhere:local \
"portal://<generated-key>@*:2000"
docker exec --user 10001:10001 nowhere-portal /nowhere statusMount an in-memory emptyDir at /tmp, use the same UID for the service and
collector, and permit that UID to create its private directory. This
container/volume fragment
uses a group-writable temporary mount and requires no privileged init process:
spec:
securityContext:
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
containers:
- name: nowhere
image: nowhere:local
args: ["portal://<generated-key>@*:2000"]
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
volumeMounts:
- name: temporary
mountPath: /tmp
volumes:
- name: temporary
emptyDir:
medium: Memory
sizeLimit: 16MiA missing, full or unwritable temporary mount disables local Telemetry IPC with an error on stderr; forwarding continues. No TCP fallback, extra capabilities or host networking are needed. Registry files are written once; messages and history are not stored in the mount. Process memory and tmpfs count against container resource budgets. Normal shutdown removes instance files; forced termination can leave files until safe discovery cleanup or destruction of the temporary mount.
Bourne-compatible shells, PowerShell and Windows Command Prompt accept the
documented double-quoted URLs. Replace KEY with nowhere generate-key output.
For a generated Portal certificate, set pin to a fingerprint verified through
a trusted channel:
nowhere "vector://KEY@portal.example/udp:2000?in=127.0.0.1:1080&pin=TRUSTED_SHA256"On Windows, use the executable's .exe name:
nowhere.exe "vector://KEY@portal.example/udp:2000?in=127.0.0.1:1080&pin=TRUSTED_SHA256"A CA-issued certificate with a matching hostname can use normal trust without a pin. See certificate trust.
Certificate and key values accept native filesystem paths. Relative paths resolve from the process working directory. Quote the URL when a path or query contains shell-significant characters.
Interactive instances stop with Ctrl+C on every platform. Unix process
managers may send SIGINT or SIGTERM. Windows services should use a wrapper
that forwards a console termination event and allows NOW_SHUTDOWN_TIMEOUT to
complete.
Local Telemetry discovery uses a protected per-user registry in the system temporary directory and local IPC: Unix sockets or Windows named pipes. Linux also checks boot, PID namespace and user namespace identity before PID-based cleanup. See the telemetry contract.
All roles publish six logical traffic and active Flow statistics over Unix sockets on Linux/macOS or local Windows named pipes. stdout and stderr carry service logs. IPC permissions, discovery, process identity and namespace validation are defined by the Telemetry contract.
The native CI workflow runs on Linux, macOS and Windows. Record validation results using Testing.