Hardware Linux Software

Making Bluetooth work on RPi4

I rarely use Bluetooth on my RPis. I’m already facing enough issues with my iMac and Mac Mini (it lags, it randomly disconnects in meetings, etc).

My pwnagotchi on the other hand is counting on a BLE network to connect to the internet: for now I am using my iPad, and while that works, it causes my iPad to disconnect from WiFi (because of course, it can only do tethering from a mobile network, not from its WiFi network).

I wanted to explore if I could set up bluetooth tethering/internet sharing from my RPi4 server… But for that BLE had to work! And for some reason BLE was not working on Liana.

[bluetooth]# power on
No default controller available

For some reason no controller was available. The drivers were definitely installed…

apt install bluetooth pi-bluetooth bluez raspberrypi-sys-mods

but hcitool dev ; hciconfig -a weren’t returning anything.

After quite some extensive Googling I found the solution

Check if this returns something:

# ls -l /dev | grep ttyAMA0
lrwxrwxrwx 1 root root           7 Sep  1 15:08 serial1 -> ttyAMA0
crw-rw---- 1 root dialout 204,  64 Sep  1 15:08 ttyAMA0

As opposed to:

# ls -l /dev | grep ttyS0
# (no output)

Then continue to do the following:

# make a backup
cp /boot/cmdline.txt /boot/cmdline.txt.bak
# edit the file
nano -w /boot/cmdline.txt
# edit the first part from
# console=ttySerial0 to console=ttyAMA0
# the line should be something similar to but do NOT blindly copy paste it as you won't be able to boot due to your PARTUUID being different
console=ttyAMA0,115200 console=tty1 root=PARTUUID=6c586e13-02 rootfstype=ext4 elevator=deadline rootwait

After rebooting … it works!

liana ~ # hcitool dev ; hciconfig -a
	hci0	DC:A6:32:B1:0E:79
hci0:	Type: Primary  Bus: UART
	BD Address: DC:A6:32:B1:0E:79  ACL MTU: 1021:8  SCO MTU: 64:1
	RX bytes:2397 acl:0 sco:0 events:118 errors:0
	TX bytes:2603 acl:0 sco:0 commands:99 errors:0
	Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87
	Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 
	Link policy: RSWITCH SNIFF 
	Link mode: SLAVE ACCEPT 
	Name: 'liana'
	Class: 0x000000
	Service Classes: Unspecified
	Device Class: Miscellaneous, 
	HCI Version: 5.0 (0x9)  Revision: 0x13b
	LMP Version: 5.0 (0x9)  Subversion: 0x6119
	Manufacturer: Cypress Semiconductor Corporation (305)

liana ~ # bluetoothctl 
Agent registered
[bluetooth]# scan on
Discovery started
[CHG] Controller DC:A6:32:B1:0E:79 Discovering: yes
[NEW] Device 7F:A9:BC:8D:E4:14 7F-A9-BC-8D-E4-14
[NEW] Device 58:EB:19:D8:D4:23 58-EB-19-D8-D4-23
[NEW] Device A4:83:E7:42:79:F6 A4-83-E7-42-79-F6
[NEW] Device 58:7B:24:1B:CC:5C 58-7B-24-1B-CC-5C
[NEW] Device D9:05:9F:DB:55:19 N0163
[NEW] Device 5F:DA:90:34:82:68 5F-DA-90-34-82-68
[NEW] Device 77:2A:1B:11:54:7D 77-2A-1B-11-54-7D
[NEW] Device 42:BF:0B:38:F3:20 42-BF-0B-38-F3-20

Next step is trying to get tethering to work…

Hardware Linux Software

Raspberry Pi 4 + SSD

All right. With the release of the new RPi4 with 8Gb of RAM I had to get myself one to see if it was already a viable desktop replacement for surfing and emails.

While a SD card works fine for certain tasks (things that don’t require a lot of IO) — for a desktop that’s a no-go… It’s just too slow.

I still had an old Macbook Pro 13″ (2o15?) SSD lying around that was collecting dust. Why not use that one to use as root for the RPi?

This article will focus on making it work on Raspbian first. Technically this should all work on other distros as well, but YMMV seeing all this is still beta.

I use Raspbian Lite: I like to work with minimalstic systems and install just what I need. But technically this should work with any flavour.

But first, let’s prep the device.


I already have a RPi4 (4Gb) at home running mostly Docker containers (nginx proxy and a few personal things and Smokeping).

