A simplified home server setup, part 1

Fabio Natali, 17 July 2024

Intro

In the first part of this post, last month, I described my attempt at using my Guix home server as a virtualisation environment. With a clever use of the Guile programming language (haha, really, by copying other people's code from the internet!) I was able to set up a small number of services, each one in its dedicated virtual machine for security-through-compartmentalisation.

While things were working, overall the system was a bit convoluted, somewhat unstable, and not the easiest to maintain. (I did mention I just copied random snippets from the internet!) I eventually decided to radically simplify my setup, reducing the number of services and features to a refreshing minimum core.

In this post I'll briefly go through my current home server and laptop configuration.

Connecting the dots

Publishing one's own dot-files (i.e. configuration files) is an established practice among users of Unix-like systems. It's good to have your dot-files under versioning (e.g. in case you need to revert a change) and saved remotely (e.g. for disaster recovery!). Sharing your dot-files publicly is also a good way to share knowledge and learn from each other.

If you're familiar with Guix system definitions and home environment definitions, you'll know that these are powerful mechanisms to describe a system and its behaviour - it's a bit like a dot-files repository, and actually much more than that.

My system configurations

So in the spirit of the dot-files tradition, and for what it's worth, my system configurations are available at this link. The repository includes:

  • my laptop's Guix system definition,
  • my laptop's Guix Home environment, including my Emacs configuration,
  • my home server's Guix system definition.

Configuration instructions are organised in separate files, one per machine, such as laptop.org and server.org. The files are written in Org, Org Mode's markup language, and follow a literate programming style, with code blocks and comments mixed together. Emacs is used to process the Org files and produce the final configuration.

A Makefile is provided as a high-level interface to some of the most common tasks, e.g. make build to "rebuild" the configuration files from the Org sources, make laptop to reconfigure the laptop, make server to reconfigure the home server.

Reading private values from a separate data file

To avoid including superfluous (and private) configuration details into the repository, I make use of a noweb function, <<get('key)>>, that retrieves values from separate, non-versioned data files.

If a data file is available with this structure:

#+name: data
#+begin_src emacs-lisp
'((host-name . "laptop")
  (user-name . "user")
  (user-group . "users")
  ...)
#+end_src

Then it's possible to define a <<get('key)>> function to insert values within the main configuration file:

#+name: get
#+begin_src emacs-lisp :var key="" data=laptop.data:data
(alist-get key data)
#+end_src

#+begin_src scheme :mkdirp yes :noweb yes :tangle build/laptop.scm
(define laptop-operating-system
  (operating-system
    (host-name "<<get('host-name)>>")
    ...
    (users (cons* (user-account
                   (name "<<get('user-name)>>")
                   (group "<<get('user-group)>>"))
                  %base-user-accounts))
    ...))
#+end_src

Data files are not meant for sensitive data such as passwords, one should use some form of encryption in those cases, e.g. with pass or GnuPG.

My laptop

My laptop's configuration mostly revolves around Emacs, which I use for the largest part of my computing needs, including:

  • as a terminal emulator (vterm),
  • as a mail client (Notmuch),
  • as a window manager (EXWM),
  • for notes, presentations, typesetting, literate programming (Org Mode plus LaTeX, …),
  • for some DevOps tasks (TRAMP),
  • for scripting and task automation with Emacs Lisp,
  • for writing and building this blog too!

Other than the Emacs configuration, my home environment primarily defines:

  • what packages to install (a pretty short list of core apps, for everything else I tend to use guix shell app-name -- app-command, sometimes with an additional --container for some level of isolation),
  • a Borg-based backup mechanism,
  • how to fetch and send email with mbsync and msmtp,
  • a miscellanea of minor things, e.g. cron jobs, SSH, GnuPG, etc.

Lastly, the laptop's system definition does very little. Beyond the essential tasks, it sets up a pretty restrictive firewall and configures my WireGuard VPN connections.

My server

After abandoning the idea of a Proxmox-like virtualisation environment, I've trimmed my server definition down to the bare minimum. For now it only includes:

  • some essential services: a firewall, a SSH server, a WireGuard VPN end-point (point-to-point setup),
  • a BorgBackup server,
  • a ReadyMedia DLNA media server (in progress).

The services are only accessible from the LAN and the VPN (with the obvious exception of WireGuard itself).

Outro

I've learned a lot by looking at other Guixers' home and system configurations. I hope that mine, although very simple, can be of help to someone too.

In my next post I should be able to share more about my DLNA media server. Until next time!

Revision 3a220d5.