matthewbauer / nixiosk

Declarative Kiosk systems built with NixOS
MIT License
141 stars 12 forks source link

You can try out a QEMU kiosk, quickly. Just run:

+BEGIN_SRC sh

$ nix-env -iA cachix -f https://cachix.org/api/v1/install $ cachix use nixiosk $ ./qemu.sh nixiosk.json.sample

+END_SRC

This sets up the Nixiosk cachix and then downloads QEMU as well as the image defined in nixiosk.json.sample. It then runs that image which boots up NixOS and a web browser window.

This is a Kiosk builder system. It can be used to make a system that single graphical program. This is useful for making systems that do video conferencing, digital signage, informational displays, Internet kiosks, and more. Right now, only Raspberry Pi 0-4 are supported.

** Configuration

To make things simple, it just reads from an ad-hoc JSON file that describe the hardware plus some other customizations. It looks like this:

+BEGIN_SRC json

{ "hostName": "nixiosk", "hardware": "raspberryPi4", "authorizedKeys": [], "program": { "package": "cog", "executable": "/bin/cog", "args": ["https://en.wikipedia.org/"] }, "networks": { "my-router": "0000000000000000000000000000000000000000000000000000000000000000", }, "locale": { "timeZone": "America/New_York", "regDom": "US", "lang": "en_US.UTF-8" }, "localSystem": { "system": "x86_64-linux", "sshUser": "me", "hostName": "my-laptop-host", } }

+END_SRC

Here’s a basic idea of what each of these fields do:

** Push to deploy :PROPERTIES: :CUSTOM_ID: push-to-deploy :END:

By default, Basalt is set up to enable push-to-deploy. This allows you to make changes to this repo and rebuild the system. Unfortunately, this requires setting up a remote builder which is kind of difficult to do. Some steps are as follows:

*** Cloning :PROPERTIES: :CUSTOM_ID: cloning :END:

Once you have a remote builder configure on your Kiosk, you can clone your Kiosk repo:

+BEGIN_SRC sh

$ git clone ssh://root@nixiosk.local/etc/nixos/configuration.git nixiosk-configuration

+END_SRC

From here, you can make some changes, and commit them to the repo. When done, you can just do:

+BEGIN_SRC sh

$ git push

+END_SRC

and read the output of the new deployment.

*** Remote builder (optional) :PROPERTIES: :CUSTOM_ID: remote-builder-optional :END:

Note: this is only necessary for 32-bit ARM systems. NixOS binary caches are provided for 64-bit ARM, available in Raspberry Pi 3 and 4.

Before starting, you need to make sure your nixiosk.json has the correct values for your local computer under localSystem. This should be a hostname that the Kiosk will be able to access. For this to work, you also need to be a trusted-user on your local system.

First, we need to give the Kiosk SSH access:

+BEGIN_SRC sh

$ echo $(ssh root@nixiosk.local cat '$HOME'/.ssh/id_rsa.pub) >> $HOME/.ssh/authorized_keys

+END_SRC

Then, we need to test that we can access the local computer through SSH:

+BEGIN_SRC sh

$ ssh root@nixiosk.local $ ssh me@my-laptop-host

+END_SRC

If all is well, then we can proceed to cloning the configuration.

** Install Nix

If you haven’t already, you need to install Nix. This can be done through the installer:

+BEGIN_SRC sh

