#linux

So — funny story.

I was walking down the road the other day, and boom! my optimix.dev website on Digital Ocean stopped working. Shocking, right?

Ok, it wasn’t a complete surprise…I was sending some commands to the server.

What do you mean, “Was it serious?”. I was just tweaking it a bit, you know.

Alright, I guess you could call an Ubuntu 17–22 OS upgrade “serious”. I mean, black holes and neutron stars are certainly serious. Are OS upgrades really on the same level? I suppose it’s all very subjective.

Backup. Backup. That word sounds familiar, but if you keep repeating it, it starts to sound strange and unfamiliar. Backup. Fun fact — this concept of repetition causing a word or phrase to lose its meaning for the listener temporarily is called semantic satiation.

Oh well.

I use the i3 tiling window manager on Gentoo Linux, and avoid heavy-weight desktop environments like GNOME or KDE. One consequence of this choice is that there isn’t any ‘system theme’ to speak of, that influences ‘Light’ and ‘Dark’ modes within GTK-based applications like Firefox. What this means is that I have no way to switch to ‘Dark’ mode for websites that follow the system theme — like this blog — unless I specially set it up.

My solution for this is fairly straightforward: add a button on my desktop that allows me to switch between light and dark modes. When I click the button, it invokes a script that toggles modes. You can see the button — the one with the 🌓 icon — in the screenshots of my desktop below, right at the bottom of the screen.

Light Mode

Desktop: Light Mode

Dark Mode

Desktop: Dark Mode

Details

The toolbar at the bottom is rendered by i3blocks, with the following configuration block:

[switch-theme]
full_text=🌓
command=/data/bin/switch-theme

The switch-theme script that the command above invokes is quite simple:

#!/bin/bash
#
# Script to toggle GTK light & dark modes.
#
# The mode is toggled by using the `xsettingsd` daemon,
# which should already be running. The `.xsettingsd`
# configuration file is updated, with exactly one of the
# following values:
#
# Net/ThemeName "Adwaita"     # Light
# Net/ThemeName "AdwaitaDark" # Dark
#
# Note that the Adwaita and Adwaita-dark themes must already
# be installed on the system.
#
# The script sends a HUP signal to the process, causing the
# setting to take effect at once.

set -euxo pipefail

CFG_PATH="$HOME/.xsettingsd"
DEF_THEME="Adwaita"
ALT_THEME="Adwaita-dark"
OLD_THEME=$(pcregrep -o1 'Net/ThemeName "(.*)"' "$CFG_PATH")
KEY="Net/ThemeName"

if [ "$?" -eq 0 ]
then
    NEW_THEME=$([ "$OLD_THEME" == "$DEF_THEME" ] &&        \
        echo -ne $ALT_THEME ||                             \
        echo -ne $DEF_THEME)
    sed -i 's#'$KEY' .*#'$KEY' "'$NEW_THEME'"#' "$CFG_PATH"
else
    echo $KEY' "'$DEF_THEME'"' >> "$CFG_PATH"
fi

killall -HUP xsettingsd

For the script above to work, you must first install the gnome-themes-standard and xsettingsd packages on Gentoo, or their equivalents on other Linux distributions. You also need to have the xsettingsd process running, which I’ve added to my .xinitrc startup script.

Imagine that you live in a weird apocalyptic future, and you want to keep your home safe, so you find yourself a sturdy front door and a high-quality deadbolt to secure it with. Everything is set, and you’re satisfied that you’re safe.

Hardly a minute goes by before you hear a knock on the door. It’s a hooligan trying to get in. You know you’re still safe, and you shoo the person away the best you can without opening the door, but a minute later there’s another knock. And then yet another — it never stops. Checking who’s at the door is tiring work, and you can’t take it anymore. You could ignore all knocks, but you do occasionally get guests, and apocalypse or no, you mustn’t ignore your social circle. What do you do?

You come up with an ingenious scheme. You let your prospective guests know that when they come to your door, they will need to use a special knock sequence that you can recognize. Only when you hear this knock sequence will you bother to even check who’s at the door. “Ignore my protocol at your own peril!”, you warn them all.

The problem with running a public SSH server on your home network is less weird but otherwise not too different from the situation above. Even after securing your server with state-of-the-art certificate authentication and unbreakable ciphers, you find people (mostly automated bots) still trying all day to connect to your server with passwords. While this is not personally tiring, it does end up consuming compute resources and polluting your authentication logs (and as a consequence, obfuscating real problems). One solution to this problem is analogous to the one above — you ask your users to send a few packets to specific ports in a particular sequence, before accepting an SSH connection on the usual port. This works out especially well if the user is you — for instance, if you are using SSH to connect remotely to your home server, and you don’t need to grant access to anyone else.

Here’s how you get this going:

On the server —

  • Step 1: Enable netfilter in your Linux kernel for packet sniffing.
  • Step 2: Set up the nftables firewall to start automatically.
  • Step 3: Configure a port knocking sequence in your firewall rules.
  • Step 4: Open up the relevant ports on your home network router firewall.

Steps 1 and 2 are usually specific to the Linux distribution you use, and I would recommend looking up its documentation. For reference, Gentoo’s documentation can provide a general idea of how this is done. Step 3 is accomplished using nftables rules that you can load (and save). Step 4 is router-dependent. For instance, my eero app has a relevant section in Settings → Network settings → Reservations & port forwarding.

✗ Test that you can no longer connect directly over SSH.

On the client —

  • Step 5: Set up your SSH configuration to knock on ports.
  • Step 6: Test your SSH connectivity.
  • Step 7: DONE!

To set up Step 5 on the client-side, you can create a simple knock script in your PATH, make it executable, and configure your SSH client to execute it automatically before connecting to your server.

✓ Test that you can once again connect over SSH.

And it’s as simple as that.