| Title: Reproducible clean $HOME in OpenBSD using impermanence | |
| Author: Solène | |
| Date: 15 March 2022 | |
| Tags: openbsd reproducible nixos unix | |
| Description: Bringing some NixOS tech to OpenBSD | |
| # Introduction | |
| Let me present you my latest project: home-impermanence, under this | |
| name is a reference to the NixOS community project impermanence. The | |
| name may not be obvious about what it is doing, let me explain. | |
| NixOS wiki about Impermanence, a community module | |
| home-impermanence for OpenBSD | |
| The original goal of impermanence in NixOS is to have a fully | |
| reproducible system mounted on tmpfs where only user-defined files and | |
| directories are hooked into the temporary file system to be persistent | |
| (such as /home, /var/lib and some /etc files for instance). Why this | |
| is something achievable on NixOS, on OpenBSD side we are far from | |
| having the tooling to go that deep so I wrote home-impermanence that | |
| allows an user to just do that at their $HOME level. | |
| What does it mean exactly? When you start your system, your $HOME | |
| directory will be mounted with an empty memory based file system (using | |
| mfs) and symbolic links to files and directories listed in the | |
| configuration file will be done in your $HOME. Every time you reboot, | |
| you will have the exact same set of files, extra files created | |
| meanwhile will be lost. When you hold a $HOME directory for long, you | |
| know you get many directories and files created in various ~/.config or | |
| ~/.local or directly as dotfiles in the top level of the home | |
| directory, with impermanence you can get ride of all the noise. | |
| A benefit is that you can run software as if it was their first run, in | |
| some software upgrade you will avoid old settings that would create | |
| troubles, or settings that would disturb a whole class of applications | |
| (like a gtk setting affecting all gtk programs), with impermanence the | |
| user can decide exactly what should remain across reboots or disappear. | |
| # Implementation | |
| My implementation is a Perl script relying on some libraries packaged | |
| on OpenBSD, it will run as root from a rc service and the settings done | |
| in rc.conf.local. It will read the configuration file from the | |
| persistent directory holding the user data and create symlinks in the | |
| target directory to the files and directories, doing some sanitizing in | |
| the process to prevent listed files to be included in listed | |
| directories which would nest symlinks incorrectly. | |
| I chose Perl because it's a stable language, OpenBSD ships with Perl | |
| and the very few dependencies required were already available in the | |
| ports tree. | |
| The program could easily be ported to Linux, FreeBSD and maybe NetBSD, | |
| the mount_mfs calls could be replaced by a mount_tmpfs and the | |
| directories symlinks could be done with a mount_bind or mount_nullfs | |
| which we don't have on OpenBSD, if someone wants to port my project to | |
| another system I could help adding the required logic. | |
| # How to use | |
| I wrote a complete README file explaining the installation and | |
| configuration process, for full instructions refer to this document and | |
| the man page that ships with home-impermanence. | |
| home-impermanence README | |
| ## Installation | |
| Quick method: | |
| ``` | |
| git clone https://tildegit.org/solene/home-impermanence/ | |
| cd home-impermanence | |
| doas make install | |
| doas rcctl enable impermanence | |
| doas rcctl set impermanence flags -u user -d /home/persist/ | |
| doas install -d /home/persist/ | |
| ``` | |
| From now, you may want to make things quickly, logout from your user | |
| and run these commands, this will move your user directory and prepare | |
| the mountpoint. | |
| ``` | |
| mv /home/user /home/persist/user | |
| install -d -o user -g wheel /home/user | |
| ``` | |
| Now, it's time to configure impermanence before running it. | |
| ## Configuration | |
| Reusing the paths from the installation example, the configuration file | |
| should be in /home/persist/user/impermanence.yml , the file must be | |
| using YAML formatting. Here is my personal configuration file that you | |
| can use as a base. | |
| ```configuration yaml file | |
| size: 500m | |
| files: | |
| - .Xdefaults | |
| - .Xresources | |
| - .bashrc | |
| - .gitconfig | |
| - .kshrc | |
| - .profile | |
| - .xsession | |
| - .tmux.conf | |
| - .config/kwalletrc | |
| directories: | |
| - .claws-mail | |
| - .config/Thunar | |
| - .config/asciinema | |
| - .config/gajim | |
| - .config/kak | |
| - .config/keepassxc | |
| - .config/lagrange | |
| - .config/mpv | |
| - .config/musikcube | |
| - .config/openttd | |
| - .config/xfce4 | |
| - .config/zim | |
| - .local/share/cozy | |
| - .local/share/gajim | |
| - .local/share/ibus-typing-booster | |
| - .local/share/kwalletd | |
| - .mozilla | |
| - .ssh | |
| - Documents | |
| - Downloads | |
| - Music | |
| - bin | |
| - dev | |
| - notes | |
| - tmp | |
| ``` | |
| When you think you are done, start the impermanence rc service with | |
| rcctl start impermanence and log-in. You should see all the symlinks | |
| you defined in your configuration file. | |
| ## Result | |
| Here is the content of my $HOME directory when I use impermanence. | |
| ``` | |
| solene@daru ~> ls -la | |
| total 104 | |
| drwxr-xr-x 8 solene wheel 1024 Mar 15 12:10 . | |
| drwxr-xr-x 17 root wheel 512 Mar 14 15:36 .. | |
| -rw------- 1 solene wheel 165 Mar 15 09:08 .ICEauthority | |
| -rw------- 1 solene solene 53 Mar 15 09:08 .Xauthority | |
| lrwxr-xr-x 1 root wheel 34 Mar 15 09:08 .Xdefaults -> /home/permanent… | |
| lrwxr-xr-x 1 root wheel 35 Mar 15 09:08 .Xresources -> /home/permanen… | |
| -rw-r--r-- 1 solene wheel 48 Mar 15 12:07 .aspell.en.prepl | |
| -rw-r--r-- 1 solene wheel 42 Mar 15 12:07 .aspell.en.pws | |
| lrwxr-xr-x 1 root wheel 31 Mar 15 09:08 .bashrc -> /home/permanent//s… | |
| drwxr-xr-x 9 solene wheel 512 Mar 15 12:10 .cache | |
| lrwxr-xr-x 1 root wheel 35 Mar 15 09:08 .claws-mail -> /home/permanen… | |
| drwx------ 8 solene wheel 512 Mar 15 12:27 .config | |
| drwx------ 3 solene wheel 512 Mar 15 09:08 .dbus | |
| lrwxr-xr-x 1 root wheel 34 Mar 15 09:08 .gitconfig -> /home/permanent… | |
| drwx------ 3 solene wheel 512 Mar 15 12:32 .gnupg | |
| lrwxr-xr-x 1 root wheel 30 Mar 15 09:08 .kshrc -> /home/permanent//so… | |
| drwx------ 3 solene wheel 512 Mar 15 09:08 .local | |
| lrwxr-xr-x 1 root wheel 32 Mar 15 09:08 .mozilla -> /home/permanent//… | |
| lrwxr-xr-x 1 root wheel 32 Mar 15 09:08 .profile -> /home/permanent//… | |
| lrwxr-xr-x 1 solene wheel 30 Mar 15 12:10 .sbclrc -> /home/permanent/so… | |
| drwxr-xr-x 2 solene wheel 512 Mar 15 09:08 .sndio | |
| lrwxr-xr-x 1 root wheel 28 Mar 15 09:08 .ssh -> /home/permanent//sole… | |
| lrwxr-xr-x 1 root wheel 34 Mar 15 09:08 .tmux.conf -> /home/permanent… | |
| lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 .xsession -> /home/permanent/… | |
| -rw------- 1 solene wheel 25273 Mar 15 13:26 .xsession-errors | |
| lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 Documents -> /home/permanent/… | |
| lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 Downloads -> /home/permanent/… | |
| lrwxr-xr-x 1 root wheel 30 Mar 15 09:08 HANGAR -> /home/permanent//so… | |
| lrwxr-xr-x 1 root wheel 27 Mar 15 09:08 dev -> /home/permanent//solen… | |
| lrwxr-xr-x 1 root wheel 29 Mar 15 09:08 notes -> /home/permanent//sol… | |
| lrwxr-xr-x 1 root wheel 33 Mar 15 09:08 quicklisp -> /home/permanent/… | |
| lrwxr-xr-x 1 root wheel 27 Mar 15 09:08 tmp -> /home/permanent//solen… | |
| ``` | |
| ## Rollback | |
| If you want to rollback it's easy, disable impermanence, move | |
| /home/persist/user to /home/user and you are done. | |
| # Conclusion | |
| I really don't want to go back to not using impermanence since I tried | |
| it on NixOS. I thought implementing it only for $HOME would be good | |
| enough as a start and started thinking about it, made a proof of | |
| concept to see if the symbolic links method was enough to make it work, | |
| and it was! | |
| I hope you will enjoy this as much as I do, feel free to contact me if | |
| you need some help understanding the setup. |