<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="https://the-empire.systems/feed.xml" rel="self" type="application/atom+xml" /><link href="https://the-empire.systems/" rel="alternate" type="text/html" /><updated>2023-12-27T03:07:06+00:00</updated><id>https://the-empire.systems/feed.xml</id><title type="html">The Empire Systems</title><subtitle>heywoodlh's ramblings</subtitle><entry><title type="html">Moving to heywoodlh.io</title><link href="https://the-empire.systems/moving-heywoodlh-io" rel="alternate" type="text/html" title="Moving to heywoodlh.io" /><published>2023-08-22T00:00:00+00:00</published><updated>2023-08-22T00:00:00+00:00</updated><id>https://the-empire.systems/Moving-to-heywoodlh.io</id><content type="html" xml:base="https://the-empire.systems/moving-heywoodlh-io">&lt;p&gt;I’m moving my blog to &lt;a href=&quot;https://heywoodlh.io&quot;&gt;https://heywoodlh.io&lt;/a&gt;. I’m not going to keep posting here, but I will keep this domain alive and will try to keep all the posts up and in the state they currently are in.&lt;/p&gt;

&lt;p&gt;Aside from this post, I’m keeping all of my posts at the new domain as well. And I will be refreshing the look of the site at my new domain as well.&lt;/p&gt;

&lt;p&gt;I chose the-empire.systems as a domain name because I couldn’t think of anything better. Switching to heywoodlh.io makes a lot more sense as my handle everywhere is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heywoodlh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hope to see people going there, but if not, I hope you’ve enjoyed reading at https://the-empire.systems so far. :)&lt;/p&gt;</content><author><name></name></author><category term="all," /><category term="heywoodlh," /><category term="domain," /><category term="moving" /><summary type="html">I’m moving my blog to https://heywoodlh.io. I’m not going to keep posting here, but I will keep this domain alive and will try to keep all the posts up and in the state they currently are in.</summary></entry><entry><title type="html">Making the iPad Suck Less (for sysadmin, development, etc.)</title><link href="https://the-empire.systems/suckless-ipad" rel="alternate" type="text/html" title="Making the iPad Suck Less (for sysadmin, development, etc.)" /><published>2023-07-31T00:00:00+00:00</published><updated>2023-07-31T00:00:00+00:00</updated><id>https://the-empire.systems/Making-the-iPad-Not-Suck</id><content type="html" xml:base="https://the-empire.systems/suckless-ipad">&lt;p&gt;At Apple’s 2023 WWDC event I found myself having a metaphorical, angry seizure because for yet another year my iPad Pro was still going to be a giant iPhone – per the lack of features announced for iPadOS at the event.&lt;/p&gt;

&lt;p&gt;I do a lot of Linux systems administration and development. The perceived shortcomings I project onto the iPad are likely very specific to me, so while the iPad might work extremely well for some, its featureset is limited for what I need and want.&lt;/p&gt;

&lt;p&gt;This post is partly an opinion piece on the current state of the iPad for power users, but also an attempt to document some of the things I have been doing to make my iPad Pro actually useful to me.&lt;/p&gt;

&lt;p&gt;P.S. I wrote this post from my iPad in Vim&lt;/p&gt;

&lt;h2 id=&quot;why-do-i-own-an-ipad&quot;&gt;Why do I own an iPad?&lt;/h2&gt;

&lt;p&gt;I bought an M1 iPad Pro in 2021 thinking it was a fairly safe bet that the iPad Pro would eventually become a viable option for me as a laptop replacement. My reasons in 2021 for thinking it would become a laptop replacement were the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Apple had recently announced iPadOS specifically for the iPad – separating it from iOS&lt;/li&gt;
  &lt;li&gt;The iPad Pro now shares the same processor as the Macs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fast-forward to Apple’s 2023 WWDC event where Apple announced almost no meaningful iPadOS updates that would help me better fulfill my goal of being able to use it for my laptop workflows. I’m not the ideal iPad user in Apple’s approach because I use Linux often (for workstations and servers) and I want to do development on languages that are not Swift.&lt;/p&gt;

&lt;p&gt;Here are the things I like about the iPad:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;I really like the form factor, combined with the Apple Magic keyboard case&lt;/li&gt;
  &lt;li&gt;The battery life is good&lt;/li&gt;
  &lt;li&gt;Compared to a laptop, the time I can get to doing things after opening the lid is much faster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are the downsides for me:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Local development just isn’t possible or limited&lt;/li&gt;
  &lt;li&gt;iPadOS lacks extensibility/flexibility compared to other desktop operating systems (MacOS, Linux, Windows, etc.)&lt;/li&gt;
  &lt;li&gt;Unfairly, on iOS/iPadOS Safari is the only browser that supports extensions&lt;/li&gt;
  &lt;li&gt;Ultimately, iPadOS still feels pretty much just like iOS with some tweaks for iPad&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, let’s get into how I try to adapt to iPadOS to lessen the impact of these perceived shortcomings.&lt;/p&gt;

&lt;h2 id=&quot;my-assumptions&quot;&gt;My assumptions&lt;/h2&gt;

&lt;p&gt;My assumptions for anyone finding this article useful are that you have an iPad Pro with an external keyboard of some sort. I prefer Apple’s Magic Keyboard case (despite it being ridiculously expensive).&lt;/p&gt;

&lt;h2 id=&quot;keyboard-driven-workflows&quot;&gt;Keyboard-driven workflows&lt;/h2&gt;

&lt;p&gt;On Linux and MacOS, I use a tiling window manager to automatically tile my opened applications. Pivotal to this workflow are keyboard shortcuts to make navigating the tiling windows and virtual workspaces possible.&lt;/p&gt;

&lt;h3 id=&quot;use-spotlight-for-switching-app-focusworkspace-switching&quot;&gt;Use Spotlight for switching app focus/workspace switching&lt;/h3&gt;

&lt;p&gt;I recently observed a coworker using Spotlight on MacOS to not only launch applications but also to switch focus to already open application windows. This workflow not only works on MacOS, but also on iPadOS. This may seem “duh” to everyone, but for me, it was a revelation.&lt;/p&gt;

&lt;p&gt;Start using Spotlight (invoked with Cmd + Space) not only to launch apps but to switch between already opened instances of apps.&lt;/p&gt;

&lt;h3 id=&quot;use-built-in-app-keyboard-shortcuts&quot;&gt;Use built-in app keyboard shortcuts&lt;/h3&gt;

&lt;p&gt;I have found that many apps on the iPad have a robust amount of keyboard shortcuts built into them. Whilst in any app on iPadOS, if you hold Cmd, an overlay will appear to show you all of the keyboard shortcuts built into the app.&lt;/p&gt;

&lt;p&gt;Start using built-in keyboard shortcut for the apps you care about. I’ve found that most apps have the same keyboard shortcuts on the iPad as they do for their desktop apps. For example, the keyboard shortcuts for Slack in iPadOS mostly translate to comparable shortcuts on Slack in MacOS or Linux.&lt;/p&gt;

&lt;p&gt;And again, if you’re in doubt on your iPad as to what the shortcuts are in the app you’re in, just hold Cmd.&lt;/p&gt;

&lt;h3 id=&quot;use-stage-manager&quot;&gt;Use Stage Manager&lt;/h3&gt;

&lt;p&gt;I won’t cover how to use Stage Manager, but it’s basically a more complex window manager for iPadOS and MacOS. Enabling Stage Manager allows a user to have rules for windows and how they open.&lt;/p&gt;

&lt;p&gt;Using Stage Manager can further enable keyboard-driven productivity.&lt;/p&gt;

&lt;h3 id=&quot;safari&quot;&gt;Safari&lt;/h3&gt;

&lt;p&gt;I don’t use other browsers on my iPad because Apple unfairly restricts them in ways that Safari is not restricted.&lt;/p&gt;

&lt;p&gt;There are a couple of things I do for being more keyboard-driven with Safari:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Use the built-in keyboard shortcuts (in particular, the Cmd+L shortcut)&lt;/li&gt;
  &lt;li&gt;Use the Vimlike Safari extension: https://apps.apple.com/us/app/vimlike/id1584519802&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tweaks make Safari a much more pleasant experience for me with being keyboard driven.&lt;/p&gt;

&lt;h2 id=&quot;development-tooling&quot;&gt;Development tooling&lt;/h2&gt;

&lt;h3 id=&quot;apple-shortcuts&quot;&gt;Apple Shortcuts&lt;/h3&gt;

&lt;p&gt;Apple Shortcuts supports a surprising amount of functionality. I would highly recommend using Apple Shortcuts to extend the programmability of your iPad.&lt;/p&gt;

&lt;p&gt;As an example, check out this post where I use Apple Shortcuts on iOS to turn on/off a Paperspace VM for gaming: https://the-empire.systems/paperspace-cloud-gaming-ios&lt;/p&gt;

&lt;h3 id=&quot;ish&quot;&gt;iSH&lt;/h3&gt;

&lt;p&gt;https://apps.apple.com/us/app/ish-shell/id1436902243&lt;/p&gt;

&lt;p&gt;I use iSH to drastically extend the functionality of my iPad. iSH is an emulated x86 32-bit Alpine Linux environment that runs on iOS and iPadOS. Being able to run command line tools like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dig&lt;/code&gt; directly on my iPad has made my iPad far more functional.&lt;/p&gt;

&lt;p&gt;I have a GitHub repository containing my iSH setup on my iPad: https://github.com/heywoodlh/ish-configs&lt;/p&gt;

&lt;h3 id=&quot;tailscale&quot;&gt;Tailscale&lt;/h3&gt;

