<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marwa</title>
    <description>The latest articles on DEV Community by Marwa (@darguechi).</description>
    <link>https://dev.to/darguechi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4192536%2F808794ed-9565-4600-8e09-299b655a1f74.png</url>
      <title>DEV Community: Marwa</title>
      <link>https://dev.to/darguechi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/darguechi"/>
    <language>en</language>
    <item>
      <title>nyxd now builds images, is rootless, runs on macOS &amp; Windows</title>
      <dc:creator>Marwa</dc:creator>
      <pubDate>Sun, 18 Oct 2026 17:23:03 +0000</pubDate>
      <link>https://dev.to/darguechi/nyxd-now-builds-images-is-rootless-runs-on-macos-windows-2e32</link>
      <guid>https://dev.to/darguechi/nyxd-now-builds-images-is-rootless-runs-on-macos-windows-2e32</guid>
      <description>&lt;p&gt;Back in May, &lt;a href="https://dev.to/zrouga"&gt;Mohamed&lt;/a&gt; wrote about getting fed up with the container stack using more RAM than the workloads on his Raspberry Pis, and building &lt;strong&gt;nyxd&lt;/strong&gt; to find out how small a correct, secure OCI stack could be.&lt;/p&gt;


&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/zrouga/i-got-tired-of-docker-eating-my-raspberry-pis-ram-so-i-built-my-own-container-orchestrator-3j3n" class="crayons-story__hidden-navigation-link"&gt;I Got Tired of Docker Eating My Raspberry Pi's RAM — So I Built My Own Container Orchestrator&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
      &lt;a href="https://dev.to/zrouga/i-got-tired-of-docker-eating-my-raspberry-pis-ram-so-i-built-my-own-container-orchestrator-3j3n" class="crayons-article__context-note crayons-article__context-note__feed"&gt;&lt;p&gt;Minimal OCI stack for CVE reduction&lt;/p&gt;

&lt;/a&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/zrouga" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2175334%2Fe47a09a0-b4cc-4518-9873-52b431dd2bc1.jpeg" alt="zrouga profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/zrouga" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mohamed Zrouga
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mohamed Zrouga
                
                
              
              &lt;div id="story-author-preview-content-3685480" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/zrouga" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2175334%2Fe47a09a0-b4cc-4518-9873-52b431dd2bc1.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mohamed Zrouga&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/zrouga/i-got-tired-of-docker-eating-my-raspberry-pis-ram-so-i-built-my-own-container-orchestrator-3j3n" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 16&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/zrouga/i-got-tired-of-docker-eating-my-raspberry-pis-ram-so-i-built-my-own-container-orchestrator-3j3n" id="article-link-3685480"&gt;
          I Got Tired of Docker Eating My Raspberry Pi's RAM — So I Built My Own Container Orchestrator
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/containers"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;containers&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/raspberrypi"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;raspberrypi&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/homelab"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;homelab&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/zrouga/i-got-tired-of-docker-eating-my-raspberry-pis-ram-so-i-built-my-own-container-orchestrator-3j3n" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;23&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/zrouga/i-got-tired-of-docker-eating-my-raspberry-pis-ram-so-i-built-my-own-container-orchestrator-3j3n#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              9&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            10 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


&lt;p&gt;I'm Marwa, a platform engineer, and I've been contributing to nyxd alongside Mohamed. A lot has landed since that post: a &lt;strong&gt;1.0 stable release&lt;/strong&gt;, then &lt;strong&gt;1.1&lt;/strong&gt;, Dockerfile builds without BuildKit, rootless mode, macOS and Windows clients, and real package repositories.&lt;/p&gt;

