A practical guide to setting up Nix in single-user mode inside a Podman rootless container using buildpack-deps:24.04 image with persistent storage. Covers the issues you’ll hit along the way and how to fix each one. Same setup works with Docker.
Goal
Run Nix in single-user mode inside a container where:
-
/nixand/homeare mounted as persistent volumes -
No
sudoor additional system packages are installed -
Packages are managed entirely through Nix
-
The setup survives container rebuilds
Why single-user mode
Single-user Nix doesn’t require a running daemon or root access. The entire Nix store lives under /nix, and the profile lives under the user’s home directory. This makes it a natural fit for containers where you want minimal system-level changes and have pre-mounted persistent volumes.
Step 0: Prepare host directories
The buildpack-deps:24.04 image already includes an ubuntu user (uid 1000) with a home directory. We’ll copy it out to a host directory so it persists across container rebuilds.
mkdir -p buildbox/nix
cd buildbox
Start a temporary container and copy the home directory out:
podman run -d --name tmp buildpack-deps:24.04 sleep 60
podman cp tmp:/home/ubuntu .
podman rm -f tmp
This gives you:
buildbox/
├── nix/ # will hold the Nix store
└── ubuntu/ # the ubuntu user's home directory from the image
Important: Check that the permissions on both directories match uid 1000, since the container runs as the ubuntu user:
ls -lan nix ubuntu
If needed, fix ownership:
sudo chown -R 1000:1000 nix ubuntu
Step 1: Start the container
podman run -it --name buildbox \
--userns keep-id \
-v ./ubuntu:/home/ubuntu \
-v ./nix:/nix \
--user ubuntu \
--workdir /home/ubuntu \
buildpack-deps:24.04
The --userns keep-id flag maps your host user to uid 1000 inside the container, which matches the ubuntu user. This ensures file permissions work correctly across the mounted volumes without running as root.
With Docker, the equivalent would be:
docker run -it --name buildbox \
-v ./ubuntu:/home/ubuntu \
-v ./nix:/nix \
--user ubuntu \
--workdir /home/ubuntu \
buildpack-deps:24.04
Step 2: Install Nix
curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install | sh -s -- --no-daemon
The --no-daemon flag selects single-user installation. The installer will complete without errors.
Gotcha: Nix won’t be on your PATH after this.
The installer adds a sourcing line to ~/.profile:
if [ -e /home/ubuntu/.nix-profile/etc/profile.d/nix.sh ]; then
. /home/ubuntu/.nix-profile/etc/profile.d/nix.sh
fi
But your container shell is /bin/bash launched as a non-login interactive shell, which reads ~/.bashrc, not ~/.profile. So Nix is installed but invisible.
Fix: Add the sourcing line to ~/.bashrc:
echo 'if [ -e /home/ubuntu/.nix-profile/etc/profile.d/nix.sh ]; then . /home/ubuntu/.nix-profile/etc/profile.d/nix.sh; fi' >> ~/.bashrc
Step 3: Source the Nix environment
Before opening a new shell, you can source it manually:
. /home/ubuntu/.nix-profile/etc/profile.d/nix.sh
Gotcha: This may silently do nothing.
The nix.sh script guards its entire body with:
if [ -n "${HOME-}" ] && [ -n "${USER-}" ]; then
# ... all the PATH setup ...
fi
In containers, USER is often not exported as an environment variable. When this condition fails, the script executes without error and without doing anything. No warning, no output! The PATH is simply unchanged.
Fix: Export USER before sourcing:
export USER=ubuntu
. /home/ubuntu/.nix-profile/etc/profile.d/nix.sh
To make this permanent, update ~/.bashrc with both lines:
cat > ~/.bashrc << 'EOF'
export USER=ubuntu
if [ -e /home/ubuntu/.nix-profile/etc/profile.d/nix.sh ]; then . /home/ubuntu/.nix-profile/etc/profile.d/nix.sh; fi
EOF
Verify:
which nix
# Should print: /home/ubuntu/.nix-profile/bin/nix
Step 4: Enable required experimental features
Modern Nix usage (the nix CLI and flake references) requires two experimental features that aren’t enabled by default.
mkdir -p ~/.config/nix
cat > ~/.config/nix/nix.conf << 'EOF'
experimental-features = nix-command flakes
EOF
Without this, commands like nix profile add nixpkgs#devbox will fail with errors about disabled experimental features. The errors are shown one feature at a time, so you’d have to fix nix-command, hit the flakes error, then fix that too. Setting them in the config file avoids this entirely.
Gotcha: This config file must exist before you run any nix command.
If you run nix before creating the config, it won’t pick up the file retroactively in the same shell session — Nix reads config at startup. Either create the file first, or start a new shell after creating it.
Step 5: Install a package
nix profile install nixpkgs#devbox
This should now work without errors or warnings.
which devbox
devbox version
Complete .bashrc for reference
# Nix setup
export USER=ubuntu
if [ -e /home/ubuntu/.nix-profile/etc/profile.d/nix.sh ]; then
. /home/ubuntu/.nix-profile/etc/profile.d/nix.sh
fi
Complete nix.conf for reference
# ~/.config/nix/nix.conf
experimental-features = nix-command flakes
Data persistence
With the volume mounts described above:
-
./nix/— the Nix store. All installed packages, derivations, and the database. Survives container rebuilds. -
./ubuntu/— user profile,~/.config/nix/nix.conf,~/.bashrc, and~/.nix-profile. Survives container rebuilds.
If you rebuild the container image, both directories live on the host. A new container starts with Nix fully set up and all previously installed packages available.
Summary of gotchas
| Issue | Symptom | Fix |
|---|---|---|
Sourcing line in .profile not .bashrc |
nix command not found after install |
Add sourcing line to ~/.bashrc |
USER not set in container |
nix.sh runs but PATH is unchanged |
export USER=ubuntu before sourcing |
nix-command feature disabled |
error: experimental Nix feature 'nix-command' is disabled |
Add to ~/.config/nix/nix.conf |
flakes feature disabled |
error: experimental Nix feature 'flakes' is disabled |
Add to ~/.config/nix/nix.conf |