&lt;p&gt;Tailscale is a user-friendly VPN service based on Wireguard. Although it is not itself specifically a tool for development, it enables me to remain always-connected to the infrastructure I use to support my iPad.&lt;/p&gt;

&lt;p&gt;Seemingly, Tailscale does not have the ability to remain always on or use iOS’ on-demand VPN featureset: https://github.com/tailscale/tailscale/issues/1534&lt;/p&gt;

&lt;p&gt;The lack of always-on/on-demand VPN hasn’t been an issue with me for Tailscale as I use an automation in Apple Shortcuts to turn on Tailscale when I’m in an app that would need to connect to servers in my Tailnet. For example, with iSH – what I use to primarily SSH into my servers – I have an Apple Shortcuts automation that will connect to Tailscale when I open the iSH app.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../images/ish-tailscale.png&quot; alt=&quot;ish-tailscale-shortcut&quot; title=&quot;Ish Tailscale Shortcut&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;pomerium&quot;&gt;Pomerium&lt;/h3&gt;

&lt;p&gt;Pomerium is also not a development tool – it is an open source, identity-aware proxy. Similar to Tailscale, my Pomerium instance allows me to remotely access my personal infrastructure via HTTPS, and as a result, Pomerium enables me to be more productive in my development workflows on my iPad.&lt;/p&gt;

&lt;p&gt;For example, here’s my self-hosted Coder instance made available via my Pomerium instance:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../images/coder-pomerium.png&quot; alt=&quot;coder-pomerium&quot; title=&quot;Coder via Pomerium&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;dedicated-linux-server&quot;&gt;Dedicated Linux server&lt;/h3&gt;

&lt;p&gt;I have a small VPS running on Vultr that I can SSH into from my iPad that has all the tooling I need that I can’t necessarily run on my iPad directly.&lt;/p&gt;

&lt;p&gt;All of the tooling I am using on that server is configured for me via the cross-platform (MacOS, Linux) package manager &lt;a href=&quot;https://nixos.org&quot;&gt;Nix&lt;/a&gt;. My Nix-managed tooling that I use on the server for my iPad is available here: https://github.com/heywoodlh/flakes&lt;/p&gt;

&lt;p&gt;Here’s a screenshot of me SSH-ed into my VM for my iPad, running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;neofetch&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../images/mobile-dev.png&quot; alt=&quot;mobile-dev&quot; title=&quot;Neofetch over SSH&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Hopefully these ideas are helpful to any sysadmin, developer or other power user who is also unhappy with the current out-of-the-box state of iPadOS. With the tweaks I’ve listed above, I find myself far more productive on my iPad.&lt;/p&gt;

&lt;p&gt;But, maybe someday Apple will make the iPad more than just an iPhone that can work with a keyboard.&lt;/p&gt;</content><author><name></name></author><category term="all," /><category term="ipados," /><category term="ipad," /><category term="macos," /><category term="linux," /><category term="sysadmin," /><category term="coding" /><summary type="html">At Apple’s 2023 WWDC event I found myself having a metaphorical, angry seizure because for yet another year my iPad Pro was still going to be a giant iPhone – per the lack of features announced for iPadOS at the event.</summary></entry><entry><title type="html">Tiny Vim Install</title><link href="https://the-empire.systems/tiny-vim-install" rel="alternate" type="text/html" title="Tiny Vim Install" /><published>2023-06-18T00:00:00+00:00</published><updated>2023-06-18T00:00:00+00:00</updated><id>https://the-empire.systems/Tiny-Vim-Install</id><content type="html" xml:base="https://the-empire.systems/tiny-vim-install">&lt;h2 id=&quot;some-background&quot;&gt;Some background&lt;/h2&gt;

&lt;p&gt;A friend recently pointed me to this repository as a place to grab a self-contained &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim&lt;/code&gt; binary: &lt;a href=&quot;https://github.com/dtschan/vim-static&quot;&gt;https://github.com/dtschan/vim-static&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most recent commit is about 4 years old and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build.sh&lt;/code&gt; script uses an old version of Vim. I wanted to see if I could improve on this process and build Vim on an automated, regular cadence and publish the binaries.&lt;/p&gt;

&lt;p&gt;So here’s my solution to that: &lt;a href=&quot;https://github.com/heywoodlh/vim-builds&quot;&gt;https://github.com/heywoodlh/vim-builds&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My build process deviates slightly from the original build.sh script but uses mostly the same process. The most notable deviation in my build is that I’m building whatever version of Vim is available at the main repository at the time of the build, and I’m using GitHub Actions + Docker’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildx&lt;/code&gt; plugin to provide an automated build that produces multiarch (x86_64, and ARM64) Linux binaries.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;Find the latest release and grab the link for the binary of your desired architecture here: &lt;a href=&quot;https://github.com/heywoodlh/vim-builds/releases&quot;&gt;https://github.com/heywoodlh/vim-builds/releases&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Assuming I was grabbing the latest binary for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9.0&lt;/code&gt; tag for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x86_64&lt;/code&gt; architecture on my Git repo, these are all the commands necessary for a fully functional Vim installation:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir -p ~/bin
curl -L 'https://github.com/heywoodlh/vim-builds/releases/download/9.0/vim-x86_64' -o ~/bin/vim
chmod +x ~/bin/vim
PATH=&quot;~/bin:$PATH&quot; # Add this to your ~/.bashrc or other shell config file to make it persistent
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To disable the warning about not being able to read &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;defaults.vim&lt;/code&gt;, create an empty &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.vimrc&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touch ~/.vimrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;why&quot;&gt;Why?&lt;/h2&gt;

&lt;p&gt;This static Vim binary is tiny and should work out of the box on all Linux distributions. If you aren’t aware, many binaries compiled on a Glibc-centered system (Ubuntu, Arch Linux, etc.) don’t work on a Musl-based system (Alpine Linux). This makes these Vim binaries a potentially ideal candidate for installations where portability is desired (containers, ephemeral environments, etc.).&lt;/p&gt;

&lt;p&gt;I’m a huge fan of Vim and love the idea of being able to build/host a totally package-manager-independent Vim binary.&lt;/p&gt;

&lt;p&gt;But mostly, I wanted to see if I could do it.&lt;/p&gt;</content><author><name></name></author><category term="all," /><category term="linux," /><category term="vim," /><category term="ide," /><category term="github," /><category term="actions" /><summary type="html">Some background</summary></entry><entry><title type="html">Remote Backups Over SSH With Rsnapshot</title><link href="https://the-empire.systems/rsnapshot-backups" rel="alternate" type="text/html" title="Remote Backups Over SSH With Rsnapshot" /><published>2023-04-01T00:00:00+00:00</published><updated>2023-04-01T00:00:00+00:00</updated><id>https://the-empire.systems/Remote-Backups-with-Rsnapshot</id><content type="html" xml:base="https://the-empire.systems/rsnapshot-backups">&lt;p&gt;During a discussion I had with a former coworker at my previous job, he introduced me to &lt;a href=&quot;https://rsnapshot.org/&quot;&gt;Rsnapshot&lt;/a&gt;. Rsnapshot is a backup program based on &lt;a href=&quot;https://github.com/WayneD/rsync&quot;&gt;rsync&lt;/a&gt;, which allows for simple but effective remote backups over SSH.&lt;/p&gt;

&lt;p&gt;I’ve built out my home lab to now support one server, my backup server, SSH-ing into my other servers and backing up the data I care about. This will be an overview on how I have this setup.&lt;/p&gt;

&lt;p&gt;Disclaimer: I primarily use NixOS and some Arch Linux for my servers, so some NixOS &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;configuration.nix&lt;/code&gt; snippets will be present&lt;/p&gt;

&lt;h2 id=&quot;rsnapshot-server&quot;&gt;Rsnapshot server:&lt;/h2&gt;

&lt;p&gt;I have one NixOS server with Rsnapshot installed and an SSH key that I’ve generated without a passphrase at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/root/.ssh/id_rsa&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At the time of writing, this is my NixOS configuration snippet for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsnapshot&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  services.rsnapshot = {
    enable = true;
    enableManualRsnapshot = true;
    cronIntervals = {
      daily = &quot;0 3 * * *&quot;;
      hourly = &quot;0 * * * *&quot;;
      weekly = &quot;0 1 * * 1&quot;;
      monthly = &quot;0 1 1 * *&quot;;
    };
    extraConfig = ''
#Separate everything with tabs, not spaces	
#Convert spaces to tabs in vim with :%s/\s\+/\t/g
snapshot_root	/media/backups/
retain	hourly	24
retain	daily	7
retain	weekly	4
retain	monthly	6

backup	root@ct-1.wireguard:/etc/	ct-1/
    '';
  };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On NixOS, this installs and configures &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsnapshot&lt;/code&gt; to run on an hourly, daily, weekly and monthly basis. The last line in my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extraConfig&lt;/code&gt; for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsnapshot&lt;/code&gt; shows the actual backup that is going to happen over SSH:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;backup	root@ct-1.wireguard:/etc/	ct-1/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will backup the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/&lt;/code&gt; folder on the remote server &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ct-1.wireguard&lt;/code&gt; and place it in a folder named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ct-1&lt;/code&gt; – if you combine that with my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;snapshot_root&lt;/code&gt; config, the actual backup path for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/&lt;/code&gt; folder would be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/media/backups/ct-1/etc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you aren’t on NixOS, the Arch Wiki has a great entry on setting up Rsnapshot:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Rsnapshot&quot;&gt;rsnapshot - ArchWiki&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add all of the remote servers and their paths to your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsnapshot&lt;/code&gt; configuration.&lt;/p&gt;

&lt;h2 id=&quot;target-servers&quot;&gt;Target servers:&lt;/h2&gt;

