summaryrefslogtreecommitdiff
path: root/site/2026-02-20-pleasant-arch-setup.md
blob: eafc3fee8af0da9c2caf61fa16f797a8850db4ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# A pleasant Arch Linux setup

<div class="post-dates">
  <time id="post-upload-date">2026-02-20</time>
  <time id="post-modification-date">2026-02-20</time>
</div>

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](https://fishshell.com/) as I do then `.profile` will not
be loaded by default, you'll have to [create a fishlogin file](https://superuser.com/a/1046884)
that sources it manually.

A better solution I found is to use [systemd's environment.d](https://www.freedesktop.org/software/systemd/man/latest/environment.d.html)
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:

<pre><code class="language-conf">
# ~/.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
</code></pre>

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](https://specifications.freedesktop.org/basedir/latest/)
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](https://github.com/b3nj5m1n/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`

<pre><code class="language-conf">
# ~/.config/environment.d/40-xdg-ninja.conf
CARGO_HOME=$XDG_DATA_HOME/cargo
RUSTUP_HOME=$XDG_DATA_HOME/rustup
# ...
</code></pre>

## 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](https://wiki.archlinux.org/title/SSH_keys#ssh-agent) 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.

<pre><code class="language-conf">
# ~/.config/environment.d/30-ssh-agent.conf
SSH_AUTH_SOCK=$XDG_RUNTIME_DIR/ssh-agent.socket
</code></pre>

## 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](https://github.com/Supreeeme/xwayland-satellite/blob/main/resources/xwayland-satellite.service)
into my user services.

<pre><code class="language-ini">
# ~/.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
</code></pre>

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.

<pre><code class="language-conf">
# ~/.config/environment.d/20-wayland-hints.conf
DISPLAY=:1
ELECTRON_OZONE_PLATFORM_HINT=wayland
_JAVA_AWT_WM_NONREPARENTING=1
</code></pre>

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