Schlink's Docs

Welcome! This is an mdbook full on notes that Sam Schlinkert has written about installing and running a Linux desktop. It's mostly for personal reference, but you may find it useful. It mostly pertains to Ubuntu-based systems.

My Config Files

Most of my Linux config files (as opposed to guides, which is what this site is mostly made up of) live in this GitHub repo. (Separately, I keep an Alacritty config file as a Gist.)

How this book is set up

This is an mdbook. The book's source files live in this GitHub repo -- if you wish to contribute to this book, please create an issue or pull request there!

The GitHub repo of my Jekyll website/blog, which is one place where this book is published, is here.

Publishing the mdbook to the GitHub Page:

The book.toml file in the mdbook source repo specifies that the mdbook builds locally to ../ (via the mdbook build command). So when you set this up you need those two directories in the same parent directory, likely code/.

Once set up, you can run a full "publish" procedure:

  1. In the mdbook source repo, run mdbook build
  2. In the Jekyll site repo, add and commit the Git changes and then run git push origin master

Contact the Author

You can find Sam on Twitter or Mastodon or contact him via more secure channels.

Installing a Fresh Distro on Oryx Pro

Once you've got the USB stick in the computer, reboot your system. You’ll need to tell the computer to boot from the live disk by holding F7 or F1 source.

If you're NOT going with Pop_OS, you'll likely need to install System76 drivers and the appropriate NVIDIA drivers. More info on this here.

Support articles

Installing System76 and appropriate NVIDIA drivers for System76 machine

Pop Docs

Initial Setup

Some App Installation and Hard Drive Mounting Basics

Installing Snap

Think it's just sudo apt install snapd.

Know that, sometimes in order to update applications that you install via Snap need to be updated with a command like snap refresh or snap refresh <app_name>. Run snap refresh --help for more information.

Generic upgrade line

sudo apt update && sudo apt dist-upgrade is a good way to upgrade everything. Can do sudo apt update && sudo apt dist-upgrade -y to auto-accept upgrades.

How to install from an AppImage if it's not going easily

This tutorial instructs to right-click the download appimage file, go to "Properties" > "Permissions" and then check "Allow executing file as program". Alternatively chmod u+x <AppImage File> to make it executable.

How to mount an external hard drive that's formatted as exFAT

Simply install these programs by running this line: sudo apt-get install exfat-fuse exfat-utils (via).

Desktop files

The Arch Wiki has an entry on desktop entries, which notes

Desktop entries for applications, or .desktop files, are generally a combination of meta information resources and a shortcut of an application. These files usually reside in /usr/share/applications/ or /usr/local/share/applications/ for applications installed system-wide, or ~/.local/share/applications/ for user-specific applications. User entries take precedence over system entries.

Desktop file example

At ~/.local/share/applications/standard-notes.desktop paste the following:

[Desktop Entry]

See the page on Standard Notes for more.

bashrc and Terminal

Here are some tips on setting up your bash environment and your terminal. Most of the config files live in this GitHub repo, for now. Below are some instruction on how to load them correctly and easily.


Here's a one-line bash command to copy down my Linux .bashrc from GitHub:

curl -o ~/.bashrc

Consider making configuring your prompt easier by using Starship.

Konsole color profile

If you're using KDE, the default terminal emulator, Konsole, is pretty good. To get my colors -- based on my Pink Moon Vim colorscheme -- and profile, run the following two lines:

curl --create-dirs -o ~/.local/share/konsole/Pink\ Moon.colorscheme\ Moon.colorscheme
curl --create-dirs -o ~/.local/share/konsole/pink-moon.profile

Alacritty terminal emulator config file

Alacritty is a cross-platform terminal emulator written in Rust, so it's really fast.

My Alacritty config file -- complete with colors -- is tested on MacOS, not Ubuntu, but if you want to try it: Place the following yaml file at ~/.config/alacritty/alacritty.yml: Alacritty config. To do this, try running:

curl --create-dirs -o ~/.config/alacritty/alacritty.yml


Before you do anything else, especially with Neovim or Vim, install git! sudo apt install git

Given the holistic setup in this document, you're going to want to use the ssh URL when cloning down repos from GitHub (as opposed to HTTPS).

Optional: Set a global gitignore

On Kubuntu, I've gotten by without a global gitignore file, but if you want to make one, I think this is the procedure I'd follow:

  1. Run git config --global core.excludesfile ~/.gitignore_global or something similar (source). Or, I think you can put in ~/.config/.gitignore_global if your prefer.

  2. Visit and generate yourself a recommended global gitignore file, given your preferred languages, code editor, and OS. For example, here's one for writing Rust, Python, and Ruby in Vim on Linux:

# Created by,ruby,python,linux,vim
# Edit at,ruby,python,linux,vim

### Linux ###

# temporary files which can be created if a process still has a handle open of a deleted file

# KDE directory preferences

# Linux trash folder which might appear on any partition or disk

# .nfs files are created when an open file is removed but is still being accessed

### Python ###
# Byte-compiled / optimized / DLL files

# C extensions

# Distribution / packaging

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.

# Installer logs

# Unit test / coverage reports

# Translations

# Django stuff:

# Flask stuff:

# Scrapy stuff:

# Sphinx documentation

# PyBuilder

# Jupyter Notebook

# IPython

# pyenv
#   For a library or package, you might want to ignore these files since the code is
#   intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.

# poetry
#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
#   This is especially recommended for binary packages to ensure reproducibility, and is more
#   commonly ignored for libraries.

# PEP 582; used by e.g.

# Celery stuff

# SageMath parsed files

# Environments

# Spyder project settings

# Rope project settings

# mkdocs documentation

# mypy

# Pyre type checker

# pytype static type analyzer

# Cython debug symbols

# PyCharm
#  JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
#  be found at
#  and can be added to the global gitignore or merged into this file.  For a more nuclear
#  option (not recommended) you can uncomment the following to ignore the entire idea folder.

### Ruby ###

# Used by dotenv library to load environment variables.
# .env

# Ignore Byebug command history file.

## Specific to RubyMotion:

## Specific to RubyMotion (use of CocoaPods):
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# vendor/Pods/

## Documentation cache and generated files:

## Environment normalization:

# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# Gemfile.lock
# .ruby-version
# .ruby-gemset

# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:

# Used by RuboCop. Remote config files pulled in from inherit_from directive.
# .rubocop-https?--*

### Rust ###
# Generated by Cargo
# will have compiled files and executables

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here

# These are backup files generated by rustfmt

# MSVC Windows builds of rustc generate these, which store debugging information

### Vim ###
# Swap
!*.svg  # comment out if you don't need vector files

# Session

# Temporary
# Auto-generated tag files
# Persistent undo

# End of,ruby,python,linux,vim

Here's the stand-alone one for Golang, if you're into that:

# Created by
# Edit at

### Go ###
# If you prefer the allow list template instead of the deny list, see community template:
# Binaries for programs and plugins

# Test binary, built with `go test -c`

# Output of the go coverage tool, specifically when used with LiteIDE

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file

### Go Patch ###

# End of


I think I used the stable ppa and followed these instructions, though given this page, we might be able to just do sudo apt install neovim at this point?

Before proceeding, make sure git is installed.

A decent init.vim file is contained in my linux-config repo.

mkdir ~/.config/nvim
curl -o ~/.config/nvim/init.vim

Next, we can install our plugins by running nvim +PlugInstall +qa.

Deoplete / Neovim

For Deoplete to work well, first I'd recommend setting up pyenv.

To update Deoplete, you may need to run :UpdateRemotePlugins in Neovim. Neovim's :CheckHealth is your friend here.

See other sections of this documentation for language-specific setup.


Installing the Snap

sudo apt install snapd

I then installed KeePassXC with snap install keepassxc,

Installing from the app image

Here's the download page. See the Basics section for AppImage installation instructions.


I installed Syncthing via the instructions at the top of this page

I then setup Syncthing, mainly to keep my KeePass database in-sync.

Useful bash functions

Requires that tmux be installed!