&lt;p&gt;On the target servers you only need the following setup:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;SSH access, preferably as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; – see my recommendations below on reducing security risk&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsync&lt;/code&gt; installed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; user is easiest to use on the remote server over SSH. However, logging in as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; is a security risk, so there are a couple of precautions I would take:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Configure &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshd_config&lt;/code&gt; to only allow &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; login using SSH keys, prohibiting password authentication, with the following configuration: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PermitRootLogin prohibit-password&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;In setting up &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/root/.ssh/authorized_keys&lt;/code&gt;, restrict the key to only be used from a specific IP address: &lt;a href=&quot;https://unix.stackexchange.com/a/353047&quot;&gt; StackExchange - How to restrict an SSH key to certain IP addresses? &lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Use a VPN and limit SSH access between your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsnapshot&lt;/code&gt; server over the VPN. I like Wireguard for VPN stuff: https://www.wireguard.com/&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;profit&quot;&gt;Profit:&lt;/h2&gt;

&lt;p&gt;Once this is setup as described, you now have a remote backup solution that works over SSH.&lt;/p&gt;</content><author><name></name></author><category term="all," /><category term="linux," /><category term="nixos," /><category term="arch," /><category term="ssh," /><category term="rsync," /><category term="rsnapshot," /><category term="backup" /><summary type="html">During a discussion I had with a former coworker at my previous job, he introduced me to Rsnapshot. Rsnapshot is a backup program based on rsync, which allows for simple but effective remote backups over SSH.</summary></entry><entry><title type="html">Sync Skyrim Mods Between Devices (with Syncthing)</title><link href="https://the-empire.systems/sync-skyrim-mods-syncthing" rel="alternate" type="text/html" title="Sync Skyrim Mods Between Devices (with Syncthing)" /><published>2023-01-23T00:00:00+00:00</published><updated>2023-01-23T00:00:00+00:00</updated><id>https://the-empire.systems/Sync-Skyrim-Mods-Between-Devices</id><content type="html" xml:base="https://the-empire.systems/sync-skyrim-mods-syncthing">&lt;p&gt;This will be a quick run-down on how I’m syncing mods with Syncthing between two of my devices that have Skyrim Special Edition installed. The two devices are my gaming PC running Windows 10 and my Steam Deck running NixOS. However, this should work with any two devices that can run Syncthing.&lt;/p&gt;

&lt;p&gt;Additionally, I suspect that this method should work with other games, I’m just using Skyrim as an example.&lt;/p&gt;

&lt;p&gt;The reason for this is pretty simple: I have a Steam Deck and I’d like to sync my Skyrim mods with it – but I already have a modded build on a Windows machine. Additionally, my Steam Deck is running NixOS (Linux) and it’s not currently very convenient to use Vortex (nexusmods.com’s mod manager) on Linux. With this setup I can install mods on my Windows machine and they should sync to my Steam Deck.&lt;/p&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites:&lt;/h2&gt;

&lt;p&gt;I’m going to assume that one of your machines already has a modded build of Skyrim, I won’t cover how to actually install mods (it’s trivial on Windows with nexusmods.com and Vortex, Nexus’ Mod Manager).&lt;/p&gt;

&lt;p&gt;Both machines should have Skyrim installed – I would suggest starting from a fresh install on the machine that doesn’t yet have the mods/build you want.&lt;/p&gt;

&lt;h2 id=&quot;installing-syncthing&quot;&gt;Installing Syncthing&lt;/h2&gt;
&lt;p&gt;I’m not going to provide a detailed walkthrough on how to install Syncthing, but I’ll provide a basic outline:&lt;/p&gt;

&lt;h3 id=&quot;on-windows-using-chocolatey&quot;&gt;On Windows (using Chocolatey):&lt;/h3&gt;
&lt;p&gt;Install Chocolatey: https://chocolatey.org/install&lt;/p&gt;

&lt;p&gt;Run the following command as Administrator (search for the Powershell app, right click Powershell, Run as Administrator):&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;choco install -y syncthing
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note: Chocolatey will install the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;syncthing.exe&lt;/code&gt; executable in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\ProgramData\chocolatey\bin\syncthing.exe&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Set Syncthing to start automatically: https://docs.syncthing.net/users/autostart.html#windows&lt;/p&gt;

&lt;h3 id=&quot;on-linux&quot;&gt;On Linux:&lt;/h3&gt;

&lt;p&gt;Use your package manager to install Syncthing.&lt;/p&gt;

&lt;p&gt;Start the syncthing service:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo systemctl enable --now syncthing@${USER}.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Alternatively, start it using just your user:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;systemctl enable --now --user syncthing.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check out the Arch Wiki for more information on Syncthing on Linux: https://wiki.archlinux.org/title/Syncthing&lt;/p&gt;

&lt;h3 id=&quot;add-both-devices-to-syncthing&quot;&gt;Add Both Devices to Syncthing&lt;/h3&gt;

&lt;p&gt;With your devices running Syncthing, make sure to add them both so they can share data with each other via Syncthing.&lt;/p&gt;

&lt;p&gt;Do the following:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Login to the local Syncthing instance’s web interface: http://localhost:8384&lt;/li&gt;
  &lt;li&gt;Select Actions &amp;gt; Show ID&lt;/li&gt;
  &lt;li&gt;On the other device, also login to Syncthing’s web interface and select “Add Remote Device”, filling out the Device ID with the ID from step 2&lt;/li&gt;
  &lt;li&gt;Back on your original device, a notification should appear in Syncthing’s web interface that your other device would like to be added – accept it&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;add-skyrims-folders-to-syncthing&quot;&gt;Add Skyrim’s Folders to Syncthing&lt;/h2&gt;

&lt;p&gt;On your modded machine, access the Syncthing web service with this URL: http://localhost:8384&lt;/p&gt;

&lt;p&gt;In Syncthing’s web interface on the device with your already modded Skyrim build, you should add Skyrim Special Edition’s folder as a shared Folder. In my case, my Skyrim Special Edition folder path is at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E:\SteamLibrary\steamapps\common\Skyrim Special Edition&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While in Syncthing, you should also add a separate shared folder for the directory on your Windows machine that contains Skyrim’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loadorder.txt&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plugins.txt&lt;/code&gt; files. By default it is at the following path on Windows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;C:\Users\$USER\AppData\Local\Skyrim Special Edition
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once your Skyrim Special Edition folder is added to Syncthing, select it, select Edit &amp;gt; Sharing and check the box next to the device you want to share it with.&lt;/p&gt;

&lt;h3 id=&quot;share-skyrims-syncthing-folders-with-your-target-device&quot;&gt;Share Skyrim’s Syncthing Folders With Your Target Device&lt;/h3&gt;

&lt;p&gt;There are three folder paths I would recommend sharing between your devices. I’m going to presume that the sources are all coming from a Windows machine, so I will use the default Windows paths:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Program Files (x86)\Steam\steamapps\common\Skyrim Special Edition&lt;/code&gt;: Skyrim game files&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Users\$USER\Documents\My Games\Skyrim Special Edition&lt;/code&gt;: Save data and local preferences&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Users\$USER\AppData\Local\Skyrim Special Edition&lt;/code&gt;: contains loadorder.txt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the other device, I would recommend deleting your freshly installed, unmodded Skyrim Special Edition folder (don’t uninstall Skyrim via Steam) and then go into Syncthing’s web interface and accept the shared folder from the machine with your desired build. I would set the path to the exact location where Skyrim was installed, so that way Steam thinks it is still present on your filesystem.&lt;/p&gt;

&lt;p&gt;Really, it doesn’t matter how you do it, mostly just place the Syncthing Skyrim SE folder at a location Steam will be able to view it as present.&lt;/p&gt;

&lt;p&gt;For the shared folder in Syncthing containing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loadorder.txt&lt;/code&gt;, you should place that folder at the default Windows path &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Users\$USER\AppData\Local\Skyrim Special Edition&lt;/code&gt; or if you are on Linux (i.e. Steam Deck) using Valve’s Proton compatibility to run Skyrim, the target path should be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.local/share/Steam/steamapps/compatdata/489830/pfx/drive_c/users/steamuser/AppData/Local/Skyrim Special Edition&lt;/code&gt;. This path might not exist if you haven’t already run Skyrim the first time, so either run Skyrim or just let Syncthing create that path.&lt;/p&gt;

&lt;h2 id=&quot;play&quot;&gt;Play!&lt;/h2&gt;

&lt;p&gt;Now with Syncthing sharing folders between devices, you will be able to have your Skyrim builds synchronize. As long as both of your devices are powered on and syncing your Skyrim builds should stay in sync.&lt;/p&gt;

&lt;h2 id=&quot;some-syncthing-tips&quot;&gt;Some Syncthing Tips&lt;/h2&gt;

&lt;h3 id=&quot;file-versioning&quot;&gt;File versioning&lt;/h3&gt;

&lt;p&gt;In Syncthing’s web interface, you should edit the folders and turn on File Versioning. This will prevent files from being deleted if you have a conflict between devices.&lt;/p&gt;

&lt;h3 id=&quot;setup-a-server&quot;&gt;Setup a Server&lt;/h3&gt;

&lt;p&gt;I would highly recommend setting up a device to behave as an always-on Syncthing server. Having a third device that you sync these folders to will ensure that if only one of your two original devices with Skyrim is turned on, the folders will still be synchronized.&lt;/p&gt;

