Debian 11 workstation

These are my notes on setting and maintaining a desktop/workstation system, a successor to the older CentOS 7 workstation, to be used--among other things--with the private server setup.


My goals were a working setup, along with an old system, simple and close to the standard one, and with encrypted /home (see also: personal data storage). To avoid possible confusion during installation or when some repairs are needed, I keep a sheet of paper with partitions listed on it.

I went for Unofficial non-free images including firmware packages, since I need GNU documentation and the Nvidia proprietary driver anyway, and it's more suitable for a rescue USB stick. Picked a live Xfce image, to be able to poke it briefly (and ensure that it works fine with the hardware) before installation, as well as for possible later use as a rescue system. Xfce is not as bloated and broken as GNOME and KDE, but not as half-baked and broken as most of the others either. I've downloaded the image via BitTorrent, and as the Installation Guide suggests, just did the equivalent of cp debian.iso /dev/sdX && sync.

There's a graphical installer available from the live system itself, which is handy for looking up documentation on the web while installing, but its functionality differs from that of the regular installer: there's no option to make a EFI system partition (ESP), so I've rebooted and used the regular installer. Although while installing Debian on another machine a bit later, I noticed that it'd handle fine a FAT32 partition mounted into /boot/efi.

As usual, I wanted to keep the old system usable and independent, so I have set this one on a separate disk, with a separate ESP, which I had to add (about 500 MB in size); the installer presented a warning about possibly making other systems hard to boot into if EFI is forced, but I've installed it on a separate disk (and adjusted UEFI boot priorities accordingly), so it was fine.

I've used btrfs for a while, but decided to go with ext4 this time, since I use btrfs's advanced features less and less, while a simpler filesystem may be more reliable. Decided to minimize dealing with partitioning in the installer, and just made a single 500 GB partition for everything (not counting ESP, and while having 1.5 TB unpartitioned on the disk). No swap partition either, since in my experience it's not helpful and only freezes the system when something goes wrong. Didn't choose a network mirror to download new packages either, so the installation went quickly and smoothly.

Initial setup

As with CentOS about 7 years ago, apparently the nouveau driver was causing the system to freeze, so I've installed the NVIDIA Proprietary Driver.

Then I've added my user into the sudo group, have set the keyboard layout to colemak with sudo dpkg-reconfigure keyboard-configuration (since the installer doesn't provide that option), have set it in Xfce's settings to use the system layout (actually in a couple of places, not sure why there's so many). While at it, removed the useless bottom panel (application launcher), have set a dark theme, nicer icons, disabled icons on the desktop.

As with servers, and perhaps more importantly than with those, decent and varied nameservers should be set. In this case /etc/resolv.conf mentions that it's generated by NetworkManager (which is rather awkward and unnecessary, and an example of little bloat task-xfce-desktop pulls), so one can adjust nameservers with nm-connection-editor.

Then I've set the previously mentioned encrypted /home (this method is a bit verbose, since I've checked that things work as intended):

sudo fdisk /dev/sda
# created another 500 GB partition for /home, sda3
sudo apt install cryptsetup
sudo cryptsetup luksFormat /dev/sda3
sudo cryptsetup luksOpen /dev/sda3 enchome
sudo mkfs.ext4 -L home /dev/mapper/enchome
sudo cryptsetup close enchome
sudo blkid | grep sda3
sudo -e /etc/crypttab
# added the following:
# enchome		UUID=PARTITION_UUID_HERE none luks
sudo -e /etc/fstab
# added the following:
# /dev/mapper/enchome   /mnt/home          ext4    defaults        0       2

Then rebooted to ensure that /mnt/home mounts fine, moved the files from /home there (with cp -a), renamed /home, have set fstab to mount it into /home. Rebooted again, checked again that everything is fine, and removed the old /home.

One may also mount /tmp into memory, reducing the data leaking to the unencrypted root filesystem, slightly speeding up some tasks, and reducing disk usage; it works for me and I like it, but there is plenty of criticizm and possible issues with that:

tmpfs           /tmp            tmpfs   size=1g,nosuid      0       0

Moved/imported my SSH and GPG keys, ~/.authinfo, some other files.

I had to remap the "menu" key (keycode 135) to left alt, which is always awkward and different; in Xfce I had to enter the GUI settings, then "session and startup", and add the xmodmap -e "keycode 135 = Alt_L" command there. Also had to unmap C-M-f to be able to use it in Emacs, in "settings" - "keyboard" - "application shortcuts".

