atuin server on a Raspberry PI - Cross compiling Rust

3 minute read

atuin server on a Raspberry PI - Cross compiling Rust

I’m a big fan of atuin, a shell history manager, which replaces the flat command history file with a local database, fully searcheable and with builtin synchronization support.

My setup of atuin, installation and configuration, can be seen in my dotfiles. But the documentation is excellent.

In case you are wondering why the sync configuration is not in my config: I try to keep all specific configuration of stuff that is not publicly available and might not be needed in all my environments outside of the dotfiles. I set $ATUIN_SYNC_ADDRESS in my ~/.profile.local.

export ATUIN_SYNC_ADDRESS=http://raspberrypi.local:8888

Atuin offers a free synchronization server at https://api.atuin.sh. Yes, it’s not a good idea to show and open up your command history to everybody. Which is why the synchronization is completely end-to-end encrypted by atuin. The synchronization server only sees gibberish, and all your clients have to be set up with a passkey to enable sync.

If you, like me, still don’t want to trust that data to a sync service, you can also run your own synchronization server, which is pretty straightforward, assuming you know a bit about services and postgresql.

Of course that means that you have to run a server somewhere…

I happen to have a rasperry pi 3 in my home network, which mainly acts as an always-on member of syncthing-synchronized directories, and as a git repository server for private repositories with gitolite. I don’t expose the Pi at all to the public internet, it is only available internally, resolveable through mDNS. I wanted to set it up as atuin synchronization server. It’s already there, it is available for all devices in my local home network. This, of course, means that I can only synchronize shell history with my machines at home. But I don’t have a problem with this limitation at all.

The problem

Atuin is not installable through the raspbian package sources. This is also true for Debian at the time of writing. On my machine, I install it with cargo, orchestrated with tuning.

So, how do you install atuin on my raspberry pi, which uses an ARM CPU? Especially if you don’t want to compile it on the pi itself, wait for ages and fill your pi with stuff you don’t really need?

The solution

Atuin is a program written in Rust. This means that

  1. Programs are compiled to architecture specific binaries
  2. Programs can be built pretty easily with Rust’s awesome package manager cargo
  3. Cross compilation is pretty straightforward, thanks to Rust.

As usual, the devil is in the details, however.

The details

Setting up Rust for cross-compilation

With rustup as rust toolchain manager, it’s easy to install the rust specific target and toolchain for the raspberry pi.

$ rustup target add armv7-unknown-linux-gnueabihf

This is not enough, however. For successful cross compilation, rust also needs the target specific gcc toolchain to link against C libraries and sysroot.

Setting up the system

You need gcc for cross-compilation with the armhf target, as well as the armhf specific libraries for dynamic linking.

On a Debian system, this can be installed like so.

$ sudo apt-get install gcc-arm-linux-gnueabihf libgcc-13-dev-armhf-cross

The installation of gcc and the sysroot is on a system level, independent from the local rust setup. This means that cargo has to be set up correctly so that it uses the correct linker.

Configuring cargo

Target specific attributes can be configured in ~/.cargo/config.toml

[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"

Compilation

After everything has been set up, cargo can be built in the local directory with this command:

$ cargo install --target=armv7-unknown-linux-gnueabihf --target-dir=$(pwd) --root=$(pwd) atuin

This will download the sources of atuin and all dependencies, cross-compile it and copy it to a bin subdirectory.

$ readelf -h bin/atuin
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0xd363d
  Start of program headers:          52 (bytes into file)
  Start of section headers:          32358908 (bytes into file)
  Flags:                             0x5000400, Version5 EABI, hard-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         10
  Size of section headers:           40 (bytes)
  Number of section headers:         44
  Section header string table index: 43

Installation

Copy the binary onto your raspberry pi, e.g. to /usr/local/bin/atuin, and you’re good to go!

tl;dr

  • atuin is great to manage shell history
  • atuin sync is great and pretty safe
  • atuin sync on a raspberry pi under your control is even safer
  • cross-compilation with Rust is relatively easy
  • the devil is in the details

Leave a comment