&lt;p&gt;Basically, just dedicate a separate device (it can be small, such as a Raspberry Pi – or it could just be any Windows, Mac, Linux machine that is always running) to always run Syncthing and share the folders with that device.&lt;/p&gt;</content><author><name></name></author><category term="all," /><category term="linux," /><category term="steam," /><category term="deck," /><category term="steamdeck," /><category term="skyrim," /><category term="special," /><category term="edition," /><category term="syncthing," /><category term="mods," /><category term="vortex," /><category term="mod," /><category term="manager," /><category term="gaming" /><summary type="html">This will be a quick run-down on how I’m syncing mods with Syncthing between two of my devices that have Skyrim Special Edition installed. The two devices are my gaming PC running Windows 10 and my Steam Deck running NixOS. However, this should work with any two devices that can run Syncthing.</summary></entry><entry><title type="html">NixOS: Managing GNOME Keyboard Shortcuts and Settings with Home Manager</title><link href="https://the-empire.systems/nixos-gnome-settings-and-keyboard-shortcuts" rel="alternate" type="text/html" title="NixOS: Managing GNOME Keyboard Shortcuts and Settings with Home Manager" /><published>2023-01-09T00:00:00+00:00</published><updated>2023-01-09T00:00:00+00:00</updated><id>https://the-empire.systems/nixos-gnome-keyboard-shortcuts</id><content type="html" xml:base="https://the-empire.systems/nixos-gnome-settings-and-keyboard-shortcuts">&lt;p&gt;EDIT: June 21, 2023: thanks to &lt;a href=&quot;https://reddit.com/u/jtojnar&quot;&gt;u/jtojnar&lt;/a&gt; for pointing out the issue on this post with using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;@as []&quot;&lt;/code&gt; for disabled dconf settings. Shortly after posting this in January, I figured out that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;disabled&quot;&lt;/code&gt; was one of the ways to disable a setting with GNOME – but I forgot to update this post! I have updated the config shown on this post. Here’s the Reddit post referring to this article: https://reddit.com/r/NixOS/comments/14fenpb/issue_with_declarative_gnome_keyboard_shortcuts/&lt;/p&gt;

&lt;p&gt;EDIT: As of June 21, 2023, for reference, here is my GNOME desktop Home-Manager configuration: &lt;a href=&quot;https://github.com/heywoodlh/nixos-configs/blob/d8f1571931d23bbbce598e73f133d3be7247c806/roles/home-manager/linux/gnome-desktop.nix&quot;&gt;gnome-desktop.nix&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will be a quick snippet on how I’m using Home Manager in my NixOS configuration to manage GNOME keyboard shortcuts and other various settings.&lt;/p&gt;

&lt;h2 id=&quot;use-home-manager-as-a-nixos-config-module&quot;&gt;Use Home Manager as a NixOS config module:&lt;/h2&gt;

&lt;p&gt;This config basically explains how I’m importing Home Manager (version 22.11) in my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nixos/configuration.nix&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{ config, pkgs, ... }:

let
  home-manager = builtins.fetchTarball &quot;https://github.com/nix-community/home-manager/archive/release-22.11.tar.gz&quot;;
