NixOS on the Pinephone Pro

Table of Contents

1. NixOS on the Pinephone Pro

1.1. What is this about

This is my personal log of experience with my work on NixOS on the Pinephone Pro. Since i am both a beginner when it comes to NixOS or hardware tinkering (besides some ESP32 stuff) this will document the failures as much as the sucecss stories. I think there are many out there like me, so maybe that helps.

I plan to keep this site evolving over the next months, so make sure you come back at times. You could also subscribe to the RSS feed of the git repo this is generated from.

If this project reaches a state from where readers can build and maintain their system, i plan to move a (corrected and formatted) version to the official nixos-mobile documentation.

If you should be interested in anything regarding mobile nixos on the PPP, let me know by opening an Issue here.

1.2. Disclaimer

As usual, when it comes to such a blog i will warn you, that since i do not 100% know what i am doing, things can break. Follow the guides at your own risk. For safety, i am not writing to the internak eMMC but rather use a SD card, which should not brick the phone when things go sideways.

2. Contact

You can contact me via

  • message on Matrix
  • message in the fediverse (Mastodon)
  • Follow me on Mastodon!
  • Codeberg issue in my repo

3. Blog

3.1. Day 1 - Building an SD card image

The procedure i went with was cloning the git repo from samuel and adding a custom local.nix file on root level of the repo. This file is not tracked since it is listed in the .gitignore. The following chapters describe how and why i added things.

3.1.1. Initialization of local.nix

{ config, libs, pkgs, ... }:

3.1.2. Declaration of variables

  user = "linux"; # Put your desired name here
  password = "123123"; # numeric password so the login manager from phosh/plasma/mobile can handle

3.1.3. Imports

We do not have anything to import so far

# imports = [];