&lt;p&gt;The original post ended with an unusually honest section: &lt;em&gt;what works, what's half-wired, what's still missing&lt;/em&gt;. So this update is structured the same way. We go back through that list and say what happened to each item.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1.0 is out&lt;/strong&gt;, with a written &lt;a href="https://github.com/zrougamed/nyxd/blob/main/docs/stability.md" rel="noopener noreferrer"&gt;compatibility promise&lt;/a&gt;: the &lt;code&gt;/v1&lt;/code&gt; API, CLI flags, on-disk data and log format stay compatible for all of 1.x.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;nyx build&lt;/code&gt;&lt;/strong&gt; builds images from a Dockerfile. No Docker, no BuildKit, no extra binary. &lt;code&gt;RUN&lt;/code&gt; steps execute in the same &lt;code&gt;crun&lt;/code&gt; sandbox as your containers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rootless&lt;/strong&gt;: start &lt;code&gt;nyxd&lt;/code&gt; as a normal user and it runs everything inside its own user namespace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;macOS and Windows&lt;/strong&gt;: a native &lt;code&gt;nyx&lt;/code&gt; CLI that drives &lt;code&gt;nyxd&lt;/code&gt; in a small Linux VM (vfkit on macOS, WSL2 on Windows).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;nyx compose&lt;/code&gt;&lt;/strong&gt; is a real orchestrator now, not just a YAML parser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signed package repos&lt;/strong&gt; at &lt;code&gt;pkgs.nyxd.io&lt;/code&gt; for apt, dnf/yum, zypper, apk and pacman, plus one-line installers.&lt;/li&gt;
&lt;li&gt;Still &lt;strong&gt;two binaries on the host&lt;/strong&gt;: &lt;code&gt;nyxd&lt;/code&gt; and &lt;code&gt;crun&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try it in a minute
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Linux and macOS&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://pkgs.nyxd.io/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Windows&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://pkgs.nyxd.io/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The installer adds the repository for your distro and sets &lt;code&gt;nyxd&lt;/code&gt; up as a service for &lt;strong&gt;systemd, OpenRC, runit or SysV init&lt;/strong&gt;. That last part matters on Alpine or a minimal Pi image, where systemd isn't a given. On macOS it sets up the nyx VM, on Windows the WSL2 machine.&lt;/p&gt;

&lt;p&gt;Then, the Docker muscle memory works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nyx run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; alpine sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--rm&lt;/code&gt; and &lt;code&gt;-it&lt;/code&gt; landed this week in 1.1.4 / 1.1.5.&lt;/p&gt;




&lt;h2&gt;
  
  
  Revisiting the "honest list"
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Health checks — &lt;em&gt;was: library-ready, not operator-ready&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;In May, &lt;code&gt;internal/health&lt;/code&gt; existed but nothing started it. Now exec / HTTP / TCP probes are &lt;strong&gt;wired into the supervisor&lt;/strong&gt;: they run with each container, &lt;code&gt;run&lt;/code&gt; waits for readiness, and an unhealthy container is &lt;strong&gt;restarted when its restart policy allows&lt;/strong&gt;. Restarts use exponential backoff with jitter, capped at 30s.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Compose — &lt;em&gt;was: a parser, not a scheduler&lt;/em&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nyx compose up            &lt;span class="c"&gt;# finds nyx-compose / docker-compose / compose / podman-compose .yml&lt;/span&gt;
nyx compose up &lt;span class="nt"&gt;--build&lt;/span&gt;    &lt;span class="c"&gt;# rebuild services that have build:&lt;/span&gt;
nyx compose stop          &lt;span class="c"&gt;# reverse dependency order&lt;/span&gt;
nyx compose down &lt;span class="nt"&gt;-v&lt;/span&gt;       &lt;span class="c"&gt;# also remove named volumes, when nothing uses them&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It now covers a practical subset of the format: &lt;code&gt;depends_on&lt;/code&gt; (list and map form) with sequential start, healthchecks, &lt;code&gt;build:&lt;/code&gt;, &lt;code&gt;env_file:&lt;/code&gt;, named volumes, &lt;code&gt;deploy.resources.limits&lt;/code&gt; mapped to cgroup v2 (memory, cpus, swap, pids, cpuset), &lt;code&gt;ulimits&lt;/code&gt;, &lt;code&gt;dns&lt;/code&gt;, &lt;code&gt;seccomp_profile&lt;/code&gt; and &lt;code&gt;apparmor_profile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;New in 1.1: &lt;strong&gt;per-network native bridges&lt;/strong&gt;. A compose network with &lt;code&gt;bridge&lt;/code&gt; and &lt;code&gt;subnet&lt;/code&gt; gets its own &lt;code&gt;nyxbr*&lt;/code&gt; bridge, its own IPAM, NAT, isolation from other bridges, and its own embedded DNS zone, so services find each other by name. Services that don't declare a network stay on &lt;code&gt;nyxbr0&lt;/code&gt;. Still no CNI plugins involved.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Registry auth — &lt;em&gt;was: anonymous Docker Hub pulls only&lt;/em&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nyx login registry.example.com     &lt;span class="c"&gt;# or reuse your existing docker / podman login&lt;/span&gt;
nyx push registry.example.com/team/myapp:1.0
nyx save &lt;span class="nt"&gt;-o&lt;/span&gt; myapp.tar myapp:1.0
nyx load &lt;span class="nt"&gt;-i&lt;/span&gt; myapp.tar              &lt;span class="c"&gt;# also accepts docker save / podman save archives&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Private registries work for pulls, pushes and compose, and pulls resume if a layer download is interrupted.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Seccomp and cgroups
&lt;/h3&gt;

