Skip to content
Declarative Kiosk systems built with NixOS
Nix Shell
Branch: master
Clone or download

Latest commit

Fetching latest commit…
Cannot retrieve the latest commit at this time.


Type Name Latest commit message Commit time
Failed to load latest commit information.

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.


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": "epiphany",
        "executable": "/bin/epiphany",
        "args": [""]
    "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:


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

$ git clone ssh://root@nixiosk.local/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 root@nixiosk.local cat '$HOME'/.ssh/ >> $HOME/.ssh/authorized_keys

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

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

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:

$ bash <(curl -L


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

Then, use the nixiosk cache:

$ cachix use nixiosk

Initial deployment

The deployment is pretty easy provided you have Nix installed. Here are some steps:

$ git clone
$ 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/
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 run nixpkgs.wpa_supplicant -c wpa_passphrase my-network

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:

$ ./ /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 an Epiphany browser, loading


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://root@nixiosk.local/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.


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.

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.


/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 parititions! 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 run nixpkgs.utillinux -c wipefs /dev/mmcblk0
You can’t perform that action at this time.