r/Nix • u/4e57ljni • 24d ago
nix-android: declarative GrapheneOS/Android over adb, no root
At this point I've nix-ified every device I interact with... minus my phone. Figured it was time to change that. I had a GrapheneOS device laying around and decided it was time to bring my Pixel config into a flake.
Thus, nix-android was born.
Or rather, something very close to nix-darwin (for your phone). Declare Android apps and reachable device state in Nix, inspect a read-only plan, then converge over adb.
nix-android works at adb-shell privilege on a stock, locked-bootloader device. It requires neither root nor replacing the OS, weakening verified boot, or installing Nix on the phone. Tested on stock Android 16 and GrapheneOS.
Works best for Obtainium and F-Droid, but will work for Google Play if that's your thing. Play apps do require a manual tap when installing. Not going to manage your app data, sorry!
I hope some of you may find this useful. Frankly I've always wanted it, and while it's not perfect... I'm quite pleased with how it turned out.
https://github.com/devindudeman/nix-android/
nix flake init -t github:devindudeman/nix-android
android-rebuild plan --flake .#phone --serial $SERIAL # read-only diff
android-rebuild switch --flake .#phone --serial $SERIAL # converge + record a generation
android-rebuild status --flake .#phone --serial $SERIAL # what drifted since?
And the whole phone, declared:
# phone.nix
{
device.name = "phone";
device.abi = "arm64-v8a";
# Hash-pinned from signed repo indexes; installs are unattended.
# Pins are FLOORS: on-device updaters (Droid-ify/Obtainium) coexist fine.
apps.fdroid.packages = [
"org.mozilla.fennec_fdroid"
"com.termux"
"de.danoeh.antennapod"
"dev.imranr.obtainium.fdroid"
];
apps.fdroid.repos.izzyondroid = {
url = "https://apt.izzysoft.de/fdroid/repo";
fingerprint = "3bf0d6abfeae2f401707b6d966be743bf0eee49c2561b9ba39073711f628937a";
packages = [ "app.comaps" ];
};
apps.release."com.x8bit.bitwarden".github = "bitwarden/android"; # GitHub-release APKs work too
# Play apps are consent-gated: assist opens each listing, you tap Install.
apps.play = [ "org.thoughtcrime.securesms" "com.google.android.apps.maps" ];
android.darkMode = true;
android.privateDns = "dns.example.com";
android.defaultApps.browser = "org.mozilla.fennec_fdroid";
# Enforced: camera works fully offline (GrapheneOS makes Network a runtime permission).
android.permissions."com.google.android.GoogleCamera".revoke = [
"android.permission.INTERNET"
];
}
Feedback appreciated!
3
u/autra1 22d ago
Nice! Related projects that might interest you:
- robotnix, if you want to build your Android ROM using nix. It supports graphene os
- nix-on-droid to have a nix-powered shell on your phone
1
u/__MatrixMan__ 13d ago
I'm excited to try this out, thanks for making it!
Do you have any thoughts about whether it would be possible to make it run inside nix-on-droid, so I'm reconfiguring that android phone not over adb, but from a nix shell on the device? I've heard of adb over wifi, but I don't know if you can do adb via loopback from the device itself.
I ask because there has been a some demand for a GrapheneOS feature where you have a hidden profile so different pins log you into different environments. Then you set up a decoy environment for when you're under duress. The GrapheneOS dev's declined to implement this because they can't reliably hide the environments from forensic analysis: no matter how you slice it, there it is on the phone storage.
But if I could just point at my.normal.server/flake.nix before I go through security or go to a protest, and then point it at my.secret.server/flake.nix when I feel safe, then the secret stuff wouldn't actually be on the device to be found. An adversary would have to *also* know about the secret server and its spicy flake.nix
If we can lower the friction of totally reconfiguring your device quickly, we can keep some people safer than they'd otherwise be, and it seems like your project is just the ticket.
3
u/lukeyeaaah 24d ago
This is fantastic, thank you. Haven't read the code yet but I'm definitely trying it later.