Scope and prerequisites#
Commands and output are generic examples. Kernel, image, package, and service versions affect the exact behavior; check the documentation for the versions you use as you read.
Back up Android data and stop the relevant sessions before changing containers, images, mounts, or firewalls. Examples that delete data or force a stop may cause data loss. Manage NixOS system and user-environment configuration through Nix. Generic Linux instructions using apt/pacman, writing directly to /etc, or installing with pip do not apply to the NixOS host. The build, test, and switch phases of a rebuild, and functional verification after startup, are separate stages.
This article focuses on declarative Waydroid configuration on NixOS, an in-depth explanation of module options, the boundary between imperative and declarative management, and NixOS-specific troubleshooting. For the general installation process and architecture, first read Architecture in depth and the Multi-distribution installation guide.
NixOS module options in detail#
The NixOS virtualisation.waydroid module encapsulates Waydroid installation, systemd service management, and network backend selection as declarative options. Understanding what each option means and how it maps to the underlying system is essential to configuring it correctly.
Complete module options table
The following has been checked against the module on the nixos-26.05 branch. Do not treat unstable and the stable branches as one version. Base your actual configuration on the module pinned by the project's flake.lock:
| Option | Type | Default | Description |
|---|---|---|---|
enable |
boolean | false |
Enables the Waydroid container environment. Automatically installs the Waydroid package, enables the systemd service, and configures PolicyKit authorization rules |
package |
package | Selected according to networking.nftables.enable |
Uses pkgs.waydroid-nftables when nftables is enabled, otherwise pkgs.waydroid |
| Network bridge | Module implementation | waydroid0 |
This version has no virtualisation.waydroid.interface option |
| Service startup | systemd implementation | multi-user.target |
This version has no autoStart option; the module configures wantedBy for the container service |
The module source is at
nixpkgs/nixos/modules/virtualisation/waydroid.nix. Read that file directly for the latest implementation details. Reading module source is the best way to understand NixOS system behavior.
What the enable option does underneath
When you set virtualisation.waydroid.enable = true, the NixOS module does the following:
- Installs the package: adds
config.virtualisation.waydroid.package(selected by default according to the firewall configuration) toenvironment.systemPackages - Enables the systemd service: activates
waydroid-container.service, which manages the lifecycle of the Android LXC container - Integrates D-Bus: registers the selected package's D-Bus files. The service BusName is
id.waydro.Container. Check the D-Bus policy for actual authorization; do not invent a PolicyKit action - Checks kernel requirements: the 26.05 module checks ANDROID_BINDER_IPC, ANDROID_BINDERFS, and MEMFD_CREATE, and adds psi=1. The module itself does not declare the described modprobe ExecStartPre; driver probing is handled by the actual package/upstream process.
# 最小启用配置
{
virtualisation.waydroid.enable = true;
}After nixos-rebuild switch, you can check the service status with:
systemctl status waydroid-container
enable = truedoes not automatically runwaydroid init. Downloading and initializing the images must be done manually. See the section "The boundary between imperative and declarative management" below.
The package option: iptables vs. nftables variants
This is one of the most important options on NixOS. nixpkgs provides two Waydroid derivations:
| Derivation | Network backend | Use case |
|---|---|---|
pkgs.waydroid |
iptables (legacy) | Older systems using iptables firewall rules, or situations with an explicit compatibility requirement |
pkgs.waydroid-nftables |
nftables | Configurations with networking.nftables.enable enabled |
Technical background: Waydroid needs a NAT network to give the Android container access to external networks. Early Waydroid versions used iptables rules for NAT, but as the Linux ecosystem moved toward nftables, upstream Waydroid added nftables support. nixpkgs supports these backends through two separate derivations, which differ in their build-time dependencies and bundled network scripts:
pkgs.waydroid: depends oniptablesand uses theiptablescommand to create NAT and DNAT rulespkgs.waydroid-nftables: depends onnftablesand uses thenftcommand to create equivalent nftables rules
# 显式选择 nftables 变体的配置(应与实际防火墙匹配)
{
virtualisation.waydroid = {
enable = true;
package = pkgs.waydroid-nftables; # 使用 nftables 后端
};
}How to choose
- First check the current networking.nftables.enable setting; do not infer that it is enabled from the NixOS version number.
- If your NixOS configuration explicitly sets
networking.nftables.enable = falseand still uses iptables, you can fall back topkgs.waydroid.- These packages integrate different network backends. Their actual interaction with host rules still needs verification; identical behavior in every respect is not guaranteed.
How the module maps to systemd services
Waydroid on NixOS involves two levels of systemd service:
虚拟文件系统层:
waydroid-container.service (系统级)
├── 驱动探测: 由实际 Waydroid/LXC 运行流程执行
├── ExecStartPre: mkdir/挂载准备 # 创建运行时目录
├── ExecStart: waydroid container start # 启动 LXC 容器
└── ExecStop: waydroid container stop # 停止容器
用户会话层:
Waydroid 用户会话(不保证有自动生成的 waydroid-session.service)
├── Wayland socket 桥接
├── PulseAudio 音频桥接
└── Clipboard/Notification 后台服务The key distinction: waydroid-container.service is a system-level systemd service started by multi-user.target (or manually). waydroid-session is a user-session-level service and must run in a graphical session (Wayland). They communicate over D-Bus, with PolicyKit controlling permissions.
Declarative configuration approaches#
This section provides NixOS Waydroid configuration examples ranging from minimal to full setups, for direct use in configuration.nix or flake modules.
Minimal configuration
For a quick trial, enable only Waydroid itself and clipboard support:
{ config, pkgs, ... }:
{
virtualisation.waydroid = {
enable = true;
package = pkgs.waydroid-nftables;
};
# 剪贴板共享(Wayland 环境必需)
environment.systemPackages = with pkgs; [
wl-clipboard
];
}After applying the configuration, initialize it manually:
sudo nixos-rebuild switch
sudo waydroid init -s GAPPS # 或 -s VANILLA(无 Google 服务的纯净版)
systemctl start waydroid-container
waydroid session start
waydroid show-full-uiFull configuration: GPU acceleration + environment variables + toolchain
The following retains the structure for the toolchain, directory sharing, and GPU configuration. Community package/service names must be checked against the pinned nixpkgs. This is not a complete default module ready for deployment.
{ config, pkgs, lib, ... }:
let
# NUR 仓库(提供 waydroid-script 等第三方工具)
nur = import <PINNED_NUR_PATH> { # 结构示意:实际使用 flake input 并锁定 revision,不做浮动 fetchTarball
inherit pkgs;
};
in
{
# ===== Waydroid 核心 =====
virtualisation.waydroid = {
enable = true;
package = pkgs.waydroid-nftables;
# 容器服务由模块配置到 multi-user.target,
# 但需要先完成 waydroid init 才能正常工作
# 此模块版本无 autoStart 选项;按需要通过 systemd 覆盖启动策略
};
# ===== 用户组 =====
# 用户组不是本模块的默认授权接口
# 不假定存在 waydroid 用户组;用户授权按实际包与策略检查
# ===== 环境变量 =====
environment.sessionVariables = {
# GBM (Generic Buffer Management) 开关
# - 不设置:Waydroid 默认使用 GBM 进行 GPU 缓冲区管理
# - 设为 "1":禁用 GBM,回退到 SwiftShader 软件渲染
# NVIDIA 闭源驱动用户通常需要禁用 GBM
# Intel/AMD 开源驱动用户保持默认(不设置)即可
# 不导出未确认被当前版本读取的 WAYDROID_DISABLE_GBM
};
# ===== 系统包 =====
environment.systemPackages = with pkgs; [
# 剪贴板共享(必需)
wl-clipboard
# Android 调试工具(可选)
android-tools # 提供 adb、fastboot
# 嵌套 Wayland compositor(Hyprland 用户可能需要 cage 创建嵌套会话)
cage
# ARM 转译脚本(可选,来自 NUR)
# nur.repos.ataraxiasjel.waydroid-script
];
# ===== Waydroid Helper(NixOS 25.11+ 推荐) =====
# waydroid-helper 是 NixOS 社区维护的辅助包,
# 提供更声明式的目录挂载和容器管理方案
#
# 包含以下系统服务:
# - waydroid-mount.service:管理 Android 容器与宿主的目录绑定挂载
#
# 包含以下用户服务:
# - waydroid-monitor.service:监控 Waydroid 容器状态,自动处理热插拔事件
systemd = {
# 将 waydroid-helper 的 systemd 单元注册到系统
packages = [ pkgs.waydroid-helper ];
# 启用 waydroid-mount 系统服务
services.waydroid-mount = {
wantedBy = [ "multi-user.target" ];
# waydroid-mount 需要在 waydroid-container 之后启动
after = [ "waydroid-container.service" ];
};
};
# ===== 包安全提示的处理 =====
# Waydroid 在 25.11+ 上可能触发某些 nixpkgs 的不稳定性警告,
# 安全告警需要确认具体问题、受影响路径及替代版本,不把 permittedInsecurePackages 作为通用消警方案:
# nixpkgs.config.permittedInsecurePackages = [
# "python3.12-xxx" # 按实际警告内容填写
# ];
}After applying the configuration above, run the following commands to complete initialization:
# 1. 重建系统
sudo nixos-rebuild switch
# 2. 重新登录(使 group 变更生效)
# 或使用: # 不假定存在 waydroid 组
# 3. 初始化 Waydroid(-s GAPPS 表示包含 Google 服务)
sudo waydroid init -s GAPPS
# 4. 启动容器服务
sudo systemctl start waydroid-container
# 5. 启动会话
waydroid session start
# 6. 启用 waydroid-monitor(NixOS 25.11+ 带 waydroid-helper 时)
systemctl --user enable --now waydroid-monitor
# 7. 显示 Waydroid 全屏界面
waydroid show-full-uiGPU property configuration
Waydroid's GPU-related properties are stored in /var/lib/waydroid/waydroid_base.prop. The following configurations cover different GPU scenarios:
AMD/Intel open-source drivers (recommended):
# 使用宿主 GPU 加速(GBM 模式)
# 修改 /var/lib/waydroid/waydroid_base.prop
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.gralloc=gbm
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.egl=mesaNVIDIA proprietary drivers:
# NVIDIA 闭源驱动下,GBM 支持不完善,回退到 SwiftShader
# 图形覆盖放在 waydroid.cfg 的 [properties];不使用未确认环境变量
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.gralloc=default
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.egl=swiftshaderSwiftShader software rendering (fallback):
# 任何 GPU 都可用,但无硬件加速
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.gralloc=default
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.egl=swiftshaderGPU property considerations
- After modifying
waydroid_base.prop, restart the container:sudo systemctl restart waydroid-container- For a full discussion of GPU acceleration, see GPU and hardware acceleration
- The AMD/Intel Mesa path is often a workable starting point, but still verify the actual renderer and application behavior
memfd optimization
Supported Android images can use memfd instead of the old ashmem path. This is not a replacement for Binder or a guarantee of improved performance:
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 sys.use_memfd=trueThe kernel is selected by boot.kernelPackages; do not infer a fixed kernel from the NixOS release. memfd_create has been available since Linux 3.17; check image and Waydroid support for it separately. Once enabled, Android's anonymous shared memory (ashmem) uses memfd instead, reducing kernel-module dependencies.
The boundary between imperative and declarative management#
The most important concept when using Waydroid on NixOS is this: the existing module manages system-side configuration, while Android images and application data retain their own state. Understanding this boundary keeps you from the dead end of trying to "put everything in Nix".
Why it cannot be completely declarative
There is a fundamental tension between Waydroid's runtime model and NixOS's declarative philosophy:
graph LR
subgraph Declarative["NixOS 声明式领域"]
A[configuration.nix] --> B["virtualisation.waydroid.enable"]
B --> C[软件包安装]
B --> D[systemd 服务]
B --> E[PolicyKit 规则]
B --> F[环境变量]
end
subgraph Imperative["运行状态领域(模块未自动管理)"]
G["waydroid init<br/>下载 ~500MB 系统镜像"]
H["waydroid upgrade<br/>按维护窗口检查 OTA"]
I["waydroid prop set<br/>运行时属性配置"]
J["waydroid app install<br/>APK 安装"]
end
C --> G
G -.->|"镜像写入<br/>/var/lib/waydroid/"| K["模块未自动管理的镜像/数据状态"]There are three central tensions:
Downloading images is a network side effect:
waydroid initdownloads Android system images (about 300-500MB) fromsourceforge.netorota.waydro.id, which is a network I/O operation. Ordinary builds restrict network access, but fixed-output fetchers can retrieve images by hash. Whether to manage this through Nix is a matter of engineering design and update strategy.Image updates are ongoing external events: OTA updates follow upstream releases and are not guaranteed weekly. You can record the image channel, version, and hash, or even define a custom pinned source, but the existing NixOS module does not do this automatically.
Initialization writes to runtime directories:
waydroid initextracts images into/var/lib/waydroid/(system level) and writes configuration files to~/.local/share/waydroid/(user level). These paths are outside the Nix store (/nix/store/) and are not protected by NixOS's atomicity.
Declarative vs. imperative boundaries
| Operation | Declarative | Imperative | Notes |
|---|---|---|---|
| Install the Waydroid package | :heavy_check_mark: | :x: | virtualisation.waydroid.enable = true |
| Choose the nftables/iptables backend | :heavy_check_mark: | :x: | virtualisation.waydroid.package |
| Set environment variables | :heavy_check_mark: | :x: | environment.sessionVariables |
| Install helper tools | :heavy_check_mark: | :x: | environment.systemPackages |
| Manage systemd services | :heavy_check_mark: | :x: | systemd.services / systemd.packages |
| Download system images | :x: | :heavy_check_mark: | sudo waydroid init -s GAPPS |
| Upgrade system images | :x: | :heavy_check_mark: | sudo waydroid upgrade |
| Set runtime properties | :x: | :heavy_check_mark: | sudo waydroid prop set <key> <value> |
| Install APKs | :x: | :heavy_check_mark: | waydroid app install xxx.apk |
| Manage user-space data | :x: | :heavy_check_mark: | ~/.local/share/waydroid/ |
Community discussions and design judgments
The source notes provide no verifiable discussion links, so their English quotations and claims of “unanimous consensus” cannot be treated as actual community conclusions. In a real design, distinguish configuration, image inputs, and user data. The first two can be versioned or hash-pinned as needed; the last still requires backups and migration. Rolling back a system generation does not automatically roll back /var/lib/waydroid or user data.
Practical compromise patterns
The following three organizational patterns help record and reuse necessary operations. They are not presented as an unverified, uniform community recommendation:
Pattern 1: a first-install script
Wrap waydroid init in a one-time setup script, separate from the NixOS configuration:
# 在 configuration.nix 中声明一个 setup 脚本
environment.systemPackages = with pkgs; [
(writeShellScriptBin "waydroid-first-setup" ''
set -euo pipefail
echo "=== Waydroid 首次安装脚本 ==="
# 检查是否已初始化
if [ -f /var/lib/waydroid/waydroid_base.prop ]; then
echo "Waydroid 已初始化,跳过。如需重新初始化,请先执行:"
echo " sudo waydroid init -f -s GAPPS"
exit 0
fi
echo "步骤 1/3: 确保容器服务未运行..."
sudo systemctl stop waydroid-container || true
echo "步骤 2/3: 下载并初始化系统镜像..."
sudo waydroid init -s GAPPS
echo "步骤 3/3: 应用 NixOS 优化属性..."
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 sys.use_memfd=true
# AMD/Intel GPU:
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.gralloc=gbm
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.egl=mesa
# 如需 ARM 转译,取消下行的注释:
# sudo waydroid prop set ro.product.cpu.abilist x86_64,arm64-v8a,armeabi-v7a,armeabi
# sudo waydroid prop set ro.product.cpu.abilist64 x86_64,arm64-v8a
echo "=== 初始化完成 ==="
echo "现在执行:"
echo " sudo systemctl start waydroid-container"
echo " waydroid session start"
echo " waydroid show-full-ui"
'')
];Run waydroid-first-setup on the first deployment. Later runs of nixos-rebuild switch will not repeat initialization.
Pattern 2: a periodic upgrade timer
You can check for image updates during maintenance windows. Enable an automatic upgrade timer only after confirming backups, session shutdown, and the rollback strategy. The weekly setting below is only an example frequency:
systemd = {
services.waydroid-upgrade = {
description = "Waydroid OTA upgrade";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
path = with pkgs; [ waydroid-nftables ];
script = ''
if [ -f /var/lib/waydroid/waydroid_base.prop ]; then
# 更新前保存数据并协调运行会话
waydroid upgrade
fi
'';
serviceConfig = {
Type = "oneshot";
# 非关键服务,失败不影响系统
# 日志可通过 journalctl -u waydroid-upgrade 查看
};
};
timers.waydroid-upgrade = {
description = "Weekly Waydroid OTA upgrade";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "weekly";
Persistent = true; # 如果错过了执行窗口,启动后补执行
RandomizedDelaySec = "1h"; # 随机延迟,避免全网同时请求 OTA 服务器
};
};
};Pattern 3: an incremental property configuration script
Record waydroid prop set changes in a script so they can be reproduced on another machine:
environment.systemPackages = with pkgs; [
(writeShellScriptBin "waydroid-apply-props" ''
# 增量应用 Waydroid 属性(仅修改与默认值不同的项)
# 这个脚本可以安全地多次运行
props() {
sudo waydroid prop set "$1" "$2"
}
# 性能优化
# 此启动期属性不能由运行时 props 保证生效:sys.use_memfd=true
# GPU 配置(根据你的硬件选择)
# 此启动期属性不能由运行时 props 保证生效:ro.hardware.gralloc=gbm
# 此启动期属性不能由运行时 props 保证生效:ro.hardware.egl=mesa
echo "属性已应用。重启容器以生效:"
echo " sudo systemctl restart waydroid-container"
'')
];NixOS-specific problems and solutions#
NixOS's immutable infrastructure model and distinctive system organization can cause problems that do not arise on other distributions. The following are the most common failure scenarios for NixOS users and their solutions.
Issue 1: fstab warnings — "Do not install Waydroid before running nixos-generate-config"
Symptoms:
$ nixos-generate-config
warning: unknown filesystem type 'waydroid' for mount '/var/lib/waydroid'Or, more seriously:
$ sudo nixos-rebuild switch
error: fileSystems option contains an entry for '/var/lib/waydroid' with unknown filesystem typeCause: Waydroid's systemd service creates bind mounts under /var/lib/waydroid/. nixos-generate-config scans /proc/mounts and writes all mount points to hardware-configuration.nix. If the Waydroid container is running at that point, the generated configuration incorrectly includes Waydroid's internal mounts.
Solution:
# 1. 停止 Waydroid 容器
sudo systemctl stop waydroid-container
# 2. 卸载 Waydroid 的所有绑定挂载
sudo waydroid container stop
# 或手动卸载:
findmnt -R /var/lib/waydroid # 先核对挂载,不盲目递归卸载
# 3. 重新生成硬件配置
sudo nixos-generate-config
# 4. 确认 hardware-configuration.nix 中没有 waydroid 相关条目
grep waydroid /etc/nixos/hardware-configuration.nix
# 应该无输出
# 5. 重新应用配置
sudo nixos-rebuild switchBest practice: complete the initial NixOS installation and run
nixos-generate-configbefore installing Waydroid. If you have already encountered this problem, the cleanup steps above can resolve it.
Issue 2: LXC version mismatch
Symptoms:
failed to start container: lxc version mismatch
# 或
Error: container 'waydroid' is not runningCause: Waydroid and LXC in nixpkgs may have mismatched versions because channel updates are out of sync. Waydroid depends heavily on the LXC user-space toolchain (lxc-start, lxc-stop, and others). Incompatible versions can prevent the container from starting.
Diagnosis:
# 检查 Waydroid 链接的 LXC 版本
waydroid --version
file "$(command -v waydroid)" # Waydroid 通常是脚本/包装器,ldd 不能追踪其全部依赖
# 检查系统中 LXC 的版本
lxc-start --version
nix-store --query --requisites "$(readlink -f "$(command -v waydroid)")" | rg lxc # 仅作闭包线索Solution:
# 方案 1:锁定 LXC 版本(如果已知兼容版本)
{
nixpkgs.config.packageOverrides = super: let self = super.pkgs; in {
waydroid = super.waydroid.override {
lxc = super.lxc.overrideAttrs (old: {
# 如果需要特定版本,在此指定
});
};
};
}# 方案 2:清除 Waydroid 缓存并重新初始化
sudo systemctl stop waydroid-container
sudo waydroid container stop
# 破坏性清理示例:先停止会话/容器、核对路径和备份,再手动决定
# sudo rm -rf -- /var/lib/waydroid/data
# 破坏性清理示例:先停止会话/容器、核对路径和备份,再手动决定
# sudo rm -rf -- /var/lib/waydroid/rootfs
# 仅保留配置文件
sudo waydroid init -f -s GAPPS
sudo systemctl start waydroid-containerOn the NixOS unstable channel, LXC and Waydroid version discrepancies are usually fixed through PRs within a few days. If you encounter this problem, try reverting to the previous channel version or waiting for an update.
Issue 3: the binder kernel module is unavailable
Symptoms:
modprobe: FATAL: Module binder_linux not found in directory /lib/modules/...Cause: the NixOS kernel builds binder_linux as a module by default, but some custom kernel configurations may omit the ANDROID_BINDER_IPC option.
Diagnosis:
# 检查内核是否支持 binder
zgrep ANDROID_BINDER /proc/config.gz
# 期望输出:
# CONFIG_ANDROID_BINDER_IPC=y (或 =m,表示编译为模块)
# 检查模块是否可用
modinfo binder_linux
# 如果内核不支持,检查是否有 ashmem 替代
zgrep ANDROID /proc/config.gzSolution (NixOS):
{
# 方案 1:启用 binder 内核模块(标准 NixOS 内核已包含)
boot.kernelModules = [ "binder_linux" ];
# 方案 2:如果使用自定义内核,确保启用 Android 选项
boot.kernelPatches = [
{
name = "enable-android-binder";
patch = null;
extraStructuredConfig = with lib.kernel; {
ANDROID = yes;
ANDROID_BINDER_IPC = yes;
};
}
];
# 方案 3:使用 支持当前镜像的内核 的 memfd 替代 ashmem
# (在 waydroid_base.prop 中设置 sys.use_memfd=true)
# 这不需要内核模块支持
}NixOS 26.05 (kernel 6.18.x) includes
ANDROID_BINDER_IPC=mby default, so additional configuration is usually unnecessary. If you use a nonstandard kernel (such aslinux_lqxorlinux_zen), confirm that it includes this option.
Issue 4: compositor compatibility and optional nested sessions
Symptoms: after starting Waydroid on Hyprland, the window does not display correctly or input events behave erratically.
Cause: Waydroid runs as a standalone window under Wayland, but some Wayland compositors, especially wlroots-based Hyprland, may conflict with Waydroid's Wayland backend in window compositing or input-focus management.
Solution: use cage to create a nested Wayland session:
# 1. 安装 cage(已在上述完整配置中包含)
# environment.systemPackages = [ pkgs.cage ];
# 2. 在 cage 中启动 Waydroid
cage -- waydroid show-full-ui
# 或者创建一个专用的启动脚本
cat > ~/bin/waydroid-cage <<'EOF'
#!/usr/bin/env bash
# 在嵌套 Wayland 会话中运行 Waydroid,解决 Hyprland 兼容性问题
cage -s -- waydroid show-full-ui
EOF
chmod +x ~/bin/waydroid-cageHyprland users can bind a keyboard shortcut:
# ~/.config/hypr/hyprland.conf
bind = $mainMod, W, exec, ~/bin/waydroid-cageIf you use GNOME Wayland or KDE Plasma Wayland, cage is usually unnecessary. Whether a nested session is needed depends on the specific version and problem. Hyprland is not currently a wlroots-based project, so it should not be categorized that way generally.
Issue 5: hybrid-GPU multi-output configuration
Symptoms: on laptops with hybrid graphics (Intel + NVIDIA / AMD + NVIDIA), Waydroid may select the wrong GPU.
Cause: hybrid graphics on NixOS are usually managed through hardware.nvidia.prime (NVIDIA PRIME) or services.xserver.videoDrivers. Waydroid detects GPUs through render nodes under /dev/dri/ (renderD128, renderD129, and so on), and may select the wrong node.
Diagnosis:
# 检查可用的渲染节点
ls -la /dev/dri/
# 通常:
# renderD128 - 集成显卡(AMD iGPU / Intel iGPU)
# renderD129 - 独立显卡(NVIDIA / AMD dGPU)
# 检查 Waydroid 当前使用的 GPU
sudo waydroid shell dumpsys SurfaceFlinger | grep -i gpuSolution:
{
# NixOS Hybrid 配置示例(Intel + NVIDIA)
hardware.nvidia = {
modesetting.enable = true;
powerManagement.enable = true;
prime = {
# Intel iGPU 作为主渲染设备
intelBusId = "<VERIFIED_INTEL_BUS_ID>";
nvidiaBusId = "<VERIFIED_NVIDIA_BUS_ID>";
};
};
# 确保 Waydroid 能访问两个 GPU 的渲染节点
# /dev/dri/renderD128 (iGPU) 和 /dev/dri/renderD129 (dGPU)
}Specify the GPU in Waydroid's properties:
# 使用集显(推荐,功耗更低)
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.gralloc=gbm
# 启动期属性:在 waydroid.cfg 的 [properties] 中设置 ro.hardware.egl=mesa
# 如果必须使用独显
# sudo waydroid prop set ro.hardware.gralloc gbm
# sudo waydroid prop set ro.hardware.egl mesaFor NVIDIA hybrid-graphics users If you use NVIDIA PRIME render offload mode, Waydroid's support for the discrete NVIDIA GPU under Wayland is very limited. Recommendations:
- Prefer the integrated Intel/AMD GPU for Waydroid
- If your graphics path is unsupported, follow the official software-rendering FAQ to set gralloc/egl under [properties] in waydroid.cfg, then apply the configuration and verify the renderer.
Issue 6: insufficient storage and cleanup
Symptoms: /var/lib/waydroid/ uses a large amount of space (typically 5-15GB), and the / partition is running out of room.
Cause: Waydroid's Android system images and data partition are stored in this directory. The GApps version is about 1GB larger than VANILLA.
Monitoring:
# 查看 Waydroid 存储占用
du -sh /var/lib/waydroid/
du -sh /var/lib/waydroid/*/
# 查看 Android 内部存储使用
sudo waydroid shell df -hCleanup approach:
# 完全重置 Waydroid(保留系统镜像)
sudo systemctl stop waydroid-container
# 破坏性清理示例:先停止会话/容器、核对路径和备份,再手动决定
# sudo rm -rf -- /var/lib/waydroid/data
# 破坏性清理示例:先停止会话/容器、核对路径和备份,再手动决定
# sudo rm -rf -- /var/lib/waydroid/cache
sudo waydroid init -f -s GAPPS
sudo systemctl start waydroid-container
# 完全删除 Waydroid(包括系统镜像)
sudo systemctl stop waydroid-container
sudo waydroid container stop
# 破坏性清理示例:先停止会话/容器、核对路径和备份,再手动决定
# sudo rm -rf -- /var/lib/waydroid/
# 破坏性清理示例:先停止会话/容器、核对路径和备份,再手动决定
# rm -rf -- ~/.local/share/waydroid/
# 破坏性清理示例:先停止会话/容器、核对路径和备份,再手动决定
# rm -rf -- ~/.config/waydroid/
# 破坏性清理示例:先停止会话/容器、核对路径和备份,再手动决定
# rm -rf -- ~/waydroid/Checking NixOS version compatibility
The source notes do not provide enough evidence for their matrix of release codenames, fixed kernels, and default backends. Do not treat it as a verified historical table. Instead, check the actual inputs:
| Layer | What to check against | Verification criteria |
|---|---|---|
| System module | flake.lock / waydroid.nix on the corresponding branch | Supported options, kernel assertions, services, and interfaces |
| Package | The derivation in the pinned nixpkgs | Waydroid/LXC/networking-tool closure |
| Kernel | boot.kernelPackages and the running kernel | Binder, BinderFS, MEMFD, and PSI are actually available |
| Graphics | Host/image Mesa, DRM, and compositor | Renderer, UI, and application operation |
| State | Android image version and user data | Initialization, upgrades, backups, and recovery |
Summary#
Core principles for deploying Waydroid on NixOS:
- Manage declaratively what you can: package installation, systemd services, environment variables, and PolicyKit rules, all configured declaratively through
virtualisation.waydroidandsystemdoptions. - Keep the unavoidable imperative operations separate: wrap
waydroid init,waydroid upgrade, andwaydroid prop setin one-time scripts or systemd timers, maintaining a clear boundary with the NixOS configuration. - Choose the correct backend: select a consistent backend based on networking.nftables.enable and the actual package.
- Prefer integrated graphics: GBM mode with AMD/Intel open-source drivers provides the best experience; NVIDIA users need special handling.
- Use community resources:
waydroid-helper(NixOS 25.11+) and NUR'swaydroid-scriptcan simplify common operations.
Waydroid's "incomplete declarative support" is not a flaw in NixOS. It is the boundary of the existing module and runtime-state management. Accepting that boundary and bridging the gaps with scripts is the best practice for using NixOS and Waydroid together.
Verification sources#
Official Waydroid installation instructions.
Official Waydroid command documentation.
References & further reading
- Official Waydroid installation instructions ↗
- Official Waydroid command documentation ↗
- Waydroid upstream source ↗
- NixOS 26.05 Waydroid module ↗
- NixOS Wiki: Waydroid ↗
Adapted from technical notes. Examples use generic names.
Continue along a reading path
Waydroid
- 01Waydroid architecture: LXC, Binder, and session bridging
- 02Waydroid installation and basic setup
- 03Waydroid integration on NixOS
- 04Waydroid GPU detection and hardware acceleration
- 05Waydroid bridges, NAT, and security boundaries
- 06Waydroid properties, multi-window mode, and ARM translation
- 07Waydroid troubleshooting and FAQ
- 08Waydroid tips: windows, translation, and shared directories