And one of the ‘best’ purchases I made for the RPi4 was the “Raspberry Pi 4 Model B Aluminium Case” (Lazada, AliExpress). This case is passive and dissipates enough heat (even in a closed cabinet in Singapore where it’s 30°) for the CPU never to throttle back when overclocked at 2Ghz (see below).

Do note that this case (which is pretty much just a massive heat sink) gets pretty hot if the RPi is running at max performance for long periods of time.


Get one that fits your SSD and that ideally has Linux support. As Apple uses custom SSD connectors (prior to being soldered onto the motherboard) I had to get a converter from China. It was a bit of Russian Roulette to see if it would work or be supported on Linux. I got myself this one (chipset: Netchip Technology). As I didn’t remember what type of Macbook Pro this came from, using this site to compare serial/model was useful. This USB-to-SSD converted also works on Mac and Windows by the way.

The SSD with the PCB that provides the USB interface.

In my case, the RPi also did not provider enough power to the USB-SSD converter (although… it really should but whatevs), so be sure to use the provided power cable and plug it into a USB power source. Not doing so will cause the SSD to heat up and show a bunch of disconnects/errors in dmesg.

raspbian ~ # fdisk -l /dev/sda1 
Disk /dev/sda1: 233.8 GiB, 250999127552 bytes, 490232671 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
raspbian ~ # lsusb 
Bus 002 Device 002: ID 0525:622b Netchip Technology, Inc. 
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
raspbian ~ # lsusb -t
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
    |__ Port 2: Dev 2, If 0, Class=Mass Storage, Driver=usb-storage, 5000M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
Raspberry Pi 4 with USB SSD connected
Raspberry Pi 4 with USB SSD connected

eeprom update

Disconnect the USB-SSD for now.

At the time of writing we need to update the eeprom to boot from USB. I’m using the latest eeprom available to me. Note that the USB-boot eeprom is about to hit stable so you might not need to do this anymore.

There are two methods for updating. We can do it manually:

cd /lib/firmware/raspberrypi/bootloader/beta
rpi-eeprom-update -d -f ./pieeprom-2020-06-15.bin
# BCM2711 detected
# VL805 firmware in bootloader EEPROM
# BOOTFS /boot
# *** INSTALLING ./pieeprom-2020-06-15.bin ***
# BOOTFS /boot
# EEPROM update pending. Please reboot to apply the update.
# RPi should come back online after a reboot

Or we use rpi-eeprom-update (see article, at the bottom):

nano -w /etc/default/rpi-eeprom-update
# edit critical to stable
rpi-eeprom-update -a

The good thing is that, even if you boot from a Raspbian that does not have /etc/default/rpi-eeprom-update edited to use stable instead of critical, it will not downgrade your eeprom.

Now you can plug in the SD card in an USB-SD card reader, and test if the RPi boots from USB. Note that the SD card might be slower.

RPi booting the SD card from USB (/dev/sda)

All right — so everything is working. I am keeping this SD card to update the eeprom again at a later stage (as the one we flashed is beta). If we use Archlinux or Ubuntu the eeprom update tools won’t be included.

Next step is to flash Raspbian to the USB-SSD.

This screenshot shows Ubuntu, but for the sake of this article, we’ll use Raspbian still. I’m using Etcher to flash.

Boot-up from the USB-SSD.


In case you are getting an error similar to start4.elf: is not compatible you’ll need to copy paste /boot/start4.elf from a Raspbian that ran rpi-update (i.e. the one from the SD card, or see below).

If you are booting (a fresh) Raspbian, it might complain about cma: Failed to reserve 256 MiB (and several other errors). The solution is running rpi-update.

Boot from the working Raspbian (using the SD card):

