The joys of a self hosted Atuin server
Author: -fab- <fab@redterminal.org>
License: CC BY-SA 4.0
Published on: Mon, 19 Aug 2024 10:19:20 +0200
Last updated: Mon, 19 Aug 2024 10:19:20 +0200
Yesterday (or better last night) I set up my own Atuin shell history server. I've been using Atuin for a while now, since February'24 I think. But these were only the isolated shell histories of my 3 main machines. I wasn't aware of the Atuin history sync server, which I can easily self-host. Until now!
Atuin - Making your shell magical
Atuin - Documentation
Atuin - Server setup guide
Free History Hosting Service or Self-Hosted
The developers even host a public end-to-end encrypted Atuin History Sync Service for free. They couldn't see my history, but I don't want to rely on an external service provider (who maybe changes terms of service), when I can self-host this thing on my infrastructure which is already in place.
Features
Only with the server I can get the full potential from my collected CLI history. I have all the commands from all machines available on all of them instantly. It furthermore adds some more context to my inputs. I can filter commands by host, users, directories or sessions if I like, it also stores timestamps, duration and exit code, and then I can make a fuzzy search through them.
Atuin Setup
Atuin is packaged in the [extra] Arch repo which I enabled on my Artix systems. So it's pretty current. And it's the only package I need on the machines I want to use Atuin on. It also has a daemon in the binary, which needs to run in the background to get the full performance from the server.
On Artix I had to write a little OpenRC script to start/stop the Atuin daemon and put it into '/etc/init.d/atuin-daemon'. It has to be executable.
#!/usr/bin/openrc-run
# file: /etc/init.d/atuin-daemon
supervisor=supervise-daemon
# change this to the user using atuin
USER=artix
command_user="${USER}"
command_args=""
command="/usr/bin/atuin daemon"
Then I had to add it to the OpenRC startup scripts and start it afterwards to avoid a reboot.
$ sudo rc-update add atuin-daemon default
$ sudo rc-service atuin-daemon start
On systems with different init systems this process has to be done accordingly to the used init system. But most of the time you'll have to create your own init scripts (eg. for systemd).
After that comes the configuration of Atuin in the '~/.config/atuin/config.toml' user file. The defaults are pretty sensible and I just needed to add a few lines at the end of the file.
[sync]
records = true
[daemon]
enabled = true
Later after the installation of the server I just had to adjust the 'sync_address' setting to point to my own server.
Now I had to add the Atuin history tool to the shell resource file. I show it here for the ZSH shell, but bash and others are similar:
$ echo 'eval "$(atuin init zsh)"' >> ~/.zshrc
After that I restarted my shell and imported my local history:
# restart shell
$ exec zsh
# To import the history of the running shell (ZSH)
$ atuin import auto
Now I could use Atuin already locally with my current history.
Server Installation
While the Atuin binary also includes the corresponding server, I chose the docker-compose setup though, because a postgresql database is also needed. Therefore I created an .env file containing the postgresql credentials, and a docker-compose.yml file.
.env:
# file: ~/.env
ATUIN_DB_NAME=atuin
ATUIN_DB_USERNAME=atuin
# Choose your own secure password
ATUIN_DB_PASSWORD=supersecurepassword
docker-compose.yml:
# file: ~/docker-compose.yml (needs editing)
services:
atuin:
restart: always
# The docs suggest to choose the latest tagged release but I simply used
# image: ghcr.io/atuinsh/atuin
# because I got errors concerning GLIBC
image: ghcr.io/atuinsh/atuin:<LATEST TAGGED RELEASE>
command: server start
volumes:
- "./config:/config"
links:
- postgresql:db
ports:
- 8888:8888
environment:
ATUIN_HOST: "0.0.0.0"
ATUIN_OPEN_REGISTRATION: "true"
ATUIN_DB_URI: postgres://$ATUIN_DB_USERNAME:$ATUIN_DB_PASSWORD@db/$ATUIN_DB_NAME
RUST_LOG: info,atuin_server=debug
postgresql:
# I use postgresql version 16 instead of 14 as written in the docs
image: postgres:16
restart: unless-stopped
volumes: # Don't remove permanent storage for index database files!
- "./database:/var/lib/postgresql/data/"
environment:
POSTGRES_USER: ${ATUIN_DB_USERNAME}
POSTGRES_PASSWORD: ${ATUIN_DB_PASSWORD}
POSTGRES_DB: ${ATUIN_DB_NAME}
I had to fix some file permission problems on my Proxmox container, which shouldn't be too difficult if needed. When everything was in place I already could start the server.
# At first omit the -d flag to see if some errors occur
$ docker-compose up
# If no errors occur and the server runs you can abort with CTRL-C
# and start the server in daemon mode
$ docker-compose up -d
It should automatically restart now if I for example restart my server.
Create Account and first Login
Now I had to have the right server address in place in my Atuin config on my workstations: 'sync_address = "https://services.srv:8888"' and restarted my shell: 'exec zsh'. Then I entered the following command to create an account on my server:
$ atuin register --username <name> --password <secret> --email <email>
Then I needed to log into my newly created account and did my first sync:
$ atuin login --username <name> --password <secret>
# We use the -f (force) option here to make a complete sync
$ atuin sync -f
Now the workstation was already syncing but still lonely. If I wanted to merge all the history list into one on all computers I needed to get the right key for the repository while I'm logged into the first computer. This is the way to get the encryption key for the account to connect further systems:
This spitted out a list of words which I needed to provide for logging into subsequent machines:
$ atuin login --username <name> --password <secret> --key "<list of words>"
# We also do a initial sync to merge the histories
$ atuin sync -f
With the last two commands I could add my other two machines to the merged history list. And it works perfectly! I have a merged history list from 3 machines which I can search through with fuzzy finding filtered by hosts, users, directories and sessions. I believe searching through time periods is also possible although I haven't checked that out yet.
TLS
Although TLS (https) is not strictly needed in a homelab environment I do appreciate the additional security. Especially because I have a local net certificate authority already in place. So I created a certificate signed by my local CA and added it to the server ~/config/ directory and edited the server.toml file accordingly.
If you really want this you need to create a certificate/key pair signed by your local Certificate Authority which must be added to your certificate store on all connected machines. But I won't cover that in this walkthrough. There are some good tutorials out there how to maintain your own CA. Maybe I'll make a tutorial on that later, too.
I'm already hooked
I've used Atuin in local mode for half a year now and got used to it's convenient features. But merged histories are a huge level higher. For example I used a lot of awk commands on my desktop for different purposes. Now I have these commands also available in the history of my other machines. Same with other commands like sed, grep or find. Or commands sequences with lots of pipes. All available everywhere. It's simply awesome! I can only recommend it to you!
All in all - Have fun!
-fab-
--
Back to index
Homepage