Yannick's picture


I am proud to announce that I was able to port the latest v17 turnkey system to the raspberry pi 4. I was able to port the following preliminary images if you want to start testing:

Raspberry pi 4 demo images:

Don't forget that this is not production ready! You can download any of these images and write them to SD card using a program like raspberry pi imager or balena etcher. I suggest a 4G card or bigger to test. The image will resize itself on first boot to take all free space available.

Raspberry pi 4 TKLDEV docker for PC/MAC:

I also created a docker image that runs a virtual arm platform to run the arm raspberry pi tkldev image on your pc or mac. This way, you don't even need a real raspberry pi to run the arm version of tkldev (or in theory, any appliance). It can be used to try things without requiring flashing a real raspberry pi. In fact, it could be used for instance as a build agent that can build any arm appliance image.

To use the docker you can perform the following command:

docker pull heneault/tkldev-arm64-qemu-amd64:latest

docker run --rm -it -p 6022:22 -v /absolute/path/on/host:/mnt heneault/tkldev-arm64-qemu-amd64:latest

The default login and password for the container is root : root. The -p 6022:22 is used to access the docker via ssh. Otherwise, only the console is available. You can change the 6022 to any unused port on your host.  The -v option is optional and is used to map an absolute path on the host into the emulator as the /mnt folder. This makes life easier to share files built inside the container using the buildtasks commands for instance. Otherwise, you can use ssh to copy out the files.

Technical details

I tried to keep this image aligned with the raspberry pi image produced by debian. That means it uses the standard debian packages like the amd64 version. I also recompiled the required turnkey packages the usual way with “pool”. Thus, I consider both versions of amd64 and arm64 to be very close. An issue in one will probably exist in the other and vice-versa.

To complete this project, the 4 following PR need to be merged

