A pleasant Arch Linux setup

Recently I distrohopped back to Arch Linux on my laptop and, given the opportunity for a fresh start, wanted to keep the setup tidy. In this post I note down a bunch of small changes I made that make my system more neat, lean and aesthetically pleasant by my judgement. I will (hopefully) periodically update this post as I find and implement new improvements.

Environment variables

First order of business is setting environment variables since so much else is configured through them. Traditionally one might put their variables into shell initialization files, such a ~/.profile or ~/.bashrc. I don’t like this for a few reasons. First it pollutes my home directory with configuration files that don’t belong there, and second it’s not portable across shells. If you opt to use fish shell as I do then .profile will not be loaded by default, you’ll have to create a fishlogin file that sources it manually.

A better solution I found is to use systemd’s environment.d to set variables set by the corresponding systemd user service (user@<uid>.service). I created the ~/.config/environment.d directory and populated it with a few files for different types of assignments. For example here’s the file I use to set my XDG base directories:


# ~/.config/environment.d/10-user-dirs.conf
XDG_CONFIG_HOME=$HOME/.config
XDG_CACHE_HOME=$HOME/.cache
XDG_DATA_HOME=$HOME/.local/share
XDG_STATE_HOME=$HOME/.local/state

This approach has a few benefits and a few downsides. It means my variables aren’t dependent on my shell, that they’re located in a common location, and have a dead-simple format that’s not interspersed with other shell stuff. However it also means that ~/.config/ is necessarily my config home (after all you can’t read $XDG_CONFIG_HOME before you’ve set it) and that reloading my environment requires reloading the user service and all services after it. So far the easiest way I’ve found to do this is to do a full systemctl soft-reboot.

Keeping my $HOME clean

In our blessed year of 2026 a nontrivial amount of programs still don’t respect the XDG Base Directory Specification by default. Thankfully a lot of them have environment-based configuration options I can use to fix that. To detect such cases I periodically run xdg-ninja which helpfully lists out offending programs on my system as well as the fix, if any is available.

Most fixes tend to be environment variables, and as such I have the following file in my environment.d


# ~/.config/environment.d/40-xdg-ninja.conf
CARGO_HOME=$XDG_DATA_HOME/cargo
RUSTUP_HOME=$XDG_DATA_HOME/rustup
# ...

SSH agent

Loading the SSH agent is yet another pain point when using a shell based approach. The Arch wiki even recommends using a bash snippet in your .bashrc that uses pgrep to find the current running ssh agent instance and source its environment variable in the current shell as a method of dealing with it. Too janky for my tastes. Thankfully the very next section notes that a systemd user service for the agent is included with the openssh package that I can use it instead, so long as I set the SSH_AUTH_SOCK environment variable manually.

Therefore an invocation of systemctl --user enable ssh-agent.service along with creating the following environment file solves my troubles.


# ~/.config/environment.d/30-ssh-agent.conf
SSH_AUTH_SOCK=$XDG_RUNTIME_DIR/ssh-agent.socket

Xwayland

By default the xwayland-satellite package does not start the satellite nor set up a service for it. It should be clear by now that I prefer using systemd services for this sort of thing rather than mechanisms like niri’s spawn-at-startup. Therefore I dropped this service file into my user services.


# ~/.config/systemd/user/xwayland-satellite.service
[Unit]
Description=Xwayland outside your Wayland
BindsTo=graphical-session.target
PartOf=graphical-session.target
After=graphical-session.target
Requisite=graphical-session.target

[Service]
Type=notify
NotifyAccess=all
ExecStart=/usr/local/bin/xwayland-satellite
# ^^ this needed adjustment ^^
StandardOutput=journal

[Install]
WantedBy=graphical-session.target

X based applications also expect the DISPLAY environment variable to be set so I created put that into my wayland workarounds environment file. That file also contains other environment-based hints to programs that they should really use wayland pretty-please.


# ~/.config/environment.d/20-wayland-hints.conf
DISPLAY=:1
ELECTRON_OZONE_PLATFORM_HINT=wayland
_JAVA_AWT_WM_NONREPARENTING=1

I’m not sure whether the exact number you choose for the display has any effect.