# Via:
function ss {
  if tmux has-session -t synct 2>/dev/null; then
    echo "Syncthing session already started at" >&2
    return 1
  echo "Starting up Syncthing at"
  tmux new-session -d -s synct "syncthing -no-browser"

function se {
  if ! tmux has-session -t synct 2>/dev/null; then
    echo "No Syncthing session to end." >&2
    return 1
  echo "Stopping Syncthing and killing the tmux session"
  tmux send-keys -t synct C-c

Setting up Standard Notes on Linux

As of January 2020, Standard Notes is available as a snap.

sudo snap install standard-notes

But I originally installed Standard Notes via the AppImage, so I'll leave those instructions here.

First, let's download Standard Notes for Linux from the Standard Notes site, which gives us an AppImage file.

Where to put the AppImage file?

Here's one way that works: Create a directory at ~/standard-notes/ and move the AppImage file there. Also, go download a PNG of the Standard Notes logo and place it in this directory.

Creating the .desktop file

If you don't yet have a .desktop file for Standard Notes, we'll create one. At ~/.local/share/applications/standard-notes.desktop paste the following:

[Desktop Entry]

Now, after a computer restart, Standard Notes should come up when you search your applications.

More on desktop files in the Arch Wiki.


Note from 2022: Consider using age, especially for file encryption, rather than PGP.

GNU Privacy Assistant

For a GPG GUI application for Linux/Ubuntu for key management etc., try sudo apt install gpa which installs a program called "GNU Privacy Assistant"

GPG conf

Let's make sure we've got good GPG settings. To do this, create a new file at ~/.gnupg/gpg.conf.

Then do one or all of the following:

  1. Trust the decent gpg.conf I made for myself in 2021 below.
  2. Copy this guide's "hardened" config (actual gpg.conf file)
  3. Read through this guide, which points to this Github repo.

A decent gpg.conf

Put this in ~/.gnupg/gpg.conf

# This gpg.conf takes inspiration from: 
#   - Riseup OpenPGP Best Practices 
#   - DrDuh:
# Put this in ~/.gnupg/gpg.conf

# behavior

# Disable inclusion of the version string in ASCII armored output

# Disable comment string in clear text signatures and ASCII armored messages

# Display long key IDs
keyid-format 0xlong

# List all keys (or the specified ones) along with their fingerprints

# Display the calculated validity of user IDs during key listings
list-options show-uid-validity
verify-options show-uid-validity

# Try to use the GnuPG-Agent. With this option, GnuPG first tries to connect to
# the agent before it asks for a passphrase.

# Enable smartcard (from:

# keyserver

# This is the server that --recv-keys, --send-keys, and --search-keys will
# communicate with to receive keys from, send keys to, and search for keys on
keyserver hkps://

# Set the proxy to use for HTTP and HKP keyservers - default to the standard
# local Tor socks proxy
# It is encouraged to use Tor for improved anonymity. Preferrably use either a
# dedicated SOCKSPort for GnuPG and/or enable IsolateDestPort and
# IsolateDestAddr
#keyserver-options http-proxy=socks5-hostname://

# Don't leak DNS, see
keyserver-options no-try-dns-srv

# When using --refresh-keys, if the key in question has a preferred keyserver
# URL, then disable use of that preferred keyserver to refresh the key from
keyserver-options no-honor-keyserver-url

# When searching for a key with --search-keys, include keys that are marked on
# the keyserver as revoked
keyserver-options include-revoked

# algorithm and ciphers

# list of personal digest preferences. When multiple digests are supported by
# all recipients, choose the strongest one
personal-cipher-preferences AES256 AES192 AES CAST5

# list of personal digest preferences. When multiple ciphers are supported by
# all recipients, choose the strongest one
personal-digest-preferences SHA512 SHA384 SHA256 SHA224

# message digest algorithm used when signing a key
cert-digest-algo SHA512

# This preference list is used for new keys and becomes the default for
# "setpref" in the edit menu
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed

Using a PGP private key from a Smartcard on Ubuntu

  1. Add the public key to your system: Get the .asc file onto your system, then run gpg2 --import <file-name>.asc
  2. Plug the smartcard into your computer.
  3. Try running gpg2 --card-status.


  • If the above doesn't work try installing scdaemon and pcscd with sudo apt install scdaemon and then sudo apt install pcscd. You may also need to sudo apt install gpgsm
  • You may also need to kill and restart scdaemon with:
killall scdaemon
pgrep scdaemon

You can now encrypt and decrypt files with the pgp keys on your smartkey using the gpg2 command line tool. To decrypt a file run something like this: gpg --output test --decrypt '/home/schlinkert/keepass-databases/key-files/fly1.key.gpg'. Check that you can decrypt a Keepass database AND that you can alter settings.

Other Apps to Install

  • Download and install Signal
  • Install Tor Browser (forget how exactly I did this-- maybe Tor Browser Launcher? From POP store?)
  • Install Chromium via the POP app store if you like.

Onionshare (consider the CLI)

If OnionShare's GUI installations are throwing errors, try installing and using the CLI. I'd recommend installing it with pipx rather than pip. Here's an example:

# Install pipx (see:
python3 -m pip install --user pipx
python3 -m pipx ensurepath
# Install onionshare-cli
pipx install onionshare-cli
onionshare-cli --help

Upgrading onionshare-cli

If using pipx, try pipx upgrade onionshare-cli

If using regular pip3, try something like pip3 install --user --upgrade onionshare-cli

GUI Markdown editors

While Neovim/Vim is fine for editing Markdown, if you want a different aesthetic, try Typora (with my forked theme), Apostrophe, or Ghostwriter.

Manuskript seems like a decent novel-writing app for Linux, but there are others.

Standard Notes .desktop file

If you install any of the programs below, you may need to create your own "desktop" file, so that your Desktop Environment can "find" these applications. These desktop files go in ~/.local/share/applications.

And sometimes you need to go download a PNG file to serve as the Icon.

Standard Notes

[Desktop Entry]



[Desktop Entry]

Ricochet (no longer maintained)

Download a Ricochet icon as a png if necessary.

[Desktop Entry]

Chrome and Flash

The best way to watch things that might require Flash(?) like Hulu is to do it through the Chrome browser (not Chromium)

Download Chrome and then install it (I forget the steps).

You may need to also install some sort of flash plugin. In the past I've tried running: sudo apt-get install flashplugin-installer and then restarting Chrome.

I've Googled and found blog posts like this one with other things to try.

Development Environment


Installing Pyenv

I'm not sure if you have to uninstall any versions of Python before you do this, but I doubt it. You might want to checkout your bashrc to make sure there isn't any weird Python PATH stuff in there before we start.

  1. Install Pyenv, probably via the "Basic GitHub Checkout" method. Could also try new auto-installer, which seems to make updating easier.
  2. Add the necessary stuff to your .bashrc (not .bash_profile)
  3. Restart terminal
  4. Maybe install dependencies? (You may be good to go already.)
  5. Run pyenv install --list and pick new-ish-but-stable versions of python2 and python3 to install. For example: pyenv install 3.7.4 && pyenv install 2.7.16
  6. You can set version 3 as the global, with 2 as fall-back: pyenv global 3.7.4 2.7.16. You could also set the system version as a fallback, with pyenv global 3.7.0 2.7.15 system.
  7. Check that pip is installed (I think it's included?). You should be able to upgrade pip3 with pip3 install --upgrade pip and pip2 with pip2 install --upgrade pip

Let's see how we did: If successful, python2 gets you Python 2, python3 or python gets you Python 3. Similar with pip2/pip3/pip.

To install autosub (which I think necessitates Python2) run pip2 install autosub

Deoplete / Neovim

Now that we've got a nice little Python and Pip environment set up, let's make sure Deoplete is using it.

If you use Neovim + Deoplete, you probably want to run pip3 install neovim or pip3 install pynvim to ensure Deoplete works smoothly (see Deoplete's requirements).

Another tip to try is to explicitedly tell Neovim which Python3 to use. Do this by including this line in your Neovim config file:

let g:python3_host_prog = expand('~/.pyenv/shims/python')

I don't think you need to provide Neovim with a version of Python2 these days to make Neovim do its job well.

At this point, you may need to update Deoplete by running :UpdateRemotePlugins in Neovim. (Neovim's :CheckHealth is your friend here.)

Tips for writing Python in Vim/Neovim


For a formatter, I like Black so far. All you need to integrate it into Vim is to install the Vim plugin:

Plug 'psf/black', { 'branch': 'stable' }

And I'll probably add this to my vimrc to have it run on save:

autocmd BufWritePre *.py execute ':Black'

Note that I did not need to run any pip install commands to get it working.

Syntax and style checker

For checking Python syntax and style you could try flake8.

After installing with pip install flake8 (reference), you can run it on individual python files from the command line with flake8 <filename>.py, which will print out recommendations to the terminal.

It also has a corresponding Vim plugin, though after installing it the default mapping, <F7>, didn't work, so I had to run :call flake8#Flake8(). Obviously I could try mapping it to a key myself.

2023 Update: Try ruff and these docs on Vim & Neovim integration!

2020 updates / notes

These two blog posts may offer better, newer solutions for Python environment set ups:


Specifically, if you've been using pip to install packages solely for use on the command-line (as opposed to active development using Python), like the neovim package, I'm hoping that pipx may be a better, more self-contained solution. Though given that you need either Homebrew or pip to install pipx, it might not be as strong of a solution on Ubuntu as it is on MacOS.

2023 updates

  • Rye looks like a possible all-in-one solution for future machines where I need access to Python.

  • For packages: uv? For formatting: ruff.

  • There's also "Python launcher"?

Ruby and rbenv

  1. Install rbenv (via "basic github checkout")
  2. Install ruby-build as an rbenv plugin.
  3. At this point you made need to run sudo apt-get install -y libssl-dev libreadline-dev zlib1g-dev before proceeding
  4. rbenv install -l lists available versions of Ruby. Pick one to install.
  5. Set that version to global.

You can update the Ruby versions available to rbenv by running rbenv_upgrade (found in bashrc).

function rbenv_upgrade {
  cd ~/.rbenv && git pull
  cd ~/.rbenv/plugins/ruby-build && git pull
  cd ~

Alternative Ruby version managers

Frum is a new Ruby version manager written in Rust.

RVM is another, more well-known option.

Rust + Neovim

This assumes you have Neovim installed already.

  1. Install Rust. Make sure to add export PATH="$HOME/.cargo/bin:$PATH" to end of ~/.bashrc. Note: you can uninstall at anytime with rustup self uninstall.

  2. Install rustfmt and its Vim counterpart, rust.vim

  3. Install Rust Clippy

Getting Autocomplete in Neovim with Deoplete

Install Deoplete

  • You may first be required to install some Python stuff. You may want to get your pyenv setup working first. However, in a pinch, these commands have worked for me in the past:
    • Install pip3 with sudo apt-get install python3-pip
    • and then pip3 install neovim

Then make sure you've got all this (or something similar) in your init.vim file:

" Auto-complete
if has('nvim')
  Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }
  Plug 'Shougo/deoplete.nvim'
  Plug 'roxma/nvim-yarp'
  Plug 'roxma/vim-hug-neovim-rpc'

" then further down
let g:deoplete#enable_at_startup = 1

rust-analyzer and LanguageServer

To get some nice Rust-specific, IDE-esque goodies in Neovim, we're going to install rust-analyzer. Below, I outline the relatively simple installation option that uses LanguageClient-neovim, though do check documentation for latest instructions.

1. Install rust-analyzer Language Server Binary

Install rust-analyzer Language Server Binary by running the following:

git clone && cd rust-analyzer
cargo xtask install --server

Think this installs the project's code to ~/.config/nvim/rust-analyzer/. Executable is rust-analyzer, so can check that it's in your PATH by running rust-analyzer --version. Assume you'd upgrade by running git pull && cargo xtask install --force --server?

2. Configure by adding this to your vim/neovim config file...

...replacing the existing Rust-specific line if it exists:

let g:LanguageClient_serverCommands = {
\ 'rust': ['rust-analyzer'],
\ }

3. Get the neovim LanguageClient installed

Plug 'autozimu/LanguageClient-neovim', {
\ 'branch': 'next',
\ 'do': 'bash',
\ }

" (Optional) Multi-entry selection UI.
Plug 'junegunn/fzf'

Then down below the g:LanguageClient_serverCommands bit, let's add some mappings. The plugin's readme provides some ideas, but as a minimum:

nmap <F5> <Plug>(lcn-menu)

4. Install plugins

Back in the terminal, run nvim +PlugInstall +UpdateRemotePlugins +qa

Think you should now be good-to go? F5 will give you some options for analysis.

Notes on alternative approaches to making Neovim more of a Rust IDE

Alternative methods of installing rust-analyzer

For rust-analyzer, there is an alternative installation process described where it's integrated with coc.nvim, which you might be using anyway, or like for its other features. To me, right now, it seems a bit intense, and requires Node to be installed.


There also seems to be another way to "teach" Neovim about the Rust language using Racer ("code completion for Rust") and its associated Vim plugin, but I think I tried it before and it through halting errors as I was typing code.

Installing Go

As of 2023, on Linux, I prefer the method outlined on this page

It involves:

  1. Downloading the linux-amd64 file, e.g. go1.20.linux-amd64.tar.gz, from to your ~/Downloads directory.
  2. cd ~/Downloads
  3. sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.20.linux-amd64.tar.gz
  4. Check with go version

If it's your first time installing Go on the machine, you'll need to add this Go binary to your PATH by adding something like export PATH=$PATH:/usr/local/go/bin to your ~/.profile or ~/.bashrc.

GitHub and ssh keys

Make sure Git is installed

1. Set git username (email) and email locally

Via this post:

To set your global commit name and email address run the git config command with the --global option:

git config --global "Your Name"
git config --global ""

Once done, you can confirm that the information is set by running: git config --list

These commands save the values in the global configuration file, ~/.gitconfig:

2. Generate a new shh key pair on your machine, then upload the public key to Github

I followed these instructions, creating an ssh key locally, with a passphrase that I stored in my Keepass database.

3. ssh-agent stuff

In the bashrc included in this repo is some code that handles your ssh-agent. I got it from this section of the Arch Linux wiki. Here's the bash code if you need:

if ! pgrep -u "$USER" ssh-agent > /dev/null; then
    ssh-agent -t 1h > "$XDG_RUNTIME_DIR/ssh-agent.env"
if [[ ! "$SSH_AUTH_SOCK" ]]; then
    source "$XDG_RUNTIME_DIR/ssh-agent.env" >/dev/null

It was once this:

if ! pgrep -u "$USER" ssh-agent > /dev/null; then
    ssh-agent > ~/.ssh-agent-thing
if [[ "$SSH_AGENT_PID" == "" ]]; then
    eval "$(<~/.ssh-agent-thing)"

4. ssh config

touch ~/.ssh/config and in that file write AddKeysToAgent yes, as per the Arch wiki entry.

Given this setup, you're going to want to use the ssh URL ( when cloning down repos from GitHub (as opposed to HTTPS).

Notes/alternative approaches

Alternatively, you could try storing ssh key in KeePassXC database, but I haven't had luck with that in the past.

GitHub blog with Jekyll

  1. Be sure rbenv is set up and a modern version of Ruby is set to global.
  2. gem install jekyll bundler
  3. git clone
  4. cd into the repo
  5. bundle exec install
  • To publish changes: commit changes, then run bundle exec jekyll build, then git push origin master


Some System-Level Basics (Gnome)

  1. In settings > "Mouse and Track Pad", put "Mouse Speed" about in the dead center and turn off "Natural Scrolling"
  2. In Gnome Keyboard settings, change "Switch windows of an application" OR "Switch windows of an app directly" to "Super + Escape"
  • You may also want to remap commands like "View split on left" and "Move one monitor left", as well as the Workspace commands
  1. Download the Gnome Tweaks Tool via the Pop app store. In Tweaks:
  • Remap Caps Lock to Control in "Keyboard & Mouse" > "Additional Layout Options".
  • Suggested: Change "Mouse" "Acceleration Profile" to "Flat"
  1. Change your desktop background!

  2. Disable blinking cursor in gnome-terminal: In terminal: gsettings set org.gnome.desktop.interface cursor-blink false

Gnome-terminal profile

Head over to my linux-config repo to load my Gnome terminal profile.

If there's a problem, dconf dump /org/gnome/terminal/legacy/profiles:/ might be helpful, as it lists the profiles loaded on your system.

Changing Default Fonts

Weirdly the only place I could find this is in Gnome Tweak Tool (which I think I installed via the GUI Pop software store). Here are the defaults and what I changed them to:

  - Window title: Fira Sans SemiBold 10 --> Noto Sans CJK KR Bold 10
  - Interface: Fira Sans Book 10        --> Noto Sans CJK KR Regular 10
  - Document: Roboto Slab Regular 11    --> IBM Plex Sans Regular 11
  - Monospace: Fira Mono Regular 11     --> Deja Vu Sans Mono Book 11

You can download IBM Plex here.

KDE Setup and Troubleshooting

Basically, if you go with the Kubuntu "Minimal Install", configure KDE with your heart.

Keyboard Stuff

In "Systems Settings", under Hardware, click "Input Devices". Make sure you're on the "Keyboard" section (you should see a menu titled "Keyboard Hardware and Layout"). Go to the "Advanced" tab. In this tab...

  1. Under "Caps Lock behavior", check "Caps Lock is also a Ctrl"
  2. Under "Position of Compose key", I like "Right Win" (aka Right Meta or Right Apple Command). This means you can insert special characters like an em dash (hold right meta/mac/win key and press the hyphen key three times). More info about the Compose Key here and here and here. (An alternative method: Under "Key to choose the 3rd level" check "Right Alt; Shift+Right Alt as Compose". This allows you to insert an em dash by holding Right Alt + Shift and then inserting three hyphens in a row.)

KDE Troubleshooting

Everything looks big!

If, after installing the proper NVIDIA drivers and restarting the machine, everything looks big, go to Fonts settings menu and "Force" the DPI to 96.

If external monitors aren't being recognized by your laptop

If external monitors aren't being recognized by your laptop, try opening "NVIDIA X Server Settings", then select "X Server Display Configuration" from the menu you on the left. Try clicking "Detect Displays".

If the external monitor appears in the layout, it may just be "disabled". If that's the case, go to the drop-down menu on the right side of the window labeled "Configuration" and try choosing "X screen 0".

An AskUbuntu question about this issue

Are your drivers up-to-date?

If your machine isn't recognizing an external monitor, another possible issue may be that you need to upgrade your NVIDIA to match your current Linux kernel. For example, at one point I needed to upgrade to 515 by running sudo apt install nvidia-driver-515. How could I have known I needed to do this? A helpful Mattermost users writes:

From the apt upgrade output, it probably said something about the Nvidia DKMS module not working with the 6.0.2 kernel. From there you'd have to know to try other Nvidia driver versions. Also we just released some updates that should make this not happen as much. It's definitely not ideal for this to happen.

More broadly, I think you need to use NVIDIA drivers (rather the FOSS ones) to use an external monitor with my Oryx Pro. I think.


Redshift + Xorg + KDE

If you're running KDE and Xorg, you'll likely need to use Redshift to tint your screen at night. "Redshift Control" is a KDE widget that gives you a nice GUI to configure Redshift (found by searching the "Get new widgets" interface).

I also found (in this video) what might be the command line way to install both redshift and the plasma widget:

sudo apt install redshift plasma-applet-redshift-control

Although elsewhere I've seen an additional program recommended:

sudo apt-get install plasma-widget-redshift plasma-applet-redshift-control

Configuring Redshift in Plasma

First, I'd recommend moving the widget to the task bar. Then, to configure it, simply right-click the widget and click configure. Hit "Locate" to automatically locate your position. Then for temperature 6500 for Day and 3250 for Night seems to work well.


For gtk-based desktop environments like GNOME, you're probably going to want to run sudo apt-get install redshift redshift-gtk

Installing TLP for Battery Management

If you're using a laptop and want to conserve battery smarter, you can install a power manager called TLP.



Rsync is a nifty back-up CLI tool. I likely installed it with sudo apt install rsync.

Handy Bash function

Throw this in your ~/.bashrc:

function rsync_all {
  if [ -d /media/sschlinkert/Seagate\ 4TB ]
    echo "External hard drive is mounted"
    echo "Running a couple rsync commands:"
    echo "Syncing keepass-databases..."
    rsync -arAX /home/sschlinkert/keepass-databases '/media/sschlinkert/Seagate 4TB/back-ups-rsync/'
    echo "Syncing pgp data..."
    rsync -arAX /home/sschlinkert/pgp '/media/sschlinkert/Seagate 4TB/back-ups-rsync/'
    echo "Syncing Documents, with --delete flag"
    rsync -arAX --delete /home/sschlinkert/Documents '/media/sschlinkert/Seagate 4TB/back-ups-rsync/'
    echo "Syncing code, with --delete flag"
    rsync -arAX --delete /home/sschlinkert/code '/media/sschlinkert/Seagate 4TB/back-ups-rsync/'
    echo "All done running rsync"
    echo "Could not find Seagate 4 TB. It may not be mounted"

Using restic to back up files

Here's the official user's guide from restic, which I found pretty helpful. Since I'm just putting backups onto USB devices, I only need to follow the instructions for a "local" back up.

Installing restic on Ubuntu

sudo apt install restic

Let's check the version really quick:

restic version prints restic 0.9.6 compiled with go1.12.12 on linux/amd64. A little outdated -- 0.12.1 is on Github as I write this -- but it'll do.

Getting set up with restic

Now let's do some backing up!

First, let's try to gain a bare-bones conceptual understanding of how Restic works. Restic has a concept called "repositories", which is where your backup(s) will live. From the docs:

The place where your backups will be saved is called a “repository”. This chapter explains how to create (“init”) such a repository. The repository can be stored locally, or on some remote server or service.

Basically we use restic to pull data into these backup repositories. So for me, my repository (singular for now) will be on my external hard drive.

Initializing a Restic repository

OK, let's initialize one of these repositories. On my external hard drive, I ran:

mkdir /media/sschlinkert/external_harddrive/restic-repo
restic init --repo /media/sschlinkert/external_harddrive/restic-repo

Restic now asks us to create a password for this back-up "repo" (restic uses encryption). We'll be asked to enter the new password as second time to confirm.

Doing our first backup

Finally, time to back-up some data. Following the docs, I composed this command using the backup subcommand to backup my entire home/ directory:

restic -r /media/sschlinkert/external_harddrive/restic-repo --verbose backup /home/sschlinkert/

We will do subsequent snapshots by running the exact same command at later times. In other words this is the command you'd run every night or week to keep the backup up-to-date.

Ensure a snapshot was created

We can do a quick check to see our first snapshot by running:

restic -r /media/sschlinkert/external_harddrive/restic-repo snapshots

Check integrity of that snapshot

One thing that's nice about restic is that you can check the state or "health" of the backup.

restic -r /media/sschlinkert/external_harddrive/restic-repo check

which should output a block of text that should end with: no errors were found. Awesome!

Now try restoring our data!

Now let's say something bad has happened and we need to restore our files from this back-up repo.

Our files aren't exactly just sitting in a directory, as they are when using a tool like rsync. (This is a bit of a downside for restic, but it's fine.) Instead, we have to use restic's restore subcommand.

First, we copy the snapshot id of the snapshot we want to restore from from that snapshot command. Then we'll make a new directory to restore to, and restore to it using restic's restore subcommand:

mkdir ~/Documents_restored
restic -r /media/sschlinkert/external_harddrive/restic-repo restore 37769142 --target ~/Documents_restored

This'll take a while, but when it's done our data should be restored to the location we specified, ~/Documents_restored. At that point, we can do a sanity-check with:

ls ~/Documents_restored

Decent list of excludes for a Restic backup of a home directory on Linux (Made in Dec 2021)

Save the text below in a new file as something like ~/restic-excludes.txt.

You can use it like: restic -r '/media/$USER/external_harddrive/restic-repo/' --verbose backup --exclude-caches --exclude-file=/home/$USER/restic-excludes.txt /home/sschlinkert/


A simpler approach for a small directory

I've got a small directory of very important documents. This directory is included in my restic snapshots, but I also want to put it in other locations as redundancies. One such location is Dropbox. However, I want it to encrypt it before I upload it to Dropbox.

Step 1: Compressing with tar

It's a directory (rather than a single file), so the first thing I'm going to do is put it in a tar ball.

tar -czvf important_documents.tar.gz important_documents/

Running this command creates important_documents.tar.gz for us. This single, compressed file will be easier for us to encrypt. (If you need more compression, try tar -cjvf.)

Step 2: Encrypting with age

I've chosen to use an encryption tool called age to encrypt and decrypt this file. I wrote a short guide here, but this'll work for our purposes:

age -p important_documents.tar.gz > important_documents.tar.gz.age

Enter a new passphrase twice. Age will create an encrypted file called important_documents.tar.gz.age.

We can safely upload this important_documents.tar.gz.age file to Dropbox or another unencrypted cloud provider (I do this through the website, but I'm sure there's a way to do it through the command line...).

Step 3: Decrypting and decompressing

We of course need to be able to restore these files. First we decrypt:

age -d important_documents.tar.gz.age > important_documents.tar.gz

Enter your passphrase to decrypt to important_documents.tar.gz. Then we extract the files from the tar ball:

tar -xzvf important_documents.tar.gz

All together (one-liners)

I think these work.

# compress and encrypt
tar -czv important_documents/ | age -p > important_documents.tar.gz.age
# decrypt and extract
age -d important_documents.tar.gz.age | tar -xzv

Couldn't we just make this a shell script?

I attempted to wed all these commands into a handy shell script called Bottle, if you want to try that.

Using symmetrical GPG encryption

If you don't want to use age (it's new), you can use gpg.


gpg -c important_documents.tar.gz


gpg --output important_documents.tar.gz --decrypt important_documents.tar.gz.gpg

Images and Video

For editing RAW photos, try Darktable of DigiKam(?). Here are some free film emulators for DarkTable.

For viewing video files, there's always trusty VLC, which is available as a snap: sudo snap install vlc

There's also GIMP and, for editing video, Kdenlive.


Go is a ~2,500-year-old abstract strategy board game that you might play or want to play. I got into it after watching the AlphaGo documentary (currently on Netflix).

If you just want to play Go on your desktop, an easy way to do it is in your browser through an online server like OGS. On iOS I like SmartGo. See more Go resources at the bottom of this page. But the bulk of this page is dedicated to playing Go through a desktop app called Sabaki.


For an all-in-one training software solution, I strongly recommend Katrain. You'll probably need pipx or pip3 to install it, and I've yet to get the audio to work on Ubuntu, but otherwise it's great.

Sabaki, a desktop Go app for Linux

A good desktop app that works for Linux is Sabaki (GitHub repo). To install it, I went with the x64 AppImage, probably from the GitHub Releases tab).

In Sabaki you can play against yourself or load and go through SGF files. But you can also "attach" a number of "game engines" to Sabaki to either play against or have analyze games. You can manage the engines available to Sabaki by going to "Engines" > "Manage Engines".

Setting up the GNU Go engine

GNU Go is an engine that's nice in that it can (a) play on multiple board sizes out of the box, and (b) has multiple levels to choose from (1 through 10 or 1 through 9, I'm not sure).

Installing GNU Go on Ubuntu

Go to the Download page and download the source code to the latest version of GNU Go. It's likely to be a tar.gz file. Once downloaded, expand it.

Inside that directory, there should be a README and an INSTALL documentation text file for you. But basically, to make the executable for a specific level, I'm pretty sure you run:

./configure --enable-level=4; make

To build a level 4 binary. (There are plenty of other options explained in one of the documentation text files.) This binary will be created and placed at ./interface/gnugo. Cool.

Now in Sabaki, go to Engines > Manage Engines and click the "Add" button. For path, enter path/to/interface/gnugo, and then for "arguments" I'm pretty sure you want to put --mode gtp. Leave "Initial commands" blank. Note that after Adding an engine, you may need to restart Sabaki to use it.

To build/attach multiple levels of GNU Go, I just duplicated the entire gnudo directory and rebuilt with the level I want. So in go-engines I've got:


each of which have their own executables at interface/gnugo to attach in Sabaki. For example, my engine named "GNUGo_lvl_3" has a path of go-engines/gnugo-3.8-lvl3/interface/gnugo ("arguments" for all of them are (still) --mode gtp).


Pachi is a pretty strong engine, but that, unlike LeelaZero, can play smaller board sizes out-of-the-box, so to speak. The developers note:

The default engine plays by Chinese rules and should be about 7d KGS strength on 9x9. On 19x19 it can hold a solid KGS 2d rank on modest hardware (Raspberry Pi, dcnn) or faster machine (e.g. six-way Intel i7) without dcnn.

Install Pachi via pre-compiled binary

To install Pachi via pre-compiled binary, head over to GitHub Releases page and download the latest Extract this.

Connecting Pachi to Sabaki

I didn't change any configurations.

Then in Sabaki, I just entered the path to the pachi-12.40-amd64 file in the unzipped directory, with no arguments or initial commands, and it seems to work. However, as I installed it, it can only do analysis on 19x19 boards I think?

Compiling Pachi from Source

I haven't tried this, but the Pachi README says it might improve performance to build it from source. Instructions here.

Setting up LeelaZero (Ubuntu)

  1. Download and install Sabaki. Make sure it runs before proceeding.
  2. Build LeelaZero from source
  3. Get a "network hash file" for LeelaZero, "likely the best network is the one you want". Download it here or find more instructions here.
  4. In Sabaki, go to Engines > Manage Engines. Enter the absolute file path to the leelaz binary file you just built, which is probably at something like leela-zero/build/leelaz. For "Arguments", enter --gtp -w path/to/weightsfile (which I think is the "network hash file"?)
  5. Restart Sabaki
  6. Find the Game Info menu item. For White, in the drop-down menu, select Leela Zero. Make sure you choose a 19 by 19 board. And you're probably going to want a large handicap.


KataGo is another new engine. I think I like it best of these options since it works on smaller board sizes and, apparently, it works well with handicaps.

To run it on Linux (or Windows), I think you want to download the appropriate binary from the GitHub release page. On my System76 Oryx Pro, I apparently prefer the version. And you also need one of the "block network" files, which I think are called "models". These files end in bin.gz or txt.gz. I think I've chosen the "40 block network" before, though I don't fully understand what that number means.

Next, you may want to have the binary create a config file tuned to your computer. From the README's "How to Use" section:

"To automatically tune threads and other settings for you based on asking simple questions, and generate a GTP config for you: ./katago genconfig -model <NEURALNET>.gz -output <PATH_TO_SAVE_GTP_CONFIG>.cfg"

Answer the questions as you like. It'll create a fresh text config file that we'll point Sabaki to (see below).

At some point, you'll want to run something like chmod a+x ./katago.

Settings for KataGo for Sabaki

gtp -model '/home/sschlinkert/code/go-engines/katago-v1.3.5-opencl-linux-x64/g170-b30c320x2-s2846858752-d829865719.bin.gz' -config '/home/sschlinkert/code/go-engines/katago-v1.3.5-opencl-linux-x64/my_oryx_pro_config.cfg'

and no "initial commands"

Note that you may need to run chmod a+x on the executable before it'll work.

How to play against a game engine in Sabaki

To play against one of these engines, open Sabaki. Be sure you're on a blank, new game. Then go to "File" > "Game Info". If you want Balck, make the engine take Whtie by clicking the down arrow next to "White" and selecting the engine you want to play. Fill out the other fields as desired, then hit the OK button. If you're Black, place a stone to start the game, and the engine should respond. To see what the engine is doing, go to "Engines" > "Toggle GTP console".

Alternatively you can manually attach an engine by going to Engines > "Attach".

To prevent engines from making moves right when you initially attach them (which can be annoying if you just want to use the engine to analyze possible moves [see below]), I would go to File > Preferences and uncheck "Start game right after attaching engines". The con to this is that to start playing a game against an engine, you have to first attach it ("Engines" > "Attach"), then (sometimes) tell it to start playing ("Engines" > "Start Playing").

Using a game engine to do analysis of a game in Sabaki

Some of these engines -- like LeelaZero and Pachi -- allow you to analyze next moves (though usually only on 19x19 games it seems?). To do this:

  1. "Engines" > "Toggle Analysis" gives you a heat map of what the engine likes for the next move. Leela will do both show the analysis of its moves as well as provide analysis for your move (you can accept by clicking on the green blob, or move somewhere else)
  2. With "Analysis" toggled on, you can also hover a piece over a space and the engine will play out the game from there, if you were to move there.

If the GPU load gets to be too much, you can always make the engine suspend by going to "Engines" > "Suspend". Toggling Analysis off will help too, as the engine won't think during your move.

Appendix: Go resources

If you're here and want to learn more about Go, I've pasted some of my notes on general Go resources below.

Learning the rules

To learn how to play Go, I'd recommend watching YouTube videos (links below), but obviously there are other ways.

Actually playing games

  • On desktop web: I like for actually playing Go games online. You can play both other humans and a variety of bots with different skill levels.
    • If you don't want to be bothered to create an account, there's this site, though it doesn't offer handicaps on smaller boards like 9 by 9, so you're probably going to lose way more than half the time.
  • On iOS: As mentioned, I've found this $2.99 app called SmartGo nice for beginners like me. If you ask, it'll estimate the score for you and even suggest a move for you. If that's not challenging enough, A Master of Go is an expensive iOS app that features high-end AI software.
  • On your desktop, you can install Sabaki and a number of Go engines to play against.
  • There are more software options listed here.


If you're don't want to play full games, you can find apps and websites that provide small exercises or puzzles to play through.

  • The iOS app SmartGo that I've mentioned above has a tutorial of live exercises somewhere in the menus.
  • has a "playlist" of puzzles for beginners, though I found them a bit too difficult?

More English-language YouTube channels


I'm not sure if you need a book or books to learn, but obviously there are plenty out there. In my cursory search of posts on r/baduk, I found and bought three popular options for beginners. I've read at least half of them, and I'd recommend reading them in this order:

  1. Learn to Play Go by Janice Kim would probably work for brand new players.
  2. Go for Beginners by Kaoru Iwamoto seems like a classic intro text.
  3. Lessons in the Fundamentals of Go by Toshiro Kageyama is still a bit advanced for me.

A curated list of command-line tools written in Rust

(This list is also available on GitHub, where it'll likely be updated more regularly.)

Note that I have not tried all of these personally, and cannot and do not vouch for all of the tools listed here. In most cases, the descriptions here are copied directly from their code repos. Some may have been abandoned. Investigate before installing/using.

The ones I use regularly include: bat, dust, fd, fend, hyperfine, miniserve, ripgrep, just, cargo-audit and cargo-wipe.

  • atuin: "Magical shell history"
  • bandwhich: Terminal bandwidth utilization tool
  • bat: A replacement for cat that provides syntax highlighting and other features.
  • bottom: Yet another cross-platform graphical process/system monitor.
  • broot: A new way to see and navigate directory trees
  • choose: A human-friendly and fast alternative to cut and (sometimes) awk
  • counts: "A tool for ad hoc profiling"
  • delta: A syntax-highlighting pager for git, diff, and grep output
  • difftastic: A syntax-aware diff
  • dog: A command-line DNS client
  • dua: "View disk space usage and delete unwanted data, fast."
  • dust: "a more intuitive version of du in Rust"
  • exa: "A modern version of ls"
  • fclones: an "efficient duplicate file finder"
  • fd: "A simple, fast and user-friendly alternative to find"
  • felix: tui file manager with vim-like key mapping
  • ffsend: "Easily and securely share files from the command line. A fully featured Firefox Send client."
  • frum: A modern Ruby version manager written in Rust
  • fselect: "Find files with SQL-like queries"
  • git-cliff: "A highly customizable Changelog Generator that follows Conventional Commit specifications"
  • gptman: "A GPT manager that allows you to copy partitions from one disk to another and more"
  • grex: A command-line tool and library for generating regular expressions from user-provided test cases
  • himalaya: Command-line interface for email management
  • htmlq: Like jq, but for HTML. Uses CSS selectors to extract bits of content from HTML files.
  • hyperfine: Command-line benchmarking tool
  • inlyne: "GPU powered yet browsless tool to help you quickly view markdown files"
  • jless: "command-line JSON viewer designed for reading, exploring, and searching through JSON data."
  • jql: A JSON query language CLI tool
  • just: Just a command runner (seems like an alternative to make)
  • legdur: A "simple CLI program to compute hashes of large sets of files in large directory structures and compare them with a previous snapshot."
  • lemmeknow: Identify mysterious text or analyze hard-coded strings from captured network packets, malwares, and more.
  • lfs: A Linux utility to get information on filesystems; like df but better
  • lsd: The next generation ls command (though personally I prefer exa)
  • macchina: Fast, minimal and customizable system information frontend.
  • mdBook: Create books from markdown files. Like Gitbook but implemented in Rust
  • mdcat: Fancy cat for Markdown
  • miniserve is "a CLI tool to serve files and dirs over HTTP". I use this as a replacement for python -m SimpleHTTPServer, or whatever the latest version of that command is.
  • monolith: Save complete web pages as a single HTML file
  • ouch: "Painless compression and decompression for your terminal"
  • pastel: A command-line tool to generate, analyze, convert and manipulate colors.
  • pipr: "A tool to interactively write shell pipelines."
  • procs: A modern replacement for ps written in Rust
  • qsv: CSVs sliced, diced & analyzed. (A fork of xsv)
  • rargs: xargs + awk with pattern matching support.
  • rip: A safe and ergonomic alternative to rm
  • ripgrep: A faster replacement for GNU’s grep command. This tool is very good. See ripgrep-all to search PDFs, E-Books, Office documents, zip, tar.gz, etc.
  • ripsecrets: Find secret keys in your code before commiting them to git. I've contributed to this one!
  • rnr: "A command-line tool to batch rename files and directories"
  • sd: Intuitive find & replace CLI (sed alternative).
  • skim: A command-line fuzzy finder.
  • tealdear: A very fast implementation of tldr in Rust.
  • teehee: "A modal terminal hex editor"
  • tin-summer: Find build artifacts that are taking up disk space
  • tokei: Count your (lines of) code, quickly
  • topgrade: Upgrade all of your tools
  • watchexec: Execute commands in response to file modifications. (Note: See cargo watch if you want to watch a Rust project.)
  • xcp: An extended cp
  • xh: "Friendly and fast tool for sending HTTP requests"
  • xsv: A fast CSV command line toolkit written in Rust. (Last updated in 2018)
  • zoxide: A smarter cd command.


  • eva: "a calculator REPL, similar to bc(1)"
  • fend: "Arbitrary-precision unit-aware calculator" (Documentation). I prefer this calculator.
  • Kalker: "a calculator with math syntax that supports user-defined variables and functions, complex numbers, and estimation of derivatives and integrals"
  • printfn: "Arbitrary-precision unit-aware calculator"

Tools to help working with Rust lang itself

  • bacon: A background Rust code checker
  • cargo watch: Watches over your Cargo project's source.
  • cargo-audit: Audit Cargo.lock files for crates with security vulnerabilities reported to the RustSec Advisory Database. See also: cargo-deny.
  • cargo-binstall: "Binary installation for [R]ust projects"
  • cargo-crev: A cryptographically verifiable code review system for the cargo (Rust) package manager.
  • cargo-dist: "shippable application packaging for Rust"
  • cargo-geiger: Detects usage of unsafe Rust in a Rust crate and its dependencies.
  • cargo-wipe: Cargo subcommand that recursively finds and optionally wipes all "target" or "node_modules" folders that are found in the current path. See also: kondo.
  • kani-verifier: A "bit-precise model checker for Rust."
  • Alacritty: A cross-platform, OpenGL terminal emulator.
  • Wezterm: A GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust
  • Starship: Customizable prompt for any shell.
  • Zellij: A terminal workspace with batteries included.

Text editors written in Rust

See this "Battle of the [Rust] text editors" post from 2022.

Email clients

  • himalaya: "Command-line interface for email management"

Other lists of Rust command line utilities


exa aliases I use in my ~/.bashrc

if hash exa 2>/dev/null; then
    alias ls='exa'
    alias l='exa -l --all --group-directories-first --git'
    alias ll='exa -l --all --all --group-directories-first --git'
    alias lt='exa -T --git-ignore --level=2 --group-directories-first'
    alias llt='exa -lT --git-ignore --level=2 --group-directories-first'
    alias lT='exa -T --git-ignore --level=4 --group-directories-first'
    alias l='ls -lah'
    alias ll='ls -alF'
    alias la='ls -A'

Shameless plug: Tools that I've written in Rust

  • Tidy: A command-line tool for combining and cleaning large word list files.
  • Medic: Check the "health" of passwords in a KeePass database

Know a good one that I don't have listed here?

Let me know in the comments, a PR, on Mastodon or Twitter.

cargo-dist tips

Sam's notes on using cargo-dist

Some notes on cargo-dist v0.4.2; following this documentation


  1. Make sure the repository variable is specified in your Cargo.toml. It takes the URL of your GitHub repo (repository = ""). You should probably also specifiy a license or license-file (but not both), and the location of the readme file. (See here for more things to specify:
  2. Install or update cargo-dist with something like cargo install cargo-dist
  3. Run a git push --tags to push any and all local tags you've created up to GitHub. If any local tags are rejected for already existing on GitHub, I recommend you just delete the local tags with git tag --delete <tag_name>.

Initializing cargo dist

  1. In your Rust project's directory, run cargo dist init. This launches a lil interactive install guide. Be sure to enable the GitHub CI; and you probably want the SHELL installer, which I'm not sure is enabled by default?
  2. This will create a new file at .github/workflows/release.yml, which tells GitHub what magic to do later, and edit your Cargo.toml. Don't worry about it.
  3. Commit these changes (git add . && git commit -m "init cargo dist")

A note on that nifty cargo dist init command from the official cargo-dist docs:

[This command] should be run again whenever you want to change your settings or want to update cargo-dist.

Just to really emphasize that: cargo dist init is designed to be rerun over and over, and will preserve your settings while handling any necessary updates and migrations. Always Be Initing.

Getting ready to create a release (testing builds)

Let's see if your code is going to make for a non-broken release.

First, run cargo dist build to try building for the platform (OS) you're currently using. cargo-dist will print the version it assume you want to release, plus paths to the files it created, so you can inspect their contents.

If that's all good, next try cargo dist plan. This too will print the version of the project it assumes you want to release -- check that it's right. Further info:

The plan command should be running the exact same logic that cargo-dist's generated CI will run, but without actually building anything. This lets you quickly check what cutting a new release will produce. It will also try to catch any inconsistencies that could make the CI error out.

Note that:

As of cargo-dist 0.3.0, we now by default run the "plan" step of your release CI on every pull-request so that we can catch breakage to your release process as early as possible. This will work even for a pull-request that sets up cargo-dist for the first time, so you can be confident you're landing something that works.

Basically, now for every PR to your project, GitHub will run part of this cargo dist plan command for you before you merge, to see if building goes well. I don't really know what happens if this build process fails... hopefully it doesn't get in the way of any troubleshooting.

Create a new release!

  1. Get your main branch into a good, working place. Commit changes, at least locally.
  2. Run cargo test, etc. as well as the tests described above (cargo dist build and cargo dist plan).
  3. Increment that version in Cargo.toml to a new highest version. Let's say we're going from v0.3.8 to v0.3.9.
  4. Optional: Add release notes to a file called, under a heading like ## Version 0.3.9, which Cargo Dist will auto-detect.
  5. Run another cargo build to make sure Cargo.lock is up-to-date.
  6. Commit changes -- message can be something like "Release v0.3.9" -- and git push origin main
  7. Create a git tag for this release. Match the version number to the one in Cargo.toml. So in our case: git tag v0.3.9. (Obviously make sure this tag has not been seen by git or GitHub before.)
  8. Push your tags to GitHub: git push --tags

At this point you're done! The generated CI script should pick up the ball and create a Github Release with all your builds over the next few minutes!

(FYI This is the point where you'd run cargo publish to push to, if your project is hosted there.)

Upgrading cargo-dist itself

If and when you upgrade cargo-dist (using cargo install cargo-dist), you'll need to take some steps within the project that you use cargo-dist to distribute.

New way of doing this (as of cargo-dist v0.7.0)

Just run cargo dist init, as per these cargo-dist docs.

My old notes on how to do this

  1. In your project's Cargo.toml file, edit the cargo-dist-version variable to match the version of cargo-dist you now have installed on your system.
  2. Re-run cargo dist init. (You may also need to run cargo dist generate afterward for changes to take affect.)
  3. Try cargo dist built and cargo dist plan, as usual, to see if everything is in working order.

Suggested Markdown to add to README of project that uses cargo-dist

## For developers: How to create a release

This project uses [cargo-dist]( to create releases. 

Some of [my personal docs are here](; but basically, `cargo install cargo-dist`. When you're ready to cut a new release, test the current state of the project with `cargo dist build` and `cargo dist plan`. If that went well, create a new git tag that matches the current project version in `Cargo.toml` with `git tag vX.X.X`. Finally, run `git push --tags` to kick off the release process. GitHub will handle it from here -- check your project's GitHub Releases page in about 5 to 10 minutes.

Installing Ubuntu on my 2009 MacBook Pro

I had an old 17-inch MacBook Pro from 2009 (college) lying around and I figured it'd be a fun challenge to install Linux on it. I had never installed or even used Linux before (to my knowledge). I also, confusingly, hadn't found a clean, step-by-step guide for doing this, so I promised I'd write my process out as thoroughly but simply as I could once I got it done.

I now realize, I think, that the reason the process of installing even a popular Linux distribution on a common (if old) model computer isn't written out or easily findable is that the process is a bit different for everyone, depending on the distro, the version, and the hardware you're starting with. Note that I didn't want to partition my hard drive to allow myself to dual-boot either in OS X or Ubuntu-- I was going for a full replacement, and thus would and did lose all the files on applications I had on the old Mac.

But regardless, here is the process I took.

About This Mac

Model name: MacBook Pro
Model Identifier: MacBookPro3,1
Processor Name: Intel Core 2 Duo
Processor Speed: 2.4GHz
Number of Processors: 1
Total number of cores: 2
L2 Cache: 4 MB
Memory: 2GB
Boot ROM Version: MBP31.0070.B07

It's a 17 inch screen. I believe I bought it in the summer of 2009.

was running:
OS X 10.9.2 (13C64)

How I Got Ubuntu 16 Installed

Again, note, this worked for me and my machine but may not for you. For example I believe I had to do steps 4, 5, 8, 9, 10, and 11 only because I have a MBP with an Intel chip.

Also, WARNING, this procedure completely wiped my OS X and all the files and applications on that installation, as I intended. There are ways to dual-boot both, but I wasn't interested in that as Mavericks was running super slow on this computer. Furthermore I think all the data I had on my USB stick is lost due to it being formatted in a certain way at some point in the procedure.

UPDATE (February 2017): Before moving ahead, you may want to consider the following. A helpful commenter, Brian Moran, writes that, when installing Ubuntu on an older Mac with a NVIDIA graphics card, it may be better to "boot in 'Legacy BIOS mode', not in 'EFI' mode":

Apparently what is happening is that both the open source and Nvidia drivers are buggy when doing an "EFI Install" on Mac machines. If full graphics performance is desired, a "Legacy BIOS Install" is needed.

From the forum post that the commenter cites, which is concerned with a MacBook Air 3,2:

The core problem with the [generic] installation is this. The graphic driver that Ubuntu installs by default (Nouveau) has bugs with the MacBook Air 3 graphic processor, the nvidia GeForce 320M (G320M). You can do a default install, it will boot normally, but you'll soon see little glitches here and there and the computer will normally crash after a few minutes of use (especially when transparency or shadow effects are used, it seems). The problem exists with Raring and I expect it arises with Precise (though see ''alternative solutions" below).

To avoid that, you need to install the proprietary nvidia driver. But here is the catch: the driver requires the computer to boot in "Legacy BIOS mode", not in "EFI" mode (see here or here). If you install the nvidia drivers while Ubuntu is in EFI mode, you'll get a blank/black screen at the beginning of the boot. (If you got to that stage, see the ''recovery for nvidia drivers EFI crash'' below). On a PC you can force Ubuntu to install in BIOS Legacy mode by selecting that mode in the computer BIOS. But on a Mac you can't (easily) do that, and if you install from a USB key by default you will be in EFI mode.

So summing up, if you do a default installation of Ubuntu from a USB on a MacBook Air 3,1 or 3,2, you'll either have buggy graphics and random crashes, or you'll install the nvdida drivers and have a blank/black screen at startup.

For the record, I followed the procedure detailed below with my MackBook Pro 3,1 and while I now believe that my nvidia card is NOT being used, basic computing (web browser, document editing coding, simple games) are working just fine. Not being a gamer I don't know much about graphics cards, but for what it's worth I believe my MacBook Pro has a G84M [GeForce 8600M GT] card, which is not the same model listed in the forum post the commenter cites.

But if I were starting over I might instead consider the procedure outlined in the forum post the commenter links to in hopes of even better performance. End of February 2017 update.

Alright, with all that said here's what I think I would do if I were starting fresh, knowing what I know now:

What I Did to Install Ubuntu

  1. Get a USB drive with at least 2 GB of storage. Know that it's going to get wiped, so move important files off it first. Then use the MacOS Disk Utility to format the USB stick as DOS FAT32.
  2. I'd follow this guide to download Ubuntu 16.04 LTS and get it onto the USB stick, using UNetbootin.
  3. As described in the final step in that guide, when you restart, hold down the option key on your Mac. In the resulting menu, select the "EFI" device as the device to boot from.
  4. You'll be confronted with a text-only menu that's from a piece of software called GNU GRUB. Key down so your cursor is on "Install Ubuntu", but instead of pressing enter, press e to edit the commands before booting.
  5. This opens an options file in a basic text editor. Find the line that has ro quiet splash in it and make that bit of the line read ro nomodeset quiet splash. Then press either F10 or Ctrl-X to boot (read the text at the bottom of the screen to be sure of the key(s) to press).
  6. If presented with a choice in GRUB (a text menu) with an option to install Ubuntu, choose that option.
  7. You should be then presented with a nice GUI (not text only) Ubuntu installer, or maybe an icon that says Install Ubuntu. Double click the icon if you see it. Go through everything, decide whether or not to connect your Wifi to download updates, decide whether or not to encrypt your home folder, and then choose restart.
  8. We now need to boot Ubuntu in recovery mode. To do this, as the computer is starting up again after restart, right after you hear the Apple/Mac start-up sound, hold the SHIFT key. Repeat step #3 above if you're presented with the EFI option. Once you're at a text-only menu, press e and add nomodeset to the line of code discussed above. Then press the key(s) to boot. Ubuntu should boot up-- though the display may be screwy. In either case, we're not done yet.
  9. Now we need to make that nomodeset setting permanent. Open terminal (ctrl+option+t) and run sudo nano /etc/default/grub. (Reference)
  10. In that file, add nomodeset to GRUB_CMDLINE_LINUX_DEFAULT as seen below:
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nomodeset"
  1. Save this text file by hitting Ctrl+O, then exit nano with Ctrl+X, then, back in Terminal, run: sudo update-grub
  2. Restart the computer (the menu for which is in the top-right corner of Ubuntu 16).

I think that would do it. I don't think I needed rEFInd. And apparently the warning on UNetbootin that I could run the device on Macs was not accurate.

For completeness sake, here is the actual process I went through over three days.

Attempt #1: Ubuntu 16.04

I found this guide which involved downloading and using the UNetbootin USB installer.

I believe I successfully downloaded the Ubuntu 16.04 ISO and UNetbootin. I then installed UNetbootin (by dragging it into Application) and then I used UNetbootin as described in the tutorial. However at step 7 when I restarted my Mac and held the option key I was presented with a menu to try or install Ubuntu. Every time I selected "install" it just went to a black screen. I waited minutes but no installation screen appeared. I then held down the power button and the computer rebooted in OS X, back to square one.

I will say that after using UNetbootin to load the USB stick the program warned the device could only boot the new OS on PCs, not on Macs. I chose to ignore that warning and try anyway, but as I reported above, it didn't work.

Upon further research I believe the Ubuntu 16.04 may not work on Intel-based MBPs made circa 2009. One page,, seemed to encourage those with MBPs this old should instead opt for Ubuntu 14.04.

I didn't want to run an old version of a distro I wasn't particualrly excited about if I could find a distro that I could run the lastest version of. Plus I couldn't quite figure out how to download an (official) copy of version 14.04.

Attempt #2: Mint 18 ("Sarah") Cinnamon 64-bit

I understand that the other distro well-reviewed for beginners is Mint. And I saw that Mint 18 was itself got good reviews.

So I headed over to their download page and chose "Cinnamon 64-bit" and downloaded it via a torrent.

The only tutorial that I found for installing Linux Mint via USB seemed strange and brief. Thus my current plan is to try to use UNetbootin again, following the Ubuntu guide but with Mint this time rather than Ubuntu 16.04.

However, as before, after using UNetbootin it told me the device could only boot the new OS on PCs, not on Macs.

When I restarted my Mac and held down the option key, I got a similar menu as when I tried Ubuntu, but eventually came to a dark black screen. I waited a few minutes, and then forced the computer to shut down by holding down the power button.

Attempt #3: Back to Ubuntu 16.04 by a different method

I followed the instructions presented here, which I was optimistic about it because it avoided using UNetbootin, along with the potentially helpful warning:

UNetbootin for Mac OS X can be used to automate the process of extracting the Ubuntu ISO file to USB, and making the USB drive bootable. The resulting USB drive, however, can be booted on PCs only.

Which mirrors the warning UNetbootin gave me.

However the method described in the link above failed in the same way the others did-- I restarted, held down the option key, chose the EFI boot, chose to install Ubuntu, and then was met with a black screen. For the first time I thought to check the light on my USB stick to see if it was at least thinking but it was off.

Attempt #4: Using rEFInd Boot Manager

From here I found an article about installing Debian (a more advanced distro of Linux).

That let me to believe rEFInd was something I needed to install first.

However this program (I admittedly didn't take the time to figure out what it actually does) did not seem to help. Afterward, and before my next attempt, I bypassed rEFInd by going to System Preferences > Start Up Disk, selecting my hard drive and hitting the restart button. Thus I do not think I actually needed to install rEFInd to successfully get Ubuntu installed, however I'm not 100% of this, since the rEFInd uninstall instructions for OS X recommend bypassing rEFInd rather than actually uninstalling it.

Attempt #5: Having bypassed rEFInd, I replace quiet splash with nomodeset

Big success!

Somewhere else I remember seeing someone recommend turning on an option called nomodeset in GNU GRUB, but for some reason didn't think I had that option in the menu that I kept getting. Turns out, as described here, when you get to the GRUB menu you hit the e key. Then you add nomodeset as a parameter in one of the lines of code in the text file that opens. Removing quiet splash seems to just present more text as output-- the nomodeset solved the problem.

After maybe 40 seconds I was presented with an Ubuntu desktop and a shortcut icon to an Ubuntu installer. I double-clicked the installer and followed the wizard.

I connected to my wifi network and told it to download updates as it installed to make things quicker. The only hard choice was whether to encrypt my home folder (which I believe you can't do later). I decided not to based on this answer as I was worried about the performance hit on decrypting on a machine with 2GB memory. Then I just waited for Ubuntu 16.04.1 LTS to install.

After installation it asked me to restart. I clicked yes. I then got an ugly error message that said something like "remove the installation device and hit enter". I still had the USB stick in, unsure when I was to remove it. I pulled it out and hit enter. The computer then restarted, making the familiar Mac start-up sound and presenting the familiar Mac gray, but then it switched to a purple Ubuntu-like color and stayed there for a minute.

Setting nomodeset permanently

When I came back from that restart it was stuck on a purple screen. I figured I needed to set nomodeset permanently on. I needed to get back to the GRUB screen, which I figured out from somewhere:

  1. Switch on your computer.
  2. Wait until the BIOS has finished loading, or has almost finished. (During this time you will probably see a logo of your computer manufacturer.)
  3. Quickly press and hold the Shift key, which will bring up the GNU GRUB menu. (If you see the Ubuntu logo, you've missed the point where you can enter the GRUB menu.)

Then, to set nomodeset to be on permanently, I followed this Ask Ubuntu answer that reads:

You should add this option to /etc/default/grub, firstly:

sudo nano /etc/default/grub

and then add nomodeset to GRUB_CMDLINE_LINUX_DEFAULT:

GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nomodeset"

And then save by hitting Ctrl+O, then exit nano with Ctrl+X, then simply run:

sudo update-grub

I saved that file and ran sudo update-grub as instructed. I then restarted my computer once again and I think that's when things went smoothly for the first time.

(FYI a similar process to the one described above seems to be given here but with some other stuff as well, if you need more help at this stage.)

Initial Thoughts

Woohoo! It seems snappier that OS X 10.9, but it's not a speed demon like my 2012 MacBook Air with 8 GB of memory.

But the desktop and dock are familiar enough to me. It comes with Firefox, Libre Office, a basic text editor, and a link to in the dock that's on the left by default. I got terminal Vim and RVM running with a few Google-able tweaks from the OS X installation process. Remapping caps lock to control was one line in Terminal (setxkbmap -option caps:ctrl_modifer), however that did not persist when restarted. I followed this AskUbuntu answer and went to Startup Applications > Add > and entered setxkbmap -option caps:ctrl_modifer. It seems to persist on restart now.

I was able to install git by running sudo apt install git. Similarly I was able to install KeePassX by running sudo apt-get install keepassx (I'm not 100% in the difference between apt and apt-get here but that's what I saw on the internet help sites I found). I also installed a fresh version of vim but I forget what line I ran in terminal.

To run a general update and upgrade, I run sudo apt update && sudo apt upgrade, which seems to work.

We'll see how much I use this old computer going forward, and what for.

Update: Just found this website that aims to teach Linux for beginners, which I might checkout. There's also this series of YouTube videos: Ubuntu Beginners Guide that looks nice, is Ubuntu-specific, and is, as of this writing, only one month old.

Security Apps and Tools

Tools for moving files between computers

I have not vetted or reviewed any of these tools. I also do not condone using any of these tools for illegal activity!

Tools that use Tor

CLI tools

Cloud-based file transferring services

Also helpful

  • Dangerzone (GitHub) takes potentially dangerous PDFs, office documents, or images and converts them to safe PDFs
  • age is a new PGP alternative for encrypting/decrypting files
  • Cwtch now supports file-sharing, but the tool is, overall, still in beta as of this writing.

A GPG GUI, if you must

sudo apt install gpa installs a GUI called "GNU Privacy Assistant". You can read more about it here.

Using a PGP private key from a Smartcard on Ubuntu

I think I need to :

  1. add the key's public half a. get the .asc file onto your system. b. run gpg2 --import <file-name>.asc
  2. Plug in the card
  3. try gpg2 --card-status If that doesn't work try installing scdaemon and pcscd with sudo apt install scdaemon and then sudo apt install pcscd. You may also need to sudo apt install gpgsm
  • you may also need to kill and restart scdaemon with:
killall scdaemon
pgrep scdaemon

You can now encrypt and decrypt files with the pgp keys on your martkey using the gpg2 command line tool.


To add GUI support on Xfce, while using Thunar file manager, it looks like I'm going to need to build some Thunar custom actions, which doesn't seem ideal. Xcfe doesn't use Nautilus by default, so I doubt installing seahorse-nautilus is going to do me any good.

Using Pidgin with a Google Account, and Setting Up OTR

Note that I would no longer advise using any the tools described here. Just use Signal!

That said, I wrote out these instructions at some point so I'll leave them here for now.


Pidgin comes installed with Ubuntu 16.04. To add my existing Google Account, I followed the steps outlined in this Stack Overflow answer.

To summarize:

In Pidgin, add a new account. Set the Protocol to "Google Talk", username to your Google username, and the Domain to "".

For the password you'll need to create a dedicated app password. You can do that in your Google accounts Security > App Passwords section. When creating the new app password, set "app" to "other" and call it something like "linux pidgin"-- it doesn't matter what you call it. Optionally, if on a secure computer, tick the "Remember password" checkmark. (Warning: This will mean your new app password will be stored in plain text in ~/.purple/accounts.xml.) Leave "Resource" and "Local Alias" blank.

Installing and Enabling OTR

Once my Google account was successfully added, I installed the Pidgin-otr plugin by running sudo apt-get install pidgin-otr in terminal. To enable and setup OTR, I followed this EFF guide. That guide also describes how to install the otr plugin through the Ubuntu Software manager if you're more into GUIs (see the early steps of that EFF guide).

Further Pidgin Customizations

To display offline buddies, go to Buddies > Show > Offline Buddies. There are more preferences, like muting sounds, in Tools > Preferences.

Not sure how to disable the pop up notifications yet though.

Other DEs

Customizing Appearance of XFCE (Ubuntu)

Desktop Background

  1. Pick one (I found one I liked here).
  2. Download the image file to your Pictures folder.
  3. Go to Settings Manager > Desktop > Background. In bottom-right change Folder to Pictures and find your desired background.


I went with axiom, which I got here. To install it:

  1. I downloaded the tar file,
  2. In terminal I ran mkdir ~/.themes
  3. I then extracted two directories from the tar file called "axiom" and "axiomd", and then moved them both into the new ~/.themes directory.
  4. Go to Settings Manager > Appearance and choose either axiom or axiomd
  5. Then is Settings Manager > Window Manager > Style and select either axiom or axiomd


I went with "Papers" icons for now, which you can find download instructions for on the offical website. After running those updates, I went to Settings Manager > Appearance > Icons and selected Paper.

Login Window

Go to Settings Manager > LightDM GTK + Greeter Settings and select the theme and icon set you like. You can also change your user image or remove it all together. Unfortunately, for me, axiom was not available here, so I went with Adwaita for now.

Note: This video helped me quite a bit:


I'm going with Noto Sans for now (the actual choice says "Noto Sans CJK JP"). I selected this font in Settings Manager > Appearance > Fonts. I also selected basically every where else I encountered a choice of font in Settings.


Odds are you Panel 1 is on top of your screen, and panel 2 is the dock-like panel that I think starts at the bottom of your screen.

For customizing Panel 1, I followed some of the instructions in the first minute of this video. I set the mode to Vertical, which puts in on the left, increased transparency, and made it 48 pixels wide, and had it never hide. Then, in Items > Applications Menu I deselected "show button title" and changed the image. In Items > Window Buttons I deselected "Show button labels", selected "Show flat buttons", deselected "Show handle", and set Window grouping to always.

I'm not sure what I want out of panel 2 (the dock) yet, so I set it to be pretty small and have it hide intelligently.

Notes on i3

Good 3-video playlist that shows i3 window manager from the start:

Install i3 on Ubuntu

  1. Log in
  2. Open Terminal
  3. sudo apt-get install i3; enter passowrd
  4. log out
  5. in menu, choose i3 to be your desktop environment
  6. Press enter to generate a config file
  7. Select mod key (think we want the "windows" key)

Basic, Default Keybindings

  • open a new instance of terminal (hope it's GNOME...): mod + Enter

  • Close window: mod + shift + q

  • app launcher: mod + d

    • change it to synapse by adding this line to the i3 cofig: bindsym $mod+d exec synapse
  • new vertical window: just open a new window

  • new horizontal window: mod + v, then open a new window

    • one question is how I get out of this mode
  • move between windows in current workspace: mod + arrow keys (or mouse)

  • move or swap a window within the current workspace: mod + shift + arrow keys

  • log out with mod + shift + e

  • lock out: enter in terminal i3lock

  • refresh your i3 config: mod + shift + r


"There is no maximize key in i3. What you want to do is move it to a different workspace."

  • move current window to a different workspace: mod + shift + number

Resizing Windows

First, enter resize mode with mod + r. Red box appears. Escape to exit resize mode.

Now can use the arrow keys to resize the current window.

Stacking and Tab mode (as opposed to tiling mode)

  • enter stacking mode with mod + s
  • navigate the stack with mod + arrows
  • return to tiling mode with mod + e

mod + w enters "tab" mode

Customization Basics


  1. How do I open a file manager window?
  • just launch dmenu or synapse and open documents or file manager
  1. How do I set it so KeePassXC as a floating window by default (at least initially?)

Trying Other Desktop Environments with Ubuntu (Besides Unity)


To install

  1. sudo apt-get install xfce4 xfce4-goodies
  2. Restart
  3. Login as "xfce session"

What You Get Straight out of the Box

  • "Whisker menu" is the Start-menu-like menu in the top left. Same as Lubuntu
  • A nice, MacOS-like dock on the bottom with GNOME Terminal, File Manager, Web Browser (default), and a search


There's a nice Settings menu in Whisker menu > Settings > Settings Manager

  • In Window Manager > Keyboard, I set up a bucnh of window resizing keyboard shorts!
  • In Session and Startup > Application Autostart, I entered a custom command to remap caps lock to control. Name: remap caps Description: remap caps lock to control Command: /usr/bin/setxkbmap -option "ctrl:nocaps"
  • In Mouse and Touchpad > Devices > Touchpad, I enabled "Disable touchpag while typing" and I disabled "Tap touchpad to click"

Memory Usage

With Firefox, Terminal, and Settings open, I've got about 980 MB out of 2GB RAM "available". (This is compared to abut 1180 MB available when using Lubuntu-- it makes sense that Xubuntu slightly heavier than Lubuntu.)


  • Nice desktop
    • has a dock by default (edit settings by right-clicking between icons)
    • Window Switcher is nice.
    • Toolbar on top is nice out of the box.
  • Available on many distros! Only have to learn the tweaks and settings once!


  • Cursor is solid white (not smart) in Neovim 0.2, and then when I quit Neovim it's solid white (not smart) in the terminal as well. Not sure how to get at it... I tried creating ~/.config/xfce4/terminal/terminalrc and setting a hard-coded cursor color there but I couldn't get it to make any effect (even after a computer restart).
  • A helpful Mastodon user pointed me to his XFCE terminal config:


To install from Ubuntu

  1. sudo apt-get install kubuntu-desktop?
  2. When you get the chance to choose between "lightdm" and "sddm", I think you want "sddm".



seems more difficult:

What if this all goes to shit

Here's a very old "How to get back to pure Ubuntu post"?

Tips for e-readers

I've read on both Kindle PaperWhites and a Kobo Libra H2O. They're both fine!


How to add custom fonts to a Kobo e-reader + Bookerly link: Plug in your Kobo e-reader, create a folder called "fonts" in the main directory. Add the .tff files directly to that folder (no subfolders). They must be named in the pattern of FontName-Style, and for style Kobo seems to accept Bold, Italic, and BoldItalic. So for example:


Some good fonts for e-reading

Managing e-books on a Linux desktop

I have used and like Calibre.

For improved reading/organization of certain file types on your Kobo device

I think koreader is a replacement for the default software on your e-reader?

There's also a Rust program for handling PDFs and other difficult filetypes:

Kobo ebook store

How to add books to a Kobo e-reader


Switching from Ubuntu to Lubuntu

To avoid the high memory usage of Ubuntu's Unity desktop environment, I installed Ubuntu's LXDE desktop environment (called Lubuntu). I had a gist that Unity was a bit of a memory hog compared to other desktop environments. I also spotted this Reddit post that compares some lightweight distros in terms of RAM consumption and Lubuntu did well.

To install Lubuntu, I ran sudo apt-get install lubuntu-desktop (I learned this from a helpful user in the Ubuntu channel). The size of the installation was about 340 mb.

After installing the Lubuntu desktop environment, you want to run the software updater (you can also update software in the Terminal by running sudo apt update && sudo apt upgrade). Then restart the computer (that seems to have been pretty important), and at the login screen choose Lubuntu (or LXDE... that's another option and I'm not sure what the difference is).

You can check how much RAM you have available by running free -m in the terminal. Thanks to this site, I knew to look for the value under "available" to get an accurate estimate of how many megabytes of my memory were "free". With my terminal and Firefox running on Lubuntu, I have about 1187 MB RAM of my 2 GB available, as opposed to Ubuntu, which generally only left about 700 or 800 MB available when I was running a couple of programs (not a very scientific test, I know).

Plus I can always switch back to regular Ubuntu via the login screen.

Lubuntu is pretty snappy! I did want to make a few simple changes right off the bat. Here's how I went about some of them.

How to disable tap to click persistently in Lubuntu

I wanted to disable my touchpad from clicking, which I did by doing this:

  1. Open ~/.config/lxsession/lubuntu/autostart or possibly ~/.config/lxsession/LXDE/autostart (not sure which)
  2. To disable tap touchpad to click, add synclient MaxTapTime=0

You can find other settings to set here, like enabling two-finger horizontal scroll (synclient HorizTwoFingerScroll=1).

Installing an application launcher for Lubuntu

On macOS I make frequent use of Alfred as an application launcher. Ubuntu's Unity desktop environment sort of had something like that, which you can initiate by pressing the command key on its own at any time. But I couldn't find something similar in LXDE-- the application menu (similar to the Start menu in Windows) was just not fast enough for me coming from macOS + Alfred).

So I found this askubuntu answer that recommends installing an application called Synapse by running sudo apt-get install synapse. By default the launcher is invoked by hitting ctrl + space, but I changed it to alt+Enter by launching Synapse and clicking on the not-super-obvious round button on the right side of the pop-up display and clicking "Preferences". Works great!

My attempt to make the Gnome terminal the default

The default Terminal in Lubuntu (think it's called LXTerminal) didn't support true color in Vim, so I looked for other options. I had gotten used to the terminal in regular Ubuntu (which I'm pretty sure is the Gnome Terminal), so I figured I could switch that in on Lubuntu. Oddly it's not in the main menu of applications though.

First, I figured out a way to set it as the "default" terminal:

  1. menu > Preferences > Default applications LXSession
  2. Launching applications > Terminal manager > More > write in "gnome-terminal" for "Manual setting"

This seems to have worked? Notably, Gnome Terminal launches when I enter the standard launch-terminal shortcut of option + control + t.

While here, I also changed default application for spreadsheets to LibreOffice Calc

To get an icon from Gnome Terminal to appear in the desktop menu, I loosely followed this forum answer and created a new file in the directory ~/.local/share/applicatons called gnome-terminal.desktop and entered the following text into that new file:

[Desktop Entry]
Name=GNOME Terminal
Keywords=console;command line;execute;

Upon saving that file, I got a new icon in menu > System Tools called "GNOME Terminal" that launches my now-beloved Gnome Terminal. Woohoo! (If Icon=gnome-terminal hadn't worked I would have used Icon=lxterminal)

See separate entry for more on using Vim in Lubuntu.

More Lubuntu configuration ideas

Just found this long forum post with more ideas of recommended features for Lubuntu. There's also the Community Help Page here.

Some lingering problems on Lubuntu

  • can't figure out how to set custom openbox keybindings
  • Want to disable scrolling in Gnome terminal

Improving Lubuntu

Swapping control and caps lock on Lubuntu 16.04

First I ran setxkbmap -option ctrl:swapcaps in gnome-terminal, and observed that the keys were switched on my Macbook keyboard.

Now, following an answer on the web whose URL I've lost, I added that line of text to ~/.config/lxsession/Lubuntu/autostart.

Note that the setxkbmap line the worked in Ubuntu 16.04, setxkbmap -option caps:ctrl_modifier, did not work immediately when run in terminal in Lubuntu.

How to Install Neovim on Lubuntu 16.04

I'm using Lubuntu 16.04 and we're assuming that we're going to be using gnome-terminal. I couldn't figure out how to get HEX colors in Vim when using Lubuntu's default Terminal application, LXTerminal.

Thus I took some steps to make Gnome terminal the default Terminal application, and added an icon for it in my menu. These steps are described in another section of this document.

Note: If you're looking for info on installing plain Vim, see the end of this post.


First, we're going to want to install git in order to use vim-plug later: sudo apt install git

Next, I went over to the Ubuntu section of the Neovim installation page

Assuming I needed this dependency, I probably ran: sudo apt-get install software-properties-common

I then chose the unstable version:

To add the PPA to my system, I ran

sudo add-apt-repository ppa:neovim-ppa/unstable
sudo apt-get update

I then installed Neovim from this PPA by running sudo apt-get install neovim. I think the nvim command worked after that.

Critical changes to Vim config file

First, since on Lubuntu I'm likely only going to use Neovim and not Vim, I renamed my vimrc to init.vim and put it in ~/.config/nvim/ (which I may have had to create myself).

I then changed my vim-plug call to download my plugins to ~/.config/nvim/plugged: call plug#begin('~/.config/nvim/plugged')

I could have chosen to set vim-plug to download plugins to another directory somewhere in ~/.local/, which may have kept the ~/.config directory closer to what I assume is its intended purpose of just being configuration files, and not actual software.

Also, I had to redo this mappings that open my vim config file:

" Quickly open a vertical split of my VIMRC and source my VIMRC
nnoremap <silent> <leader>ev :vs $MYVIMRC<CR>
nnoremap <silent> <leader>sv :so $MYVIMRC<CR>

Syntax Highlighting Colors

I also made sure that set termguicolors was definitely being run in my init.vim file-- on my Mac I ran it only conditionally based on the terminal Vim detected. For now, let's just run it, as gnome-terminal is capable of running hex color vim themes.

System Clipboard

Within Neovim I ran :CheckHealth which kindly informed me that to get system clipboard support, I'd need to install a program called XSel. So back on the terminal I ran sudo apt install xsel and then restarted my terminal.

Then in my init.vim I figured out through trial and error that I needed to use the + register to access the system clipboard, rather than * that I used on MacOS:

" use leader to interact with the system clipboard
nnoremap <Leader>p "+]p
nnoremap <Leader>P "+]P

nnoremap <Leader>y :y+<cr>
nnoremap <Leader>c ^"+c$
nnoremap <Leader>d ^"+d$

vnoremap <Leader>y "+y
vnoremap <Leader>c "+c
vnoremap <Leader>d "+d

Though strangely, custom mappings that use the systemclipboard register still work with the * rather than the +:

" place enter file on system clipboard
nnoremap <Leader>a :%y*<cr>

" In markdown files, Control + a surrounds highlighted text with square
" brackets, then dumps system clipboard contents into parenthesis
autocmd FileType markdown vnoremap <c-a> <Esc>`<i[<Esc>`>la](<Esc>"*]pa)<Esc>

Other Things To Consider

I have Lubuntu installed on an old MacBook, whose track pad sometimes gets triggered when I'm typing. Thus in this Vim configuration I chose to disable my mouse

" disable mouse
autocmd BufEnter * set mouse=

Appendix: Some Notes on Vim (not Neovim)

As of this writing, you can install Vim 7.4.X with something like sudo apt-get vim. To install, Vim 8 currently you need to use a PPA.

But with both versions of Vim I was having trouble getting access to the system clipboard, so I went with Neovim. Though you can have both installed, with their own configurations, pretty easily.

Installing rbenv on Lubuntu 16.04

We're attempting to install rbenv via the "Basic GitHub Checkout" method.

I think we're also going to want ruby-build plugin. I DON'T think I'm going to want rbenv-gemset?

Installing rbenv

As mentioned above, we're going to install rbenv via the "Basic GitHub Checkout" method. I reproduce them below, but you should consult the latest instructions for Ubuntu on that GitHub page.

Clone down rbenv:

git clone ~/.rbenv

Make it more efficient:

cd ~/.rbenv && src/configure && make -C src

Add rbenv to your PATH:

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc

And finally run this init script:

~/.rbenv/bin/rbenv init

Following instructions from the init script run, I added eval "$(rbenv init -)" to my ~/.bashrc, just below the export PATH="$HOME/.rbenv/bin:$PATH" line that we added with the echo command above.

Now restart your terminal and/or run source ~/.bashrc.

Check your rbenv installation by running type rbenv. It should say it's a function.

Installing the ruby-build plugin

Wanting to build the latest version of Ruby a nice and clean way, I installed ruby-build by running git clone ~/.rbenv/plugins/ruby-build

Installing a version of Ruby using rbenv (some problems)

Now we can install some versions of Ruby using rbenv.

rbenv install --list gives us all available versions to install.

I'm going with 2.3.3, so I ran rbenv install 2.3.3. It took a long time to install and then told my the build failed. It suggested running apt-get install -y libreadline-dev so I did that (prefaced with sudo) and that software seemed to install successfully.

On second attempt I ran rbenv install --verbose 2.3.3 so that I could better see what's going on (turns out, it's a lot!). Success this time!

Once that's all installed, I opened a new gnome-terminal window. I was greeted by this shitty message at the top of the terminal window:

The program 'rbenv' is currently not installed. You can install it by typing: sudo apt install rbenv

but I learned that this can be temporarily solved be running source ~/.profile. And that it will be solved permanently once you restart Ubuntu/Lubuntu (source: this GitHub issue).

Then I had to set Ruby v. 2.3.3 as my global version of Ruby, which I did with rbenv global 2.3.3. After that, ruby --version gave me the familiar: ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-linux]

Installing gems with rbenv

I definitely want to install the "bundler" gem. To do this, I ran: gem install bundler, just like with RVM.

From there things seem to be just fine. Installed gems just work so far.

Configuring Openbox on Lubuntu

Openbox is a window manager that comes installed with Lubuntu/LXDE.

To configure it, open ~/.config/openbox/lubuntu-rc.xml in a text editor.

Change the relevant section to this:

<!-- Keybindings for window tiling -->
<keybind key="W-Left">    
  <action name="UnmaximizeFull"/>
  <action name="MoveResizeTo">
<keybind key="W-Right">  
  <action name="UnmaximizeFull"/>
  <action name="MoveResizeTo">
<keybind key="W-Up">        
  <action name="ToggleMaximizeFull"/>
<keybind key="W-Down">     
  <action name="UnmaximizeFull"/>
  <action name="MoveResizeTo">

<keybind key="W-j">        
  <action name="UnmaximizeFull"/>
  <action name="MoveResizeTo">

<keybind key="W-k">        
  <action name="UnmaximizeFull"/>
  <action name="MoveResizeTo">
<keybind key="W-n">        
  <action name="UnmaximizeFull"/>
  <action name="MoveResizeTo">
<keybind key="W-m">        
  <action name="UnmaximizeFull"/>
  <action name="MoveResizeTo">

And here's the default section on moving to desktops

<!-- Keybindings for desktop switching -->
<keybind key="C-A-Left">
  <action name="GoToDesktop">
<keybind key="C-A-Right">
  <action name="GoToDesktop">
<keybind key="C-A-Up">
  <action name="GoToDesktop">
<keybind key="C-A-Down">
  <action name="GoToDesktop">
<keybind key="S-A-Left">
  <action name="SendToDesktop">
<keybind key="S-A-Right">
  <action name="SendToDesktop">
<keybind key="S-A-Up">
  <action name="SendToDesktop">
<keybind key="S-A-Down">
  <action name="SendToDesktop">