3.1.4. Configuration

  1. Users
    users = {
    mutableUsers = true;
    # take username from variables
    users."${user}" = {
      isNormalUser = true;
      password = password; # take password from variables
      extraGroups = [
        "wheel" # for sudo
        "users" # for login manager
  2. System Packages
    environment.systemPackages = with pkgs; [
      # Default stuff you need
      fish # may be redundant with
    # GNOME suite
      # fractal #commenting this out because it did not build on my phone
    ]; = true;
    users.defaultUserShell =;
  3. Desktop Environments
    1. Phosh
      services.xserver.desktopManager.phosh = {
        enable = true;
        user = user; # from variables
        group = "users";
  4. Services
    1. TODO SSH

      We will add SSH keys later

      services.openssh.enable = true;
  5. Calls

    I think this is for GNOME

    programs.calls.enable = true;

3.1.5. Cleanup

We wilalso include a default version here, since we need it later on the global config.

  system.stateVersion = "22.05";

3.1.6. Full local.nix

 1: { config, libs, pkgs, ... }:
 3: let
 4:   user = "linux"; # Put your desired name here
 5:   password =
 6:     "123123"; # numeric password so the login manager from phosh/plasma/mobile can handle
 7: in {
 9:   # imports = [];
11:   users = {
12:     mutableUsers = true;
13:     # take username from variables
14:     users."${user}" = {
15:       isNormalUser = true;
16:       password = password; # take password from variables
17:       extraGroups = [
18:         "wheel" # for sudo
19:         "users" # for login manager
20:         "dialout"
21:         "feedbackd"
22:         "networkmanager"
23:         "video"
24:       ];
25:     };
26:   };
28:   environment.systemPackages = with pkgs; [
29:     # Default stuff you need
30:     vim
31:     helix
32:     git
33:     curl
34:     fish # may be redundant with
35:     exa
36:     bat
37:     htop
39:     # GNOME suite
40:     chatty
41:     gnome-console
42:     megapixels
43:     epiphany
44:     # fractal #commenting this out because it did not build on my phone
45:     portfolio-filemanager
46:   ];
48: = true;
49:   users.defaultUserShell =;
51:   services.xserver.desktopManager.phosh = {
52:     enable = true;
53:     user = user; # from variables
54:     group = "users";
55:   };
57:   services.openssh.enable = true;
59:   programs.calls.enable = true;
61:   system.stateVersion = "22.05";
62: }

3.1.7. Building the image

In the repos root folder execute the following command. This can take minutes or even hours depending on your bandwidth and hardware specs.

I am building it on a Raspberry Pi4 8GB and it took around 2-3 hours on the first run. Former runs (when i changed config) took about 10-30 minutes or less.

nix-build --argstr device pine64-pinephonepro -A build.disk-image

This will take the hardware specs from the devices/pine64-pinephonepro folder (default.nix) and use them as additional inputs. Note The local.nix we built before will also be used.

The image is located in the result folder. This should also be displayed at the end of the build process.

3.1.8. Writing the SD card

With an image built, write the contents to an SD card. You can use "dd" for that or something else, i used "popsicle" on my main machine. Note The produced images had a very small size for the main partition. I resized it after flashing with "gparted". If needed, i can put a tutorial in here, but i will skip it for now.

3.1.9. Conclusion

Well, the system is bootable, the login manager logs me into phosh. Apps can be started etc. But some things are off. For example i use Nheko as my matrix client, which does not start due to some QT dependencies. That needs to be investigated. Another point is installing new apps. Since we do not have a global /etc/nixos/configuration.nix (more on that later) we can still use nix-env. But it seems some of these apps cannot access the internet, while others installed in the image seem to be able to. For this example i used bitwarden-cli and fractal. On a sidenote: i think the github branch which i based off my work is far behind the official nixos-mobile repo, so e.g. phosh is a little outdated. Maybe i will try to find the definition of the source and adjust it.

3.2. Day 2 - Open questions and where do we go from here

3.2.1. TODO Topics from the previous day

  1. QT apps on GNOME/phosh

    Since this may not occur to many persons, this topic is rather low priority and will be resolved later.

  2. TODO Apps installed via nix-env
  3. TODO Uisng a newer version of the package index

    In the root folder, there is a file called pkgs.nix which is included in the default.nix to build the image. Switching the "rev" and "sha" variable should already do the trick. To find suitable revisions, check the nixpkgs git repo.

3.2.2. New/Future Topics

  1. Using global config on the system

    Since we are using the prebuilt image only right now, i would like to go for the classic approach of using the configuration.nix to change the system later on. NixOS mobile provides way similar to "classic" NixOS to rollback to or boot into older generations. I have seen it on my Oneplus 6T (R.I.P. i bricked it somehow) but i read on mobile there is only one generation instead of multiple. Got to research this topic further. Tomorrow i will try creating the configuration.nix and hardware-configuration.nix from our local.nix and devices/pine64-pinephonepro/default.nix.

  2. Using the Nix-Installer instead of a prebuilt image

    The installer is not included in the WIP git repo yet, so i will either migrate it or move to the main branch completely while locally maintaining the PPP device files, which might be the correct call anyway.

3.3. Day 3 - Global configuration

Let's go and create a static configuration.nix to maintain the system after starting the prebuilt image. This should be the desired workflow anyway.

Since we already have some chunks of code from day 1, let us use them. Of course there is a little more stuff to do, maybe we can scrap it together from the mobile-nixos repos (at lest the hardware part).

So what do we need? Usually i try to separate my config in parts which can be saved in different files, so they can easily be imported (and thus can be commented out if we don't want to import them). This comes in handy if we want to switch out a desktop environment for another. Of course this could be controlled by variables but let us keep it that way for now.

3.3.1. Prerequisites

The imports for the built image and the global config differ, so we are using this block of code.

imports = [

3.3.2. FInal Files


 1: { config, libs, pkgs, ... }:
 2: let
 3:   user = "linux"; # Put your desired name here
 4:   password = "123123"; # numeric password so the login manager from phosh/plasma/mobile can handle
 5: in
 6: {
 8: imports = [
 9:   ./hardware-configuration.nix
10: ];
12: users = {
13: mutableUsers = true;
14: # take username from variables
15: users."${user}" = {
16:   isNormalUser = true;
17:   password = password; # take password from variables
18:   extraGroups = [
19:     "wheel" # for sudo
20:     "users" # for login manager
21:     "dialout"
22:     "feedbackd"
23:     "networkmanager"
24:     "video"
25:     ];
26:   };
27: };
29: environment.systemPackages = with pkgs; [
30:   # Default stuff you need
31:   vim
32:   helix
33:   git
34:   curl
35:   fish # may be redundant with
36:   exa
37:   bat
38:   htop
40: # GNOME suite
41:   chatty
42:   gnome-console
43:   megapixels
44:   epiphany
45:   # fractal #commenting this out because it did not build on my phone
46:   portfolio-filemanager
47: ];
49: = true;
50: users.defaultUserShell =;
52: services.xserver.desktopManager.phosh = {
53:   enable = true;
54:   user = user; # from variables
55:   group = "users";
56: };
58: services.openssh.enable = true;
60: programs.calls.enable = true;
62:   system.stateVersion = "22.05";
63: }

For the next step to work i cloned the WIP repo to my /etc/nixos. Other strategies will also work as long as you can link the device specific nix files from here. hardware-configuration.nix

  mobile-nixos = builtins.fetchGit {
    # This combination led to us having to downgrade to 22.05
    #url = "";
    #ref = "wip/pinephone-pro";     
    #rev = "e8ffe9b29c74e27c25f55161c6e952ef97870c3e";
    # Old commit (outdated)
    #rev = "22891f1742a49b87611ba79c4a89d8ac85e2d7b1";

    # This combination should be run on 22.11 channel
    url = "";
    ref = "master";
    #rev = "60251e09b121e60e5b6121b09c9099c54ca77a92";
  #mobile-nixos = ./mobile-nixos-wip;
  imports = [
    (import (mobile-nixos + "/lib/configuration.nix") { device = "pine64-pinephonepro"; })

3.3.3. Deploying the configuration

Make sure the final files are in the /etc/nixos folder.

Since the wip repo uses some old syntax/methods in its packages, we need to make sure, we are running our nix channel on the 22.05 branch. To do this use the following command as root.

nix-channel --add nixos

First we need to make sure the nix channels are up to date. For this we run the following as root:

nix-channel --update

Then deploy/rebuild the system. Again run the following command as root:

nixos-rebuild switch

This will take some time since it is copying alot of stuff from the nix store to your device. NOTE In my case it will also compile some stuff from source, e.g. Fractal. If you desire a quicker setup process, remove fractal from the sytem packages. NOTE It may also be that some packages will not even build at all. So start small and build up, otherwise you might waste 3 hours compiling stuff that fails in the end…

3.4. Day 4 - Feedback from the pros / Update to a newer state

I had some interesting talks with some people in the nixos on ARM matrix channel. They pointed out that some of my earlier issues originated in me using and old system state (22.05 base). I think it will be a good idea to pump up the versions sooner or later anyway, so why not take a cut here from the previous tasks and focus on that first. Since we generated a bootable global config in day 3 already, i think that is a good level to stop the first take on this topic. If you are interested in fiddling from there on, i think it should work for everyone - if not, let me know. Since i do not know how much time i will have due to some RL stuff, i will try to gather the pieces we need in the meantime. That would mean:

  • Creating a fork of the main branch from the nixos-mobile repo. Wether this will be on GitHub or on will have to be decided. Advantage of GH would be the "real" forking, the advantage of CB is well, not being owned by M$.
  • Migrate the pinephone pro specific device configuration to that new repo
  • Build a new system configuration off of that - either via a new SD card or via the already existing installation

Benefits from this operation should be:

  • Less things breaking on config level because upstream has figured it out already, for example the xorg stuff which made me switch to 22.05 state.
  • More up to date packages (duh!), in this case newer DE version (phosh gestures i think) and some kernel stuff (maybe we get to use the PPP keyboard drivers here, for those who have such a keyboard)

So why build a fork of the main repo here? Well the PPP specific config is not merged into the main yet. There is an open pull request, which is not complete yet. As soon as this is done i think it would be best to switch to the main again, just to get a more recent nixpkgs index etc.

I built a custom Codeberg Fork to test things out. You may use this to get things started, but i advise to fork an own repo off the main repo if you really want to test things out, since i may experiment a bit there or discontinue it altogether if the device will be merged into the original repo.

Since we are using the 22.11 release now, make sure to switch/overwrite the existing channel to the correct one

# run as root
  nixos-channel --add nixos

Sadly i cannot go more into detail about switching here, since it is just a minor change in the hardware-configuration.nix.

So building a new system off of this configuration does work, but somehow some apps (some which were working previously) now seem to stop working due to a GTK/Wayland (GTK Error 71) issue. Even gnome-control-center and such will not start. I think i do not have time to figure this out on my own, so help is appreciated. Things that do work are for example the newer phosh version with gestures etc.

On a sidenote i got to test out the NixOS rollback functionality. This happened when i borked my config my some plasma mobile fiddling. Since the system did not boot completely but got to early stage 2 i think, i remembered to have seem the generations recovery some other time on my OP6T. On the Pinephone pro you can reach the recovery menu by holding the volume down button during the Pre-Init stage. And what can i say besides it is a life saver. How many times did i bork my system to an unbootable state when i experimented with Arch Linux on the Pinephone Pro - which is still a great distribution - due to mostly me lacking knowledge, but also bad updates/bad states.

Author: Chfkch

Created: 2024-02-29 Do 11:52