&lt;p&gt;Seccomp and cgroup v2 limits are enforced, and compose services can bring their own &lt;code&gt;seccomp_profile&lt;/code&gt;. A detail worth knowing if you're coming from older nyxd: since 1.0, a &lt;strong&gt;memory limit also caps swap&lt;/strong&gt; (at twice the limit, Docker's default). Before that, a container over its limit swapped instead of getting OOM-killed, which on a Pi with an SD card is the worst of both worlds.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⏳ Still not done, honestly
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus &lt;code&gt;/metrics&lt;/code&gt;&lt;/strong&gt;: the handler exists, but the default daemon still doesn't serve it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sd_notify&lt;/code&gt;&lt;/strong&gt;: nyxd doesn't send &lt;code&gt;READY=1&lt;/code&gt; yet, so keep systemd units on &lt;code&gt;Type=simple&lt;/code&gt; (the shipped units already do).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compose gaps&lt;/strong&gt;: no &lt;code&gt;nyx volume ls&lt;/code&gt;, &lt;code&gt;depends_on&lt;/code&gt; conditions are read but only the order is used, and &lt;code&gt;restart: on-failure:N&lt;/code&gt; syntax isn't exposed yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;nyxd's socket is not the Docker API.&lt;/strong&gt; Tools that need &lt;code&gt;docker.sock&lt;/code&gt; still need a real Docker socket or DinD; there's &lt;a href="https://github.com/zrougamed/nyxd/blob/main/docs/docker-socket.md" rel="noopener noreferrer"&gt;a page on that&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The big new pieces
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;nyx build&lt;/code&gt; — Dockerfiles without BuildKit
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nyx build &lt;span class="nt"&gt;-t&lt;/span&gt; myapp:1.0 &lt;span class="nb"&gt;.&lt;/span&gt;
nyx build &lt;span class="nt"&gt;-t&lt;/span&gt; myapp:dev &lt;span class="nt"&gt;-f&lt;/span&gt; docker/Dockerfile.dev &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.2 &lt;span class="nt"&gt;--target&lt;/span&gt; runtime &lt;span class="nb"&gt;.&lt;/span&gt;
nyx run myapp:1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Dockerfile parser, layer engine and build cache all live inside &lt;code&gt;nyxd&lt;/code&gt;. For each step it mounts overlayfs over the current layers: &lt;code&gt;RUN&lt;/code&gt; goes through &lt;code&gt;crun&lt;/code&gt; with the same seccomp profile, reduced capabilities and &lt;code&gt;noNewPrivileges&lt;/code&gt; as a normal container, while &lt;code&gt;COPY&lt;/code&gt;/&lt;code&gt;ADD&lt;/code&gt; write straight into the tree from Go. The overlay's upper directory becomes the new layer, and deletions become OCI whiteouts.&lt;/p&gt;