Fab must be merged and released first before the PR of the common be merged. In fab, I added the raspberry pi 4 way of building image and I also added support for architecture specific overlay and conf. This feature forces fab to be released first. For the “common”, I moved OS specific amd64 files in a subfolder inside the turnkey.d directory. For instance, the grub files in the overlay layer are in overlays/turnkey.d/x86.d/grub . This change allows to have overlay and conf files that are architecture family specific. That mean that fab now apply overlay and conf in turnkey.d/* and turnkey.d/{arch_family}/* By deploying this fab update first, it will continue to work with the current “common” even if these sub layers are not there. After being deployed, the PR for the common layer could be merged safely.

After that, you can merge the changes in the buildroot and tkldev. To rebuild everything you will need the arm debian package and bootstrap available online. You can take mine from my repo or rebuild them using the tkldev docker or image on a real pi.

In buildtasks, I added similar tools to manipulate images like iso. I added a bt-img that builds a whole appliance. I also added the img-* tools to download, verify, release and publish pi images. There are 2 new tools called bt-prepqemu and bt-qemu-docker to build the cross-platform emulator docker. I will post separate instructions about how to use these last 2 commands to show how to rebuild the docker.

The prebuilt image and the docker use a personal public repo I set up to host the debian package and the bootstrap. This adds an extra apt source and a gpg key to validate the signature. This change is part of the prebuilt binary but not in the PR. I hope Turnkey will be able to host these files on their main website as I am not sure if I would be able to keep the repo alive forever. 


  • Only for raspberry pi 4
  • The wifi works on the pi but you cannot use the confconsole or webmin to set up. In fact if you try these tools it will scrap your config. You just have to use a text editor and open the file /etc/network/interfaces. Replace the fake ssid and password with yours, save the file and reboot or issue the command “ifup wlan0”. That should make it.

In the hope it would be useful for the community!


Jeremy Davis's picture

Great work Yannick, this looks fantastic! Great work.

I've just ordered a RPI4 so I can test this out properly! :)

I have merged the TKLDev PR and my colleague Stefan has had a quick look over the code. Stefan did have some vague concerns on the level of changes required, but didn't find anything "wrong" per se. That just means that we need to do some internal battle-testing before we merge those. But I'll need to wait until the Pi arrives before I can do that.

I haven't yet announced it, but v17.0 TKLDev stable is (finally) ready for public release. It would have been awesome to have been able to include your RPi build for v17.0, but we were already so far behind schedule and I need to keep pushing out v17.0. Regardless, I hope to side-track v17.0 a little (once my RPi arrives).

As for hosting the images and packages, yes we'll definitely take that over from you. Probably one of the first things I do, will be build the packages and upload them for arm64. Initially they'll be built to our "testing" repo, but pushing them to the "main" repo is easy once they have passed through our testing repo.

Great work on the docker image too. That's a great idea to workaround building arm stuff on amd64! I can't wait until I can have a play.

L. Arnold's picture

Just working on a PI 3 b and was thinking it would be good to put it into a TKL package.

(looks like I need a 4 though)...  

Will the PR's put out by Yannick be able to be merged.  Seems a great direction for sure.   Many TKL appliances only need a small server build and the PI world would be very happy, I feel, to see some nice installations available with a TKL stamp on them.

Nice work Yannick

Jeremy Davis's picture

Yep, it needs to be RPi4. We may look at working backwards (i.e. to support older Pis) but we'll get this working smoothly first.

Yes, I do hope to merge Yannick's PRs. I also plan to host the packages on our "offical" TurnKey apt repo, as well as provide the RPi builds via our mirror network (just like we do with the current our custom software packages and the appliances in the other builds).

The only thing I'm just not 100% clear on yet, is the timeframe. My hesitation at this point is that we're still relatively early in the v17.0 release. It's already way behind schedule and there are only so many hours in the day. On face value, Yannick's changes look solid. But I am a little concerned about the risk of regressions. Best case scenario, a regression might slow things down (e.g. time to fix a regression). Worst case, it may not be immediately obvious and end up requiring us to rebuild apps. TBH I'm probably more nervous about it that I should be, but I'm just acutely aware of the resources I currently have available, and all the work that needs doing (beyond Yannick's work).

As a final word, thanks for mentioning Node-RED. I hadn't come across that before and it looks pretty cool. I think it would make a great appliance, for RPi or our "normal" builds (note the RPi install script should work on Debian apparently too).

Jeremy Davis's picture

I had to google how to decompress the pure xz archive (I've only ever encountered tar.xz before), but it ended up being pretty damn easy! :) FWIW:

unxz turnkey-core-17.0-bullseye-arm64.img.xz
# DO NOT copy/paste the following unless you are sure that you want to overwrite /dev/sdb!
dd if=turnkey-core-17.0-bullseye-arm64.img of=/dev/sdb

I haven't done tons with it yet, but basically it "just worked" and has been awesome!

Re wifi setup, your workaround worked fine, but I do agree that we could do better. I think that we should create an inithook for setting up the wifi. That way it could be preseeded, just like the other firstboot questions if desired, or answered interactively. Also it'd be good to be able to reconfigure it via confconsole too.

I was thinking that we might be able to leverage wicd or some other similar 3rd party tool, but to my disappointment it appears that wicd is broken . FWIW wicd is written in python2 and hasn't really been maintained for years. There is a py3 port "in progress" but who knows when that might be ready.

So I had a look at both 'nmcli' (network manager cli) and 'nmtui' (network manager terminal UI - aka curses/dialog interface - same as inithooks and confconsole). They are both part of the common network manager package (i.e. alternate non-GUI frontends for the default Gnome networking tool). I thought they might be a good fit, but unfortunately it seems like they aren't as useful as I might have liked.

I haven't completely given up on the idea, but at this point, I'm thinking that I might need to pull the networking stuff out of confconsole (probably merge it in with our python netinfo module?). If I do that, then we could make improvements that would particularly be useful for RPi, but also in our "main" builds. I.e.:

  • Proper wifi support for all users (probably won't much difference for most users, but definately needed for RPi and would still add value for "normal" builds IMO).
  • Support configuration of multiple interfaces directly within confconsole
  • Support preseeded network config (e.g. configure static networking OOTB if you want)

Having said that, I'm not sure how long that might take me. So as an interim measure, I think perhaps just improving confconsole might be the best first step. IMO the very first step if to fix confconsole (and perhaps also investigate webmin too) so it doesn't clobber the existing interfaces file when it has 'wlan0' configured. A firstboot script could also be developed, but I'm inclined to see how I go with making an interface file editing library before spending too much energy on that...

Anyway mate, great work. I'm most impressed with what you've done! :)

Yannick's picture

Xz format is less popular than zip but it is used by Debian to ship their pi image and has a very good compression rate. It is easier to handle it if you use a tool like etcher ( https://www.balena.io/etcher/ ) or the original raspberry pi imager. These tools handle this format directly so they uncompress and write directly to the SD card for you. They are also cross platform (pc, linux, mac) and they properly detect the block device of the SD card to prevent the user overwriting it hard disk. Anyway if you prefer CLI, like me, here is a one liner to do it :

xzcat turnkey-core-17.0-bullseye-arm64.img.xz | dd of=/dev/sdb bs=64k oflag=dsync status=progress

but again, make sure you are using the proper device (/dev/sdb) or you could overwrite your hard disk.

I agree with you for the wifi. I think something with init hook firstboot to set it would do the job by calling confconsole to let the user set its ssid and password. Later, the user could call confconsole to change these values if required. I don't think that webmin has something for wifi but that would be great 

I am not sure I would want to keep the SSID / password in the network interface file. I followed the Debian image for that but on my other linux systems, the wifi configuration is in a separate file (wpa_supplicant.conf). Maybe it would be better to set it this way. That would separate network interface settings from it and keep programmed file manipulation easier .

Thank you for the kind words! This is alway appreciated.


Jeremy Davis's picture

I like that one liner! Thanks for that :)

Re wifi, yes I agree that storing it in the interfaces file in plain text isn't ideal.

I've playing some more with my RPi. :)

I have had a bit of a play with wpa-supplicant and it can hash the wifi password. You can then use the hash instead of the raw plain text password in your interfaces file (or via a separate wpa_supplicant.conf file).

It is important to note that it's still not particularly secure. It's just better... According to my reading, wpa-supplicant uses PBKDF2 to hash the password. By my understanding, that's a pretty good key derivation hash, but my testing (admittedly only on Debian based Proxmox and TurnKey) suggests that it's just using the SSID as the salt. I guess that makes sense but does mean the hash is deterministic. So having the SSID and hash is as good as having the SSID and password. I would argue then that the only real advantages hashing the password gives is that it's guaranteed to be a long string and not easily memorable to a human.

To check this yourself (with wpasupplicant installed), try this:

wpa_passphrase My_SSID My_secret_PASS | sed -En "s|^\t*psk=([a-f0-9]*).*|\1|p"

Every system I've tested this on, reliably gives me:


AFAIK, the only way we could "properly" lock it down would be to encrypt the filesystem. That wouldn't help while it's running, but at least then it would be encrypted "at rest". OTOH it would require you to enter a password (via physically attached keyboard) every time you reboot (and/or need to get access to the wifi password). So I don't think that's a practical solution.

Besides, this seems to be the standard and IMO using the hashed password still raises the bar a bit. Plus if we use a separate wpa_supplicant.conf file (i.e. don't store the SSID & password or hash in the interfaces file) then we could lock down it's permissions (i.e. make it only readable by root).

Using a separate wpa_supplicant.conf file also provides option for greater flexibility. E.g. roaming mode. There's also some really interesting examples in the Debian wpa-supplicant readme:

zcat /usr/share/doc/wpasupplicant/README.Debian.gz | less

At this point, I think that the more complex config is off topic for us. But I really like to adhere to the "easy things should be easy and hard things should be possible" philosophy. So in this case, I think using a simple wpa_supllicant.conf by default is a good path. That way with a fix to confconsole (so it doesn't clobber the wlan entries in the interfaces file), we'll just need a confconsole wifi plugin (to set ssid and password). We could then recycle that code for first boot too.

Here's what I'm thinking, have preconfigued wlan entry (in interfaces file) like this:

allow-hotplug wlan0
iface wlan0 inet dhcp
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

Then the wpa_supplicant.conf file can be generated like this:

wpa_passphrase My_SSID My_secret_pass > /etc/wpa_supplicant/wpa_supplicant.conf

And we can use the same mechanism that we do with the interfaces file to only edit an autogenerated wpa_supplicant.conf file. E.g. put a comment at the top, giving a wpa-supplicant.conf something like this:

# remove the above line if you edit this file


Actually, since I started writing this, I've made a couple of fairly simple python wrappers, one which scans for available networks (via iwlist) and provides a little info about them. The other creates or updates the wpa_supplicant.conf (using wpa_passphrase). I haven't tested extensively, but they seem pretty good so far... Obviously they're only building blocks, but it's a start.

That only covers the simple case where you are connecting to a wifi network that is broadcasting it's SSID. I think that's a good MVP, but I wonder what (if any) other config we should support? I'm inclined to keep it super simple, but support for "hidden" networks (i.e. don't broadcast their SSID) might be worth including?

Next I'll see if I can wrangle confconsole to not clobber the interfaces file...

Once that's done, we'd just need to make an inithook and confconsole plugin.

Yannick's picture

That is a very good analysis of the wifi setup.

As a first pass I would suggest to limit to these functionality:

  • Select a public SSID
  • Enter manually the name of a hidden SSID
  • Enter wpa passphrase for network
  • Select wifi country to comply with local regulation

I think this is similar to what raspi-config, the configuration tool shipping with raspbian image, is supporting. However this tool doesn't scan the network thus the user has to manually enter its SSID.

I realized there is an error on the first boot if wifi is not set up. Maybe we could ship the image with wpa-supplicated services disabled. When the user configures its wifi, if he needs it, your script could enable the service. This would avoid the annoying error for users who don't need it.

I would not bother with encrypting the password. A motivated user will find it ways if he has access to the SD card. Only filesystem encryption should fix all other passwords and databases at the same time but that is another story.


Jeremy Davis's picture

Thanks for the feedback. Currently the code I've written covers all your points, except wifi country. As I noted elsewhere here, there are 2 additional packages that we need for that to work. I have installed the packages and confirmed that the kernel no longer whinges about missing stuff. But I haven't actually looked into it any further, so I'm not sure what's required for the config, although figure it should be fairly straight forward.

Seeing as the password hashing comes for free, my inclination is to use it. Although ultimately I agree that the value it adds isn't huge.

The updates I've made so far to confconsole fix the bugs. And I've also started work on inithooks. My vision is for it to ask wifi credentials as the first question on firstboot (with an option to skip). That way by default it will get an IP via DHCP, meaning sec updates and Hub linkage should "just work" (assuming that you can connect to a netowkr with internet access). FWIW I haven't tested TKLBAM, so I'm not yet sure how well that works, but AFAIK it should.

Once we get a bit further along, the "official" raspi-config tool probably would be a good source for ideas for things to add to confconsole. Perhaps we could even include a raspi-config wrapper that just runs raspi-config if it's installed, but will offer to start confconsole if not?! It's a bit of a gimmick, but might be a nice touch for existing RPi users who are new to TurnKey?

Jeremy Davis's picture

I've fixed confconsole so it works properly with wlan now. At least I hope so... :) I've opened a pull request. If you want to test it (and can't be bothered building it from my pi-wifi-improvement branch) you can just replace the ifutil.py file (it goes in /usr/lib/confconsole).

Here's my interfaces file:

# remove the above line if you edit this file

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp

allow-hotplug eth1
iface eth1 inet dhcp

allow-hotplug wlan0
iface wlan0 inet dhcp
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

allow-hotplug wlan1
iface wlan1 inet dhcp
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

To make it all work, you'll also need to generate the /etc/wpa_supplicant/wpa_supplicant.conf file as noted in previous post.

L. Arnold's picture

Well, lots going on here.

Let me see if I can istall something.  By my read the 3 b and 4 are both 64 bit so should be able to install the same OS.  Do you want me to try one?

So that "IMG" file up there.  Does that get generated before an ISO?  I could see that being helpful in some other places as well - not just on a pi.


Jeremy Davis's picture

Yeah, Yannick has done a great job and I've been busy on my time off.

TBH, I have no idea if it will work on an RPi 3 or not. No harm trying I guess if you have a spare SD card handy and are happy to try it?! It'd be cool to know if it works there too!

And yes, it's like an "alternate" ISO build, that isn't an ISO.

Although it still shares most of the code with ISO builds, it just doesn't do the final step of packaging as an ISO (instead it packs it up into an archive).

The thing with using the ISO for the alternate amd64 builds is that we can ensure that all the builds of the same version are essentially the same (i.e. have exactly matching package versions). And it means that we can run the alternate builds at different times, but they still match the original release (i.e. v16.1 Core on the Hub is exactly the same as a local VirtualBox VM running from OVA, or bare metal install from ISO). Once you deviate from using that common ISO, that will no longer be the case. I.e. a v17.0 RPi build will not be an exact arm64 copy of the v17.0 amd64 ISO. There is/will be some minor divergence. It shouldn't really be a problem but for support it's much easier to be able to make some assumptions.

With regard to making some other alternate build for amd64 hardware, that's easy enough (if you know how). You just need to extract the rootfs back out of the ISO. FWIW that's mostly what the 'bt-...' scripts in buildtasks do. Unpack the filesystem from the ISO and then reconfigure it in various ways for the various builds. If we know what format you need, then we could write a bt-script for that and you could build your own from our ISOs any time you liked!

Getting back to ARM though, TBH, I don't know a lot about ARM and what's available and how it all works, but I note that Debian provide ISO for ARM. Under "normal" circumstance, I'd be inclined to do exactly the same thing with the ARM64 build as we do with AMD64, i.e. build to ISO, then process ISO to generate specific alternate builds. However, ARM hardware tends to be more heterogeneous, so from my understanding an ISO isn't often that generically useful and a specific image built for one specific hardware configuration, may not work for another. So in the case of ARM it'd be IMG builds for specific hardware setups. As I think the value of distributing an ARM64 ISO is limited, and we don't have any plans to support other ARM hardware (other than RPi) at this point, I think cutting out the double handling (i.e. skipping the ISO building and extracting steps) makes sense in this case.

Yannick's picture

I just realized that pi 3 is also supporting 64 bits. I tested my pi core image on pi 3 and everything seems to work work correctly (bootup, wifi,...)

I verified the differences in the debian image about pi3 and pi4 and aside from a kernel switch that should not cause trouble on pi 3 they are the same. Thus I think we can say pi 3 and pi 4 are supported with the same image file!

Jeremy Davis's picture

Looking at the RPiOS page they note model 3A+, 3B & 3B+ (and higher/newer) are supported. But I'm not clear if there was a "model 3A"? My initial searching was inconclusive, but a closer look at the wikipedia model comparison notes that 3B was the first model 3 release, followed by 3A+ & 3B+?!

Regardless, it's a welcome discovery and it seems that it should support all of the "3" models!

Jeremy Davis's picture

I've noticed kernel error messages in the journal because 'wireless-regdb' & 'crda' packages aren't installed. From my limited understanding, these packages allow the kernel to adjust wifi strength so it is compliant with local radio frequency restrictions.

I think that it's probably worth including them. But I'm open to counter argument. My rationale is that by including them, we're assisting newbs to be compliant with their local law. Those who don't care about their local laws can remove those packages if they wish.

L. Arnold's picture

It is quite common these days for computers/devices, what have you, to have both Ethernet ports and Wifi on them, or one or the other.  I have a few ARM devices here in fact, but also laptops, desktops etc.

Why not work the Wifi Config possibility into all of the builds..  Have it be "optional" but you could also give choices off preferences (wired or wireless?)..  Other parts here is that multiple port setups could be used for integrating router and vpn possibilities in having both.  Hooking into "bluetooth" or other networks (MSTP for instance) could also be interesting in the future.

Jeremy Davis's picture

Yep, I was planning to port these changes back to confconsole at least. Although if the inithook component is done the right way, that should be easy enough to include for all appliances. Obviously it's only useful on hardware, but an old laptop could be a good cheap home, development and/or portable server for some, so I agree it has value.

Your other extension ideas sound cool, although I'm not sure how widespread their use and/or need might be? With limited resources, it's important to remember that saying "yes" to one thing, is also saying "no" to a million other possibilities... So we need to target our efforts for the most value (or the most fun when I'm playing in my own time! :).

L. Arnold's picture

I am pretty new to Pi.  I get the idea of "etching" the image.

Are all the BT(build task) and elated PR's in place to do some damage?

I was going to ask if I need a separate install drive to put to a boot drive but it looks like the image in fact is a complete, post install, ready to be initialized (I like that approach, lets do more).

Time short but interested in all of this.  I have a Pi 3 model B, so glad we worked through that.


Add new comment