in {
  imports = [ &amp;lt;home-manager/nixos&amp;gt; ];
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;using-home-manager-to-manage-gnome&quot;&gt;Using Home Manager to manage GNOME:&lt;/h2&gt;

&lt;p&gt;With Home Manager imported, I can now use it’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;home-manager.users.&amp;lt;username&amp;gt;.dconf.settings&lt;/code&gt; option. I’ll just dump my current &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;home-manager.users.heywoodlh&lt;/code&gt; configuration to show what I currently have set as an example (I feel like it’s pretty self-explanatory):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  home-manager.users.heywoodlh = {
    home.stateVersion = &quot;22.11&quot;;
    dconf.settings = {
      &quot;org/gnome/shell&quot; = {
        disable-user-extensions = false;
        disabled-extensions = &quot;disabled&quot;;
        enabled-extensions = [
          &quot;native-window-placement@gnome-shell-extensions.gcampax.github.com&quot;
          &quot;pop-shell@system76.com&quot;
          &quot;caffeine@patapon.info&quot;
          &quot;hidetopbar@mathieu.bidon.ca&quot;
          &quot;gsconnect@andyholmes.github.io&quot;
        ];
        favorite-apps = [&quot;firefox.desktop&quot; &quot;kitty.desktop&quot;];
        had-bluetooth-devices-setup = true;
        remember-mount-password = false;
        welcome-dialog-last-shown-version = &quot;42.4&quot;;
      };
      &quot;org/gnome/shell/extensions/hidetopbar&quot; = {
        enable-active-window = false;
        enable-intellihide = false; 
      };
      &quot;org/gnome/desktop/interface&quot; = {
        clock-show-seconds = true;
        clock-show-weekday = true;
        color-scheme = &quot;prefer-dark&quot;;
        enable-hot-corners = false;
        font-antialiasing = &quot;grayscale&quot;;
        font-hinting = &quot;slight&quot;;
        gtk-theme = &quot;Nordic&quot;;
        toolkit-accessibility = true;
      };
      &quot;org/gnome/desktop/wm/keybindings&quot; = {
        activate-window-menu = &quot;disabled&quot;;
        toggle-message-tray = &quot;disabled&quot;;
        close = [&quot;&amp;lt;Super&amp;gt;q&quot;];
        maximize = &quot;disabled&quot;;
        minimize = [&quot;&amp;lt;Super&amp;gt;comma&quot;];
        move-to-monitor-down = &quot;disabled&quot;;
        move-to-monitor-left = &quot;disabled&quot;;
        move-to-monitor-right = &quot;disabled&quot;;
        move-to-monitor-up = &quot;disabled&quot;;
        move-to-workspace-down = &quot;disabled&quot;;
        move-to-workspace-up = &quot;disabled&quot;;
        toggle-maximized = [&quot;&amp;lt;Super&amp;gt;m&quot;]';
        unmaximize = &quot;disabled&quot;;
      };
      &quot;org/gnome/desktop/wm/preferences&quot; = {
        button-layout = &quot;close,minimize,maximize:appmenu&quot;;
        num-workspaces = 10;
      };
      &quot;org/gnome/shell/extensions/pop-shell&quot; = {
        focus-right = &quot;disabled&quot;;
        tile-by-default = true;
        tile-enter = &quot;disabled&quot;;
      };
      &quot;org/gnome/desktop/peripherals/touchpad&quot; = {
        tap-to-click = true;
        two-finger-scrolling-enabled = true;
      };
      &quot;org/gnome/settings-daemon/plugins/media-keys&quot; = {
        next = [ &quot;&amp;lt;Shift&amp;gt;&amp;lt;Control&amp;gt;n&quot; ];
        previous = [ &quot;&amp;lt;Shift&amp;gt;&amp;lt;Control&amp;gt;p&quot; ];
        play = [ &quot;&amp;lt;Shift&amp;gt;&amp;lt;Control&amp;gt;space&quot; ];
        custom-keybindings = [
          &quot;/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/&quot;
          &quot;/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1/&quot;
          &quot;/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom2/&quot;
          &quot;/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom3/&quot;
        ];
      };
      &quot;org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0&quot; = {
        name = &quot;kitty super&quot;;
        command = &quot;kitty -e tmux&quot;;
        binding = &quot;&amp;lt;Super&amp;gt;Return&quot;;
      };
      &quot;org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom1&quot; = {
        name = &quot;kitty ctrl_alt&quot;;
        command = &quot;kitty -e tmux&quot;;
        binding = &quot;&amp;lt;Ctrl&amp;gt;&amp;lt;Alt&amp;gt;t&quot;;
      };
      &quot;org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom2&quot; = {
        name = &quot;rofi-rbw&quot;;
        command = &quot;rofi-rbw --action copy&quot;;
        binding = &quot;&amp;lt;Ctrl&amp;gt;&amp;lt;Super&amp;gt;s&quot;;
      };
      &quot;org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom3&quot; = {
        name = &quot;rofi launcher&quot;;
        command = &quot;rofi -theme nord -show run -display-run 'run: '&quot;;
        binding = &quot;&amp;lt;Super&amp;gt;space&quot;;
      };
    };
  };
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using Home Manager this way allows me to have an easy, declarative GNOME setup.&lt;/p&gt;

&lt;h2 id=&quot;tips-for-modifying-dconf-settings&quot;&gt;Tips for modifying dconf settings:&lt;/h2&gt;

&lt;p&gt;If you install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf-editor&lt;/code&gt; you can see what options are available when you run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf-editor&lt;/code&gt; application.&lt;/p&gt;

&lt;p&gt;One of the things that I do when I want to make a setting persist in my config, is I run the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dconf dump / &amp;gt; old-conf.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then I make a change in my GNOME settings and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dconf dump&lt;/code&gt; again:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;dconf dump / &amp;gt; new-conf.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can now run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diff old-conf.txt new-conf.txt&lt;/code&gt; to figure out what options in your GNOME settings changed and then codify it in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;configuration.nix&lt;/code&gt; with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;home-manager.users.&amp;lt;username&amp;gt;.dconf.settings&lt;/code&gt; attribute.&lt;/p&gt;</content><author><name></name></author><category term="all," /><category term="linux," /><category term="nix," /><category term="nixos," /><category term="keyboard," /><category term="settings," /><category term="home," /><category term="manager" /><summary type="html">EDIT: June 21, 2023: thanks to u/jtojnar for pointing out the issue on this post with using &quot;@as []&quot; for disabled dconf settings. Shortly after posting this in January, I figured out that &quot;disabled&quot; was one of the ways to disable a setting with GNOME – but I forgot to update this post! I have updated the config shown on this post. Here’s the Reddit post referring to this article: https://reddit.com/r/NixOS/comments/14fenpb/issue_with_declarative_gnome_keyboard_shortcuts/</summary></entry><entry><title type="html">Installing NixOS on the Steam Deck</title><link href="https://the-empire.systems/nixos-steamdeck" rel="alternate" type="text/html" title="Installing NixOS on the Steam Deck" /><published>2023-01-03T00:00:00+00:00</published><updated>2023-01-03T00:00:00+00:00</updated><id>https://the-empire.systems/nixos-on-steam-deck</id><content type="html" xml:base="https://the-empire.systems/nixos-steamdeck">&lt;p&gt;&lt;img src=&quot;../images/steam-deck.gif&quot; alt=&quot;alt text&quot; title=&quot;Steam Deck booting NixOS&quot; /&gt;&lt;/p&gt;

&lt;p&gt;January 14, 2023 update: added changes to make GNOME touch friendly (using Home Manager to manage GNOME settings) with this commit: &lt;a href=&quot;https://github.com/heywoodlh/nixos-configs/commit/e20277093d53390e5a5cb0bb516f80022ff0be37&quot;&gt;https://github.com/heywoodlh/nixos-configs/commit/e20277093d53390e5a5cb0bb516f80022ff0be37&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;why-not-keep-steamos&quot;&gt;Why not keep SteamOS?&lt;/h2&gt;

&lt;p&gt;I have a Steam Deck and I really enjoy it. SteamOS on the Steam Deck is based on Arch Linux and I’m very comfortable with Arch as a long-time user. However, there are two issues that I have with the Steam Deck’s base OS:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;It wipes out custom changes I’ve made between updates, specifically, I have to reinstall and re-enable Wireguard between SteamOS updates&lt;/li&gt;
  &lt;li&gt;I’m not a fan of KDE at all – I definitely prefer GNOME&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wireguard is especially important to me on my Steam Deck because I use Wireguard and the open source &lt;a href=&quot;https://github.com/moonlight-stream&quot;&gt;Moonlight project&lt;/a&gt; to remotely connect to my more powerful gaming PC using Nvidia’s proprietary gamestream protocol to do the majority of my gaming.&lt;/p&gt;

&lt;p&gt;I’ve been using NixOS on my Linux workstations and Nix on Darwin on my Macs and I enjoy having a declarative/reproducible workstation. So I did some initial research and found that the NixOS community is actively developing stuff for the Steam Deck here: &lt;a href=&quot;https://github.com/Jovian-Experiments/Jovian-NixOS&quot;&gt;Jovian-NixOS&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;installing-nixos-on-the-steam-deck&quot;&gt;Installing NixOS on the Steam Deck:&lt;/h2&gt;

&lt;p&gt;For those uninterested in the rest of the how-to, here’s my current NixOS config on the Steam Deck: https://github.com/heywoodlh/nixos-configs/blob/master/workstation/steam-deck.nix&lt;/p&gt;

&lt;h3 id=&quot;requirementsassumptions&quot;&gt;Requirements/Assumptions:&lt;/h3&gt;

&lt;p&gt;My desired setup uses GNOME as the desktop environment and installs NixOS as the exclusive operating system on the Steam Deck. If you want anything outside of these constraints, modify this guide to your needs.&lt;/p&gt;

&lt;p&gt;The main requirements are the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Absolutely required: an external monitor and the necessary dongles/cables to connect the Steam Deck to it (required as of this Github Issue: &lt;a href=&quot;https://github.com/Jovian-Experiments/Jovian-NixOS/issues/39&quot;&gt;Jovian-Experiments/Jovian-NixOS/issues/39&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;An external keyboard and mouse and necessary dongles/cables to connect to the Steam Deck&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;creating-an-installer-iso-and-to-bootable-usb&quot;&gt;Creating an Installer ISO and to Bootable USB:&lt;/h3&gt;

&lt;p&gt;Assuming you have the Nix package manager installed on a Linux or MacOS machine and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; installed on your machine, you should be able to create a GNOME installer ISO with the following command (it takes quite a long time):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/Jovian-Experiments/Jovian-NixOS
cd Jovian-NixOS
nix-build -A isoGnome
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When the command completes, it should show the resulting ISO in your filesystem.&lt;/p&gt;

&lt;p&gt;I’ve uploaded a copy of my ISO to Google Drive, which may save some time if you download it. Feel free to use this link (I’m not malicious but you should definitely be cautious of strangers on the internet):&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://drive.google.com/file/d/1veXUlM-48ODxdnmRZ5YnaHS6jQefu_3m/view?usp=sharing&quot;&gt;nixos-steam-deck-22.11-x86_64-linux.iso&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use your preferred method to flash the ISO to a bootable USB. &lt;a href=&quot;https://www.balena.io/etcher/&quot;&gt;Balena Etcher&lt;/a&gt; is a very user friendly option for creating bootable USB drives.&lt;/p&gt;

&lt;h3 id=&quot;boot-the-bootable-usb&quot;&gt;Boot the Bootable USB:&lt;/h3&gt;

&lt;p&gt;Shut down your Steam Deck. Before powering it on, connect it to an external display – this is absolutely required as of this Github issue: https://github.com/Jovian-Experiments/Jovian-NixOS/issues/39. At least for me, I couldn’t boot from USB until I had an external display connected.&lt;/p&gt;

&lt;p&gt;To enter the boot menu, hold down the Volume- and tap the Power button with the bootable USB connected to the Steam Deck.&lt;/p&gt;

&lt;h3 id=&quot;install-nixos&quot;&gt;Install NixOS:&lt;/h3&gt;

&lt;p&gt;These steps are mostly identical to the NixOS &lt;a href=&quot;https://nixos.org/manual/nixos/unstable/index.html#sec-installation-manual&quot;&gt;Manual Installation Instructions&lt;/a&gt;, just modified for the internal storage as the target drive to install.&lt;/p&gt;

&lt;p&gt;Run these commands as the root user in the live environment:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;parted /dev/nvme0n1 -- mklabel gpt

parted /dev/nvme0n1 -- mkpart primary 512MB -8GB

parted /dev/nvme0n1 -- mkpart primary linux-swap -8GB 100%

parted /dev/nvme0n1 -- mkpart ESP fat32 1MB 512MB

parted /dev/nvme0n1 -- set 3 esp on

mkfs.ext4 -L nixos /dev/nvme0n1p1

mkswap -L swap /dev/nvme0n1p2

mkfs.fat -F 32 -n boot /dev/nvme0n1p3

mount /dev/disk/by-label/nixos /mnt

mount /dev/disk/by-label/boot /mnt/boot

swapon /dev/nvme0n1p2

nixos-generate-config --root /mnt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Before installing NixOS, you can download my current (as of writing) config for the Steam Deck which sets up GNOME and the relevant modules from the Jovian-NixOS repository:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl -L 'https://raw.githubusercontent.com/heywoodlh/nixos-configs/ebe30a392abee0426a80158af2f97ad56975d946/workstation/steam-deck.nix' -o /mnt/etc/nixos/steam-deck.nix
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should modify the newly downloaded &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mnt/etc/nixos/steam-deck.nix&lt;/code&gt; file – particularly lines 4 and 5 to match your username and user description. Additionally, you should modify the rest of the config files in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mnt/etc/nixos/&lt;/code&gt; to work for your&lt;/p&gt;

&lt;p&gt;Your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/mnt/etc/nixos/configuration.nix&lt;/code&gt; can look something like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running ‘nixos-help’).

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
      ./steam-deck.nix
    ];

  # Use the systemd-boot EFI boot loader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  networking.hostName = &quot;nix-steam-deck&quot;; # Define your hostname.

  # Set your time zone.
  time.timeZone = &quot;America/Denver&quot;;

  system.stateVersion = &quot;22.11&quot;;

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once your config suits your needs, install NixOS:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nixos-install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Set the root password and reboot. Once you login as root, run the following command to change the password for your normal, non-root user:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;passwd &amp;lt;username&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion:&lt;/h2&gt;

&lt;p&gt;With this setup, by default, NixOS will boot into the handheld Steam UI. For me, it works identically to SteamOS until I use “Switch to Desktop” – which then boots into my preferred desktop environment (GNOME) and preferred OS (NixOS).&lt;/p&gt;

&lt;h3 id=&quot;switch-back-to-steam-after-running-switch-to-desktop&quot;&gt;Switch back to Steam after running “Switch to Desktop”:&lt;/h3&gt;

&lt;p&gt;I’m currently working on this, but in order to switch back into Steam’s handheld Steam Deck UI after running “Switch to Desktop” I run the following command while in GNOME:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pkill -9 gnome-shell
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name></name></author><category term="all," /><category term="linux," /><category term="nix," /><category term="nixos," /><category term="steam," /><category term="deck," /><category term="steamdeck" /><summary type="html"></summary></entry><entry><title type="html">Launch Powershell in Tmux with -NoLogo Argument</title><link href="https://the-empire.systems/tmux-pwsh-nologo" rel="alternate" type="text/html" title="Launch Powershell in Tmux with -NoLogo Argument" /><published>2022-11-13T00:00:00+00:00</published><updated>2022-11-13T00:00:00+00:00</updated><id>https://the-empire.systems/tmux-pwsh-nologo</id><content type="html" xml:base="https://the-empire.systems/tmux-pwsh-nologo">&lt;p&gt;I recently switched to Powershell as my main shell on Linux and MacOS and I couldn’t find any examples online on how to launch Powershell Core, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pwsh&lt;/code&gt;, in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-NoLogo&lt;/code&gt; argument. So this is my quick solution to that.&lt;/p&gt;

