Arch Linux config

Arch Linux config

I’ve decided to switch to Arch Linux and configure it declaratively with metapac.

System installation

Installation

On installation, see https://wiki.archlinux.org/title/Installation_guide and/or use archinstall.

Don’t forget to run

pacman -Sy archlinux-keyring

Before archinstall.

After installation

Update everything:

sudo pacman -Syyu

Install git, python and yadm:

sudo pacman -Syu python git pacman-contrib yadm

Select top-6 fastest mirrors to work with. Generate a mirrorlist file using this service: https://archlinux.org/mirrorlist/, then use rankmirrors from pacman-contrib (see Mirrors on Arch Wiki).

sudo -i
cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.backup
rankmirrors -n 6 /etc/pacman.d/mirrorlist.backup > /etc/pacman.d/mirrorlist

If there isn’t enough RAM (e.g. running in a VM), turn off mounting /tmp as tmpfs:

sudo systemctl mask tmp.mount

Install paru:

sudo pacman -S --needed base-devel
git clone https://aur.archlinux.org/paru.git
cd paru
makepkg -si

Install metapac:

paru -Syyu metapac

Enable multilib by uncommenting the [multilib] section in /etc/pacman.conf.

Then install Arch packages with metapac:

mkdir ~/00-Scratch/
git clone https://github.com/SqrtMinusOne/dotfiles.git ~/00-Scratch/dotfiles/
cp -r ~/00-Scratch/dotfiles/.config/metapac ~/.config/
metapac s

Then, install the ssh and gpg keys (put them into the ~/.ssh folder). To export gpg keys:

gpg --output private.pgp --armor --export-secret-keys <keyname>

And to import:

gpg --import private.pgp
gpg --edit-key <keyname>
trust

Also the following to ~/.ssh/config:

Host *
    AddKeysToAgent yes

And run:

systemctl enable --user --now ssh-agent

It looks like it is necessary to run at least once.

Then, clone the dotfiles repo with yadm:

yadm clone git@github.com:SqrtMinusOne/dotfiles.git

Checkout the changed files.

Clone org-mode and passwords repos:

git clone ssh://git@git.sqrtminusone.xyz:222/sqrtminusone/org-mode.git "/home/pavel/30-39 Life/32 org-mode"
git clone ssh://git@git.sqrtminusone.xyz:222/sqrtminusone/passwords.git "/home/pavel/.password-store"

And don’t forget to configure git:

git config --global user.email "thexcloud@gmail.com"
git config --global user.name "SqrtMinusOne"

Install wakatime:

cd ~/00-Scratch/
git clone https://github.com/wakatime/wakatime-cli.git
cd ./wakatime-cli
go build
mv wakatime-cli ~/bin

And create the ~/.wakatime.cfg file with the following contents:

[settings]
api_key = <api-key>

Then run emacs and make sure it starts. Run:

  • M-x nerd-icons-install-fonts
  • M-x all-the-icons-install-fonts
  • M-x treesit-install-language-grammar

Run rclone config, configure the remotes. Then M-x my/index-commands-sync.

If everything works, login into EXWM.

Create some directories:

mkdir -p /home/pavel/Pictures/screenshots/
mkdir -p /home/pavel/.mpd/playlists/

Also run:

sudo chmod +s /usr/bin/light

For I’ve decided to use NetworkManager, but Arch Linux uses iwd by default, which causes issues. Disable it by:

sudo systemctl disable --now iwd
sudo systemctl disable --now systemd-networkd
sudo systemctl enable --now NetworkManager

And reboot. After the reboot, NetworkManager should run using wpa_supplicant as backend for Wi-Fi.

Don’t forget to sync mail and enable the sync timer.

sudo usermod -a -G libvirt pavel
sudo usermod -a -G kvm pavel
sudo virsh net-autostart default

Install zotero-better-bibtex manually.

Run init-nvm:

bash /usr/share/nvm/init-nvm.sh

Add flatpak remote:

flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo

To install xrdp, configure an unpriviliged user:

sudo useradd xrdp -d / -c 'xrdp daemon' -s /usr/sbin/nologin

Then uncomment these lines in /etc/xrdp/xrdp.ini:

runtime_user=xrdp
runtime_group=xrdp

And in /etc/xrdp/sesman.ini:

SessionSockdirGroup=xrdp