&lt;p&gt;Layers are extracted and created &lt;strong&gt;in-process&lt;/strong&gt; now, with no host &lt;code&gt;tar&lt;/code&gt;. That's one more external tool off the list. Multi-stage builds, &lt;code&gt;--target&lt;/code&gt;, &lt;code&gt;--build-arg&lt;/code&gt;, &lt;code&gt;.dockerignore&lt;/code&gt; and the cache all work, and it works rootless.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rootless
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nyxd                      &lt;span class="c"&gt;# as your normal user: rootless is automatic&lt;/span&gt;
nyx run alpine:3.20 &lt;span class="nb"&gt;id&lt;/span&gt;    &lt;span class="c"&gt;# uid=0(root) inside, your uid on the host&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;nyxd&lt;/code&gt; re-executes itself inside its own user namespace, and containers run inside that namespace too. Root in a container is your user on the host, never real root. It needs Linux ≥ 5.11 and unprivileged user namespaces. Ubuntu 24.04+ blocks those through AppArmor by default, and &lt;a href="https://github.com/zrougamed/nyxd/blob/main/docs/rootless.md" rel="noopener noreferrer"&gt;the rootless docs&lt;/a&gt; cover the one sysctl to change.&lt;/p&gt;

&lt;h3&gt;
  
  
  macOS and Windows
&lt;/h3&gt;

&lt;p&gt;People asked "can I use this on my laptop?" Now you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;macOS&lt;/strong&gt;: &lt;code&gt;nyx machine&lt;/code&gt; runs &lt;code&gt;nyxd&lt;/code&gt; + &lt;code&gt;crun&lt;/code&gt; in a small Alpine VM on &lt;strong&gt;vfkit&lt;/strong&gt;, and the Mac talks to it over vsock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows&lt;/strong&gt;: &lt;code&gt;nyx.exe&lt;/code&gt; drives &lt;code&gt;nyxd&lt;/code&gt; inside a minimal &lt;strong&gt;WSL2&lt;/strong&gt; distro.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CLI is native, but the runtime is always Linux, so compose, bridges and cgroups behave the same as on a Pi. There's a &lt;a href="https://github.com/zrougamed/nyxd/blob/main/docs/platform-matrix.md" rel="noopener noreferrer"&gt;platform matrix&lt;/a&gt; showing exactly what works in rootful, rootless, userns-remap, macOS and Windows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built to survive a 2AM failure
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dev.to/itskondrat"&gt;@itskondrat&lt;/a&gt; commented on the first post that a custom orchestrator's real cost shows up at 3AM, when something crashes and there are no docs to search. Fair point, and a lot of the work since then has gone into exactly that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crash recovery&lt;/strong&gt;: if &lt;code&gt;nyxd&lt;/code&gt; is &lt;code&gt;SIGKILL&lt;/code&gt;ed while containers keep running, the next start &lt;strong&gt;re-adopts&lt;/strong&gt; them, including &lt;code&gt;exec&lt;/code&gt; into them, rootless too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bounded logs&lt;/strong&gt;: rotation by size (3 × 10 MiB per container by default), &lt;code&gt;nyx logs --tail&lt;/code&gt; reads from the end, and &lt;code&gt;-f&lt;/code&gt; follows across rotations. No more logs quietly filling an SD card.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stress testing in CI&lt;/strong&gt;: a weekly workflow runs 50 containers at once, 200 short-lived ones, a log flood, an OOM kill next to a healthy service, and a daemon crash with 10 containers running. It fails the run if containers aren't re-adopted within 30s, or if daemon memory or open files grow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test coverage gate&lt;/strong&gt; in CI over unit and end-to-end tests. Writing those tests found and fixed real bugs, such as &lt;code&gt;image prune&lt;/code&gt; deleting images still in use, and &lt;code&gt;exec -i&lt;/code&gt; hanging after the command exits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs&lt;/strong&gt; at &lt;a href="https://nyxd.io" rel="noopener noreferrer"&gt;nyxd.io&lt;/a&gt;, including a get-started page and an OpenAPI explorer for the control API.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A correction to the first post
&lt;/h2&gt;