&lt;p&gt;I placed this at the beginning of my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.tmux.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;if-shell &quot;bash -c 'echo ${SHELL} | grep -q pwsh'&quot; &quot;set -g default-command 'pwsh -NoLogo'&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will run a check using BASH (because if I’m running a system with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; installed, it will likely have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bash&lt;/code&gt; installed as well) to see if Powershell Core is my default shell. If it is, then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; will use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pwsh -NoLogo&lt;/code&gt; as its default command.&lt;/p&gt;</content><author><name></name></author><category term="all," /><category term="linux," /><category term="tmux," /><category term="pwsh," /><category term="nologo," /><category term="banner," /><category term="powershell," /><category term="core" /><summary type="html">I recently switched to Powershell as my main shell on Linux and MacOS and I couldn’t find any examples online on how to launch Powershell Core, pwsh, in tmux with the -NoLogo argument. So this is my quick solution to that.</summary></entry><entry><title type="html">Simple nfdump Setup (in Containers) for Netflow Collection and Analysis</title><link href="https://the-empire.systems/a-simple-nfdump-setup" rel="alternate" type="text/html" title="Simple nfdump Setup (in Containers) for Netflow Collection and Analysis" /><published>2022-07-20T00:00:00+00:00</published><updated>2022-07-20T00:00:00+00:00</updated><id>https://the-empire.systems/simple-nfdump-setup</id><content type="html" xml:base="https://the-empire.systems/a-simple-nfdump-setup">&lt;p&gt;This post will outline my simple Netflow collection setup running with some containers with nfdump tooling I setup for this purpose.&lt;/p&gt;

&lt;h2 id=&quot;assumptions&quot;&gt;Assumptions:&lt;/h2&gt;

&lt;p&gt;I’m going to make the following assumptions:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;You’re in a Unix-like environment&lt;/li&gt;
  &lt;li&gt;Docker is the targeted container engine&lt;/li&gt;
  &lt;li&gt;Netflow binaries will be stored in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/flows&lt;/code&gt; on your system&lt;/li&gt;
  &lt;li&gt;You already have another system that supports sending Netflow data to a remote host, such as a switch or router (I will not cover how to setup sflow on a Linux machine)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modify the content to your needs if any of these assumptions don’t line up with your setup.&lt;/p&gt;

&lt;h2 id=&quot;why-nfdump&quot;&gt;Why nfdump?&lt;/h2&gt;

&lt;p&gt;At a previous role I was introduced to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt; and really liked it. It’s like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tcpdump&lt;/code&gt; in the fact that it’s a command line tool and provides a user with the ability to inspect the netflow data based on filters such as time or source or destination hosts/ports – but unlike &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tcpdump&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt; is used against Netflow binary files that have the captured data on your filesystem.&lt;/p&gt;

&lt;p&gt;The repository for nfdump is here: &lt;a href=&quot;https://github.com/phaag/nfdump&quot;&gt;phaag/nfdump&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;setup-nfcapd&quot;&gt;Setup nfcapd&lt;/h2&gt;

&lt;p&gt;Nfcapd is a daemon included with nfdump that receives Netflow data and writes it to disk for inspection with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, let’s create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/flows&lt;/code&gt; directory and make sure that UID 1000 owns it (that UID/GID is used in the container):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo mkdir -p /flows
sudo chown -R 1000 /flows
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can spin up an nfcapd receiver with the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run -d --restart=unless-stopped --name=nfcapd -p 9995:9995/udp -v /flows:/flows heywoodlh/nfcapd:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that nfcapd is setup, you can send Netflow to UDP port 9995 on your Docker host and it should start writing the received data to binary files in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/flows&lt;/code&gt; directory. My container image by default will organize flows into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/flows&lt;/code&gt; directory by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;year/month/day/hour&lt;/code&gt;. For example, flows captured between 4:00 p.m. to 5:00 p.m. July 20th, 2022 would be in the following folder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/flows/2022/07/20/16&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you do not like the defaults I have set in my &lt;a href=&quot;https://hub.docker.com/r/heywoodlh/nfcapd&quot;&gt;heywoodlh/nfcapd&lt;/a&gt; image, you can check out &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfcapd&lt;/code&gt;’s arguments by running this command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run -it --rm heywoodlh/nfcapd --help
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can then provide your desired &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfcapd&lt;/code&gt; arguments to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run&lt;/code&gt; command. If you are going this route I can assume you are technical enough to figure out what you need so I will not cover any thing more of going outside the defaults I have set.&lt;/p&gt;

&lt;h2 id=&quot;accessing-the-captured-netflow-data&quot;&gt;Accessing the Captured Netflow Data:&lt;/h2&gt;

&lt;p&gt;For actually accessing the data you need to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt; tool. You can either install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt; on your machine – or just run a Docker container I have setup for this purpose. I will cover how to use the container as that will be a bit more predictable.&lt;/p&gt;

&lt;p&gt;Use the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker&lt;/code&gt; command to recursively access ALL of the Netflow data in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/flows/2022&lt;/code&gt; directory:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run -it --rm -v /flows:/flows heywoodlh/nfdump -R /flows/2022
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As I stated earlier in this post, you can use filters with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt; to parse out the data you actually want to see. For example, if I want to see all traffic related to destination port 80 from an IP address at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.143&lt;/code&gt;, I could run this command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run -it --rm -v /flows:/flows heywoodlh/nfdump -R /flows/2022 &quot;dst port 80 and src host 192.168.1.143&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can access &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt;’s help section with the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run -it --rm heywoodlh/nfdump --help
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt; on your machine directly, all of the above arguments to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt; should work the same.&lt;/p&gt;

&lt;p&gt;The filters provided with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt; can provide really cool pieces of information about what’s going on with your network. Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfdump&lt;/code&gt; also allows you to have flexibility to build simple but effective monitoring tools around Netflow.&lt;/p&gt;

&lt;h2 id=&quot;additional-reading&quot;&gt;Additional Reading:&lt;/h2&gt;

&lt;p&gt;Github repo: &lt;a href=&quot;https://github.com/phaag/nfdump&quot;&gt;phaag/nfdump&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Man pages: &lt;a href=&quot;https://manpages.ubuntu.com/manpages/jammy/man1/nfcapd.1.html&quot;&gt;nfcapd&lt;/a&gt;, &lt;a href=&quot;https://manpages.ubuntu.com/manpages/jammy/man1/nfdump.1.html&quot;&gt;nfdump&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dockerfiles: &lt;a href=&quot;https://github.com/heywoodlh/dockerfiles/blob/master/nfcapd/Dockerfile&quot;&gt;heywoodlh/nfcapd&lt;/a&gt;, &lt;a href=&quot;https://github.com/heywoodlh/dockerfiles/blob/master/nfdump/Dockerfile&quot;&gt;heywoodlh/nfdump&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github Actions used to build the images: &lt;a href=&quot;https://github.com/heywoodlh/actions/blob/master/.github/workflows/nfcapd-buildx.yml&quot;&gt;nfcapd-buildx&lt;/a&gt;, &lt;a href=&quot;https://github.com/heywoodlh/actions/blob/master/.github/workflows/nfdump-buildx.yml&quot;&gt;nfdump-buildx&lt;/a&gt;&lt;/p&gt;</content><author><name></name></author><category term="all," /><category term="linux," /><category term="netflow," /><category term="network," /><category term="nfdump" /><summary type="html">This post will outline my simple Netflow collection setup running with some containers with nfdump tooling I setup for this purpose.</summary></entry><entry><title type="html">A More Secure Linux Desktop</title><link href="https://the-empire.systems/a-more-secure-linux-desktop" rel="alternate" type="text/html" title="A More Secure Linux Desktop" /><published>2022-07-06T00:00:00+00:00</published><updated>2022-07-06T00:00:00+00:00</updated><id>https://the-empire.systems/a-more-secure-linux-desktop</id><content type="html" xml:base="https://the-empire.systems/a-more-secure-linux-desktop">&lt;p&gt;This is going to be a guide on some tooling and workflows I use to secure my Linux desktop. As with all security tooling, nothing except for being completely disconnected from the internet can keep you perfectly secure – this guide will serve to add some layers of protection. A lot of this tooling could be made more elegant but rather than focus on making something without flaws, I’m publishing this guide to serve as a starting point.&lt;/p&gt;

&lt;h2 id=&quot;why&quot;&gt;Why?&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Note: this section is all my opinion, feel free to skip this if you just want the details on the workflows/tooling&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Linux has a (justified) reputation for being very secure. I think on the server-side this is absolutely true. On the desktop, I feel that there are some big gaps in functionality in regard to tooling compared to some of the security tooling available for Windows or MacOS. My experience is that people consider Linux on the desktop “more secure” but it’s really not very secure by default – it’s just a much less lucrative target for bad actors because of how little market share it has.&lt;/p&gt;

&lt;p&gt;My thought process is this: if you were phished and a bad actor got a shell on your machine what could they access? With my security experience as a security engineer and Linux enthusiast, I don’t think I would have any problem eventually getting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; on a Linux workstation because there are so few desktop protections enabled by default.&lt;/p&gt;

&lt;p&gt;Again, I specifically mean there is a lack of tooling to protect desktop users. For example, on MacOS &lt;a href=&quot;https://www.obdev.at/products/littlesnitch/index.html&quot;&gt;Little Snitch&lt;/a&gt; and &lt;a href=&quot;https://objective-see.org/products/lulu.html&quot;&gt;Lulu&lt;/a&gt; exist to help a user monitor network connections if a non-whitelisted application tries to connect to the internet. Patrick Wardle has developed a gigantic list of tools that help users increase visibility on their machine: [Objective See’s MacOS Tools].&lt;/p&gt;

&lt;p&gt;There are a number of tools and workflows that I have found that help close the gaps I have mentioned.&lt;/p&gt;

&lt;h2 id=&quot;what-gaps&quot;&gt;What Gaps?&lt;/h2&gt;

&lt;p&gt;I will be focusing on what I consider are &lt;em&gt;simple to implement&lt;/em&gt; tweaks. I will not be focusing on tools like SELinux that make your system so secure to the point it’s difficult to use.&lt;/p&gt;

