-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
Add the ability to specify Nix packages in zsync.toml that get automatically provisioned on the remote machine, enabling consistent development environments without requiring root access on the remote.
Motivation
When syncing to remote development machines (especially cloud GPUs, HPC clusters, or shared servers), you often want specific tools available (neovim, ripgrep, fd, etc.) but:
- Don't have root access to install packages
- Don't want to manually set up each machine
- Want reproducible environments across different remotes
Research: Rootless Nix Options
1. nix-portable (Recommended)
Repo: https://github.com/DavHau/nix-portable
Pros:
- Single static binary (~100MB), no installation needed
- Works on any Linux without root or configuration
- Supports x86_64 and aarch64
- Uses bubblewrap (fast, user namespaces) or falls back to proot
- Flakes and nix-command enabled by default
- MIT licensed, actively maintained (1.1k stars)
Cons:
- proot fallback has significant performance overhead
- Programs from nix-portable can't link against system programs
- macOS not supported (but zsync remote is always Linux)
How it works:
- Self-extracting archive →
$HOME/.nix-portable/ - Virtualizes
/nix/storeusing bubblewrap or proot - Runtime selection: nix → bubblewrap → proot (in preference order)
2. nix-user-chroot
Repo: https://github.com/nix-community/nix-user-chroot
Pros:
- Enables nix sandbox (better isolation)
- Auto-mounts OpenGL/CUDA libraries (good for GPU machines)
- Rust-based, static binary available
Cons:
- Currently unmaintained
- Requires user namespaces (disabled on RHEL/CentOS by default)
- More complex setup than nix-portable
3. Native Nix rootless install
Newer Nix versions support --no-daemon single-user install, but still typically needs write access to create /nix or use of user namespaces.
Recommendation: nix-portable
Best balance of simplicity, compatibility, and maintenance status. Falls back gracefully when user namespaces aren't available.
Proposed Design
Config (zsync.toml)
[nix]
# Packages to provision on the remote
packages = [
"neovim",
"ripgrep",
"fd",
"jq",
"gh",
]
# Optional: use a flake instead of packages
# flake = "github:user/devenv"
# Auto-add nix packages to PATH (default: true)
setup_path = trueBehavior
-
On first sync to a new remote:
- Check if nix/nix-portable is available
- If not, download nix-portable binary to
~/.zsync/nix-portable - Run
nix-portable nix profile install nixpkgs#<package>for each package
-
On subsequent syncs:
- Check if packages are installed, install missing ones
- Optionally update packages (
nix profile upgrade)
-
PATH setup:
- Add
~/.nix-profile/binto shell rc files - Or source a zsync-generated env script
- Add
Implementation Notes
- nix-portable binary is ~100MB, cache it on remote
- Package installation happens async/parallel with file sync
- Could show progress:
Provisioning neovim, ripgrep... - Store package state in
~/.zsync/nix-state.jsonto avoid re-checking
Open Questions
- Flake support? Allow specifying a flake for more complex environments?
- Shell integration? Auto-add to
.bashrc/.zshrcor require manual sourcing? - Update policy? Auto-update packages? On every sync? Manual only?
- Binary cache? Use cachix or other binary caches for faster installs?
Alternatives Considered
- Just document manual nix-portable setup - Works but loses the "it just works" UX
- Embed nix-portable in zsync-agent - Too large, not all users need it
- Use system package managers - Not portable, requires root
Related
- nix-portable: https://github.com/DavHau/nix-portable
- nix-user-chroot: https://github.com/nix-community/nix-user-chroot
- Nix rootless discussion: https://discourse.nixos.org/t/rootless-nix-profile/39212