&lt;p&gt;The first post said the runtime had &lt;strong&gt;three&lt;/strong&gt; external Go modules. That's no longer true, and we'd rather say so. The OCI spec modules are gone (we use our own types), but interactive TTYs and the embedded DNS server brought in others. The direct list today is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;github.com/creack/pty      # nyx run -it / exec TTYs
github.com/miekg/dns       # embedded DNS for service names
golang.org/x/sys
golang.org/x/term
gopkg.in/yaml.v3           # compose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five direct modules, two indirect. Still small, still auditable in an afternoon, and Dependabot now watches all of them. On the host it's still just &lt;code&gt;nyxd&lt;/code&gt; + &lt;code&gt;crun&lt;/code&gt;, with &lt;code&gt;nft&lt;/code&gt; for port publishing and no &lt;code&gt;/opt/cni/bin&lt;/code&gt; unless you choose &lt;code&gt;-net-driver=cni&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  About those benchmarks
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/fyodorio"&gt;@fyodorio&lt;/a&gt; asked how nyxd compares with Podman on RAM. We promised proper numbers, and we haven't published them yet. What we have done is publish the &lt;strong&gt;method&lt;/strong&gt;: three identical Alpine 3.23 guests under QEMU (Docker, Podman, nyxd), the same workload, the same load generator, and a &lt;a href="https://github.com/zrougamed/nyxd/tree/main/benchmarks" rel="noopener noreferrer"&gt;template&lt;/a&gt; for recording every setting. The stress workflow also reports daemon RSS at idle, under load and at peak on every run.&lt;/p&gt;

&lt;p&gt;The comparison post comes next, with the numbers and how to reproduce them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Thank you
&lt;/h2&gt;

&lt;p&gt;Thanks to everyone who commented on the first post. Those questions shaped this release. Thanks also to &lt;a href="https://github.com/SvenNellerz" rel="noopener noreferrer"&gt;Sven Nellemann&lt;/a&gt;, who set up the documentation site. If you hit a bug, there are issue forms on GitHub, and the docs are open to contributions.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/zrougamed/nyxd" rel="noopener noreferrer"&gt;https://github.com/zrougamed/nyxd&lt;/a&gt;&lt;br&gt;
👉 &lt;strong&gt;Docs:&lt;/strong&gt; &lt;a href="https://nyxd.io" rel="noopener noreferrer"&gt;https://nyxd.io&lt;/a&gt;&lt;br&gt;
👉 &lt;strong&gt;Install:&lt;/strong&gt; &lt;code&gt;curl -fsSL https://pkgs.nyxd.io/install.sh | sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions for the comments:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you tried nyxd since May, what broke first?&lt;/li&gt;
&lt;li&gt;Which compose keys are you missing that stop you moving a stack over?&lt;/li&gt;
&lt;li&gt;Rootless or rootful on your edge boxes, and why?&lt;/li&gt;
&lt;li&gt;What should the Docker vs Podman vs nyxd benchmark measure that most benchmarks skip?&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;nyxd is free for personal and other noncommercial use under the PolyForm Noncommercial License 1.0.0.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>containers</category>
      <category>opensource</category>
      <category>homelab</category>
      <category>go</category>
    </item>
  </channel>
</rss>