Installed a bit more of software: sudo apt install emacs emacs-common-non-dfsg telnet vlc tor mu4e isync rsync xsltproc clementine git elpa-magit elpa-haskell-mode cabal-install lynx whois nmap ncat dnsutils knot-dnsutils, and better-defaults and mu4e-alert via Emacs's package manager (since they weren't in the system repositories). Generally it's a good idea to stick to a single package manager, since then you shouldn't run into version mismatches. update-alternatives --config editor to set vim as the default editor (running a new emacs instance may be a bit slow for quick sudo -e editos, emacsclient won't always work, setting a small emacs clone just for that seems excessive, and the default nano is just awkward, so vim is an okay option; though perhaps one can also set emacs -Q -nw).

By 2022, I had to start using Tor bridges (since Tor is being blocked around here): install obfs4proxy, then append to /etc/tor/torrc:

UseBridges 1
ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy managed

And bridge records received from or by other means, prefixed with "Bridge" (Bridge obfs4 ...).

Configured Firefox: Sans Serif font, disallowed pages to choose their own fonts, increasing monospace font size to be the same as others (16), setting a minimal font size equal to those, "wp" keyword for Wikipedia search and "wt" for Wiktionary search, installing uBlock Origin (with "annoyance" lists additionally enabled) to cut out junk, NoScript to cut out more junk, FoxyProxy to use Tor for websites blacklisted around here and the ones I don't want to track me, HTTPS everywhere to mitigate local data retention practices, Stylus to set a global dark theme for comfortable browsing when it's dark around.

Configured isync and Emacs, later installed rexmpp's xmpp.el. Attempted a minimal Emacs configuration this time (though most likely it'll grow), so used the built-in rcirc (with rcirc-track-minor-mode and just setting rcirc-server-alist), not much of mu4e configuration. Something like this:

(require 'package)
(add-to-list 'package-archives '("melpa" . "") t)

(require 'better-defaults)
(global-set-key [mode-line mouse-4] 'previous-buffer)
(global-set-key [mode-line mouse-5] 'next-buffer)

(add-to-list 'load-path "~/.emacs.d/elisp/")
(load "cyrillic-colemak")
(load "blueish-theme")

(rcirc-track-minor-mode t)
(setq rcirc-buffer-maximum-lines 2000)
(setq rcirc-server-alist
      '(("" :port 1500 :encryption tls
         :password "password-here")))

(setq ansi-color-names-vector
      ["#aaaaaa" "#faa" "#95e454" "#cae682" "#8bf" "#dd99dd" "#8dd" "#ffffff"])

(require 'haskell-interactive-mode)
(require 'haskell-process)
(add-hook 'haskell-mode-hook 'interactive-haskell-mode)
(add-hook 'haskell-mode-hook 'haskell-decl-scan-mode)

(require 'html-wysiwyg)
(add-hook 'html-mode-hook 'html-wysiwyg-mode)

(require 'smtpmail)

(add-hook 'after-init-hook #'mu4e-alert-enable-mode-line-display)

(defun suppress-messages (old-fun &rest args)
  (cl-flet ((silence (&rest args1) (ignore)))
    (advice-add 'message :around #'silence)
         (apply old-fun args)
      (advice-remove 'message #'silence))))

(with-eval-after-load "mu4e"
  (advice-add 'mu4e-update-mail-and-index :around #'suppress-messages)
  (advice-add 'mu4e-index-message :around #'suppress-messages)
  (advice-add 'progress-reporter-done :around #'suppress-messages)
    :name "uberspace"
    :enter-func (lambda ()
                  (mu4e-message "Switch to the uberspace IMAP context")
                  ;; (mu4e~request-contacts)
    :leave-func (lambda () (mu4e-clear-caches))
    :match-func (lambda (msg)
                  (when msg
                     :to "")))
    :vars '( (user-mail-address            . "")
             (user-full-name               . "defanor")
             (smtpmail-default-smtp-server . "")
             (smtpmail-local-domain        . "")
             (smtpmail-smtp-user           . "defanor")
             (smtpmail-smtp-server         . "")
             (smtpmail-stream-type         . starttls)
             (smtpmail-smtp-service        . 587)
             (mu4e-get-mail-command        . "mbsync -q uberspace")
             (mu4e-update-interval         . 300)
             (mu4e-view-show-addresses     . t)
             (mu4e-maildir                 . "~/Maildir/uberspace/")
             (mu4e-mu-home                 . "~/.mu/uberspace")
             (mu4e-user-mail-address-list  . (""))
;; more contexts here

And .mbsyncrc records like this:

IMAPAccount uberspace
Port 993
User defanor
Pass password-here
AuthMechs *

IMAPStore uberspace-remote
Account uberspace

MaildirStore uberspace-local
Path ~/Maildir/uberspace/
Inbox ~/Maildir/uberspace/inbox/

Channel uberspace
Master :uberspace-remote:
Slave :uberspace-local:
Patterns *
Create Both
Remove Both
Expunge Both
SyncState *

This was a sufficient setup to listen to a radio (vlc ''), local music collection (which I keep on a separate partition, so just mounted it via fstab into the same path as before, and the playlist also stored on it contained correct paths), communicate (IRC, XMPP, email), do Haskell programming, browse WWW relatively comfortably, play Discworld MUD over telnet, and publish these notes. At that point I've adjusted dwproxy to be able to build it using only dependencies from the system repositories (for related rants and musings, see the notes on software packaging and deployment and everyday programming in Haskell), and built a few work projects: since it's Cabal 3 now, had to set cabal.project in order to use internal libraries, and made some other minor adjustments to handle newer versions of dependencies. C projects (rexmpp in particular) also required minor adjustments to handle newer versions of the compiler and libraries, but fairly straightforward.