Quick start
You can try out a QEMU kiosk, quickly. Just run:
$ nix-env -iA cachix -f https://cachix.org/api/v1/install
$ cachix use nixiosk
$ ./qemu.sh nixiosk.json.sample
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.
How it works
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:
{
"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",
}
}
Here’s a basic idea of what each of these fields do:
- hostName: Name of the host to use. If mDNS is configured on your network, this can be used to identify the IP address of the device via “<hostName>.local”.
- hardware: A string describing what hardware we are using. Valid values currently are “raspberryPi0”, “raspberryPi1”, “raspberryPi2”, “raspberryPi3”, “raspberryPi4”.
- authorizedKeys: A list of SSH public keys that are authorized to make changes to your device. Note this is required because no passwords will be set for this system.
- program: What to do in the kiosk. This should be a Nixpkgs attribute (package), an executable in that package, and a list of args.
- networks: This is a name/value pairing of SSIDs to PSK passphrases. This can be found with the wpa_passphrase(8) command from wpa_supplicant.
- locale: This provides some information of what localizations to use. You can set regulation domain, language, time zone via “regDom”, “lang”, and “timeZone”. If unspecified, defaults to US / English / New York.
- localSystem: Information on system to use for remote builder. Optional.
Push to deploy
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
Once you have a remote builder configure on your Kiosk, you can clone your Kiosk repo:
$ git clone ssh://[email protected]/etc/nixos/configuration.git nixiosk-configuration
From here, you can make some changes, and commit them to the repo. When done, you can just do:
$ git push
and read the output of the new deployment.
Remote builder (optional)
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:
$ echo $(ssh [email protected] cat '$HOME'/.ssh/id_rsa.pub) >> $HOME/.ssh/authorized_keys
Then, we need to test that we can access the local computer through SSH:
$ ssh [email protected]
$ ssh me@my-laptop-host
If all is well, then we can proceed to cloning the configuration.
Setup
Install Nix
If you haven’t already, you need to install Nix. This can be done through the installer:
$ bash <(curl -L https://nixos.org/nix/install)
Cache
To speed things up, you should setup a binary cache for nixiosk. This can be done easily through Cachix. First, install Cachix:
$ nix-env -iA cachix -f https://cachix.org/api/v1/install
Then, use the nixiosk cache:
$ cachix use nixiosk
For more information refer to https://app.cachix.org/cache/nixiosk.
Initial deployment
The deployment is pretty easy provided you have Nix installed. Here are some steps:
$ git clone https://github.com/matthewbauer/nixiosk.git
$ cd nixiosk/
$ cp nixiosk.json.sample nixiosk.json
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:
$ cat $HOME/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC050iPG8ckY/dj2O3ol20G2lTdr7ERFz4LD3R4yqoT5W0THjNFdCqavvduCIAtF1Xx/OmTISblnGKf10rYLNzDdyMMFy7tUSiC7/T37EW0s+EFGhS9yOcjCVvHYwgnGZCF4ec33toE8Htq2UKBVgtE0PMwPAyCGYhFxFLYN8J8/xnMNGqNE6iTGbK5qb4yg3rwyrKMXLNGVNsPVcMfdyk3xqUilDp4U7HHQpqX0wKrUvrBZ87LnO9z3X/QIRVQhS5GqnIjRYe4L9yxZtTjW5HdwIq1jcvZc/1Uu7bkMh3gkCwbrpmudSGpdUlyEreaHOJf3XH4psr6IMGVJvxnGiV9 mbauer@dellbook
which will give you a line for “authorizedKeys” like:
"authorizedKeys": ["ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC050iPG8ckY/dj2O3ol20G2lTdr7ERFz4LD3R4yqoT5W0THjNFdCqavvduCIAtF1Xx/OmTISblnGKf10rYLNzDdyMMFy7tUSiC7/T37EW0s+EFGhS9yOcjCVvHYwgnGZCF4ec33toE8Htq2UKBVgtE0PMwPAyCGYhFxFLYN8J8/xnMNGqNE6iTGbK5qb4yg3rwyrKMXLNGVNsPVcMfdyk3xqUilDp4U7HHQpqX0wKrUvrBZ87LnO9z3X/QIRVQhS5GqnIjRYe4L9yxZtTjW5HdwIq1jcvZc/1Uu7bkMh3gkCwbrpmudSGpdUlyEreaHOJf3XH4psr6IMGVJvxnGiV9 mbauer@dellbook"],
and you can get a PSK value for your WiFi network with:
$ nix-shell -p wpa_supplicant --run 'wpa_passphrase my-network'
network={
ssid="my-network"
#psk="abcdefgh"
psk=17e76a6490ac112dbeba996caa7cd1387c6ebf6ce721ef704f92b681bb2e9000
}
so your .json file looks like:
"networks": {
"my-network": "17e76a6490ac112dbeba996caa7cd1387c6ebf6ce721ef704f92b681bb2e9000",
},
Now, after inserting your Raspberry Pi SD card into the primary slot, you can deploy to it with:
$ ./deploy.sh /dev/mmcblk0
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:
$ git clone ssh://[email protected]/etc/nixos/configuration.git nixiosk-configuration
$ cd nixiosk-configuration
Then, make some changes in your repo. After your done, you can just run ‘git push’ to redeploy.
$ git add .
$ git commit
$ git push
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:
$ ./redeploy.sh kodpi2.json kodipi2.local
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:
$ ./build.sh kodipi2.json
Additional arguments are passed to nix-build
.
ADVANCED: NixOS module / Flake configuration
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:
$ nix --experimental-features 'nix-command flakes' flake new -t github:matthewbauer/nixiosk myproject
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:
$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \
nixiosk-build --flake ./myproject#nixosConfigurations.example-rpi4
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:
$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \
nixiosk-deploy /dev/sdb --flake ./myproject#nixosConfigurations.example-rpi4
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:
$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \
nixiosk-redeploy --flake ./myproject#nixosConfigurations.example-rpi4
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:
$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \
nixiosk-qemu --flake ./myproject#nixosConfigurations.example-qemu
On a non-graphical session, you can run:
$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \
nixiosk-qemu --vnc --flake ./myproject#nixosConfigurations.example-qemu
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:
$ nix --experimental-features 'nix-command flakes' shell github:matthewbauer/nixiosk -c \
nixiosk-pixiecore --flake ./myproject#nixosConfigurations.example-pxe
Technology
Here are some of the pieces that make the Kiosk system possible:
- Cage / Wayland: Cage is a Wayland compositor that allows only one application to display at a time. This makes the system a true Kiosk.
- NixOS - A Linux distro built on top of functional package management.
- Basalt: A tool to manage NixOS directly from Git. This allows doing push-to-deploy directly to NixOS.
- Plymouth: Nice graphical boot animations. Right now, it uses the NixOS logo but in the future this should be configurable so that you can include your own branding.
- OpenSSH: Since no direct login is available, SSH is required for remote administration.
- Avahi: Configures mDNS registration for the system, allowing you to remember host names instead of IP addresses.
- Cog: A minimalist browser based on WebKitGTK.
I would also like to include some more tools to make administration easier:
- ddclient / miniupnp: Allow registering external IP address with a DNS provider. This would enable administration outside of the device’s immediate network.
Troubleshooting
/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:
$ nix-shell -p utillinux -run 'wipefs /dev/mmcblk0'
failed to open ‘/dev/disk2’: Resource busy
You may have to unmount your sd drive to continue. You can try running:
$ sudo diskutil unmountDisk /dev/disk2
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:
hostfwd_add tcp::2222-:22
Now you can SSH under the 2222 port:
$ ssh -p 2222 root@localhost
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:
$ 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
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.