# check which drive is your USB-SSD (i.e. using fdisk -l or dmesg). 
# In my case I booted from USB-SD (/dev/sda) and we'll update the new/clean Raspbian on the SSD (/dev/sdb).
# First resize the partition, if the system never booted it'll be 1.5Gb and thus not big enough:
# Device     Boot  Start     End Sectors  Size Id Type
# /dev/sdb1         8192  532479  524288  256M  c W95 FAT32 (LBA)
# /dev/sdb2       532480 3620863 3088384  1.5G 83 Linux
fdisk /dev/sdb
# Type the following:
# p (and visually check it all makes sense)
# d
# 2
# n
# Select (default p): p
# Partition number (2-4, default 2): <enter>
# First sector (2048-490234751, default 2048): 532480 (or whichever is the same "start" from the 2nd partition) 
# Last sector, +/-sectors or +/-size{K,M,G,T,P} (532480-490234751, default 490234751): <enter>
# Created a new partition 2 of type 'Linux' and of size 233.5 GiB.
# Partition #2 contains a ext4 signature.
# Do you want to remove the signature? [Y]es/[N]o: n
# p (visually check once again it makes sense, if not you can cancel/quit by typing q)
# w (if it makes sense)
# The last command will write the changes to the partition table and sync all changes. 
# Then we need to check and resize the filesystem:
e2fsck -f /dev/sdb2
resize2fs /dev/sdb2
# If all that worked we can start mounting everything
mkdir /tmp/ssd
mount /dev/sdb2 /tmp/ssd/
mount /dev/sdb1 /tmp/ssd/boot/
mount /proc/ /tmp/ssd/proc/ -t proc
mount --rbind /sys/ /tmp/ssd/sys/
mount --rbind /dev/ /tmp/ssd/dev/
# Once everything is mounted, we're chrooting into the fresh Raspbian running on the SSD
chroot /tmp/ssd/ /bin/bash
# you can double confirm the partition size using:
df -h
# And we update the system. Again, if all this hits stable it might not be needed.
# say "y" when it's asking you to.
# exit the chroot and turn off the device, remove the USB-SD and leave USB-SSD connected. 

My first reboot the boot process threw errors about failing to mount the root fs.

We’ll need to update /etc/fstab with the correct partuuid.

# Boot from the (USB-)SD card again
# In my case sdb became sda and vice versa, so double check
# be sure to select the right disk (the SSD, no the SD)!
mkdir /tmp/ssd
mount /dev/sda2 /tmp/ssd/
# And find the SSD here as well.
# look for the last column, partuuid, something like 
nano -w /tmp/ssd/etc/fstab
# edit the existing partuuid's with the ones from blkid
# you'll need to edit both /boot (-01) and / (root, -02).
# When rebooting from the SSD it'll go through a fsck. In my case for some reason it failed and dropped to a shell. I did a manual check and everything was fine. Rebooted and it booted normally... *shrug*


At this stage booting from the USB-SSD should work just fine. You have a working system booting from USB.

It’s working! Now I can configure my system.


Last thing I’d recommend is getting a bit more juice out of your four cores.

You can quite easily overclock the RPi4 to 2Ghz (per core). It’s a pretty nice boost (~25%) and worth going for. I haven’t seen any heat issues leading to underclocking (throttling back), and everything runs stable. Note that under real circumstances you are unlikely to be running at 100% for extended period of times.