Fix the permissions:

sudo chmod 640 /etc/xrdp/cert.pem /etc/xrdp/key.pem /etc/xrdp/rsakeys.ini
sudo chown root:xrdp /etc/xrdp/cert.pem /etc/xrdp/key.pem /etc/xrdp/rsakeys.ini
sudo systemctl enable --now xrdp

Set the default browser:

xdg-settings set default-web-browser glide-browser-bin.desktop

Disable systemd coredumps by editing /etc/systemd/coredump.conf

[Coredump]
Storage=none
ProcessSizeMax=0
systemctl --user enable --now gnome-keyring-daemon.service gnome-keyring-daemon.socket

Metapac configuration

metapac is a declarative wrapper around different package managers, including pacman and paru. This means the required packages can be listed in configuration files and checked into version control.

I’ve also tried decman, but it turned out to be too unstable because it ships its own logic for building AUR packages, which doesn’t always work. So wrapping paru seems like a saner approach. Also, sometimes AUR drops packets, and decman can’t handle it gracefully.

In metapac, packages are listed in “groups”, each group being a TOML file stating which package has to be installed by which package manager. I declare groups as Org tables, see the “System configuration” section in Emacs.org.

Below is the table enabling different groups on different hostnames:

Profile archlinux weiss violet schwarz
browsers + + + +
console + + + +
desktop + + + +
desktop-misc + + + +
desktop-polybar + + + +
desktop-rofi + + + +
dev + + + +
emacs + + + +
latex + + + +
mail + + + +
music + + + +
nvidia +
office + + + +
system + + + +
printer +
games +
geo +
remote +

And the code to format it as TOML:

