commit 89245d496a0c270d4a24468841c4cbb55d9f4a05 Author: WanderingPenwing Date: Sun Oct 13 17:45:15 2024 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b2be92b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +result diff --git a/README.md b/README.md new file mode 100644 index 0000000..b1ecf4c --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# Building a NixOS SD image for a Raspberry Pi Zero 2 w + +## 1. Update `zero2w.nix` +In particular, don't forget: +- to configure your wifi +- to add an admin user able to connect through ssh + +## 2. Build the image +#### - On arm processor + +```sh +nix build -L .#nixosConfigurations.zero2w.config.system.build.sdImage +``` + +#### - On x86 processor : + +add this to your config : +```nix +boot.binfmt.emulatedSystems = [ "aarch64-linux" ]; +``` +and then run : +```sh +nix build -L .#nixosConfigurations.zero2w.config.system.build.sdImage --system aarch64-linux +``` + +## 3. Copy the image in your sd card +```sh +DEVICE=/dev/disk5 # Whatever your sd card reader is +sudo dd if=result/sd-image/zero2.img of=$DEVICE bs=1M conv=fsync status=progress +``` + +## 4. Boot your Zero + +## 5. From another machine, rebuild the system: +```sh +ZERO2_IP= +SSH_USER= +nix run github:serokell/deploy-rs .#zero2w -- --ssh-user $SSH_USER --hostname $ZERO2_IP +``` + +## Notes +- The Zero 2 doesn't have enough RAM to build itself. An initial lead was to create a swap partition, but it turns out it was a bad idea, as it would have decreased the sd card lifetime (sd cards don't like many write operations). A `zram` swap is not big enough to work. Hence the use of `deploy-rs`. + - Note that `nixos-rebuild --target-host` would work instead of using `deploy-rs`. but as `nixos-rebuild` is not available on Darwin, I'm using `deploy-rs` that works both on NixOS and Darwin. +- I still couldn't find a way to use `boot.kernelPackages = pkgs.linuxKernel.packages.linux_rpi3`. +- the `sdImage.extraFirmwareConfig` option is not ideal as it cannot update `config.txt` after it is created in the sd image. + +## See also +- [this issue](https://github.com/NixOS/nixpkgs/issues/216886) +- [this gist](https://gist.github.com/plmercereau/0c8e6ed376dc77617a7231af319e3d29) + +--- + +# mine + +update +```sh +nix run github:serokell/deploy-rs .#zero2w -- --ssh-user penwing --hostname 192.168.1.33 +``` diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..2287785 --- /dev/null +++ b/flake.lock @@ -0,0 +1,95 @@ +{ + "nodes": { + "deploy-rs": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": "nixpkgs", + "utils": "utils" + }, + "locked": { + "lastModified": 1698921442, + "narHash": "sha256-7KmvhQ7FuXlT/wG4zjTssap6maVqeAMBdtel+VjClSM=", + "owner": "serokell", + "repo": "deploy-rs", + "rev": "660180bbbeae7d60dad5a92b30858306945fd427", + "type": "github" + }, + "original": { + "owner": "serokell", + "repo": "deploy-rs", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1668681692, + "narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "009399224d5e398d03b22badca40a37ac85412a1", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1671417167, + "narHash": "sha256-JkHam6WQOwZN1t2C2sbp1TqMv3TVRjzrdoejqfefwrM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bb31220cca6d044baa6dc2715b07497a2a7c4bc7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1699099776, + "narHash": "sha256-X09iKJ27mGsGambGfkKzqvw5esP1L/Rf8H3u3fCqIiU=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "85f1ba3e51676fa8cc604a3d863d729026a6b8eb", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "deploy-rs": "deploy-rs", + "nixpkgs": "nixpkgs_2" + } + }, + "utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..8d93666 --- /dev/null +++ b/flake.nix @@ -0,0 +1,34 @@ +{ + description = "Flake for building a Raspberry Pi Zero 2 SD image"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + deploy-rs.url = "github:serokell/deploy-rs"; + }; + + outputs = { + self, + nixpkgs, + deploy-rs, + }: rec { + nixosConfigurations = { + zero2w = nixpkgs.lib.nixosSystem { + modules = [ + "${nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" + ./zero2w.nix + ]; + }; + }; + + deploy = { + user = "root"; + nodes = { + zero2w = { + hostname = "zero2w"; + profiles.system.path = + deploy-rs.lib.aarch64-linux.activate.nixos self.nixosConfigurations.zero2w; + }; + }; + }; + }; +} diff --git a/sd-image.nix b/sd-image.nix new file mode 100644 index 0000000..9c38bde --- /dev/null +++ b/sd-image.nix @@ -0,0 +1,40 @@ +# This module extends the official sd-image.nix with the following: +# - ability to add options to the config.txt firmware +{ + config, + lib, + pkgs, + ... +}: { + options.sdImage = with lib; { + extraFirmwareConfig = mkOption { + type = types.attrs; + default = {}; + description = lib.mdDoc '' + Extra configuration to be added to config.txt. + ''; + }; + }; + + config = { + sdImage.populateFirmwareCommands = + lib.mkIf ((lib.length (lib.attrValues config.sdImage.extraFirmwareConfig)) > 0) + ( + let + # Convert the set into a string of lines of "key=value" pairs. + keyValueMap = name: value: name + "=" + toString value; + keyValueList = lib.mapAttrsToList keyValueMap config.sdImage.extraFirmwareConfig; + extraFirmwareConfigString = lib.concatStringsSep "\n" keyValueList; + in + lib.mkAfter + '' + config=firmware/config.txt + # The initial file has just been created without write permissions. Add them to be able to append the file. + chmod u+w $config + echo "\n# Extra configuration" >> $config + echo "${extraFirmwareConfigString}" >> $config + chmod u-w $config + '' + ); + }; +} diff --git a/zero2w.nix b/zero2w.nix new file mode 100644 index 0000000..85a9774 --- /dev/null +++ b/zero2w.nix @@ -0,0 +1,108 @@ +{ + lib, + modulesPath, + pkgs, + ... +}: { + imports = [ + ./sd-image.nix + ]; + + nixpkgs.hostPlatform = "aarch64-linux"; + # ! Need a trusted user for deploy-rs. + nix.settings.trusted-users = ["@wheel"]; + system.stateVersion = "23.11"; + + zramSwap = { + enable = true; + algorithm = "zstd"; + }; + + sdImage = { + # bzip2 compression takes loads of time with emulation, skip it. Enable this if you're low on space. + compressImage = false; + imageName = "zero2.img"; + + extraFirmwareConfig = { + # Give up VRAM for more Free System Memory + # - Disable camera which automatically reserves 128MB VRAM + start_x = 0; + # - Reduce allocation of VRAM to 16MB minimum for non-rotated (32MB for rotated) + gpu_mem = 16; + + # Configure display to 800x600 so it fits on most screens + # * See: https://elinux.org/RPi_Configuration + hdmi_group = 2; + hdmi_mode = 8; + }; + }; + + # Keep this to make sure wifi works + hardware.enableRedistributableFirmware = lib.mkForce false; + hardware.firmware = [pkgs.raspberrypiWirelessFirmware]; + + boot = { + # TODO doesn't work + # kernelPackages = pkgs.linuxKernel.packages.linux_rpi3; + + initrd.availableKernelModules = ["xhci_pci" "usbhid" "usb_storage"]; + loader = { + grub.enable = false; + generic-extlinux-compatible.enable = true; + }; + + # Avoids warning: mdadm: Neither MAILADDR nor PROGRAM has been set. This will cause the `mdmon` service to crash. + # See: https://github.com/NixOS/nixpkgs/issues/254807 + swraid.enable = lib.mkForce false; + }; + + networking = { + interfaces."wlan0".useDHCP = true; + wireless = { + enable = true; + interfaces = ["wlan0"]; + # ! Change the following to connect to your own network + networks = { + "Le Ninternet" = { + psk = "XcTsS9mnz2ePwE7dps"; + }; + }; + }; + }; + + # Enable OpenSSH out of the box. + services.sshd.enable = true; + + # NTP time sync. + services.timesyncd.enable = true; + + # ! Change the following configuration + users.users.penwing = { + isNormalUser = true; + home = "/home/penwing"; + description = "Me"; + extraGroups = ["wheel" "networkmanager"]; + # ! Be sure to put your own public key here + openssh.authorizedKeys.keys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN/SQbXjL6O2zjKFdybiMLu7Imc10IGrTMUnRtIxf0jJ nicolas.pinson31@gmail.com"]; + }; + + security.sudo = { + enable = true; + wheelNeedsPassword = false; + }; + + nixpkgs.config.allowUnfree = true; + + environment.systemPackages = (with pkgs; [ + # CLIs + starship # shell more pretty + git # code versioning + bottom # task manager + micro # text editor + fastfetch + yazi + ]); + + # ! Be sure to change the autologinUser. + services.getty.autologinUser = "penwing"; +}