This guide explains how to overclock Raspbian (but the same applies for Ubuntu RPi — I’ll eventually be using Ubuntu as the OS due to its 64 bit support; at the moment Raspbian only supports a 64 bit kernel (beta) and the userland still runs 32 bit. But that’ll be a follow-up article.

The gist of the article is to edit /boot/config.txt and add:


Save the file, reboot and monitor temp (echo $((cat /sys/class/thermal/thermal_zone0/temp/1000))) and core frequency (watch -n 1 vcgencmd measure_clock arm) while running stress -c 4 to make sure the cores are running at 100%.

Raspberry Pi 4 running at 2Ghz
Raspberry Pi 4 running at 2Ghz. It never throttled back after running for ~30 minutes.
Linux Networking Software

Running WireGuard in a Docker container (RPi)

This follows the my two other posts about WireGuard.

Most of this can be copied from the amd64 post — with a minor change for making it work on RPi4. This is the full git repo (including both rpi and amd64).

The main difference is in the file. The installation is a bit different and we’ll need to install the Raspberry Pi kernel headers.

WireGuard is also installed from testing instead of Debian backports.

Note that for older RPi’s (ie gen 1) you’ll need to compile from scratch.

Linux Networking Software


This is the first post of several. Next posts will focus on running WireGuard inside a Docker container on amd64 Linux and a Raspberry Pi.

I’ve been running WireGuard for a few months now and I’ve been loving it.

I first started using it about a year ago when in China — OpenVPN was once again being actively blocked and it was driving me nuts. Overnight I set up a DigitalOcean server in Singapore and ran WireGuard from it — both my phone and laptop were able to actively bypass the GFW and (at that time) surf the internet freely once more. As WireGuard gains popularity, I am sure the GFW will start detecting it — it’s a quiet but not a stealthy protocol.

Since then I’ve dug quite a bit deeper in WireGuard and am really looking forward to what it’s going to bring.

WireGuard differentiates itself to be an extremely simple VPN server (which can make getting started and debugging a bit more challenging) — but it wants to seamlessly work together with existing tools. One of the main features still missing is for example running a DHCP server on the server and dynamically assigning IPs (like oVPN does).

WireGuard network
Simplified diagram of my network. Using static routing my clients can access the WireGuard network even without running WireGuard directly. (Some of) my containers are also able to access the network, this allows me to run Resilio Sync over WireGuard. It’s using one big subnet to create one big LAN.

It’s also pretty cool because any node can both be a server and a client at the same time. In my setup I am running two servers: one running at home in Singapore on a RPi4 (1Gbit fiber connection) and one on a virtual machine in Amsterdam (1Gbit as well). The RPis at my parents are connected to the server in Amsterdam, my iPad and phones are connected to the server in Singapore. If I am in Europe I might switch over and let my iDevices connect to the AMS server instead.

WireGuard and traffic shaping
Click to enlarge.
Bandwidth stats from Resilio Sync, transferring several big files. We can clearly see a speed increase (from 2-5mb/s to 11mb/s) when routing the exact same traffic over WireGuard. Traffic shaping at its best.

The example above clearly shows speed gains by cloaking the traffic in UDP packets. The shared folder has only two nodes (sender and receiver) and shows several big files being transferred from Amsterdam to Singapore. Resilio Sync uses the Bittorrent protocol, something ISPs generally hate and tend to slow down as much as they can — thanks Starhub.

Wireguard also allows the client to decide what to route through the server: only the VPN LAN traffic, or a whole subnet, or So for my iPhone I for example route all traffic through VPN to avoid hotel/airport/… WiFi’s to mine/log/scan my data. For my laptop I have two configs, one to only connect to the LAN, but another that routes all my traffic through the VPN if I want to avoid exposure or circumvent censoring.

Note that I am not running WireGuard to remain anonymous and I’ll definitely leak some information — just trying to minimise and remain in control of what I leak. This is not a Tor replacement.

Apple Linux Networking Software VM

Box — Docker shell server

A couple of months ago I had the great idea to set up a shell server in Docker. Simply because my docker skillz were quite rusty and a shell server was something I actually genuinely needed.

Shell servers… so 2005. I remember in the good old IRC days people asking for (free) shell servers to run their eggdrop and stuff. OMG am I getting old? Anyhow…

I ssh quite often. I manage quite a few servers (~15?) and routers that require me to login and do some random stuff. I also work on a laptop quite often and that means closing the lid and moving around.

First of all, mosh is amazing and allows you to stay connected via ssh, even with crappy (airport/hotel) internet as well as moving around networks — that solves half the problem. If you are not using it, start using it now!

Second, during my datacenter technician days at Google we used to have a “jump server” — a shell server that allowed us to bridge the corporate network and ssh into prod machines. Doubt that’s still used nowadays, but the idea stuck. I wanted something similar to ssh from, wherever I was, and easily connect to my servers. And as the network the shell server is running on is stable, I only need to use mosh to the shell server. Thereafter, the connection very rarely dies.

And I guess, third, I recently purchased an iPad Pro and I really need to have my local “dev” environment with my git repo that I edit quite frequently but iPadOS isn’t really your average computer, and doesn’t even have a proper terminal. This is my experiment to make iPadOS work as a main computer when on the move.

Enter box — Docker shell server

I’ve copied over the files I use to this example repo, and added some comments. Mind you that this repo acts as a proof of concept and isn’t kept up to date, as I have my own private repo — but this should give you a good idea on how to set up your own shell server with Docker. — this is a simple script that I execute when I first run or need to update the container. I execute the same file on two different servers: Liana, my Raspberry Pi at home and Ocean, my server in Amsterdam. — this installs what I care about for zsh. This could be part of the Dockerfile but for some reason I separated it. ¯\_(ツ)_/¯ — this clones my Git repos so I can edit and commit stuff from the shell server. — this file is launched by Dockerfile at the end and executes what matters: the ssh daemon. It also adds a Wireguard route and executes the scripts above.

Dockerfile — this installs everything I need and configures the whole thing. I’ve added tons of comments that should get you going.

I am also cloning misc and homefiles as submodules in files/ — but you should change this to something that works for you. See the Dockerfile for more info.