&lt;p&gt;These are the security gaps that I’ll focus on:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Basic security suggestions&lt;/li&gt;
  &lt;li&gt;Application autostart monitoring&lt;/li&gt;
  &lt;li&gt;Application sandboxing&lt;/li&gt;
  &lt;li&gt;Network application firewalling/monitoring&lt;/li&gt;
  &lt;li&gt;Container security&lt;/li&gt;
  &lt;li&gt;Miscellaneous tweaks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;assumptions&quot;&gt;Assumptions:&lt;/h2&gt;

&lt;p&gt;As there is a wide variety of Linux distributions, I will try to avoid distribution-specific instructions (i.e. how to install a package on one distribution) – however, I will admit I have zero interest in Red Hat based distros (RHEL, CentOS, Fedora, Rocky, AlmaLinux, etc.) so most of my suggestions have been tested by me on Arch Linux and Debian-based distributions. Apologies to any Fedora users who find my instructions to be not as compatible with their environment.&lt;/p&gt;

&lt;p&gt;I will assume you’re using a systemd-based distribution.&lt;/p&gt;

&lt;p&gt;I am going to assume the desktop environment in use will be GNOME.&lt;/p&gt;

&lt;p&gt;I will also assume that the reader will implement my opinionated suggestions so I won’t try to cover all alternatives that are available to a tool/workflow that I recommend.&lt;/p&gt;

&lt;h2 id=&quot;basic-security&quot;&gt;Basic Security:&lt;/h2&gt;

&lt;p&gt;I’m mostly going to focus on things I do that are specific to desktop systems. I would recommend using this more comprehensive guide for best hardening practices for Linux systems generally:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://madaidans-insecurities.github.io/guides/linux-hardening.html&quot;&gt;madaidan’s Linux Hardening Guide&lt;/a&gt; – an &lt;em&gt;excellent and detailed document&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;disk-encryption&quot;&gt;Disk Encryption:&lt;/h3&gt;

&lt;p&gt;This is more of a physical security suggestion so I’ll keep this brief: implementing disk encryption is a great way to secure your data on your hard drive (i.e. if somebody steals your laptop). You should encrypt your drives using full-disk encryption.&lt;/p&gt;

&lt;p&gt;If you can’t use full-disk encryption (or have setup an unencrypted system that you don’t want to reinstall) and are on a system with a more aggressive release cycle (Arch Linux or Fedora), check out my entry in the ‘Misc’ section on systemd-homed for a decent alternative.&lt;/p&gt;

&lt;h3 id=&quot;use-ufw&quot;&gt;Use UFW:&lt;/h3&gt;

&lt;p&gt;UFW is a simple wrapper script around &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iptables&lt;/code&gt;. IPTables is a powerful, but complex Linux firewall and UFW makes it much simpler.&lt;/p&gt;

&lt;p&gt;Install UFW on your distribution.&lt;/p&gt;

&lt;p&gt;After UFW is installed, enable the service and activate it to block all incoming connections to your machine:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;systemctl enable ufw.service
ufw enable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By default this will block all incoming connections and allow outbound connections. You can configure UFW to block outbound connections, but as that can be terribly inconvenient I will not cover doing that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Docker circumvents IPTables/UFW – I would recommend either setting up rootless Docker, Docker Desktop for Linux, Podman, or follow my instructions for using Lima for running Docker in a VM&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;clamav&quot;&gt;ClamAV:&lt;/h3&gt;

&lt;p&gt;Disclaimer: I can’t stand most proprietary Antivirus products. But I think it’s very useful to know if a known malicious file is on your machine. ClamAV gets you access to a great malware database without all the other buzz-word features and spyware that comes with a lot of antivirus.&lt;/p&gt;

&lt;p&gt;Install ClamAV and ClamTK (a graphical interface to ClamAV).&lt;/p&gt;

&lt;p&gt;Run the following command to update the local ClamAV database on your machine:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo freshclam
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Open ClamTK &amp;gt; Settings &amp;gt; Check the following boxes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Scan files beginning with a dot&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Scan directories recursively&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Optionally: Scan files larger than 20MB&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Back in settings select Scheduler and choose a time to scan your home directory daily.&lt;/p&gt;

&lt;p&gt;If you want to be able to scan files from your file manager, I would recommend checking out the plugins:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/dave-theunsub/clamtk#plugins&quot;&gt;https://github.com/dave-theunsub/clamtk#plugins&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Further reading on ClamTK’s usage:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/dave-theunsub/clamtk#usage&quot;&gt;https://github.com/dave-theunsub/clamtk#usage&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;application-autostart-monitoring&quot;&gt;Application Autostart Monitoring:&lt;/h2&gt;

&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites:&lt;/h3&gt;

&lt;p&gt;I’ve chosen to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inotify&lt;/code&gt; to monitor each these so please install the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inotify-tools&lt;/code&gt; package. Please also install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notify-send&lt;/code&gt; so desktop notifications can be sent to alert the user.&lt;/p&gt;

&lt;h3 id=&quot;why-1&quot;&gt;Why?&lt;/h3&gt;

&lt;p&gt;If I were a bad actor on your machine with an unprivileged shell there are a couple of places I would place a malicious application to run on startup (for persistence): the user’s cron jobs, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/autostart&lt;/code&gt; directory and the user’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/systemd/user&lt;/code&gt; directory.&lt;/p&gt;

&lt;h3 id=&quot;user-cron-monitoring&quot;&gt;User cron monitoring:&lt;/h3&gt;

&lt;p&gt;For those unfamiliar with cron jobs: cron is a tool for running jobs on a schedule. You can easily modify a cron to run a job as a particular user on a regular basis. As a bad actor (with an unprivileged shell), I could easily setup a cron to repeatedly attempt to do a malicious task such as establish a reverse shell to a server somewhere.&lt;/p&gt;

&lt;p&gt;Create a script in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/opt/scripts/cron-monitor.sh&lt;/code&gt; with the following contents:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/env bash

notify-send &quot;Started cron monitoring script&quot;

mkdir -p ~/.tmp/

crontab -l &amp;gt; ~/.tmp/orig-cron.txt

while true
do
    crontab -l &amp;gt; ~/.tmp/new-cron.txt

    if cmp ~/.tmp/orig-cron.txt ~/.tmp/new-cron.txt
    then
	echo 'Crontab unmodified'
    else
	crontab -l &amp;gt; ~/.tmp/orig-cron.txt
	notify-send 'User crontab modified: check crontab with `crontab -l`'
    fi

    sleep 5
done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Make it executable:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chmod +x ~/opt/scripts/cron-monitor.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now create a file at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.local/share/applications/cron-monitor.desktop&lt;/code&gt; to execute our monitoring script with the following content:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[Desktop Entry]
Name=Crontab Monitoring Script
Exec=bash -c &quot;${HOME}/opt/scripts/cron-monitor.sh&quot;
Icon=org.gnome.Terminal
Type=Application
Categories=Security;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, symlink that application to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/autostart&lt;/code&gt; directory so the application runs when you login:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ln -s ~/.local/share/applications/cron-monitor.desktop ~/.config/autostart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you open the “Cron Monitoring Script” application it should notify you that the monitoring script has started. You can test that you get notifications with the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;crontab -l | { cat; echo &quot;* * * * * echo hello world&quot;;  } | crontab -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Make sure to remove the test cron job with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crontab -e&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;homeconfigautostart-monitoring&quot;&gt;$HOME/.config/autostart monitoring:&lt;/h3&gt;

&lt;p&gt;On most Linux desktop, desktop applications are defined in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.desktop&lt;/code&gt; file with a bunch of parameters defining the application. Any valid &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.desktop&lt;/code&gt; files placed in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/autostart&lt;/code&gt; directory will be executed when a user logs in to their desired desktop environment such as GNOME. This could be used to create a false, malicious application that can will start when a user logs in.&lt;/p&gt;

&lt;p&gt;Create a script in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/opt/scripts/autostart-monitor.sh&lt;/code&gt; with the following contents:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/env bash

notify-send &quot;Started autostart monitoring script&quot;

inotifywait --format='%f' -m -e create $HOME/.config/autostart | while read filename
do
    notify-send &quot;Desktop autostart file added: ${filename}&quot;
done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Make it executable:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chmod +x ~/opt/scripts/autostart-monitor.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now create a file at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.local/share/applications/autostart-monitor.desktop&lt;/code&gt; to execute our monitoring script with the following content:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[Desktop Entry]
Name=Autostart Monitoring Script
Exec=bash -c &quot;${HOME}/opt/scripts/autostart-monitor.sh&quot;
Icon=org.gnome.Terminal
Type=Application
Categories=Security;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, symlink that application to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/autostart&lt;/code&gt; directory so the application runs when you login:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ln -s ~/.local/share/applications/autostart-monitor.desktop ~/.config/autostart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you open the “Autostart Monitoring Script” application it should notify you that the monitoring script has started. You can test that you get notifications with the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touch ~/.config/autostart/dummy-application.desktop &amp;amp;&amp;amp; rm ~/.config/autostart/dummy-application.desktop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;homeconfigsystemduser-monitoring&quot;&gt;$HOME/.config/systemd/user monitoring:&lt;/h3&gt;

&lt;p&gt;I would say that Systemd is the backbone of most modern Linux systems as it manages all the services. As an unprivileged user you can create user services so that repeated tasks are executed as you which could easily be used for running repeated, malicous tasks for a bad actor to establish persistence.&lt;/p&gt;

&lt;p&gt;Create a script in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/opt/scripts/systemd-monitor.sh&lt;/code&gt; with the following contents:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;#!/usr/bin/env bash