(let* ((hostnames (cdr (nth 0 groups)))
       groups-by-hostname)
  (cl-loop for row in (cdr groups)
           for group = (nth 0 row)
           do (cl-loop for i from 0
                       for sign in (cdr row)
                       for hostname = (nth i hostnames)
                       if (not (string-empty-p sign))
                       do (push group (alist-get hostname groups-by-hostname
                                                 nil nil #'equal))))
  (cl-loop for (hostname . groups) in groups-by-hostname
           concat (format "%s = [%s]\n" hostname
                          (mapconcat (lambda (g) (format "\"%s\"" g)) groups ","))))

Which is used in the config:

enabled_backends = ["arch", "flatpak"]
hostname_groups_enabled = true

[hostname_groups]
<<metapac-groups-format()>>

[arch]
package_manager = "paru"

paru configuration

Configuring paru to work with my custom Emacs build.

Include = /etc/paru.conf

[private]
Url = https://github.com/SqrtMinusOne/sqrt-emacs.git
GenerateSrcinfo
SkipReview

pacserve

https://wiki.archlinux.org/title/Pacserve

Arch dependencies
pacserve
systemctl enable --now pacserve

System packages

Some necessary Arch packages:

Arch dependency
amneziavpn-bin
base
base-devel
debtap
gnome-keyring-daemon
grub
iwd
lightdm
lightdm-gtk-greeter
linux
linux-firmware
inetutils
nano
networkmanager
metapac
openssh
pacman-contrib
paru
pipewire
pipewire-audio
pipewire-alsa
pipewire-pulse
pipewire-jack
sof-firmware
smartmontools
vim
xterm
wget
wireless_tools
wireplumber
yadm
zram-generator

Various drivers, I’m not sure which I actually need, so…

Arch dependency
libva-intel-driver
intel-media-driver
vulkan-intel
vulkan-radeon
xf86-video-amdgpu
xf86-video-ati

Also opensnitch, a firewall.

Arch dependency
opensnitch
apparmor
firejail

A tool to downgrade a package.

Arch dependency
downgrade

NVIDIA drivers & AI stuff for violet

Category Arch dependency
nvidia cuda
nvidia nvidia-utils
nvidia nvidia-open
nvidia llama.cpp-vulkan
nvidia nvidia-container-toolkit

Printer packages.

Category Arch dependency
printer cups
printer usbutils
printer brlaser
printer naps2-bin
printer brscan4

Remote connectivity packages.

Category Arch dependency
remote xorgxrdp

To type stuff

Arch dependency
xvkbd

(my/format-arch-dependencies category)
<<packages("nvidia")>>
<<packages("printer")>>
<<packages("remote")>>
<<packages()>>

Notes on VMs

Linux

Install spice-vdagent and reboot to enable clipboard sharing.

Check View > Scale Display > Auto resize VM with window. Then, running

xrandr --output Virtual-1 --auto

Will resize the display to the VM window. This question has some info on how to automate that, I’m fine with executing the command manually.

To add a shared folder, do:

  • Memory > Enable shared memory
  • Add hardware > Filesystem with virtiofs, e.g.
<filesystem type="mount">
  <source dir="/home/pavel/00-Scratch"/>
  <target dir="shared"/>
  <driver type="virtiofs"/>
</filesystem>

Then, in order to mount:

mkdir ~/00-Scratch/
sudo mount -t virtiofs shared /home/pavel/00-Scratch/

To make in permanent, add the following to /etc/fstab

shared /home/pavel/00-Scratch virtiofs defaults 0 0

Windows

References:

When creating a VM, check “Customize configuration before install”. Make the following changes:

  1. In the CPUs tab, select “Copy host CPU configuration” and click Apply.

  2. In the XML version edit the <clock> section as follows:

    <clock offset='localtime'>
      <timer name='rtc' present='no' tickpolicy='catchup'/>
      <timer name='pit' present='no' tickpolicy='delay'/>
      <timer name='hpet' present='no'/>
      <timer name='kvmclock' present='no'/>
      <timer name='hypervclock' present='yes'/>
    </clock>
    

    The source says it will disable all timers except for the hypervclocks, reducing idle CPU usage.

    Also enable Hyper-V enlightenments in <hyperv>:

    <hyperv>
      <relaxed state='on'/>
      <vapic state='on'/>
      <spinlocks state='on' retries='8191'/>
      <vpindex state='on'/>
      <synic state='on'/>
      <stimer state='on'>
        <direct state='on'/>
      </stimer>
      <reset state='on'/>
      <frequencies state='on'/>
      <reenlightenment state='on'/>
      <tlbflush state='on'/>
      <ipi state='on'/>
    </hyperv>
    

    Add this device under <devices>:

    <channel type='unix'>
      <source mode='bind'/>
      <target type='virtio' name='org.qemu.guest_agent.0'/>
      <address type='virtio-serial' controller='0' bus='0' port='2'/>
    </channel>
    
  3. In the SATA Disk 1 section, section set the Disk bus type to VirtIO.

  4. In NIC section, set the device model to virtio.

  5. Download VirtIO drivers

  6. Add a CD-ROM device with the VirtIO driver ISO.

During installation, load the VirtIO driver in \amd64\w11. The disk should appear.

After installation, open the VirtIO driver ISO and run virtio-win-guest-tools.exe. Then, the option at View > Scale Display / Auto resize VM with window should work.

Configure DNS to 1.1.1.1

To configure a shared folder:

  1. Toggle “Enable shared memory” in the memory tab.
  2. Click “Add hardware” -> Filesystem, select virtiofs as the driver and specify the paths.
  3. Install WinFSP on the VM.
  4. Run:
    sc.exe create VirtioFsSvc binpath= "C:\Program Files\Virtio-Win\VioFS\virtiofs.exe" start=auto depend="WinFsp.Launcher/VirtioFsDrv" DisplayName="Virtio Filesystem Service"
    sc.exe start VirtioFsSvc
    
  5. Reboot the VM.

Copying VMs between machines

To copy a VM, first, copy the image:

rsync -avP /var/lib/libvirt/images/debian12-vpn.qcow2 /run/media/pavel/A6E5-4138/vms/

Then, export the configuration:

virsh -c qemu:///system dumpxml debian12-vpn > debian12-vpn.xml

To restore, copy the image back:

sudo rsync -avP /run/media/pavel/A6E5-4138/vms/debian12-vpn.qcow2 /var/lib/libvirt/images/

And import the configuration:

sudo virsh define debian12-vpn.xml

Assign a static IP to a VM

To assign a static IP to a VM, run:

sudo EDITOR=vim virsh net-edit default

And inside the <dhcp> section, insert:

<host mac='52:54:00:58:7f:82' name='myvm' ip='192.168.122.50'/>

After which, restart the network:

sudo virsh net-destroy default
sudo virsh net-start default

Network

Don’t forget to set iptables in /etc/libvirt/network.conf:

firewall_backend = "iptables"

Notes on Software

Upgrading Python and AUR packages

After upgrading Python from 3.13 to 3.14, lieer has stopped working

$ gmi
Traceback (most recent call last):
  File "/usr/bin/gmi", line 20, in <module>
    from lieer import Gmailieer
ModuleNotFoundError: No module named 'lieer'

The issue is that the package has been installed for Python 3.13:

pacman -Ql lieer-git | grep -E '\.py$|site-packages'
lieer-git /usr/lib/python3.13/site-packages/
lieer-git /usr/lib/python3.13/site-packages/lieer-1.6.dist-info/
lieer-git /usr/lib/python3.13/site-packages/lieer-1.6.dist-info/METADATA
lieer-git /usr/lib/python3.13/site-packages/lieer-1.6.dist-info/RECORD
lieer-git /usr/lib/python3.13/site-packages/lieer-1.6.dist-info/WHEEL
lieer-git /usr/lib/python3.13/site-packages/lieer-1.6.dist-info/licenses/
lieer-git /usr/lib/python3.13/site-packages/lieer-1.6.dist-info/licenses/COPYING.GPL-3.0+
lieer-git /usr/lib/python3.13/site-packages/lieer-1.6.dist-info/licenses/LICENSE.md
lieer-git /usr/lib/python3.13/site-packages/lieer-1.6.dist-info/top_level.txt
lieer-git /usr/lib/python3.13/site-packages/lieer/
lieer-git /usr/lib/python3.13/site-packages/lieer/__init__.py
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/__init__.cpython-313.opt-1.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/__init__.cpython-313.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/gmailieer.cpython-313.opt-1.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/gmailieer.cpython-313.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/local.cpython-313.opt-1.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/local.cpython-313.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/nobar.cpython-313.opt-1.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/nobar.cpython-313.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/remote.cpython-313.opt-1.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/remote.cpython-313.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/resume.cpython-313.opt-1.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/__pycache__/resume.cpython-313.pyc
lieer-git /usr/lib/python3.13/site-packages/lieer/gmailieer.py
lieer-git /usr/lib/python3.13/site-packages/lieer/local.py
lieer-git /usr/lib/python3.13/site-packages/lieer/nobar.py
lieer-git /usr/lib/python3.13/site-packages/lieer/remote.py
lieer-git /usr/lib/python3.13/site-packages/lieer/resume.py

And the Python version is 3.14:

$ python --version
Python 3.14.2

Simply rebuilding the package doesn’t help because something has been cached. It is neccessary to use the --rebuild tag:

$ paru -S lieer-git --rebuild

Installing MS Office 2007

MS Office 2007, which I need for work, installs reasonably well on PlayOnLinux, except for one library that can be downloaded with winetricks:

WINEPREFIX=~/.PlayOnLinux/wineprefix/Office2007 WINE=~/.PlayOnLinux/wine/linux-x86/4.0/bin/wine winetricks msxml3

Issues with DBeaver

In /usr/lib/jvm/java-21-openjdk/conf/security/java.security, in jdk.tls.disabledAlgorithms in lines:

ECDH, TLS_RSA_*, rsa_pkcs1_sha1 usage HandshakeSignature, \
ecdsa_sha1 usage HandshakeSignature, dsa_sha1 usage HandshakeSignature

Leave only ECDH

Running MAX in Firejail

Firejail config:

include disable-common.inc
include disable-devel.inc
include disable-programs.inc

private ~/.sandbox/max
private-tmp
private-cache
private-dev

caps.drop all
nonewprivs
[Desktop Entry]
Type=Application
Terminal=false
Name=MAX
Exec=firejail --profile=max /usr/share/max/bin/max %U
DBusActivatable=false
Icon=/usr/share/pixmaps/max.png
MimeType=x-scheme-handler/max;
Comment=MAX Messenger Client Application
Comment[ru]=Клиентское приложение мессенджера MAX
StartupWMClass=max
Categories=Chat;Network;InstantMessaging;Qt;
Keywords=max;chat;im;messaging;messenger;sms;
SingleMainWindow=true
X-GNOME-UsesNotifications=true
X-GNOME-SingleWindow=true

Don’t forget to run:

mkdir -p ~/.sandbox/max
update-desktop-database ~/.local/share/applications