$ bash <(curl -L https://nixos.org/nix/install)

+END_SRC

** Cache

To speed things up, you should setup a binary cache for nixiosk. This can be done easily through [[https://nixiosk.cachix.org/][Cachix]]. First, install Cachix:

+BEGIN_SRC sh

$ nix-env -iA cachix -f https://cachix.org/api/v1/install

+END_SRC

Then, use the nixiosk cache:

+BEGIN_SRC sh

$ cachix use nixiosk

+END_SRC

For more information refer to https://app.cachix.org/cache/nixiosk.

** Initial deployment

The deployment is pretty easy provided you have [[https://nixos.org/nix/][Nix installed]]. Here are some steps:

+BEGIN_SRC sh

$ git clone https://github.com/matthewbauer/nixiosk.git $ cd nixiosk/ $ cp nixiosk.json.sample nixiosk.json

+END_SRC

Now you need to make some changes to nixiosk.json to reflect what you want your system to do. The important ones are ‘authorizedKeys’ and ‘networks’ so that your systems can startup and you can connect to it.

If you have an SSH key setup, you can get its value with:

+BEGIN_SRC sh

$ cat $HOME/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC050iPG8ckY/dj2O3ol20G2lTdr7ERFz4LD3R4yqoT5W0THjNFdCqavvduCIAtF1Xx/OmTISblnGKf10rYLNzDdyMMFy7tUSiC7/T37EW0s+EFGhS9yOcjCVvHYwgnGZCF4ec33toE8Htq2UKBVgtE0PMwPAyCGYhFxFLYN8J8/xnMNGqNE6iTGbK5qb4yg3rwyrKMXLNGVNsPVcMfdyk3xqUilDp4U7HHQpqX0wKrUvrBZ87LnO9z3X/QIRVQhS5GqnIjRYe4L9yxZtTjW5HdwIq1jcvZc/1Uu7bkMh3gkCwbrpmudSGpdUlyEreaHOJf3XH4psr6IMGVJvxnGiV9 mbauer@dellbook

+END_SRC

which will give you a line for “authorizedKeys” like:

+BEGIN_SRC json

"authorizedKeys": ["ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC050iPG8ckY/dj2O3ol20G2lTdr7ERFz4LD3R4yqoT5W0THjNFdCqavvduCIAtF1Xx/OmTISblnGKf10rYLNzDdyMMFy7tUSiC7/T37EW0s+EFGhS9yOcjCVvHYwgnGZCF4ec33toE8Htq2UKBVgtE0PMwPAyCGYhFxFLYN8J8/xnMNGqNE6iTGbK5qb4yg3rwyrKMXLNGVNsPVcMfdyk3xqUilDp4U7HHQpqX0wKrUvrBZ87LnO9z3X/QIRVQhS5GqnIjRYe4L9yxZtTjW5HdwIq1jcvZc/1Uu7bkMh3gkCwbrpmudSGpdUlyEreaHOJf3XH4psr6IMGVJvxnGiV9 mbauer@dellbook"],

+END_SRC

and you can get a PSK value for your WiFi network with:

+BEGIN_SRC sh

$ nix-shell -p wpa_supplicant --run 'wpa_passphrase my-network' network={ ssid="my-network"

psk="abcdefgh"

psk=17e76a6490ac112dbeba996caa7cd1387c6ebf6ce721ef704f92b681bb2e9000

}

+END_SRC

so your .json file looks like:

+BEGIN_SRC json

"networks": { "my-network": "17e76a6490ac112dbeba996caa7cd1387c6ebf6ce721ef704f92b681bb2e9000", },

+END_SRC

Now, after inserting your Raspberry Pi SD card into the primary slot, you can deploy to it with:

+BEGIN_SRC sh

$ ./deploy.sh /dev/mmcblk0

+END_SRC

Note that this will take quite a while right now because I don’t have a binary cache setup. Stay tuned so that this part hopefully gets easier. It will also take a few minutes to write to your SD card.

You can now eject your SD card and insert it into your Raspberry Pi. It will boot immediately to a Cog browser, loading en.wikipedia.org.

** Redeployment *** Git push

You can pretty easily make changes to a running system given you have SSH access. This is as easy as cloning the running config:

+BEGIN_SRC sh

$ git clone ssh://root@nixiosk.local/etc/nixos/configuration.git nixiosk-configuration $ cd nixiosk-configuration

+END_SRC

Then, make some changes in your repo. After your done, you can just run ‘git push’ to redeploy.

+BEGIN_SRC sh

$ git add . $ git commit $ git push

+END_SRC

You’ll see the NixOS switch-to-configuration log in your command output. If all is successful, the system should immediately reflect your changes. If not, the output of Git should explain what went wrong.

*** Redeploy script

Some machines like the Raspberry Pi 0 are too small to rebuild themselves. For this, we can use the =update.sh= script. This works by building a configuration, then running =nix copy= to move it to the machine, then activating the configuration. Make sure you have plenty of space on your SD card so that we don’t run out of space!

For example, with retropi1.json, you can do this:

+BEGIN_SRC sh

$ ./redeploy.sh kodpi2.json kodipi2.local

+END_SRC

** Development

You can fork and make changes to this repo . A =release.nix= lists all of the configurations that are tested in CI. There is a =build.sh= script as well.

It can be used like:

+BEGIN_SRC sh

$ ./build.sh kodipi2.json

+END_SRC

Additional arguments are passed to =nix-build=.

For more advanced usage, we can utilize a full NixOS module configuration. This requires experimental Nix 2.4 features to work. First, we start with a template from nixiosk template directoy.

To setup a new project:

+BEGIN_SRC sh

$ nix --experimental-features 'nix-command flakes' flake new -t github:matthewbauer/nixiosk myproject

+END_SRC

You can look at myproject/flake.nix to get an idea of what you can configure. Most of the settings in ‘nixosModule’ correspond to what is available in the custom .json files. One advantage over .json is your package does not need to be in Nixpkgs. In addition, you can override other NixOS settings as needed.

The script commands work with flake if you provide a =--flake= argument. For instance, to build your new configuration:

+BEGIN_SRC sh

$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \ nixiosk-build --flake ./myproject#nixosConfigurations.example-rpi4

+END_SRC

This is the SD image for a Raspberry Pi 4 system. Targets for ISO (packages.x86_64-linux.isoImage), VirtualBox .ova (packages.x86_64-linux.virtualBoxOVA), and QEMU .qcow2 (packages.x86_64-linux.qcow2) are also available. All of these are cached on x86_64-linux.

You will most likely want to provide your own "nixiosk.program", "authorizedKeys", and "networks" in the template baseConfig. Make sure to also use nixiosk cachix to speed up building.

If you have your Raspberry Pi SD card inserted at /dev/sdb, you can write to it directly with:

+BEGIN_SRC sh

$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \ nixiosk-deploy /dev/sdb --flake ./myproject#nixosConfigurations.example-rpi4

+END_SRC

You can insert the SD card directly into the Raspberry Pi and boot it up.

If the Raspberry Pi connects to your local network, you can deploy changes with:

+BEGIN_SRC sh

$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \ nixiosk-redeploy --flake ./myproject#nixosConfigurations.example-rpi4

+END_SRC

If you don’t have a Raspberry Pi, you can run the QEMU emulator to test out your configuration locally. This requires hardware virtualization support to work well. On a graphical session, you can run:

+BEGIN_SRC sh

$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \ nixiosk-qemu --flake ./myproject#nixosConfigurations.example-qemu

+END_SRC

On a non-graphical session, you can run:

+BEGIN_SRC sh

$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \ nixiosk-qemu --vnc --flake ./myproject#nixosConfigurations.example-qemu

+END_SRC

You must set the vnc password in the qemu console with =change vnc password abcdef=. Connect to it in your VNC client with vnc://localhost (replacing localhost with your local network hostname).

You can also create a PXE server with:

+BEGIN_SRC sh

$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \ nixiosk-pixiecore --flake ./myproject#nixosConfigurations.example-pxe

+END_SRC

Here are some of the pieces that make the Kiosk system possible:

I would also like to include some more tools to make administration easier:

** /dev/mmcblk0 is not a valid device

If this file doesn’t exist, you may not have your SD card inserted properly. If it is inserted properly, you may have a different device name. Look in /dev for other devices.

** /dev/mmcblk0 has partitions! Reformat the table to avoid loss of data

You need to reformat the partition table to ensure we aren’t losing data. You can do this with wipefs:

+BEGIN_SRC sh

$ nix-shell -p utillinux -run 'wipefs /dev/mmcblk0'

+END_SRC

** failed to open '/dev/disk2': Resource busy

You may have to unmount your sd drive to continue. You can try running:

+BEGIN_SRC sh

$ sudo diskutil unmountDisk /dev/disk2

+END_SRC

** SSH into QEMU

In order to SSH into a running QEMU Nixiosk system, you must follow the following steps:

In the QEMU window, go to the top Menu bar and select "View" → "compat_monitor0". This will enter into a terminal view.

Within the terminal, type the following followed by enter:

+BEGIN_SRC text

hostfwd_add tcp::2222-:22

+END_SRC

Now you can SSH under the 2222 port:

+BEGIN_SRC sh

$ ssh -p 2222 root@localhost

+END_SRC

You can switch back to the manu QEMU window by selecting "View" → "virtio-vga".

If you have multiple QEMU windows open at once, you will need to use a different port for each one. Just follow the above steps substituting 2222 with 2223.

** SSH requires a password

If you cannot SSH following any of the above instructions, and get something like:

+BEGIN_SRC sh

$ ssh -p 2222 root@localhost (root@localhost) Password: (root@localhost) Password: (root@localhost) Password: root@localhost's password: Permission denied, please try again. root@localhost's password: Permission denied, please try again. root@localhost's password: Received disconnect from 127.0.0.1 port 2222:2: Too many authentication failures

+END_SRC

You have not configured your public keys correctly. Make sure the contents on =$HOME/.ssh/id_rsa.pub= or similar are included in authorizedKeys for your system configuration.