notify-send &quot;Started systemd monitoring script&quot;

inotifywait --format='%f' -m -e create $HOME/.config/systemd/user | while read filename
do
    notify-send &quot;User systemd file added: ${filename}&quot;
done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Make it executable:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;chmod +x ~/opt/scripts/systemd-monitor.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now create a file at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.local/share/applications/systemd-monitor.desktop&lt;/code&gt; to execute our monitoring script with the following content:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[Desktop Entry]
Name=Systemd User Monitoring Script
Exec=bash -c &quot;${HOME}/opt/scripts/systemd-monitor.sh&quot;
Icon=org.gnome.Terminal
Type=Application
Categories=Security;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, symlink that application to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.config/autostart&lt;/code&gt; directory so the application runs when you login:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ln -s ~/.local/share/applications/systemd-monitor.desktop ~/.config/autostart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you open the “Systemd User Monitoring Script” application it should notify you that the monitoring script has started. You can test that you get notifications with the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;touch ~/.config/systemd/user/dummy.service &amp;amp;&amp;amp; rm ~/.config/systemd/user/dummy.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;application-sandboxing&quot;&gt;Application Sandboxing:&lt;/h2&gt;

&lt;p&gt;Unlike MacOS, most Linux distributions don’t have application sandboxing at all or very minimal application sandboxing. So if a malicious actor gets a shell by exploiting an application like Firefox they would be able to see anything your user could access. With sandboxing, getting a shell via an application exploit would severely limit what the malicious actor could access.&lt;/p&gt;

&lt;p&gt;There are a couple of not-so-invasive methods for implementing restrictions around what an application can access:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;AppArmor (an alternative to SELinux that is very non-intrusive in my experience)&lt;/li&gt;
  &lt;li&gt;Snaps/Flatpaks&lt;/li&gt;
  &lt;li&gt;Firejail&lt;/li&gt;
  &lt;li&gt;Bubblewrap&lt;/li&gt;
  &lt;li&gt;Containers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’m going to focus on AppArmor and Firejail. I actively dislike Canonical’s approach to Snaps and &lt;a href=&quot;https://flatkill.org/&quot;&gt;Flatpak’s sandbox implementation isn’t very good&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;apparmor&quot;&gt;AppArmor&lt;/h3&gt;

&lt;p&gt;AppArmor provides similar functionality to SELinux while not making your system impossible to work with. AppArmor allows you to define clear boundaries for what a process can and cannot access on your system. It can be configured to be more restricted if desired. Additionally, &lt;a href=&quot;https://wiki.archlinux.org/title/Firejail#Enable_AppArmor_support&quot;&gt;AppArmor can integrate with Firejail&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;AppArmor is installed and enabled by default on Ubuntu systems: &lt;a href=&quot;https://ubuntu.com/server/docs/security-apparmor&quot;&gt;Ubuntu Docs: AppArmor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once AppArmor is installed you can check its status with the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo aa-status
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On Debian-based systems, additional AppArmor profiles can be installed with the following commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y apparmor-profiles apparmor-profiles-extra 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On Arch, those profiles can be loaded by enabling and starting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apparmor&lt;/code&gt; service:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo systemctl enable --now apparmor.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can get notifications when the AppArmor policies denies an application:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/AppArmor#Get_desktop_notification_on_DENIED_actions&quot;&gt;Arch Wiki: AppArmor – Get desktop notifications on DENIED actions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additional Reading:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/AppArmor&quot;&gt;Arch Wiki: AppArmor&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;firejail&quot;&gt;Firejail:&lt;/h3&gt;

&lt;p&gt;After installing Firejail on your machine, use the following command to set up profiles for all of your installed applications that are already defined:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo firecfg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I would recommend integrating AppArmor with Firejail:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Firejail#Enable_AppArmor_support&quot;&gt;Arch Wiki: Enable AppArmor support&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://manpages.ubuntu.com/manpages/bionic/man1/firejail.1.html#apparmor&quot;&gt;Ubuntu Manpage: Firejail AppArmor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On Arch you can integrate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pacman&lt;/code&gt; operations with Firejail:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.archlinux.org/title/Firejail#Using_Firejail_by_default&quot;&gt;Arch Wiki: Using Firejail by default&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;application-firewall&quot;&gt;Application Firewall:&lt;/h2&gt;

&lt;p&gt;On Linux, there aren’t many fully-featured/working application firewalls comparable to Little Snitch on MacOS. For those unfamiliar with what an application firewall does: an application firewall allows a user to permit or block access to network resources per application. For example, if I run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl google.com&lt;/code&gt; an application firewall would block &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; from accessing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;google.com&lt;/code&gt; until I either permit or block the request. This is beneficial if an application is making undesirable network requests (i.e. a malicious binary attempts to connect to a server, or a program is collecting unwanted analytics, etc.).&lt;/p&gt;

&lt;p&gt;There are two application firewalls on Linux that I am aware of:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/evilsocket/opensnitch&quot;&gt;OpenSnitch&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://safing.io/portmaster/&quot;&gt;Portmaster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve never had success with OpenSnitch, but Portmaster has worked very well for me and seems to be very polished with GNOME.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.safing.io/portmaster/install/linux&quot;&gt;Portmaster Docs: Install on Linux&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once Portmaster is running, open the Portmaster application and go to Settings &amp;gt; Privacy Filter &amp;gt; General &amp;gt; Default Network Action and set it to “Prompt”. This will set Portmaster to prompt you to Allow or Deny every network request to a new host per process. For example, if I run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl google.com&lt;/code&gt; and I deny that request in Portmaster any future network request to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;google.com&lt;/code&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; will be denied.&lt;/p&gt;

&lt;h2 id=&quot;container-security&quot;&gt;Container Security:&lt;/h2&gt;

&lt;p&gt;If you are a Docker user, using the default, privileged Docker daemon is a poor practice on a workstation as it completely bypasses the local firewall. Even worse, if your user has access to that privileged Docker daemon (i.e. added to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker&lt;/code&gt; group) it is fairly trivial to access restricted resources if that user is compromised.&lt;/p&gt;

&lt;p&gt;Some alternatives to the privileged Docker Daemon:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/lima-vm/lima&quot;&gt;Lima&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rancherdesktop.io/&quot;&gt;Rancher Desktop&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.docker.com/desktop/linux/install/&quot;&gt;Docker Desktop for Linux&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.docker.com/engine/security/rootless/&quot;&gt;Rootless Docker&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://podman.io/&quot;&gt;Podman&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For rootless Docker and Podman, the following warning from the Arch Wiki applies: “Rootless Podman relies on the unprivileged user namespace usage &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONFIG_USER_NS_UNPRIVILEGED&lt;/code&gt; which has some serious security”. However, this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONFIG_USER_NS_UNPRIVILEGED&lt;/code&gt; parameter is required for sandboxing in things like Electron applications (for example, the Zoom application on Linux won’t work if this parameter isn’t set). Another note from the Arch Wiki explains more: “Note: The user namespace configuration item &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONFIG_USER_NS&lt;/code&gt; is currently enabled in linux (4.14.5 or later), linux-lts (4.14.15 or later), linux-zen (4.14.4-2 or later) and linux-hardened. Lack of it may prevent certain sandboxing features from being made available to applications.”&lt;/p&gt;

&lt;p&gt;Lima, Rancher Desktop and Docker Desktop all utilize virtual machines to run Docker rather than attaching to the host’s kernel and resources like the privileged Docker daemon does. My preference is Lima as it leverages QEMU and in my experience is the most minimal and simple (for me) of all those options. I prefer using a VM to provide a bit of isolation from my system.&lt;/p&gt;

&lt;h2 id=&quot;misc&quot;&gt;Misc:&lt;/h2&gt;

&lt;h3 id=&quot;systemd-homed&quot;&gt;Systemd-homed:&lt;/h3&gt;

&lt;p&gt;If you use Arch Linux or Fedora, you can use &lt;a href=&quot;https://systemd.io/HOME_DIRECTORY/&quot;&gt;systemd-homed&lt;/a&gt; to create an ultra-portable home directory for your user.&lt;/p&gt;

&lt;p&gt;The security benefits of systemd-homed are the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Totally portable home directory&lt;/li&gt;
  &lt;li&gt;LUKS encrypted home directory&lt;/li&gt;
  &lt;li&gt;Automatic locking of your home directory when your system is suspended&lt;/li&gt;
  &lt;li&gt;Better handling of credentials compared to the decades old Shadow system (admittedly, I don’t understand the details as to why or how it’s better but that is a feature touted by the systemd contributors)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have already setup your user without systemd-homed, don’t fret as the systemd folks have a nice guide on migrating an existing user to systemd-homed:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://systemd.io/CONVERTING_TO_HOMED/&quot;&gt;systemd.io: Converting Existing Users to systemd-homed managed Users&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to use LUKS encryption as the storage mechanism for your home directory create your user with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--storage=luks&lt;/code&gt; flag set:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;homectl create --storage=luks &amp;lt;username&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Additional reading: &lt;a href=&quot;https://wiki.archlinux.org/title/Systemd-homed&quot;&gt;Arch Wiki: systemd-homed&lt;/a&gt;&lt;/p&gt;</content><author><name></name></author><category term="all," /><category term="linux," /><category term="security," /><category term="desktop," /><category term="gnome," /><category term="firejail," /><category term="containers" /><summary type="html">This is going to be a guide on some tooling and workflows I use to secure my Linux desktop. As with all security tooling, nothing except for being completely disconnected from the internet can keep you perfectly secure – this guide will serve to add some layers of protection. A lot of this tooling could be made more elegant but rather than focus on making something without flaws, I’m publishing this guide to serve as a starting point.</summary></entry></feed>