A user-space development environment powered by Bubblewrap.
Bubblebox is an approach to running the Nix package manager on Linux without needing sudo or modifying the host system, while keeping the entire Nix installation inside your $HOME.
It started as an experiment on Fedora Atomic:
Can I get a proper Nix development environment without layering Nix onto an immutable system?
Apparently, yes.
The basic idea is to use Bubblewrap to construct a temporary filesystem namespace, give Nix the filesystem layout it expects, and keep the persistent parts of the installation in the user's home directory.
The goal is simple:
Keep the host clean. Put the weird stuff in the bubble. 🫧
Immutable Linux systems are great until you want to install some random development tool that expects to live in /usr, /opt, or somewhere else the operating system doesn't particularly want you touching.
Nix already solves a large part of this problem by providing its own package store and user profiles. The annoying part is getting Nix itself onto a system where modifying the base filesystem isn't desirable.
Bubblebox puts the two together:
┌──────────────────────────────────────────┐
│ Linux Host |
│ |
│ /usr /etc /run /var |
│ │ │ │ │ |
│ └───────────┴───────┐──┴──────────┴────┐
│ | │
│ Bubblewrap │
│ | │
│ ┌────────────────────────────────────┐ │
│ │ Nix Environment │ │
│ │ │ │
│ │ /nix → ~/.nix │ │
│ │ /home → /var/home │ │
│ │ temporary filesystem root │ │
│ │ │ │
│ │ Nix packages / profiles / flakes │ │
│ └────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────┘
The host remains untouched while Nix gets the environment it needs.
Bubblebox currently consists of two small scripts:
| Component | Purpose |
|---|---|
nix-shell-env |
Starts an interactive sandboxed shell for Nix operations |
nix-exec |
Transparently executes individual Nix binaries from the host |
| Bubblewrap | Provides the sandbox and namespace machinery |
| Nix Profile | Provides per-user package installation without a daemon |
The current environment uses several layers of filesystem isolation:
/usr,/etc, and/runare exposed read-only.- The sandbox starts with a temporary filesystem root.
- Only selected parts of the host filesystem are bind-mounted into the environment.
- The Nix store lives inside the user's home directory at
~/.nix. - The network is shared with the host where required.
- Nix runs in single-user mode without a system-wide daemon.
- No root privileges are required for the Nix installation itself.
This is not intended to be a replacement for a full container runtime or a security boundary for hostile workloads.
It is primarily a way of constructing a useful user-space development environment on systems where modifying the host filesystem is undesirable.
You need:
- Bubblewrap
~/.local/binsomewhere in your$PATH- A Linux system
That's it, I guess.
Bubblewrap is already present on many desktop Linux systems, particularly if you use Flatpaks.
mkdir -p ~/.nix ~/.local/binPlace nix-shell-env and nix-exec in:
~/.local/bin/
Then make them executable:
chmod +x ~/.local/bin/nix-shell-env ~/.local/bin/nix-execLaunch the Bubblewrap environment:
nix-shell-envThen install Nix in single-user mode:
curl --proto '=https' --tlsv1.2 -sSf -L https://nixos.org/nix/install | sh -s -- --no-daemonNote: As always with
curl | sh, read the script before running it if you are uncomfortable executing remotely fetched code. The command above is the standard Nix installation method used by this setup.
Inside nix-shell-env:
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.confAnd that's the basic setup.
Enter the environment:
nix-shell-envInstall packages through a Nix profile:
nix profile install nixpkgs#<package_name>For example:
nix profile install nixpkgs#ripgrepThen leave the environment:
exitnix-exec can be used as a wrapper so that individual Nix-installed programs can be invoked directly from the host.
For example:
rm -f ~/.local/bin/rg
ln -s ~/.local/bin/nix-exec ~/.local/bin/rgNow running:
rgwill cause the wrapper to execute the corresponding Nix profile binary inside the Bubblewrap environment.
The result is effectively:
Host shell
│
▼
~/.local/bin/rg
│
▼
nix-exec
│
▼
Bubblewrap
│
▼
~/.nix-profile/bin/rg
The host gets the command.
Nix gets to keep doing Nix things.
Everyone is happy.
Probably.
Because the Nix store lives in the user's home directory, you can clean unused store paths with:
nix-shell-env
nix store gcThis is especially useful if you've been installing packages purely because you wondered what they were.
You know who you are.
There are currently a few rough edges.
To make direnv show up and usable on host, the following needs to be added to .bashrc:
if command -v direnv &>/dev/null && command -v bwrap &>/dev/null; then
eval "$(direnv hook bash | sed "s|/nix/store/[^/]*/bin/direnv|$HOME/.local/bin/direnv|g")"
fiYes, this uses sed inside eval.
No, I am not proud of this.
Yes, I have a story about this.
The Nix integration itself is working properly.
The normal Nix CLI can be exposed through Bubblebox, including flakes and development environments. In particular, nix develop works correctly with project-local flake.nix files and dependencies:
nix developThis has been tested with development environments containing packages such as cowsay and lolcat, with the resulting tools available from the expected /nix/store/... paths.
So if you want a development environment from a flake, nix develop is currently the reliable way to do it.
direnv, with nix, however, is another story.
The current integration can evaluate the flake and produce the correct development environment, but getting that environment applied cleanly to the existing interactive Bash session is currently unreliable.
This is not a failure of nix develop or the underlying Bubblebox/Nix environment. The problem is specifically the direnv → interactive shell integration.
I have also never personally managed to get the combination of Nix + direnv to behave particularly nicely, even on systems where Nix is installed normally. Bubblebox has apparently decided to continue this proud tradition.
For now:
Nix ✓
flakes ✓
nix develop ✓
project-local dev environments ✓
direnv with nix ¯\_(ツ)_/¯
A working automatic environment-activation mechanism may be explored later.
Bash completions do not currently work currently.
This is something I still need to investigate, particularly how Nix profiles expose and manage completion files.
Bubblebox is currently developed and tested on Fedora Atomic, specifically the Fedora COSMIC Atomic Spin.
It should work across the broader Fedora Atomic family, including Universal Blue distributions such as Bazzite, Bluefin, and Aurora.
It should also be applicable to other immutable Linux distributions such as:
- openSUSE Aeon
- openSUSE Kalpa
- openSUSE MicroOS
Despite being designed with immutable systems in mind, there is nothing particularly Atomic-specific about the underlying approach.
It should also work on traditional mutable distributions such as:
- Fedora
- Ubuntu
- Gentoo
- and probably most other Linux distributions
REMEMBER TO ACTUALLY CHANGE THE /var/home related things in nix-shell-env and nix-exec to make it work on other distros. The checks maybe automated in the future.
It should even work on NixOS.
Why you would want to do this on NixOS is, of course, a question for the reader.
The current setup is Bash-only.
I use Bash, and that is what I have tested. I have no idea yet how well this translates to Zsh, Fish, or other shells, particularly when shell initialization, completions, and environment hooks are involved.
Contributions and experimentation in this area are very welcome.
So far, I have not encountered problems with SELinux or AppArmor during testing.
That is not a guarantee that every possible security policy or configuration will behave identically. Linux security configurations vary, and this project has not been tested against every possible setup.
If you encounter something interesting, please open an issue.
There is still plenty of unnecessary nonsense to build on top of this.
Naturally, I intend to do so.
Things I'd like to explore include:
- Bash completions — because apparently getting the actual environment working wasn't enough.
- Other shells — particularly Zsh and Fish.
- Alternative package managers and development tools — such as uv, Cargo, and whatever else seems fun.
- Better host integration — while keeping the core idea small and user-space focused.
- More development workflows — because once you have a bubble, the natural question becomes what else can I put in it?
The goal isn't to reinvent Nix, Bubblewrap, package managers, containers, or shells.
It's mostly to see how far this little pile of Bubblewrap, namespaces, Nix, shell scripts, and questionable decisions can go.
This project would not exist without the work that came before it.
The original inspiration came from Ivan Molodetskikh (YaLTeR) and his article:
Easy Sandboxing on Linux with Bubblewrap
That article demonstrated how Bubblewrap can be used to construct a practical, low-friction sandbox from ordinary Linux filesystem primitives.
That was the starting point for experimenting with a similar approach for a user-space Nix environment.
A huge thank-you to YaLTeR for writing the article and showing how approachable Bubblewrap-based sandboxing can be.
Bubblebox stands on top of several projects and technologies that do the difficult parts.
- Bubblewrap — provides the unprivileged sandboxing and namespace machinery used to construct the environment.
- Nix — provides the package management, store, profiles, flakes, and development-environment machinery.
- Linux namespaces — provide the kernel-level isolation primitives underlying technologies such as Bubblewrap.
- Linux kernel — provides the namespace, mount, and filesystem machinery underneath the entire stack. In particular, see
fs/namespace.c.
This project is an application of those technologies, not an attempt to re-implement them.
Special thanks to:
- Ivan Molodetskikh (YaLTeR) — for the original Bubblewrap sandboxing article that inspired this project.
- The Bubblewrap contributors — for building and maintaining the sandboxing tool that makes this approach possible.
- The Linux kernel contributors — for the namespace and filesystem primitives underneath the entire stack.
- The Nix community and contributors — for building the package-management and development-environment machinery used here.
- Everyone who has written documentation, examples, experiments, and strange little shell scripts that make Linux easier to understand.
And, inevitably, the random people on the internet whose offhand comments somehow turn into several evenings of Linux experimentation.
Bubblebox is licensed under the MIT License.
See LICENSE for the full text.
This project is an experiment that happens to be useful.
It has been tested on my setup. It has not been tested on every Linux distribution, shell, security policy, filesystem configuration, or combination of weird software that exists in the wild.
Read the scripts.
Understand what they do.
Especially the part involving eval.
And for the love of all that is holy, be prudent with sed. 🫧