The solnix handbook
The solnix Operating System is a supported distribution of illumos built entirely with the Nix package manager and the NixOS module system — the illumos analog of NixOS (Linux) and nixbsd (FreeBSD/OpenBSD).
The solnix OS targets four CPU architectures — x86_64, aarch64,
RISC-V, and SPARC (the x86_64-solaris, aarch64-solaris,
riscv64-solaris, and sparcv9-solaris systems) — and is designed for both
server and desktop use. It is optimized for virtualized hosting on all the
major cloud platforms (AWS/EC2, Microsoft Azure, Google Cloud, and the rest),
while remaining a first-class OS on bare metal.
Describe an illumos machine declaratively in Nix; get a bootable, atomically upgradeable, rollback-capable system backed by ZFS boot environments.
Status: early / preview. The first bootable image has landed — an unstable-edition x86_64 ISO + raw disk image (v2026.08.07), preview-grade (Download). The positioning above describes the target the solnix OS is designed for, not everything that runs today. x86_64 is the primary target; aarch64, RISC-V, and SPARC are in bring-up (see CPU architecture support). Desktop is now within reach: the COSMIC desktop runs on solnix, proving the graphical stack works on illumos — Rust, Wayland, GTK4, and GPU acceleration via Mesa RADV + Vulkan (a graphical install ISO is coming soon). This handbook documents the design and the working infrastructure (binary cache, package search) as they come online. It does not over-claim: sections marked planned are not yet real.
Why
illumos-gate is fully buildable from source today, ships ZFS + zones + bhyve +
LX-branded zones, and already has a native atomic-upgrade story (beadm boot
environments). Nix’s immutable store + generation model maps cleanly onto that.
solnix marries the two.
How, in one breath
Reuse NixOS’s evaluator and module system verbatim; add an *-illumos platform
and a fine-grained pkgs.solnix.* world to a nixpkgs fork; drive services
through SMF (not systemd) via an smf.services.* module; bake /nix/store
paths into ELF RUNPATH with the Solaris link-editor (no GNU tooling); map
each Nix generation onto a ZFS boot environment. This is nixbsd’s playbook,
retargeted to illumos.
Where to go next
- New here entirely? A short history explains what solnix descends from (SunOS → Solaris → illumos → solnix) in a page.
- Coming from Linux or NixOS? For Linux (and NixOS) users is the orientation map (systemd→SMF, Docker→zones, ext4→ZFS, and so on).
- New to illumos? Start with illumos features — the ZFS / DTrace / SMF / zones / boot-environment platform solnix inherits.
- Know Nix already? See How solnix is built for how the illumos target is wired, and Learning Nix for what differs.
- Want to use what is live today? Getting started, the binary cache, and package search.
For Linux (and NixOS) users
You know Linux. Maybe you know NixOS. solnix is neither — it is illumos managed with Nix. Most of your instincts transfer, but the substrate is different: a different kernel, a different init, a different filesystem, a different firewall, a different way to run containers. This page is the map. Each row points at the deeper handbook page.
If you know Nix already, the Nix half transfers almost unchanged (same
language, store, module system) — see Learning Nix. What
changes is everything the packages target. If you also came from Solaris/IPS
packaging, read Learning Nix for the pkg → Nix mapping.
The one-screen map
| You know (Linux / NixOS) | On solnix (illumos) | Where |
|---|---|---|
systemd (systemctl, unit files, journalctl) | SMF (svcs, svcadm, svccfg, XML manifests) | SMF services |
systemctl status / journalctl -u | svcs -x + /var/svc/log/<fmri>.log | SMF · Debugging |
| iptables / nftables | ipfilter (ipf, ipnat) | Networking |
bridges / veth / tc / netns | Crossbow: dladm, ipadm, flowadm | Networking (Crossbow) |
| cgroups + namespaces / Docker / LXC | Zones (native), LX zones for Linux bins | Zones · LX zones |
| ext4 / xfs / btrfs + LVM / mdadm | ZFS (pool + datasets, checksums, snapshots) | ZFS storage |
/proc + strace / perf / ftrace / eBPF | DTrace (+ truss, pargs, pfiles, procfs) | DTrace · Debugging |
apt / dnf / pacman | Nix — pkgs.solnix.*, declarative config | Learning Nix |
| NixOS generations (Linux) | Nix generations → ZFS boot environments | Boot environments |
| GRUB | loader (x86, FreeBSD-derived) / OpenBoot (SPARC) | Boot environments |
| glibc | illumos libc (pkgs.solnix.libc, not glibc) | How solnix is built |
ldd / patchelf / RPATH (GNU) | elfdump + Solaris link-editor writing RUNPATH | How solnix is built |
sudo | pfexec (RBAC/privilege-backed) | see RBAC below |
gdb / core dumps | MDB (mdb), coreadm, crash dumps | Debugging |
hardware errors in dmesg | FMA (fmadm faulty, fmdump) | illumos features |
The differences that actually bite
A few of these are more than a command swap — they change how you think:
Init is SMF, and SMF is always running. You do not write systemd units; you
describe smf.services.* and solnix renders SMF manifests. When something is
broken, the reflex is not journalctl — it is svcs -x, which walks the
dependency graph and tells you which service is stuck and where its log is. A
service that keeps crashing lands in maintenance (not a restart loop) until you
svcadm clear it. See SMF services.
Containers are zones — and Linux binaries need an LX zone. A native zone is an isolated illumos environment on the shared kernel (stronger isolation than a container, near-native speed). But a native zone runs illumos userland. To run Linux binaries you use an LX-branded zone, which presents the Linux syscall ABI on the illumos kernel — no VM. On solnix, native zone tooling is early and LX is a roadmap item; see Zones and LX zones.
The filesystem is ZFS, all the way down — including your OS upgrades. There is no separate LVM/mdadm layer; ZFS is pool + volume manager + filesystem in one, with checksums and cheap snapshots. Crucially, your system generations live in ZFS too: each Nix generation is a boot environment (a bootable ZFS clone of root), so upgrade is atomic and rollback is instant — the same idea as NixOS generations, but the bootloader points at a whole bootable root dataset. See ZFS storage and Boot environments.
Observability is DTrace, not eBPF/strace/perf. DTrace predates them and does
the whole job — kernel and userland, safe on production — from one language. Your
strace foo becomes truss foo for quick work, and dtrace -n '...' for
anything real. There is a /proc, but you inspect it with pargs, pfiles,
pstack rather than reading files by hand. See DTrace.
pfexec, not sudo — and it’s backed by real privileges. illumos has
fine-grained RBAC (roles) and process privileges — the kernel splits
“root” into dozens of distinct privileges a process can hold or drop
individually, and roles grant only the profiles a user needs. pfexec runs a
command with the profiles your user is authorized for. This is least-privilege
built into the OS, finer-grained than Linux capabilities and older. This handbook
uses pfexec for privileged commands throughout.
The linker is Solaris ld, and there is no patchelf. Nix’s model bakes
absolute /nix/store paths into binaries. On Linux nixpkgs that uses GNU ld
and patchelf; on solnix the Solaris link-editor writes ELF RUNPATH and
you inspect it with elfdump. Same outcome, native tooling. This matters if you
package software that has GNU-linker assumptions baked in. See
How solnix is built.
What solnix is not
To keep expectations straight (the full story is in the history):
- Not Linux — different kernel, libc, and init.
- Not NixOS — same Nix, different target OS.
- Not Oracle Solaris — the open illumos branch, not Oracle’s closed product.
Where to go from here
- Coming to Nix fresh, or from IPS/
pkg? Learning Nix. - Want the platform features in depth? illumos features.
- Want the backstory? A short history.
Getting started
Early / preview. A first bootable solnix image now exists — an unstable-edition x86_64 ISO + raw disk image (v2026.08.07), preview-grade: see Download. Also live: the binary cache (
cache.solnix.io) and package search (search.solnix.io). Treat the image as a preview for testing in a VM, not a daily driver. The install steps below will firm up as the images stabilize.
New here entirely? Start with the introduction for what solnix is and how it is put together, then come back.
Try it in your browser (no install)
The fastest look at solnix needs nothing installed: https://solnix.io/tryit
boots a real solnix riscv64 kernel in a WebAssembly RISC-V emulator — OpenSBI →
kernel → init → a live $ shell running the actual coreutils. Try ls,
cat /etc/release, echo hi.
Two things to expect. It runs the kernel’s full self-test log before the prompt
(fork/exec, copy-on-write faults, SMP + IPI wakeup, timer preemption, FP context
switching), so the $ takes a minute or two to appear — that scrolling log is
the boot, not a hang. And it is a demonstration image: its runtime linker prints
a few [ld.so.1] proof lines before every command, and the minimal /bin/sh has
no pipes or > redirection.
This is also the honest state of the RISC-V port: the kernel boots to a shell, but there is no riscv64 builder or binary cache yet (see CPU support).
Try the preview image
The first bootable image (v2026.08.07, unstable/preview — for a VM, not a daily driver) is on the download page. Quickest way to see it boot, in a VM:
# fetch + verify the ISO (checksum is on the download page / release manifest)
curl -LO https://cache.solnix.io/images/release-224-v2/solnix-x86_64-minimal.iso
sha256sum solnix-x86_64-minimal.iso # compare to the published sum
# boot it in QEMU (BIOS or UEFI; the ISO is hybrid-bootable)
qemu-system-x86_64 -m 4096 -smp 2 -cdrom solnix-x86_64-minimal.iso
There is also a raw disk image (solnix-raw.img.gz) for writing to a disk or
attaching directly. Expect rough edges — this is an early preview to kick the
tires, report what breaks, and help the arches along, not a supported install.
Use the binary cache
If you build software that solnix has already built, point nix at the cache
and skip the recompilation:
# /etc/nix/nix.conf
substituters = https://cache.solnix.io https://cache.nixos.org
trusted-public-keys = cache.solnix.io-1:8UNrVAOSOrI9PGHc8/pD2Yqp265ZeYb3OId+gv4+wm8= cache.nixos.org-1:6NCHdD59EeA7KA8wG4nSXk...
Prove the cache is real before you commit any config to it — ask it directly, no setup required:
$ nix store info --store https://cache.solnix.io
Store URL: https://cache.solnix.io
Public key: cache.solnix.io-1:8UNrVAOSOrI9PGHc8/pD2Yqp265ZeYb3OId+gv4+wm8=
Every store path is signed with the cache.solnix.io-1 key and Nix verifies
the signature before use, so it does not matter where the bytes came from. See
The binary cache for the full story, including the planned
BitTorrent distribution and how seeding works.
Search for packages
Browse the package registry at search.solnix.io — BM25-ranked full-text search across the solnix package set. It answers the question you actually have: is X packaged, and for which arch? See Package search.
Read the man pages
The man pages that ship with cached packages are browsable at solnix.io/docs — A–Z by package and section. Coverage is early (it grows as packages land), and every package in search links straight to its own man pages; for anything not yet indexed, the upstream illumos man pages are the reference.
Cross-compile from Linux
You do not need an illumos box to build for solnix. From a Linux machine with
Nix, add the cache above and build against the x86_64-solaris /
aarch64-solaris platforms — prebuilt store paths come straight from the cache
instead of being recompiled locally. This is how the non-primary architectures
are populated today (see the news on cross-build artifacts). What
does not cross-build from Linux is illumos-gate itself; see
How solnix is built for why, and
CPU architecture support for per-arch status.
Contribute
The project lives at:
- Infra + services:
codeberg.org/gregburd/solnix-infra - Site + handbook:
codeberg.org/gregburd/solnix-site - The distribution itself: the solnix repo (illumos + Nix work)
Ports, packaging, and docs are all open. See Contributing.
Learning Nix
solnix is built on Nix and the NixOS module system. This handbook documents what is specific to solnix — the illumos target, the package set, boot environments, SMF, the binary cache. For Nix itself — the language, the CLI, flakes, the module system — the upstream documentation is excellent and we link to it rather than duplicate it.
If you administer illumos or Solaris today with IPS / pkg, the biggest
adjustment is not the syntax — it is the shift from imperative to declarative.
This page leads with that translation, then links out to the Nix fundamentals.
(Coming from Linux/NixOS instead? See
For Linux (and NixOS) users.)
For IPS / pkg users: the mental shift
IPS is imperative and stateful. You run pkg install, pkg update,
pkg uninstall; each command mutates the live system image in place, and IPS
tracks the resulting state in its own database. The image is the accumulation of
every command you’ve ever run against it. To make that safe, IPS updates snap a
new boot environment so you can fall back if an update goes wrong.
Nix is declarative and reproducible. You do not mutate a live image. You
describe the desired system — the full set of packages and services — in a Nix
configuration, and Nix builds that description into an immutable set of
/nix/store paths, then activates it atomically. There is no accumulated
state to drift; the configuration is the system. Two machines with the same
configuration are the same system, byte for byte.
The payoff for a pkg user: the thing IPS does defensively — snapshot a boot
environment around a risky update — is the normal, every-time mode in solnix.
Every configuration change produces a new Nix generation, and solnix maps
each generation onto its own ZFS boot environment.
Rollback is not a recovery procedure; it is picking the previous BE at the
loader. IPS bolts BEs onto updates; solnix’s whole model is generations-as-BEs.
pkg → Nix, command by command
| Task | IPS / pkg (imperative) | solnix / Nix (declarative) |
|---|---|---|
| Install a package | pkg install X | add to environment.systemPackages in config → rebuild; or ad-hoc nix profile install nixpkgs#X |
| Remove a package | pkg uninstall X | remove it from the config → rebuild (it’s gone from the new generation); or nix profile remove X |
| List installed | pkg list | nix profile list, or just read the config; the store shows the closure |
| Search available | pkg search X | nix search nixpkgs X, or search.solnix.io for the solnix set |
| Update the system | pkg update (+ auto new BE) | rebuild the config → new generation → new boot environment, activated atomically |
| Roll back | beadm activate <old-BE> | beadm activate the previous generation’s BE, or pick it at the loader |
| Show/set repos | pkg publisher / set-publisher | substituters + trusted-public-keys in nix.conf → cache.solnix.io |
| Name a package | IPS FMRI pkg://.../X@version | a Nix attribute — pkgs.solnix.* (never pkgs.illumos.*) |
| Verify / fix an image | pkg verify / pkg fix | rebuild the generation — the store path is the definition, so “fix” = re-realize |
Note: the
pkgcolumn mutates one live image; the Nix column changes a description and produces a new, independently-bootable generation. You never edit the running system in place — you build a new one and switch to it.
FMRIs → attributes, publishers → substituters
Two IPS concepts map cleanly onto Nix:
- An IPS FMRI (
pkg://solaris/system/library@0.5.11,...) names a package and version in a publisher’s catalog. In solnix a package is a Nix attribute —pkgs.solnix.libc,pkgs.solnix.sys, and so on (the fine-grained illumos world; see How solnix is built). The version is pinned by the Nix expression / flake input, not resolved at install time. - An IPS publisher (a repository
pkgfetches from) maps onto a Nix substituter:cache.solnix.iois the solnix substituter, added with itstrusted-public-keysinnix.conf. Wherepkg publisherlists your repos,nix.conf’ssubstituterslists your caches — and every store path is signature-verified before use.
And the SMF story you already know carries straight over: on illumos an IPS
update reconfigures services through SMF; on solnix, services are declared with
smf.services.* and re-imported on activation. See SMF services.
Start here (Nix fundamentals)
- nix.dev — the official learning hub; tutorials from zero.
- Nix language basics — the language you write solnix configurations in.
- Nix manual —
nixCLI, the store, derivations, flakes. - Nixpkgs manual — stdenv, builders, overlays, packaging conventions.
- NixOS manual — the module system, which solnix reuses verbatim (services differ: solnix uses SMF).
- Package/options search (nixos.org) — for the upstream nixpkgs set. solnix’s own set is at search.solnix.io.
What is different in solnix
Once you know Nix, these are the solnix-specific pieces to read here:
- How solnix is built — how the illumos target is wired.
- SMF services —
smf.services.*instead ofsystemd.services.*. - ZFS boot environments — generations as BEs.
- The binary cache —
cache.solnix.io+ BitTorrent. - Package search — the package graph, backed by an EDN datom
store (
pg_mentat).
For illumos itself — the platform underneath solnix — see the illumos features overview, For Linux (and NixOS) users if you’re bridging from Linux, and Further reading & resources.
Community (Nix-wide)
solnix is a friendly neighbor in the wider Nix ecosystem:
- NixOS Discourse — the Nix community forum.
- Nix community on Matrix.
solnix’s own channels are on the Community page.
The binary cache
cache.solnix.io is a standard Nix binary cache — functionally like
cache.nixos.org. Add it as a substituter and pull prebuilt, signed store
paths for every architecture solnix targets.
Setup
# /etc/nix/nix.conf
substituters = https://cache.solnix.io https://cache.nixos.org
trusted-public-keys = cache.solnix.io-1:8UNrVAOSOrI9PGHc8/pD2Yqp265ZeYb3OId+gv4+wm8= cache.nixos.org-1:6NCHdD59EeA7KA8wG4nSXk...
Every store path is signed with the cache.solnix.io-1 key. Nix verifies the
signature against your trusted-public-keys before using anything — so it does
not matter where the bytes came from, only that they match a signature you
trust.
How it is distributed
Cache objects will also be distributed over BitTorrent: each NAR is a
torrent, seeded by the hub and by other solnix users. This is not yet enabled
— the narinfo served by cache.solnix.io always carries a plain HTTP URL: as
the guaranteed fallback, so a stock nix works today over HTTP; the peer layer
is an enhancement layered on top.
The property that matters: the more solnix users, the faster and cheaper the cache — bandwidth scales with the community instead of with one origin’s egress bill.
Seeding (please read)
Once you have opted in, a machine using the solnix cache seeds the public, signed cache artifacts it fetches to other solnix users. This is deliberate and is how a multi-arch cache stays sustainable.
- It is default on when you have opted in (
solnix.cache.seed.enable = true), and gated by the privacy master switch — a machine whose config never touches it stays completely private and seeds nothing. See Peer-to-peer distribution and Privacy & telemetry. - It only ever shares public Nix store paths — never your private data.
- Integrity is enforced by the cache signature regardless of source.
We state this plainly so no one is surprised to find their machine seeding.
Package search
search.solnix.io is full-text search over the solnix
package set — the illumos analog of search.nixos.org/packages. Use it to find
whether a tool is packaged, which architectures it is built for, and how to
install it.
Using it
- Type a name or keyword; results rank the best match to the top and refine as you type.
- Prefix matching:
rtlfindsrtldbefore you finish typing. - Typo-tolerant:
opnsshstill findsopenssh. - Each result shows the architectures it is available for and, in the detail
view, how to install it (declarative
environment.systemPackages,nix profile,nix-env, or an ephemeralnix shell) plus links to its man pages and dependencies.
Everything found there is served by the binary cache — add the cache and the package installs without recompiling.
Following new packages
The registry publishes update feeds so you can track new and changed packages:
The announce@ mailing list rolls these up (once list
subscription is open).
Programmatic access
There is a public REST + GraphQL API for the package data (search, package detail, dependency graph, man pages, systems). See the API reference at https://search.solnix.io/api/v1/openapi — this is tooling for building on top of solnix, not something you need for everyday use.
illumos features
illumos is not a Linux distribution and not a kernel-only project — it is a complete Unix operating system descended from OpenSolaris, carrying a set of capabilities that were, in several cases, invented there. solnix inherits all of them from the illumos gate. This page is a feature-by- feature overview: what each thing is, why it matters, and where solnix stands on it today. Each has a fuller page linked from here.
On solnix status, up front. These are illumos platform features; solnix inherits them by being an illumos distribution. Where solnix’s own tooling around a feature (a Nix module, a builder) is still planned, this page says so. The features themselves — ZFS, DTrace, SMF, zones, FMA — are real illumos features and work on any illumos host.
OpenZFS
What it is. A pooled-storage filesystem and volume manager in one. ZFS groups devices into a pool, carves datasets (filesystems) and volumes out of it on demand, and end-to-end checksums every block. It was developed at Sun in the early 2000s, open-sourced in 2005 as part of OpenSolaris, and illumos is a founding member of the OpenZFS community.
Why it matters. Cheap atomic snapshots and clones, send/receive for
replication, on-demand scrubbing, and self-healing in redundant configurations —
data integrity you cannot get from a traditional filesystem plus separate volume
manager. Snapshots and clones are also the mechanism behind
boot environments.
solnix relevance. ZFS is the substrate for the whole solnix upgrade model: each Nix generation is a ZFS boot environment, and cheap clones are what make atomic upgrade and instant rollback affordable. See ZFS storage.
DTrace
What it is. A safe, production-grade dynamic tracing framework spanning the
whole system — kernel and userland, from one language (the D language).
Thousands of instrumentation points (probes) sit dormant at zero cost until you
enable them.
Why it matters. You can ask questions about a running production system — “which files is this process opening,” “what is the latency distribution of this syscall,” “which function is burning CPU” — without recompiling, restarting, or risking a crash. DTrace is designed to be safe to run on live systems.
solnix relevance. For a Nix-built system, DTrace is the answer to “why is this store path’s binary behaving this way in production.” See DTrace.
Service Management Facility (SMF)
What it is. The init system and service supervisor. SMF tracks service
dependencies, supervises and restarts processes, disables perpetually crashing
services (moves them to maintenance), and keeps live configuration in a
repository rather than only in flat files.
Why it matters. Dependency-aware startup, automatic restart with a fault
boundary, and a single query (svcs -x) that tells you what is broken and why —
the things you would otherwise assemble from several tools.
solnix relevance. SMF is the direct replacement for systemd.services.*.
solnix renders SMF manifests from a declarative smf.services.* Nix module and
converges the system to a milestone on activation. See SMF services.
Zones
What it is. OS-level virtualization: isolated illumos environments that share one kernel but have their own filesystem, process table, users, and network — a “virtual machine without the hypervisor overhead.” Zones predate Linux containers by years.
Why it matters. Strong isolation at near-native performance, plus branded zones — including LX-branded zones that run Linux binaries on the illumos kernel — and integration with ZFS (a zone on its own dataset) and resource controls.
solnix relevance. Zones are a natural target for reproducible, Nix-built environments, but solnix’s own zone tooling is early — see Zones for the honest status. Running Linux workloads on solnix via the LX brand is a stated roadmap direction — see LX-branded zones.
Boot environments
What it is. Bootable ZFS clones of the root filesystem, managed with
beadm. Each is an independent, bootable root; exactly one is the default boot
target.
Why it matters. Upgrades become atomic (switch the boot target, do not mutate the live root) and rollback becomes instant (boot the previous environment). This is illumos’s native answer to safe system upgrades.
solnix relevance. This is the mechanism solnix maps Nix generations onto — the illumos analog of NixOS generations. See ZFS boot environments.
Fault Management Architecture (FMA)
What it is. A subsystem that collects hardware and software error telemetry,
diagnoses it into faults, and takes automated action — retiring a bad CPU or
memory page, or handing a service to SMF to restart. You interact with it via
fmadm and fmdump.
Why it matters. Errors become diagnosed faults with a stable message ID you can look up, instead of cryptic log lines. The system can degrade gracefully (offline a failing component) rather than crash. FMA and SMF are wired together: a service fault and a hardware fault flow through the same machinery.
solnix relevance. FMA is inherited from the gate; solnix does not replace it.
For a system where the software layer is immutable Nix store paths, FMA’s focus
on hardware and service faults complements Nix’s focus on software correctness.
fmadm faulty is part of the debugging toolkit.
Other platform pieces
illumos also carries, and solnix inherits:
- RBAC and process privileges — illumos splits the traditional all-or-
nothing “root” into dozens of fine-grained privileges a process can hold
or drop individually, and layers role-based access control (RBAC) on top:
users assume roles granted only the profiles (bundles of authorizations)
they need.
pfexecruns a command with the profiles your user is authorized for — the least-privilegesudo-equivalent used throughout this handbook. This is finer-grained than Linux capabilities and predates them; it is why solnix can hand a service exactly the privileges it needs and no more. - The modular debugger (MDB /
mdb) — inspects running processes, core files, and kernel crash dumps, using CTF type data. Central to debugging. - Virtual networking — Crossbow (
dladm) — the in-kernel network- virtualization stack: virtual NICs, virtual switches (etherstubs), VLANs, link aggregation, and flow/bandwidth controls, including per-zone networking. See Networking (Crossbow). ipfilter— the host (and per-zone) firewall.- bhyve / KVM — hardware virtualization ported to illumos, for full VMs alongside zones.
Further reading
- ZFS storage · ZFS boot environments
- DTrace · SMF services · Zones · LX-branded zones
- Networking (Crossbow) — the network-virtualization stack.
- Debugging — MDB, crash dumps, FMA in practice.
- Further reading & resources — canonical books and docs.
SMF services
On illumos the init system is the Service Management Facility (SMF) — not
systemd, not SysV rc, not BSD rc.conf. If you come from NixOS you will reach
for systemd.services.*; on solnix the equivalent is smf.services.*. This
page explains what SMF is, the concepts you need (FMRIs, states, milestones,
manifests), the commands you use day to day (svcs, svcadm, svccfg), and
how solnix layers a declarative Nix module on top.
On illumos generally SMF has been the init and service supervisor since Solaris 10 (2005) and is mature and load-bearing. On solnix the
smf.services.*module that renders manifests from Nix is planned (roadmap T1.11/T1.12); SMF itself is inherited from the illumos userland and is real. Commands likesvcs/svcadm/svccfgbelow are the genuine illumos commands.
SMF versus systemd, in one table
If you know systemd, this mapping gets you most of the way:
| Concept | systemd | SMF |
|---|---|---|
| Service identity | sshd.service | FMRI svc:/network/ssh:default |
| Definition | unit file (.service) | manifest (XML) + method script |
| List services | systemctl list-units | svcs -a |
| Start / stop | systemctl start/stop | svcadm enable/disable |
| Restart | systemctl restart | svcadm restart |
| Why did it fail? | systemctl status / journalctl | svcs -x / service log |
| Boot targets | targets (multi-user.target) | milestones (svc:/milestone/multi-user) |
| Config store | unit files on disk | SQLite repository (svc.configd) |
| Reload config | systemctl daemon-reload | svccfg import / manifest-import |
| Auto-restart on crash | Restart= | restarter policy + fault boundary |
The biggest conceptual difference: SMF keeps live service configuration in a
repository (a SQLite database owned by svc.configd), not only in flat
files. Manifests seed the repository; running config can be changed with
svccfg without editing the manifest. solnix treats the manifest as the source
of truth and re-imports on activation — the Nix way.
Ground truth: the concepts
FMRIs
Every service is named by a Fault Managed Resource Identifier (FMRI):
svc:/<category>/<name>:<instance>
For example svc:/network/ssh:default or svc:/system/console-login:default.
You can usually abbreviate to the shortest unambiguous suffix, so svcs ssh
works. A service can have multiple instances (:default, :vt2, …);
each instance runs and is enabled/disabled independently.
Service states
An instance is always in exactly one state. svcs shows it in the STATE
column:
| State | Meaning |
|---|---|
online | Running and healthy. |
offline | Enabled but a dependency is not yet satisfied. |
disabled | Administratively off (persists across reboot). |
maintenance | Failed too many times / method error — needs a human. |
degraded | Running but not fully functional. |
uninitialized | Not yet examined by its restarter. |
legacy_run | An old rc-style script, tracked but not managed. |
maintenance is the one you will care about most — it means SMF gave up
restarting the service because it kept failing. See Debugging.
Milestones
Milestones are pseudo-services that group other services, like systemd targets:
svc:/milestone/single-user— single-user mode.svc:/milestone/multi-user— normal multi-user, no network servers.svc:/milestone/multi-user-server— multi-user plus network services.
The solnix Phase-1 target is multi-user-server. You can boot to a milestone
(boot -m milestone=single-user) or move the running system with
svcadm milestone.
Manifests and method scripts
A manifest is an XML file describing a service — its FMRI, dependencies,
start/stop methods, and default properties — conforming to
service_bundle.dtd.1. Manifests live under:
/lib/svc/manifest/<category>/<name>.xml
The commands SMF runs to start/stop/refresh a service are method scripts,
conventionally under /lib/svc/method/. A start method exits 0 on success;
SMF watches the process and applies the restart policy if it dies.
At boot, svc:/system/manifest-import:default scans the manifest directories
and imports anything new or changed into the repository. You can do it by hand:
pfexec svccfg import /lib/svc/manifest/network/ssh.xml
Note: solnix uses
pfexec(illumos’ssudo-equivalent, backed by RBAC profiles) for privileged commands throughout this handbook.
The repository
Live configuration lives in a SQLite database at
/etc/svc/repository.db, owned by the svc.configd daemon. You never edit it
directly — you go through svccfg. svc.startd is the master restarter that
actually runs services and enforces dependencies.
Commands you use every day
svcs — list and inspect
svcs # all enabled instances and their state
svcs -a # include disabled instances
svcs ssh # one service
svcs -x # explain anything not running that should be
svcs -p svc:/network/ssh:default # show the processes of a service
svcs -l svc:/network/ssh:default # long form: deps, method, log location
svcs -d svc:/network/ssh:default # dependencies
svcs -D svc:/network/ssh:default # dependents
svcs -x is the single most useful command when something is wrong — it walks
the dependency graph and tells you which service is blocking and where its log
is.
svcadm — change state
pfexec svcadm enable svc:/network/ssh:default # start now + on boot
pfexec svcadm enable -t svc:/network/ssh:default # start now, not persistent (-t = temporary)
pfexec svcadm disable svc:/network/ssh:default # stop now + on boot
pfexec svcadm restart svc:/network/ssh:default # restart
pfexec svcadm refresh svc:/network/ssh:default # reread config (like SIGHUP)
pfexec svcadm clear svc:/network/ssh:default # clear maintenance, retry
pfexec svcadm milestone milestone/multi-user-server # move the whole system
svcadm clear is how you retry a service that landed in maintenance after you
have fixed the cause.
svccfg — edit configuration and manifests
pfexec svccfg import /path/to/service.xml # import/update a manifest
pfexec svccfg export svc:/network/ssh:default # dump current config as XML
svccfg -s svc:/network/ssh:default listprop # list an instance's properties
pfexec svccfg -s svc:/network/ssh:default \
setprop config/listen_port = integer: 2222 # change a property
pfexec svcadm refresh svc:/network/ssh:default # make the change take effect
Logs
Each service instance has its own log — this is where a start-method’s stdout and stderr go:
/var/svc/log/<fmri-with-slashes-as-dashes>.log
# e.g. /var/svc/log/network-ssh:default.log
svcs -l <fmri> prints the exact logfile path. The workflow for a failed
service is almost always:
svcs -x # 1. what is broken and why
svcs -l svc:/network/ssh:default # 2. find its log
tail /var/svc/log/network-ssh:default.log # 3. read the actual error
The system-wide boot/service log is /var/svc/log/svc.startd.log.
How solnix manages services
The NixOS module system is reused verbatim, but the service layer is replaced.
Where NixOS has systemd.services.<name>, solnix has:
smf.services.<name> = {
# declarative description: command, dependencies, environment, restart policy
};
The module renders the SMF XML manifest and the method script from that
declaration into the system closure, and the activation step runs
svccfg import followed by svcadm to bring the system to the target milestone
(multi-user-server). This is the direct analog of nixbsd rendering rc.conf +
/etc/rc.d entries and driving the FreeBSD rc system.
The key asymmetry with NixOS on Linux: SMF is already running when the
activation script executes. solnix is not the init system — svc.startd is.
solnix feeds the init system a manifest and asks it to converge. That keeps
the module small and means a solnix generation switch is “import the new
manifests, converge to the milestone,” not “become PID 1.”
Further reading
- SMF
smf(7)— the concept manual page. svcs(1),svcadm(8),svccfg(8)— command references.- See Debugging for diagnosing failed services with
svcs -x. - See Further reading & resources for the canonical SMF admin guides.
ZFS storage
ZFS (OpenZFS) is the illumos filesystem and volume manager, and the substrate
solnix’s upgrade model is built on. If you come from NixOS you may have used ZFS
as an optional root filesystem; on illumos it is the filesystem — the root
pool, the swap, the dump device, and every boot environment live on it. This
page covers the concepts (pools, datasets, snapshots, clones) and the zpool
and zfs commands you need, then ties it back to
boot environments.
On illumos generally ZFS is mature and load-bearing — illumos is a founding OpenZFS platform. On solnix ZFS is inherited from the illumos gate; the commands below are the real illumos commands. What is planned on solnix is the tooling that ties Nix generations to ZFS boot environments (see that page).
The model: pools and datasets
Traditional systems layer a filesystem on a partition on a disk. ZFS collapses
that: you build a pool (a zpool) out of one or more devices with a chosen
redundancy, and then create datasets inside the pool that draw from its
shared free space on demand. There are two kinds of dataset:
- Filesystems — mountable trees of files (most datasets).
- Volumes (zvols) — block devices carved from the pool, used for swap, the crash-dump device, and zone/VM disks.
The root pool is conventionally named rpool. Boot environments live under
rpool/ROOT/.
zpool — manage pools
zpool list # pools, size, health, capacity
zpool status # per-device health, errors, scrub progress
zpool status -v # verbose, lists any damaged files
pfexec zpool scrub rpool # verify every block against its checksum
pfexec zpool create tank mirror c1t0d0 c1t1d0 # a mirrored pool
zpool status is your first stop for disk health. A scrub reads every block
and checks it against its checksum; in a redundant pool it repairs bad blocks
from the good copy automatically (“self-healing”). Scrub on a schedule.
Redundancy is chosen at pool creation — mirror, raidz, raidz2, raidz3 —
and ZFS integrates the volume-manager job (which disks, what redundancy) with
the filesystem, so it always knows which copy is good.
zfs — manage datasets
zfs list # datasets, used/avail/refer, mountpoint
zfs list -t snapshot # snapshots
pfexec zfs create rpool/data # a new filesystem dataset
pfexec zfs set compression=on rpool/data # a property
zfs get all rpool/data # every property of a dataset
Datasets have properties (compression, quota, mountpoint, recordsize, …) that are inherited down the tree unless overridden — a clean way to manage a hierarchy of filesystems from one place.
Snapshots
A snapshot is a read-only, point-in-time image of a dataset. It is copy-on-write, so it costs nothing at creation and grows only as the live dataset diverges from it.
pfexec zfs snapshot rpool/data@before-upgrade # take a snapshot
zfs list -t snapshot rpool/data # list them
pfexec zfs rollback rpool/data@before-upgrade # revert the dataset to it
pfexec zfs destroy rpool/data@before-upgrade # remove a snapshot
You can browse a snapshot’s contents read-only under the dataset’s hidden
.zfs/snapshot/<name>/ directory without rolling back — handy for recovering
one file.
Clones
A clone is a writable dataset created from a snapshot; it shares the snapshot’s blocks copy-on-write and only consumes space as it is written to. Clones are the mechanism behind boot environments:
pfexec zfs clone rpool/data@snap rpool/data-copy
send / receive — replication and backup
A snapshot can be serialized to a byte stream and applied elsewhere — the same pool, another disk, or another machine over the network:
pfexec zfs send rpool/data@snap | pfexec zfs receive tank/data
# incremental, only the delta between two snapshots:
pfexec zfs send -i @snap1 rpool/data@snap2 | ssh host pfexec zfs receive tank/data
This is the foundation of ZFS backup and disaster recovery — full and incremental, verifiable end to end.
How this ties to boot environments
Everything on the ZFS boot environments page is these primitives applied to the root filesystem:
- A boot environment is a dataset under
rpool/ROOT/. - Creating a BE takes a snapshot of the current root and makes a clone of it — which is why it is instant and nearly free.
- The clones share blocks, so twenty generations do not cost twenty full roots.
beadmis a convenience layer over exactly thesezfsoperations, aware of the boot loader.
So the same integrity guarantees (checksums, scrub, self-healing) and the same
send/receive backup story that protect your data also protect your
generations.
Further reading
zpool(8)·zfs(8)— command references.- ZFS boot environments — snapshots and clones as the upgrade mechanism.
- Further reading & resources — the canonical ZFS admin guide.
ZFS boot environments
illumos ships a native atomic-upgrade story that predates and closely mirrors
NixOS’s generations: boot environments (BEs), managed with beadm. A boot
environment is a bootable clone of the root filesystem living on its own ZFS
dataset. solnix maps each Nix generation onto a boot environment, so the
mental model you already have from NixOS transfers almost directly.
On illumos generally
beadmand ZFS boot environments are mature and are how every illumos distribution does upgrades and rollback. On solnix the generation-to-BE mapping in the activation path is planned (there is no bootable image yet — see Introduction); thebeadmcommands below are the real illumos commands and work on any illumos host.
The NixOS analogy (read this first)
If you run NixOS, you already understand boot environments — they are the same idea with a different mechanism:
| NixOS on Linux | solnix on illumos |
|---|---|
Generation (a /nix/store system closure) | Nix generation → one ZFS boot environment |
nixos-rebuild switch | build config → create + activate a new BE |
| GRUB submenu of past generations | boot loader menu of past BEs |
| Roll back = pick an older generation | Roll back = beadm activate an older BE, or pick it at boot |
nix-collect-garbage frees old generations | beadm destroy removes old BEs |
| Copy-on-write nothing (store paths shared) | ZFS clones share blocks (cheap) |
The important difference: on Linux the bootloader points at a kernel + initrd + store path; on illumos the bootloader points at a whole bootable root dataset (the BE). ZFS makes that whole-root switch as cheap as NixOS’s per-path sharing, because a new BE is a clone, not a copy.
What a boot environment is
A BE is a ZFS dataset (under rpool/ROOT/ by convention) containing a complete,
bootable root filesystem. Because ZFS clones are copy-on-write, creating a new
BE from the running one:
- costs almost no space initially (blocks are shared),
- is near-instant,
- leaves the current BE completely untouched and independently bootable.
You can have many BEs on one pool. Exactly one is active (the default boot target); you can also boot a non-active BE once without changing the default.
The beadm commands
List
beadm list
BE Active Mountpoint Space Policy Created
solnix-1 N / 8.1G static 2026-01-10 09:14
solnix-2 NR / 2.3G static 2026-01-12 11:02
The Active column: N = active now (the running BE), R = active on reboot
(the default boot target), NR = both. beadm list -a shows the datasets and
snapshots that make up each BE.
Create
pfexec beadm create solnix-3 # clone the running BE
pfexec beadm create -e solnix-1 solnix-3 # clone from a specific BE
Creating a BE does not activate it — the running system is unaffected.
Activate
pfexec beadm activate solnix-3
Sets solnix-3 as the default boot target (R). It takes effect on the next
reboot; the current system keeps running until then. This is the atomic switch:
nothing on the live root is mutated.
Boot once without activating
At the boot loader menu you can select any BE for a single boot without making
it the default — the illumos equivalent of picking an old NixOS generation from
the GRUB submenu. If it works, beadm activate it; if not, reboot back to the
default.
Destroy
pfexec beadm destroy solnix-1
Removes a BE and its datasets. You cannot destroy the currently running BE. This is the analog of garbage-collecting old NixOS generations.
Mount / unmount (inspect without booting)
pfexec beadm mount solnix-3 /mnt
# inspect /mnt ...
pfexec beadm unmount solnix-3
Useful for comparing two generations or repairing one from another.
Snapshots and BEs
A BE is built on ZFS snapshots and clones (see ZFS storage). Two things follow:
- Creating a BE takes a snapshot of the source root and clones it. The snapshot is what makes the operation cheap and instant.
beadm create solnix-3@backup(name with@) creates a snapshot of a BE rather than a new BE — a point-in-time marker you can later turn into a BE.
Because it is all ZFS underneath, the same integrity, zfs send/receive, and
scrub guarantees that protect your data protect your boot environments too.
Safe upgrade and rollback, end to end
The upgrade cycle solnix targets, framed the NixOS way:
- Build a new system configuration → a new Nix generation.
- Create a boot environment for that generation (
beadm create). - Populate the new BE with the generation’s closure.
- Activate the new BE (
beadm activate) — a boot-target change, not an in-place mutation. - Reboot into the new generation. The previous BE remains bootable and untouched.
- Roll back if needed: boot the previous BE from the loader menu, or
beadm activateit and reboot. No packages to reinstall, no state to unwind — you are back on the exact prior root.
The properties that make this worth it:
- Atomic — the switch is a single pointer change; a power loss mid-upgrade leaves you on the old, intact BE.
- Instant rollback — the previous root is right there, bootable.
- Cheap — clones share blocks, so twenty generations do not cost twenty full roots.
Boot loader integration
illumos on x86 uses the loader (the FreeBSD-derived boot2/loader,
replacing the older GRUB on modern distributions); SPARC uses OpenBoot. Either
way, beadm activate updates the loader’s default and the menu lists the
available BEs, so choosing an older generation at boot is a menu selection. This
is the mechanism illumos already ships and trusts — solnix reuses it rather than
inventing a bootloader story.
Further reading
beadm(8)— the command reference.- ZFS storage — the snapshots and clones BEs are built on.
- How solnix is built — how generations map into the system.
- Further reading & resources — canonical ZFS/BE admin guides.
DTrace
DTrace is illumos’s dynamic tracing framework: a single tool that instruments the entire system — kernel and userland — safely enough to run on production. It was invented at Sun and is one of the reasons people run illumos at all. For a solnix user, DTrace is the observability answer to “what is this Nix-built binary actually doing on this machine, right now, without a rebuild.”
On illumos generally DTrace is mature, safe, and load-bearing. On solnix DTrace is inherited from the illumos gate; the one-liners below are real DTrace. Getting a full solnix system to the point where you are tracing your own services is gated on the bootstrap (see Introduction) — but the framework itself is not solnix’s to build.
What it is
DTrace exposes tens of thousands of instrumentation points (probes) across
the kernel and userland. Every probe is dormant and costs nothing until you
enable it. You write small scripts in the D language — a C-like language
with awk-style pattern/action structure — that say “when this probe fires, in
this context, do this.”
A probe is named by four parts:
provider:module:function:name
For example syscall::open:entry (the entry to the open syscall) or
proc:::exec-success (a process successfully exec’d). Leaving a field blank
matches all values, so syscall:::entry matches the entry of every syscall.
Providers
Providers are the sources of probes. The ones you reach for first:
| Provider | What it traces |
|---|---|
syscall | Every system call, entry and return. |
proc | Process lifecycle: exec, fork, exit, signals. |
profile | A timer — sample all CPUs at a fixed rate (profiling). |
pid | Any function or instruction in a specific userland process. |
fbt | Function boundary tracing in the kernel (every kernel function). |
io | Block-device I/O — sizes, latency, which device. |
sched | Scheduler events — on-cpu, off-cpu, run-queue. |
The pid provider is how you trace your program’s functions with zero
instrumentation compiled in — DTrace attaches to the live process.
A few one-liners
Which programs are being executed, system-wide:
pfexec dtrace -n 'proc:::exec-success { trace(curpsinfo->pr_psargs); }'
Count system calls by process name for a few seconds, then print a table:
pfexec dtrace -n 'syscall:::entry { @[execname] = count(); }'
Files being opened, and by whom:
pfexec dtrace -n 'syscall::open*:entry { printf("%s %s", execname, copyinstr(arg0)); }'
A latency distribution (a quantize power-of-two histogram) of read syscalls:
pfexec dtrace -n 'syscall::read:entry { self->t = timestamp; }
syscall::read:return /self->t/ { @ = quantize(timestamp - self->t); self->t = 0; }'
Sample kernel stacks at 997 Hz to see where CPU time goes:
pfexec dtrace -n 'profile-997 { @[stack()] = count(); }'
Aggregations (@) are DTrace’s headline feature: they sum/count/quantize in the
kernel and only ship the summary to userland, so tracing a busy system stays
cheap.
Safety — why you can run this in production
DTrace was designed from the start to be safe on live systems, and this is not a footnote — it is the reason it exists:
- Probes are zero-cost when disabled and cheap when enabled.
- The
Dlanguage has no loops and no arbitrary memory writes — a DTrace script cannot hang or corrupt the kernel. - Accessing userland memory goes through safe copy-in (
copyinstr, etc.) that faults gracefully instead of panicking. - There are tunable limits on buffers and drops so a misbehaving script degrades (drops records) rather than harming the system.
This is what lets you point DTrace at a production process and ask hard questions without a maintenance window.
Why it matters for solnix
On a Nix system the software layer is immutable, reproducible store paths — great for building correctly, silent about runtime behavior on real hardware and real load. DTrace is the missing half: it tells you what a store-path binary does when it runs — which syscalls, which files, where the latency and CPU actually go — with no rebuild and no restart. It pairs naturally with MDB and core-file analysis for the post-mortem case.
Further reading
dtrace(8)— command reference.- Debugging — DTrace alongside MDB, core files, and crash dumps.
- Further reading & resources — the DTrace book and the one-liner collections.
Zones
Zones are illumos’s OS-level virtualization: isolated environments that share one kernel but each have their own filesystem, process table, users, network stack, and resource limits. They predate Linux containers by years and are, in several ways, what containers grew up to imitate — with stronger isolation and first-class integration with ZFS, DTrace, and the fault management architecture.
On illumos generally zones are mature and heavily used (SmartOS runs essentially everything in zones). On solnix zones are inherited from the illumos gate, but solnix’s own declarative zone tooling is early / not yet built — only a preview image exists so far (see Introduction), let alone a
solnix.zones.*module. This page describes the illumos feature and the intended solnix relevance honestly, not a shipped capability.
What a zone is
A zone is a walled-off slice of one running illumos kernel. From inside, it looks like its own machine: its own root filesystem, its own processes and PIDs, its own users and hostname, its own network interfaces. From outside (the global zone), the operator sees and controls every zone. Because all zones share the single kernel, there is no hypervisor overhead — starting a zone is closer to starting a process than booting a VM.
- Global zone — the base OS; it owns the hardware and administers all other zones.
- Non-global zones — the isolated environments you create.
Branded zones
A zone’s brand determines the userland and syscall environment it presents:
- Native (
illumos/ipkg) zones — a normal illumos environment. - LX-branded zones — present the Linux system-call interface, so most Linux binaries run unmodified on the illumos kernel. This is how illumos distributions run Linux workloads without a VM. solnix plans to pull LX support in from SmartOS — see LX-branded zones.
Isolation and integration
Zones are not just namespaces bolted on — they are wired into the rest of the platform:
- ZFS — a zone typically lives on its own dataset, so snapshots, clones, and quotas apply per zone. See ZFS storage.
- Virtual networking — Crossbow creates a virtual NIC (VNIC) per zone; the zone gets a real, isolated network stack. Put the VNICs on an etherstub for a private network between zones.
- Resource controls — CPU, memory, and process caps are enforced per zone.
- DTrace — from the global zone you can trace across zones; a zone can be granted limited DTrace on itself. See DTrace.
- SMF — each zone runs its own SMF instance and service graph. See SMF services.
Brief usage (on any illumos host)
Zone administration is zonecfg (define) then zoneadm (install / boot /
manage):
pfexec zonecfg -z web # interactively define a zone named "web"
pfexec zoneadm -z web install
pfexec zoneadm -z web boot
zoneadm list -cv # list all zones and their state
pfexec zlogin web # get a shell inside the zone
pfexec zoneadm -z web halt # stop it
solnix relevance
Zones are an obvious fit for reproducible, Nix-built environments — a native zone
whose entire userland is a set of /nix/store paths, created and torn down
declaratively, would be the illumos analog of a NixOS container. That is a
natural direction for solnix but it is not built yet: the prerequisites are
a working native solnix system (the bootstrap, see
How solnix is built) and an SMF module, both of which
come first. Treat zones today as “a powerful illumos feature solnix will be able
to exploit,” not “a solnix feature.”
Further reading
zones(7)·zonecfg(8)·zoneadm(8)— references.- LX-branded zones — running Linux binaries in a zone, and the solnix roadmap for it.
- Networking (Crossbow) — how per-zone networking is built.
- illumos features — zones in context with ZFS, DTrace, SMF, and FMA.
- Further reading & resources — zone administration guides.
LX-branded zones (Linux on illumos)
illumos zones come in brands — a brand decides which userland and system-call environment a zone presents. The most interesting brand for a mixed shop is the LX brand: an LX-branded zone presents the Linux system- call interface, so unmodified Linux binaries run directly on the illumos kernel — no virtual machine, no emulation of a whole CPU, no second kernel.
On illumos generally LX zones are a real, shipping feature — SmartOS runs Linux workloads this way in production. On solnix LX support is a roadmap item, not yet built (see the solnix plan below). This page describes the feature and the plan honestly; nothing here is a shipped solnix capability.
What an LX-branded zone is
A native zone runs illumos userland on the illumos kernel. An LX zone runs a
Linux userland (a Linux distribution’s files — Debian, Alpine, etc.) on the
same illumos kernel. The trick is a brand: a thin translation layer that
implements the Linux system-call ABI in terms of illumos kernel facilities. When
a Linux binary in the zone calls, say, epoll_create or clone, the LX brand
maps it to the illumos equivalent.
The result:
- Linux ELF binaries run as-is — no recompilation, no
patchelf, no VM. - Only one kernel runs (the illumos kernel), so there is no hypervisor overhead and no second OS to manage. It is a zone, with a zone’s near-native performance.
- The zone still gets full illumos integration underneath — a ZFS dataset, a Crossbow VNIC, resource controls, and observability from the global zone with DTrace.
Compare the alternatives: a Linux VM (bhyve/KVM) runs a whole second kernel and pays for it; QEMU user-mode emulation is slow. The LX brand is neither — it is a syscall-translation shim, so Linux processes are just illumos processes wearing a Linux ABI.
How SmartOS pioneered the modern LX brand
An early lx brand existed in OpenSolaris but bit-rotted. The modern LX
brand — the one that runs contemporary 64-bit Linux distributions — was built
and is maintained by the SmartOS community (Joyent, now MNX). SmartOS’s
whole model is “everything in a zone,” and LX zones let it run the vast catalog
of Linux software (and Linux Docker images, via its Docker-to-zone layer)
alongside native illumos zones on one kernel. That work lives in illumos-gate
and the SmartOS platform, and is the reference implementation of LX today.
The solnix plan (roadmap)
solnix intends to pull LX-zone support in from SmartOS so that a solnix machine can run Linux workloads alongside native illumos ones — without a VM. The intent, stated plainly:
- Bring the SmartOS LX brand into solnix so Linux binaries run in an LX zone on a solnix host.
- Let users run Linux Docker-style workloads / Linux-only binaries that have no illumos build, next to native solnix (illumos + Nix) zones, on the same kernel.
- Eventually wire this into solnix’s declarative model — a Nix-described LX zone,
the same way native zones are a natural target for a
solnix.zones.*module (see Zones).
Why it matters
Not everything has an illumos build. An LX zone means you do not have to choose between “illumos-native” and “the Linux software I need” — you run the Linux thing in an LX zone and the illumos-native things in native zones, one kernel, one machine, full observability across all of it. For a solnix user that is the difference between “illumos for the workloads that have illumos builds only” and “illumos as a general-purpose host that also runs your Linux workloads.”
Honest status
This is not in solnix today. The prerequisites come first: a bootable native solnix system (the bootstrap — see How solnix is built) and the zone tooling generally (Zones is early). Pulling in the SmartOS LX brand is a stated direction, not a shipped feature. Treat LX-on-solnix as “planned, and here is why we plan it,” not “available now.”
Further reading
- Zones — native zones and brands in general; the foundation LX builds on.
- Networking (Crossbow) — the per-zone VNICs an LX zone gets.
- illumos features — zones and the rest of the platform in context.
- SmartOS documentation — the reference LX-brand implementation and Linux-workload guides.
Networking (Crossbow)
illumos does not bolt virtual networking on as an afterthought — it ships an integrated network-virtualization stack in the kernel called Crossbow. Crossbow turns the network stack into something you carve up the way ZFS carves up storage: virtual NICs, virtual switches, and bandwidth/flow controls, all first-class and all administered with a small set of commands. It is the plumbing under per-zone networking.
On illumos generally Crossbow has been part of the platform since OpenSolaris (2009) and is mature and load-bearing — every zone’s network comes through it. On solnix Crossbow is inherited from the illumos gate; the
dladm/flowadm/ipadmcommands below are the genuine illumos commands and work on any illumos host. What is not yet built on solnix is a declarativesolnix.networking.*Nix module that renders these from config — that is a roadmap item, like the SMF module. Today you configure networking imperatively with the commands below, the same as on any illumos system.
For the Linux admin: what Crossbow replaces
If you came from Linux, you assembled virtual networking from several independent tools. Crossbow unifies that same functionality — and it did so years earlier:
| You’d reach for (Linux) | On illumos (Crossbow) |
|---|---|
ip link add … type veth / tap | dladm create-vnic (a virtual NIC) |
brctl / ip link add … type bridge | dladm create-etherstub (a virtual switch) |
ip link set … master br0 | VNICs created over an etherstub share it |
network namespaces (ip netns) | zones get their own VNICs |
tc (traffic shaping / rate limits) | dladm set-linkprop maxbw / flowadm |
ip addr / ip route | ipadm (IP addresses and interface config) |
VLAN subinterfaces (ip link … type vlan) | dladm create-vlan |
| bonding / LACP | dladm create-aggr (link aggregation) |
The mental model is close, but Crossbow is one coherent stack rather than a
half-dozen loosely related tools, and the datalink/IP split (dladm for links,
ipadm for IP) is cleaner than Linux’s overloaded ip.
The three command families
illumos splits network administration by layer:
dladm— the datalink layer (layer 2): physical NICs, VNICs, etherstubs, VLANs, aggregations, and per-link properties (MTU, MAC, bandwidth caps).ipadm— the IP layer (layer 3): addresses, interface configuration, and tunables. (This replaced the oldifconfig.)flowadm— flows: policy on classified traffic (by port, protocol, address), including bandwidth limits and priorities finer-grained than a whole-link cap.
dladm — datalinks
List every datalink and its state:
dladm show-link
dladm show-phys # physical NICs only
dladm show-vnic # virtual NICs only
Create a VNIC over a physical NIC (this is the workhorse — every zone gets one):
pfexec dladm create-vnic -l net0 vnic0
Create an etherstub (a virtual switch with no physical uplink) and hang VNICs off it — this is how you build an isolated internal network between zones, with no external connectivity unless you add it:
pfexec dladm create-etherstub stub0
pfexec dladm create-vnic -l stub0 vnic_a
pfexec dladm create-vnic -l stub0 vnic_b
# vnic_a and vnic_b can now talk to each other, and nothing else
Set a bandwidth cap on a link (the simple, whole-link rate limit):
pfexec dladm set-linkprop -p maxbw=100M vnic0 # cap vnic0 at 100 Mbit/s
dladm show-linkprop -p maxbw vnic0 # check it
Other common link operations:
pfexec dladm create-vlan -l net0 -v 42 vlan42 # VLAN tag 42 on net0
pfexec dladm create-aggr -l net0 -l net1 aggr0 # LACP aggregation of two NICs
pfexec dladm set-linkprop -p mtu=9000 net0 # jumbo frames
pfexec dladm delete-vnic vnic0 # tear a VNIC down
ipadm — IP configuration
Once a datalink exists (physical or virtual), ipadm gives it an IP:
ipadm show-if # list IP interfaces
pfexec ipadm create-if vnic0 # bring vnic0 up as an IP if
pfexec ipadm create-addr -T static \
-a 192.0.2.10/24 vnic0/v4 # static IPv4 address
pfexec ipadm create-addr -T dhcp vnic0/dhcp # or DHCP
ipadm show-addr # list all addresses
pfexec ipadm set-prop -p forwarding=on ipv4 # enable IP forwarding
flowadm — flows and finer bandwidth control
A flow classifies a subset of a link’s traffic and applies policy to it —
more surgical than the whole-link maxbw:
# Cap only HTTPS traffic on vnic0 to 50 Mbit/s
pfexec flowadm add-flow -l vnic0 \
-a transport=tcp,local_port=443 -p maxbw=50M https-flow
flowadm show-flow # list flows
flowadm show-flowprop https-flow # its properties
pfexec flowadm remove-flow https-flow # remove it
Flows are how you say “throttle backups but not interactive traffic” or “give this service priority” without touching the rest of the link.
How Crossbow underpins zones
Crossbow is why zones get real, isolated network stacks rather than shared plumbing. The usual pattern:
- Create a VNIC per zone (
dladm create-vnic -l net0 zoneA0). - Assign that VNIC to the zone in its
zonecfg(ananet/netresource). - Inside the zone, that VNIC looks like a dedicated physical NIC — the zone has
its own IP, routing, and firewall (
ipfilter), fully isolated from the global zone and other zones.
Put the zones’ VNICs on an etherstub instead of the physical NIC and you
have a private virtual network between zones with no external exposure — the
illumos equivalent of a Docker bridge network or a set of namespaces on a
veth bridge, but built into the OS and older than either.
Firewalling
Packet filtering is a separate subsystem, ipfilter (ipf/ipnat),
configurable globally and per zone. It is the illumos analog of
iptables/nftables. Crossbow shapes and switches; ipfilter filters and NATs.
solnix status, honestly
- The Crossbow stack itself is real and inherited from the gate — it works on any illumos host today.
- Declarative solnix networking is not built yet. There is no
solnix.networking.*module renderingdladm/ipadm/flowadmstate from Nix; that waits on a bootable solnix system (see How solnix is built) and follows the same pattern as the planned SMF module. Until then, configure networking with the commands above.
Further reading
dladm(8)·ipadm(8)·flowadm(8)— command references.- Zones — how per-zone networking is wired on top of Crossbow.
- For Linux (and NixOS) users — the Linux-to-illumos networking mapping in context with the rest of the platform.
- Further reading & resources — network administration guides.
How solnix is built
solnix reuses NixOS’s evaluator and module system verbatim, then retargets everything below it to illumos. This is nixbsd’s playbook applied to a different kernel and userland: keep the Nix language, the store, and the module system; replace the OS the packages target. This page describes the layers — the illumos gate, kernel versus userland, how Nix sits on top, and the two toolchains — for a reader who knows Nix/NixOS but is new to illumos.
The illumos gate
illumos is distributed as illumos-gate: a single source repository holding
the kernel, the core libraries, the link-editor and runtime linker, and the
base userland (libc, the C runtime, the ELF/CTF tools, svc.startd, and so on)
— all built together as one coherent tree. Downstream distributions (OmniOS,
OpenIndiana, SmartOS) take the gate and add packaging, installers, and extra
software on top.
solnix is one such downstream, but instead of a traditional package manager it uses Nix. The gate provides the kernel and the load-bearing userland pieces that must match the kernel’s ABI; Nix provides everything above that and the mechanism for building, distributing, and activating it.
Bootstrap constraint (stated honestly): illumos-gate does not cross-build from Linux. The bootstrap must start on an illumos host — a stage0 seed toolchain, extracted from a gate build, has to run natively on illumos before Nix can take over. See “Seed toolchain” below.
Kernel versus userland
Two boundaries matter on illumos and they shape how Nix layers on:
- The kernel (
unix,genunix, and modules) is inherited from the gate. It provides the system-call interface, ZFS, DTrace, zones, and the fault management architecture. solnix does not rebuild the kernel with Nix in the general case; it is part of the platform the seed and the boot environment carry. - The userland splits into a load-bearing base —
libc.so.1, the runtime linkerld.so.1, the C runtime objects, the link-editorld, and the SMF machinery — which must be ABI-compatible with the kernel, and everything else, which is ordinary software Nix can build and place in/nix/store.
solnix packages the load-bearing base as a fine-grained world so that even the lowest layers are Nix-managed store paths, then builds the rest the normal Nix way.
How Nix layers on illumos
Platform tuple
Add x86_64-solaris (GNU triple x86_64-unknown-solaris2.11) to a nixpkgs
fork. nixpkgs already carries partial Solaris support — kernels.solaris,
isSunOS, and an ld-solaris-wrapper — which is load-bearing for the
bootstrap. The other targets follow the same pattern; see
CPU architecture support.
pkgs.solnix.* — the fine-grained world
A dedicated package world holds the base illumos pieces as individual Nix derivations:
pkgs.solnix.libc— the Solarislibc.so.1(not glibc).pkgs.solnix.rtld— the runtime linkerld.so.1.pkgs.solnix.ld— the Solaris link-editor.pkgs.solnix.sys— the base tools and headers needed to reach multi-user.
These are the “world slices”: libc, rtld, ld, sys. Everything else in the solnix
package set builds against them. (Use pkgs.solnix.*, not pkgs.illumos.*.)
Seed toolchain (stage0)
Because the gate cannot cross-build from Linux, the bootstrap begins with a
relocatable seed tarball extracted from an illumos-gate build: a compiler, a
linker, libc, the C runtime objects (crt), headers, the runtime linker, and the
ELF/CTF tools. It is unpacked into /nix/store and used to build a native Nix
stdenv on the illumos host. Once that native stdenv exists, the seed is never
referenced again — every later package is built by the Nix-native toolchain,
and its outputs land in the binary cache so no one rebuilds
them.
RUNPATH with the Solaris link-editor
Nix’s whole model depends on baking absolute /nix/store paths into binaries so
they find their exact dependencies. On solnix this is done with the Solaris
link-editor writing ELF RUNPATH, and inspected with elfdump — no GNU
tooling. This is a real divergence from Linux nixpkgs, which leans on GNU ld
and patchelf; on solnix the native ld and elfdump do the equivalent work.
Init and generations
- Init is SMF, not systemd. solnix renders SMF manifests and drives
svc.startdon activation. See SMF services. - Generations map onto ZFS boot environments — each Nix generation is a bootable BE, giving atomic upgrade and instant rollback. See ZFS boot environments.
The two toolchains
illumos-gate historically builds with a specific compiler, and modern illumos work supports both GCC and Clang. solnix carries two toolchains:
- GCC 14 (current pin) — the primary toolchain, matching the direction illumos-gate has moved for its main build.
- Clang 21 (current pin) — the alternate toolchain, useful for code that expects Clang and for cross-checking correctness/diagnostics.
Carrying both is deliberate: it keeps solnix honest about portability and gives package authors a fallback when one compiler chokes on illumos-specific code. The seed toolchain provides whichever compiler the stage0 gate build shipped; the Nix-native stdenv then rebuilds GCC 14 and Clang 21 (current pins) as ordinary packages.
Why this order matters
illumos-gate does not cross-build from Linux, so the bootstrap must start on an illumos host. Once a native Nix stdenv exists on illumos, the rest of the package set builds the usual Nix way — and those artifacts land in the binary cache so the community never rebuilds them. The architecture is, in one line: inherit the kernel and load-bearing userland from the gate, Nix-manage everything from libc up, activate through SMF and boot environments.
Further reading
- illumos features — the platform capabilities solnix inherits (ZFS, DTrace, SMF, zones, FMA).
- CPU architecture support — the four CPU targets and status.
- The binary cache — where built artifacts go.
CPU architecture support
The solnix OS is a supported distribution of illumos aimed at four CPU
targets — x86_64, aarch64, RISC-V, and SPARC — across both
server and desktop use, and optimized for virtualized hosting on the major
cloud platforms (AWS/EC2, Microsoft Azure, Google Cloud, and the rest). That
is the design target; this page states current support honestly — the table
reflects reality, not aspiration. Only x86_64 is a working primary target; the
others are at various stages of bring-up, and desktop is a future core-team
goal. This page gives the status of each CPU target, what “bring-up” means for
it, and how cross-compilation fits in.
The four targets
| Arch | Platform tuple | Status | Cache | Phase |
|---|---|---|---|---|
| x86_64 (amd64) | x86_64-solaris | Primary target | live | 1 |
| aarch64 | aarch64-solaris | Out-of-tree illumos port exists; integrate it | live | 3 |
| SPARC v9 (sun4v) | sparcv9-solaris | Bit-rotting in-gate; revive with fork patches | live | 4 |
| RISC-V | riscv64-solaris | Kernel boots to a shell (try it in your browser); no builder/cache yet | planned | 5 |
amd64 first, always. No phase starts before the previous phase’s gate is green. This is the same honesty stance the binary cache takes: platforms without a builder yet appear as “no objects yet,” never as coverage that does not exist.
What each status means
x86_64 (amd64) — primary
The reference platform. illumos-gate builds natively on amd64, the seed toolchain is extracted here, and this is where the Nix-native stdenv comes up first. Everything in the roadmap is validated on amd64 before any other arch starts. If a solnix feature works anywhere, it works here first.
aarch64 — integrate the existing port
There is an out-of-tree illumos aarch64 effort. The work is not “port illumos to ARM from scratch” but “integrate that port and bring a Nix-native stdenv up on it.” The cache line is live because it can serve Linux cross-build artifacts today (see cross-compilation below); illumos-native aarch64 objects light up when an aarch64 builder is running.
SPARC v9 (sun4v) — revive
SPARC support exists in illumos-gate but has bit-rotted from disuse. Bringing it back means fork patches to get the gate building again for sun4v, then the usual seed-and-bootstrap path. This is later in the roadmap (Phase 4) precisely because it is revival work, not integration.
RISC-V — planned
No illumos RISC-V port exists yet in a usable state; this is the furthest-out target (Phase 5). Listed so the intent is clear, marked planned so no one mistakes it for working.
Cross-compilation notes
There are two distinct build directions and they matter for how the cache is populated per arch:
- Linux → target (cross). nixpkgs can cross-compile many packages from a Linux builder to a Solaris target tuple. This is what lets the cache line read live for arches whose native builder is not yet running: the cross-built artifacts are real, signed, and installable. It does not cover the load-bearing base or anything that needs a native illumos build — the gate does not cross-build from Linux (see How solnix is built).
- Native (illumos host). The seed toolchain and the load-bearing
pkgs.solnix.*world must be built natively on an illumos host of that arch. This is the gated part: an arch is only fully supported once a native builder for it exists.
So “Cache: live” for a non-primary arch means “cross-build artifacts are available”; full native coverage arrives with a native builder, and the cache never advertises coverage it does not have.
Further reading
- How solnix is built — how the platform tuple, seed toolchain, and native stdenv fit together.
- The binary cache — per-arch coverage and how artifacts are distributed.
- Contributing — every arch needs a builder; this is the most direct way to help.
Peer-to-peer distribution
solnix distributes both its binary cache and this website peer-to-peer, so the more people use solnix, the faster and cheaper it gets for everyone — bandwidth scales with the community instead of with one origin’s egress bill.
Both forms of sharing are governed by the same privacy master switch as telemetry; see Privacy, telemetry & the community pulse.
Cache objects over BitTorrent
Each cache artifact (NAR) is distributed as a torrent, seeded by the hub and by other solnix users. When you have opted in, your machine seeds the public, signed cache artifacts it has fetched to other solnix users:
solnix.cache.seed.enable = true; # default on when you have opted in
- It only ever shares public Nix store paths — never your private data.
- Integrity is enforced by the
cache.solnix.iosignature regardless of where the bytes came from, so a torrented NAR is exactly as trustworthy as one pulled over HTTP.
It complements the HTTP cache — it never replaces it
The narinfo served by cache.solnix.io always carries a plain HTTP URL: as
the guaranteed fallback. A stock nix works today over HTTP; the peer layer is
an enhancement layered on top. If no peer has what you need, Nix simply fetches
it from cache.solnix.io as usual. See The binary
cache.
The site over WebRTC
The solnix website itself can be shared browser-to-browser over WebRTC, so visitors help serve the site to each other. There are two distinct audiences here, governed by two different mechanisms — don’t conflate them:
Website visitors (your browser)
When you open solnix.io in a browser, sharing is off by default. No WebRTC
connection is made until you actively opt in through the consent prompt at the
bottom of the page (“Help serve this site?”). The choice is stored in your
browser (localStorage, key solnix.p2p.consent.v1) and is revocable in one
click from the “P2P sharing” toggle in the footer, on any page.
WebRTC exposes your IP address to the peers you connect to, exactly as any direct peer-to-peer connection does. That is inherent to how a swarm works and is why it is opt-in. It is a different posture from the telemetry promise (“region only, IP dropped at the edge”): the site never collects or stores your IP, but it cannot hide it from your peers. If you don’t turn it on, your browser never peers with anyone. See Privacy.
solnix machines (the OS)
A solnix host can participate in serving the site’s static files too. That is governed by a Nix module option on the machine, not a browser prompt:
solnix.site.p2p.enable = true; # default on once you've opted in (privacy.enable = false)
This is a browser/host enhancement layered on top; the site always loads normally from the origin over HTTP regardless of whether any peer sharing is on.
Opting out
Because both features are gated by the privacy master switch, a machine whose config never touches it does not seed and does not share — the default is fully private. To opt into the community pulse and then pare P2P back:
Note the inversion:
solnix.privacy.enable = falseturns sharing on — it opts you in, it does not disable privacy. See the warning in Privacy.
solnix.privacy.enable = false; # opt in
solnix.cache.seed.enable = false; # ...but don't seed the cache
solnix.site.p2p.enable = false; # ...and don't share the site
The effective rule is the same one telemetry uses:
(not privacy.enable) && <feature>.enable. The master switch always wins. We
state this plainly so no one is surprised to find their machine seeding.
Debugging
illumos has a deep, unusually coherent debugging toolkit — crash dumps, the
modular debugger mdb, DTrace, core files with CTF type data, and the fault
management architecture — and solnix inherits all of it from the
gate. This page walks the common cases: a service that
will not start, a program that crashed, and a system that panicked or hung. It
is adapted from the illumos user guide and framed for a solnix user.
Honest status. solnix is early — only a preview image exists so far (see Introduction), so end-to-end “debug your live solnix box” is not yet an everyday thing. The commands below (
svcs,mdb,savecore,pstack,coreadm,dumpadm,fmadm) are the real illumos commands and work on any illumos host. Where a step is solnix-specific and not built yet, it says so.
Note: commands that need privilege are shown with
pfexec(illumos’s RBAC-backedsudo-equivalent). On some systemssudois used instead.
A service failed to start
This is the most common everyday case and the fastest to diagnose. If something that should be running is not, ask SMF why:
svcs -x
svcs -x walks the service dependency graph and prints, for each broken
service, the state, the likely cause, and the path to its log. Then read that
log:
svcs -l svc:/network/ssh:default # find the logfile: line
tail -50 /var/svc/log/network-ssh:default.log
If the service is in maintenance because it kept failing, fix the cause and
retry:
pfexec svcadm clear svc:/network/ssh:default
See SMF services for the full state model and command set.
A program crashed (core files)
When a userland process crashes, illumos can save a core file — a snapshot of the process’s memory — that you inspect after the fact.
Check the core configuration first:
coreadm
global core file pattern:
global core file content: default
init core file pattern: core
global core dumps: disabled
per-process core dumps: enabled
If per-process core dumps are enabled and the global pattern is empty, a crash
writes a file named core in the process’s working directory. To set a
predictable global location and pattern:
pfexec coreadm -g /var/cores/core.%f.%p -e global -e per-process
# %f = executable name, %p = pid; see coreadm(8) for all specifiers
Read the core file
The quick answer — the stack at the point of the crash:
pstack core
The deep answer — open it in the modular debugger:
mdb core
> ::status # summary: signal, faulting instruction
> $C # C stack backtrace
> ::stack # same, another form
> ::regs # registers at the fault
> $q # quit
Because illumos binaries carry CTF type data, mdb can print structures
with their real field names and types — you are not staring at raw hex. On
solnix the binary is a /nix/store path; mdb resolves its symbols and CTF the
same way it does for any illumos binary, and the store path pins the exact build
that produced the core.
The system panicked or hung (crash dumps)
When the kernel panics, illumos saves a crash dump of kernel memory to the dump device, then reboots. On the next boot you extract and analyze it.
Check the dump configuration:
pfexec dumpadm
Dump content: kernel pages
Dump device: /dev/zvol/dsk/rpool/dump (dedicated)
Savecore directory: /var/crash/<hostname>
Savecore enabled: yes
Save compressed: on
Extract the dump after the reboot:
pfexec mkdir -p /var/crash/`hostname`
pfexec savecore
cd /var/crash/`hostname`
savecore writes unix.<n> (the kernel) and vmcore.<n> (memory). Then pull
the essential post-mortem information into one file with mdb:
echo '::panicinfo
::cpuinfo -v
::threadlist -v 10
::msgbuf
*panic_thread::findstack -v
::stacks' | mdb <n> > ~/crash.<n>
Keep crash.<n> (and, if you can, the dump itself) for a bug report. Note that a
crash dump can contain confidential in-memory data — use judgment before sharing
it publicly.
Forcing a dump from a hung system
If the system is wedged but responsive enough:
pfexec savecore -L # live dump without rebooting
# or
pfexec reboot -d # reboot and force a dump
For a truly frozen box, illumos supports dropping into the kernel debugger
(kmdb) via the boot loader or an NMI; that is advanced and hardware-specific —
see the illumos user guide linked below.
Hardware and diagnosed faults (FMA)
The fault management architecture turns error telemetry into diagnosed faults:
fmadm faulty # currently diagnosed faults and affected components
fmdump # the fault log
fmdump -v # verbose, with the fault event detail
fmstat # fault-manager module statistics
Each fault carries a stable message ID (like ZFS-8000-8A) you can look up. FMA
covers hardware (CPU, memory, disks) and some software faults, and it hands
service faults to SMF — so fmadm faulty and svcs -x together cover “what is
wrong with this machine.”
Live tracing (DTrace)
For behavior on a running system — not a crash — reach for DTrace: which syscalls a process makes, where latency comes from, what is burning CPU, without a rebuild or restart. See DTrace.
Reporting a bug to solnix
When you hit something you believe is a solnix (not upstream illumos) problem, include:
- what you did and what you expected versus what happened;
- the solnix generation / boot environment (
beadm list) so the exact build is identifiable; - the relevant artifact:
svcs -xoutput and the service log for a service failure;pstack/mdboutput for a crash; thecrash.<n>file for a panic;fmadm faultyfor a hardware fault; - the store path(s) involved — a
/nix/storepath pins the exact build, which is the whole point of a reproducible system.
Send it to the development list — see Contributing for the
current channels (hackers@solnix.io, planned). If the bug reproduces on stock
illumos with no Nix involved, it likely belongs upstream at
illumos.org.
Further reading
- Debugging broken systems (illumos user guide)
- Debugging applications (illumos user guide)
mdb(1)·savecore(8)·coreadm(8)·dumpadm(8)·fmadm(8)- SMF services · DTrace · Further reading & resources
Contributing
solnix is early (preview-image stage) and every arch needs builders. Contributions welcome.
Repos
| Repo | What |
|---|---|
codeberg.org/gregburd/solnix-infra | Infra + services (Nix, terranix, k8s) |
codeberg.org/gregburd/solnix-site | This site + handbook |
| solnix (distribution) | illumos + Nix bootstrap, pkgs.solnix.*, modules |
Ways to help
- Port an architecture. Each of aarch64, SPARC v9, and RISC-V needs work — and each needs a builder that can produce artifacts for the cache.
- Package illumos software. Grow
pkgs.solnix.*. - The seed toolchain. Help harden the stage0 extraction from illumos-gate.
- Docs. Every page here has an edit link (top right).
Mailing lists
Development discussion happens on hackers@solnix.io; announcements and the
weekly digest on announce@solnix.io (both planned). Archives will be public
via public-inbox, and a GitGitGadget-style bridge will turn pull requests into
patch series on hackers@ — the model the Git and Linux communities use.
How the community keeps costs sane
The binary cache is distributed peer-to-peer (over BitTorrent): using solnix helps distribute it, so bandwidth scales with the community rather than with one origin. See The binary cache.
Privacy, telemetry & the community pulse
No personally-identifiable information is ever collected — region-only, and the IP is dropped at the edge. That is the whole promise, and everything below is just detail on how it is kept.
One exception is worth stating up front: if you opt into browser peer-to-peer sharing on the website, peers exchange IP addresses directly with each other, as any peer-to-peer connection does. We never collect or store them, but we cannot hide them from your peers. This is off unless you turn it on, and revocable from the footer toggle on any page. See P2P distribution.
By default, a solnix machine phones home to no one. Participation in the community pulse is something you turn on deliberately; the default is silence.
What is and isn’t collected
Nothing is collected unless you opt in (see the master switch below). When you do, every event carries only: the event kind, the package attribute(s) and architecture, a coarse region (country + admin area + postal-prefix, roughly ZIP-equivalent), a day-bucket timestamp, and a rotating anonymous nonce (explained below).
The event kinds are:
- Platform census — active-machine count by host kind (arch, illumos flavor, VM / bare-metal / zone), by region. “How many people, on what kind of host.”
- Packages in daily use — the set of packages a machine actively uses (hashed attr set + arch + region), reported once per day.
- Package installed — install events (package + arch + region).
- Package seeding — a machine offering its built solnix packages to the BitTorrent swarm reports what it can seed (package + arch + region), so the swarm view is real.
What is never collected: no name, no phone number, no IP address, no MAC address, no hostname, no machine ID. No raw events are ever exposed — only aggregates (see k-anonymity below).
The solnix.privacy.enable master switch
One switch governs everything. It defaults to true, which means fully
private — no phone-home:
Note the inversion — this reads backwards.
solnix.privacy.enable = true(the default) means NO data is sent. To join the community pulse you set it tofalse. Settingenable = falseturns telemetry on, not off. We know this is a footgun; a positively-namedsolnix.telemetry.enable(defaultfalse) is planned to replace it.
solnix.privacy.enable = true; # DEFAULT: fully private, phone-home OFF
A machine whose config never touches this stays completely private. Nothing is sent, nothing is shared.
To opt into the community pulse, set it to false. The individual features then
default on, and you can pare any of them back:
solnix.privacy.enable = false; # opt into the community pulse
# with privacy off, these default true — override any individually:
solnix.telemetry.enable = true; # group: all phone-home
solnix.telemetry.census.enable = true; # platform / active-user census
solnix.telemetry.packages.enable = true; # transferred / installed / in-use
solnix.cache.seed.enable = true; # P2P: seed built packages (BitTorrent)
solnix.site.p2p.enable = true; # P2P: browser WebRTC site sharing
The effective rule, in plain language: a feature is active only when the
master switch is off and its group is on and the feature itself is on —
(not privacy.enable) && telemetry.enable && <feature>.enable. The master
switch always wins. Someone who never touches config is fully private; someone
who opts in gets everything, then can turn off any piece.
See Peer-to-peer distribution for cache.seed and site.p2p.
How the anonymity works
- Region at the edge, IP dropped. The ingest service resolves your IP to a coarse region and then discards the IP immediately. The IP never touches storage or logs.
- Rotating per-day nonce. Same-day duplicate events are collapsed using a nonce that rotates every day and is not persisted beyond that day’s dedup. It is never a stable identifier — there is nothing to correlate you across days.
- k-anonymity. Every public aggregate suppresses any bucket smaller than k = 5. If a region or host kind has too few machines to be anonymous, it simply isn’t shown.
- Aggregates only. The public views are Datalog aggregate counts. No raw event is ever exposed.
The wire format is EDN, posted to
https://search.solnix.io/telemetry.
Why opt in
The default is private, and that is respected — no one is defaulted in silently. But there is an honest reason to participate: a visible, growing, active community is the return solnix gives back to the people who run it. Census data is what makes the pulse real — it shows that solnix is alive, which packages people actually use, and where the project is growing. That signal is self-reinforcing: a community that can see itself attracts more people, more builders, more architectures. Opting in is how you add yourself to that picture. Staying private is entirely fine too.
Where to see the results
- The community dashboard: solnix.io/pulse.html — active machines, a coarse regional heatmap, top packages, swarm size, and growth over time.
- Package popularity surfaces in search: search.solnix.io.
Further reading & resources
solnix documents what is specific to solnix; for illumos and Nix themselves, the canonical upstream material is excellent and we point at it rather than duplicate it. This is a curated reading list in the style of the SmartOS “illumos and SmartOS basics” page: the books, manuals, and sites worth knowing, grouped by topic, plus the solnix-specific resources.
Many of these describe Solaris/illumos as a general platform. The commands and concepts (SMF, ZFS, DTrace, zones, MDB, boot environments) apply directly to solnix, which is an illumos distribution — solnix changes how the system is built and activated (Nix), not how these subsystems work.
illumos itself
- illumos.org — the project home: news, downloads, the distribution list.
- illumos documentation — the docs this handbook’s structure and tone are modeled on (features, user guide, developer guide).
- illumos manual pages — the authoritative reference for every command and subsystem below.
- solnix man pages — the man pages that ship with the packages actually in the binary cache, browsable A–Z by package and section (like manned.org, for solnix). Coverage is early and grows as more packages land; for anything not yet here, the upstream illumos man pages are the reference. Every package in search also links straight to its man pages.
- illumos-gate — the source tree solnix inherits its kernel and load-bearing userland from. See How solnix is built.
- The illumos Developer’s Guide — building and contributing to the gate.
Basic system administration
- Service Management Facility
smf(7)— the SMF concept page; start here for services. Thensvcs,svcadm,svccfg. See SMF services. beadm(8)— boot environment management. See ZFS boot environments.- OpenZFS documentation — the
cross-platform OpenZFS admin docs; plus
zpoolandzfs. See ZFS storage. zonecfg(8)/zoneadm(8)— zone administration. See Zones and LX-branded zones.dladm(8)/ipadm(8)/flowadm(8)— the Crossbow network- virtualization stack. See Networking (Crossbow).- The classic Solaris/illumos System Administration material (network,
dladm,ipfilter, users, RBAC/pfexec) — much of it still accurate for illumos; the manual pages are the current source of truth.
Not yet documented (known gaps)
Accurate detail on these is thin in this handbook today; they are real illumos topics worth a page as solnix matures. Listed here so they aren’t lost:
- RBAC / privileges in depth — roles, profiles, authorizations, and the
full privilege set. Briefly covered in illumos features
(
pfexec, least-privilege); a dedicated walkthrough is a gap. Reference:rbac(7),privileges(7),pfexec(1). - Kernel modules —
modinfo,modload/modunload,add_drv, and how the gate’s kernel modules load. Not yet written up; relevant once solnix builds kernel bits. Reference:modinfo(8). - FMA in depth — partly covered in illumos features
and Debugging (
fmadm faulty,fmdump); the diagnosis engine and event protocol are a gap. - pkgsrc — the package system SmartOS and some other illumos distributions use, and the thing solnix replaces with Nix. Mentioned in the history; a comparison page is a gap.
Performance, profiling, and programming (DTrace)
- DTrace: Dynamic Tracing in Oracle Solaris, Mac OS X and FreeBSD (Gregg & Mauro) — the DTrace book; the canonical reference and a deep performance-analysis text.
dtrace(8)— command reference. See DTrace.- Brendan Gregg’s DTrace one-liners and Systems Performance — practical starting points for observability.
Kernel and debugging
- The Modular Debugger
mdb(1)and the MDB guide — inspecting live processes, core files, and kernel crash dumps. - Writing Device Drivers — including the chapter on debugging, testing, and tuning drivers.
- Debugging broken systems and debugging applications — the illumos user-guide pages this handbook’s Debugging page is adapted from.
- Solaris Internals (McDougall & Mauro) — the classic deep dive into the kernel architecture illumos descends from.
Nix and NixOS
- nix.dev — the official Nix learning hub.
- Nix manual · Nixpkgs manual · NixOS manual — the CLI, packaging, and module system solnix reuses. See Learning Nix.
- nixbsd — NixOS retargeted to the BSDs; the closest prior art to what solnix does for illumos, and the playbook solnix follows. See How solnix is built.
solnix-specific
- The solnix Handbook — this book.
- The binary cache —
cache.solnix.io; add it as a substituter and skip the recompilation tax. - Package search —
search.solnix.io; full-text search over the solnix package set. - Community pulse — active machines, regions, and popular packages (opt-in; see Privacy & telemetry).
- Contributing — repos, mailing lists, and how to help (every architecture needs a builder).
A short history: from SunOS to solnix
solnix did not appear from nowhere. It is the newest link in a chain that runs back more than forty years, through some of the most influential operating- system engineering ever done. Knowing the lineage makes the rest of this handbook click into place — why the commands look the way they do, why ZFS and DTrace and zones all live in one coherent system, and what solnix is (and isn’t).
SunOS — the BSD years (early 1980s)
Sun Microsystems shipped its first workstations running SunOS, a Unix built
on BSD (the Berkeley variant of AT&T Unix). Through the 1980s SunOS was a
BSD-flavored system — bsd-style tooling, the fast filesystem, sockets — tuned
for Sun’s hardware. This is the root of the family tree: solnix is, at bottom, a
descendant of BSD Unix.
SunOS 5 / Solaris — the SVR4 rewrite (1992)
In 1992 Sun made a decisive break. Together with AT&T it moved to System V
Release 4 (SVR4) — the “unification” of the BSD and System V Unix branches —
and shipped it as SunOS 5, marketed as Solaris 2. (Confusingly, “SunOS”
became the kernel/version name reported by uname, while “Solaris” was the
product.) This SVR4 heritage is why illumos — and therefore solnix — uses SVR4
conventions: /usr layout, the packaging model that became IPS, service and
device frameworks, and much of the userland shape a Linux admin finds slightly
unfamiliar.
The Solaris innovations (late 1990s–2000s)
Over the next fifteen years Solaris became a laboratory for operating-system ideas that the rest of the industry later imitated. The ones solnix inherits directly:
- ZFS — a pooled-storage filesystem and volume manager with end-to-end checksums, cheap snapshots, and clones. See ZFS storage.
- DTrace — safe, production-grade dynamic tracing of the whole system, kernel and userland, from one language. See DTrace.
- SMF — the Service Management Facility: a dependency-aware init system and service supervisor with a fault boundary. See SMF services.
- Zones — OS-level virtualization years before Linux containers. See Zones.
- Crossbow — network virtualization: virtual NICs, virtual switches, and bandwidth controls in the kernel. See Networking (Crossbow).
- FMA — the Fault Management Architecture: hardware and software errors diagnosed into faults with stable message IDs. See illumos features.
Any one of these would have been a notable system. Solaris shipped all of them, integrated, in one OS — which is exactly the platform solnix builds on.
OpenSolaris — the open-sourcing (2005)
In 2005 Sun released most of Solaris as open source under the CDDL, the OpenSolaris project. For the first time the kernel, ZFS, DTrace, SMF, and zones were all public, buildable source. A community of developers and downstream distributions grew around it.
Oracle closes Solaris (2010)
Oracle acquired Sun in early 2010 and, later that year, effectively ended OpenSolaris — Solaris development continued behind closed doors as a proprietary product. The open source drops stopped. The community that had grown around OpenSolaris was suddenly without an upstream.
The community forks: illumos (2010)
Rather than let the open codebase die, the community forked the last open OpenSolaris drop into a new project: illumos. The name nods to illumination and to the ON (“OS/Net”) consolidation it descends from. illumos replaced the last few closed-source bits Oracle had never opened, and became a fully open, community-maintained continuation of the OpenSolaris kernel and core userland — what this handbook calls the illumos gate. See How solnix is built.
illumos is not Solaris and is not owned by Oracle. It is the open, living branch of the same tree; Oracle’s Solaris is the closed one.
The illumos distribution ecosystem
Just as Linux is a kernel that many distributions package, illumos is a gate that several distributions build on:
- OpenIndiana — a general-purpose desktop/server distribution, the most direct OpenSolaris successor.
- OmniOS — a minimal, stable server distribution.
- SmartOS (Joyent/MNX) — a hypervisor-focused distribution that runs everything in zones and pioneered the modern LX-branded zone (running Linux binaries on the illumos kernel — see LX-branded zones).
- Tribblix — a retro-flavored distribution with its own lightweight package manager.
Each takes the same gate and differs mostly in packaging, defaults, and focus.
And finally: solnix
solnix — the solnix Operating System — is the newest illumos distribution, and it differs in one specific way: instead of a traditional package manager (IPS, or SmartOS’s pkgsrc), it uses Nix and the NixOS module system to build and manage the whole system declaratively. It is designed as a first-class OS across four CPU targets — x86_64, aarch64, RISC-V, and SPARC — for both server and desktop use, and optimized for virtualized hosting on the major cloud platforms. Each configuration change produces a new, atomically-activated system backed by a ZFS boot environment; rollback is instant.
To be precise about what solnix is and isn’t:
- solnix is illumos — the same kernel, ZFS, DTrace, SMF, zones, Crossbow, and FMA described above — packaged and managed with Nix.
- solnix is not Linux. It does not use the Linux kernel, glibc, or systemd.
- solnix is not NixOS. It reuses NixOS’s evaluator and module system, but targets the illumos kernel and userland, not Linux.
- solnix is not Oracle Solaris. It descends from the open illumos branch, not Oracle’s closed product.
Status. solnix is early — a first preview image just landed (see Introduction). The history above is real and settled; solnix’s own place in it is just beginning.
Further reading
- illumos features — the platform capabilities this history produced, in depth.
- How solnix is built — how solnix layers Nix onto the illumos gate.
- For Linux (and NixOS) users — a quick orientation if you’re coming from Linux.
- Further reading & resources — books and docs on the whole lineage.