It's not the first time I'm switching to Ubuntu. I've been, as they say, around the block when it comes to operating systems. I started out on MS, from DOS to XP, then Ubuntu from 5.10 Breezy to 9.10 Karmic, then on Apple from OSX 10.5 Leopard to macOS 10.14 Mojave. Both in terms of productivity and delight I had my best years on Apple and I didn't think I'd ever look back. But here we are.

Why? I (guess I'm the only person alive that) didn't mind the TouchBar or lack of a real escape key (can map Caps Lock to that). And I liked having 4 USB-C+ ports that I could do anything with. But yes, The Keyboard.

I spent the most money I ever did on this MacBook Pro, and it's also the worst machine I ever had because the keyboard breaks down (like, it won't register the s). When I dock it and use a different keyboard, it's fine of course. But sometimes I visit my co-founder in Berlin, or want to work from a coffee shop, and then it's nice to have a working keyboard. So far I've brought it in for repairs three times, and each time I'm without my workhorse for a week. Those are unplanned holidays that are dragging my productivity--and basically my company down.

I personally also feel macOS has taken a freefall regarding robustness and polish, but that might be just me. It's the keyboard that ultimately made me feel just really concerned about having my productivity/company/future so tightly coupled to what Apple ships next.

So what machine did I get? I played it safe and went for a Dell XPS. They come with Ubuntu pre-installed so you know you won't have to go through hoops to get all the hardware going. There's a time and a place for those things, and it's called ~college :smile: Honestly: I really enjoyed experimenting with Linux and occasionally breaking it around my 20s. Back then (5.10 Breezy) it was not uncommon to compile Wi-Fi support into your kernel. I learned a lot and would not trade that experience for anything. But these days with a family and a company rightfully demanding my time, the time I spend behind a computer needs to be accounted for and it can't really be: 3 days, got webcam to work. In short: less surprises is better for me now. There may be superior options to an XPS for sure, probably research any hardware you intend on buying for Linux compatibility (also just for things like webcams) and you'll find good options. I do like the XPS, it feels rugged, fast, polished, it has roughly the same ports that my MacBook Pro had, battery life is good. My only regret is that I didn't go for the larger 15". I dock it a lot, but for those other times, 13" is just a tad bit too small to do serious damage for me. And, at least with this "13 version, <PgUp> and <PgDn> are awefully close to <Left> and <Right>. That will take some getting used to and I wouldn't have minded if they left them out, and <Ctrl>Up was <PgUp>, for instance.

As for why Ubuntu, similar reason. There may very well be superior distros on many different metrics out there (and NixOS has me tempted), but the sheer community size of Ubuntu makes sure I'm not the first one running into a problem, and I'll find a solution online before it really slows me down. askubuntu.com is right up there with the big ones. Community size is a quality which's benefits may be hard to quantify yet I find pays dividends. Even when I search for a non-Ubuntu-specific Linux question, I find that adding Ubuntu to my search query often improves the results.

So, can Linux be my workhorse?

Yes. But this is not a sales pitch. If you walk away thinking/knowing Linux is still too much trouble, that's a fair takeway. There are sacrifices and struggles and whether those are worth it to you depends on, well, you. I don't intend to win anybody over to either side.

Ok let's dive in, I'll try to describe the things I ran into, the things I can't fix, and straight up howto's for the things I could.

Things that bothered me immediately

  • One day, scrolling was superfast. Turns out I had to unplug the USB dongle that came with my mouse and insert it back in.
  • Device support is still lacking. I could not get Apple's Magic Trackpad 2 to work without soul crushingly fragile hacks. But I guess a newer kernel is coming that will fix this :crossedfingers:. I was unable to get my TomTom Running Watch to sync. My Fujitsu SnapScan document scanner had no Linux tools (on macOS it can automatically OCR & archive to my Dropbox). This is very dear to me so I ended up using VirtualBox with a Windows VM for that. _Edit 2021-02-08: The Magic Trackpad 2 is now working, but you do need to increase finger sensitivity via xinput, added instructions for this.
  • Photos. Leaves to be desired. This is the main reason I'll probably always at least keep an iPad or very lightweight MacBook around. But if I don't have to get a maxed out MacBook Pro 1, I could get a high-end Linux machine and a modest Apple device, and still save money.
  • Copy paste is still horribly 'broken'. I guess <Cmd>C isn't a thing on Linux and <Ctrl>C has a different meaning in terminals, so I can get with that. And I guess there are tricky/valid historical reasons for having different clipboards, but for the end user, it's not great if you lose your buffer when you close the originating app. Or having data in one clipboard while you need it in the other. Luckily I found a workaround that I listed further down. Wholeheartedly recommended. Paired with training muscle memory to do <Ctrl><Insert> (copy) and <Shift><Insert> (paste) on Ubuntu, that solved the problem for me.
  • I invested in a screen with high DPI, but it's not 'Retina', and the fonts don't render like they do on macOS. It seems like a small thing, but 4 weeks in, I never would have thought I still sometimes feel as though my eyes are dry and almost literally hurting :thinking: Did Steve Jobs spoil/ruin me for life? Edit: I wrote this before my upgrade to Cosmic, and it got significantly better afterwards
  • If I close the lid of my XPS and open it 2 days later, the battery is fully drained. I just opened my MacBook after leaving it for weeks, and it still has juice enough to do serious work with (if the keyboard only allowed!). So it seems hibernation is much better on a Mac. Edit: as pointed out by GD in the comments, this: isn't actually Linux' but MSFT's and Dell's fault for promoting "connected standby"
  • Every reboot my screen brightness is so low I can barely see a thing. The button to increase brightness is maxed out. It turned out I have to venture into the power saving settings to crank the brightness up there, but it does not persist across reboots. I avoid reboots now. If someone knows how to automate this let me know in the comments below!
  • Selecting the right audio/video input/output is a proper chore. My Mac seemed to pick sane seemingly obvious defaults, whether I hooked up a screen with webcam, removed it, etc. With Ubuntu I have to open the audio settings and select the proper i/o at least twice a week as it doesn't pick obvious candidates. It's annoying for me, and often enough also for my teammates who I video conference a lot with. Sorry folks!
  • I thought Snaps were really cool until I used them in my day to day. I used snaps for GitHub Desktop, Spotify, VSCode, Slack, and have since reverted all of that to using plain APT repositories. Issues ranged from intense CPU hogs, to links in Slack not opening, or always opening in a new Firefox window, seemingly random segfaults, etc. I guess it's still a bit too early and some programs don't like to be contained so much, or I'm just plain unlucky. I didn't have time to deep dive, APT works fine. Edit: I later learned that people also dislike about Snaps due to their closed/non-standard nature.
  • There are other ways but if I want to type an Γ©, out of the box, I have to type: <Ctrl><Shift>U 00e9, and then, that doesn't work in my code editor. Long-pressing a button on macOS wins! I keep forgetting this code, too, so I'm saying Renee a lot. Sorry RenΓ©e! Edit: readers suggested to use the Compose key. I've updated CLI instructions with it and it works much better. A default mapped key and brief introduction for new users may be a good idea.
  • As tedthetrumpet points out in the comments, I too really miss Preview on Spacebar. Edit: as Cory Flick mentions in the comments we can install gnome-sushi for that. Thanks!! - Edit2: In Groovy Sushi broke, you have to compile it from source to get it to work again
  • I upgraded to 19.10 Eoan and when I rebooted it said error: Unknown TPM error.", followed by "error: you need to load the kernel first and that was that. It turned out I had to disable TPM in my Bios. To this day I haven't done the deepdive on what that even is and why it would matter but that solved it :shrug:
  • In VSCode when switching tabs or scrolling, the brightness would flicker. It turned out I had to pass the --disable-gpu argument or set "window.titleBarStyle": "native" which is a bit sad because I had custom colored titlebars per project before.
  • When I upgraded to the 5.x kernel that comes with Eoan, my Wi-Fi hardware wasn't recognized. I reverted and it looks like I'll be stuck on the OEM kernel by Dell for a while.

1 Since I run a video encoding business, having our test suites pass faster locally ramps up my productivity near-linearly, so the company is happy to sponsor the fastest machine. I do realize I'm incredibly privileged like that. If this is something you feel you need to get in on, come work for us.

Things I could fix

So here's what I did to make Ubuntu usable as a day-to-day workhorse, coming from Mac. Please regard it as a grabbag containing opinionated things that may very well drive you nuts, and probably don't blindly paste my entire setup.

Most of the apps and settings in this post, you'll be able to pick from Ubuntu's graphical interfaces. However by having everything as CLI commands, I can paste it all and have a new machine configured identically in minutes. So I'll be referring to this post myself and will tweak it as I go. Any changes I make to my machine that I want to persist, even if I initially make them in the GUI, I'm sure to document those back as CLI commands right here.

Disclaimer: This worked for Ubuntu 19.04. It may not work for other versions. If you use a more recent version and know how to make things compatible, please drop a line in the comments below.

Basics

Small Tools & Utilities

Install basic tools, some of which (curl, dconf-cli, xdotool) we'll also need to execute further steps.

sudo apt install \
  awscli \
  curl \
  dconf-cli \
  gnome-startup-applications \
  exiftool \
  htop \
  ipcalc \
  jq \
  logtail \
  mc \
  mlocate \
  tmux \
  whois \
  xdotool \
;
# ^-- was dconf-tools before Ubuntu 19.04

Overwrite APT repositories in a denser way, and enable more repos

This will also unlock (but not install yet) non-free codecs for example.

release=$(lsb_release -cs)
echo "deb http://archive.ubuntu.com/ubuntu/ ${release} main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ ${release}-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ ${release}-security main restricted universe multiverse
" | sudo tee /etc/apt/sources.list \
  && sudo apt update

Apt-file

So you can search for e.g. apt-file search bin/aws to find out what APT package the aws command belongs to again.

sudo apt install apt-file && sudo apt-file update

Browser

Trying to have less Google in my life and so I'll open up a Terminal and install Firefox as my main driver:

# This also installs some of those non-free codecs so I can watch videos online:
sudo apt install firefox ubuntu-restricted-extras

As a backup for whenever Google Hangouts does not work in Firefox, this installs Chrome:

curl -fsSL https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - \
  && echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" | sudo tee /etc/apt/sources.list.d/google-chrome.list \
  && sudo apt update \
  && sudo apt install google-chrome-stable \
  ;

Or to check out Brave:

sudo apt install apt-transport-https curl gnupg \
  && curl -s https://brave-browser-apt-release.s3.brave.com/brave-core.asc | sudo apt-key --keyring /etc/apt/trusted.gpg.d/brave-browser-release.gpg add - \
  && echo "deb [arch=amd64] https://brave-browser-apt-release.s3.brave.com/ stable main" | sudo tee /etc/apt/sources.list.d/brave-browser-release.list \
  && sudo apt update \
  && sudo apt install brave-browser \
  ;

1Password Password Manager

sudo apt-key --keyring /usr/share/keyrings/1password.gpg adv --keyserver keyserver.ubuntu.com --recv-keys 3FEF9748469ADBE15DA7CA80AC2D62742012EA22 \
  && echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/1password.gpg] https://downloads.1password.com/linux/debian edge main' | sudo tee /etc/apt/sources.list.d/1password.list \
  && sudo apt update \
  && sudo apt install 1password \
  ;

Email

Haven't found a really neat one yet. So far using Thunderbird for work email and a web interface (yeah still Gmail) for personal. Thunderbird is fast and functional and doesn't surprise me in bad ways. That's about all the nice things that I can say about it :smile: To install it:

sudo apt install thunderbird

Spotify

Can't not have music! We'll add their own APT repository so we can enjoy regular updates. And you can read a little higher up why I try to stay away from Snaps for now, and use APT instead.

curl -fsSL https://download.spotify.com/debian/pubkey.gpg | sudo apt-key add - \
  && echo "deb http://repository.spotify.com stable non-free" | sudo tee /etc/apt/sources.list.d/spotify.list \
  && sudo apt update \
  && sudo apt install spotify-client \
  ;

Collaboration

Slack

cd /tmp \
  && curl -fsSLo slack.deb https://downloads.slack-edge.com/linux_releases/slack-desktop-4.0.2-amd64.deb \
  && sudo apt install ./slack.deb \
  && cd -

Dropbox

cd /tmp \
  && apt install libpango1.0-0 libpangox-1.0-0 python3-gpg \
  && curl -fsSLo dropbox.deb https://www.dropbox.com/download?dl=packages/ubuntu/dropbox_2019.02.14_amd64.deb \
  && sudo apt install ./dropbox.deb \
  && dropbox autostart y
  ;
# now type CMD+SPACE (or just CMD if you don't remap like I did below), type dropbox, ENTER

Signal

We use this with the team to transmit secrets to each other.

echo "deb [arch=amd64] https://updates.signal.org/desktop/apt xenial main" | sudo tee -a /etc/apt/sources.list \
  && curl -fsSL https://updates.signal.org/desktop/apt/keys.asc | sudo apt-key add - \
  && sudo apt update \
  && sudo apt install signal-desktop \
  ;

# Do not register Signal as the default App to open html files
# https://github.com/signalapp/Signal-Desktop/issues/3602
if xdg-mime query default text/html | grep -q signal; then
  echo "Fixing bug: Found Signal as mime type handler for text/html"
  if which firefox > /dev/null; then
    echo "Restoring handler for text/html as Firefox"
    xdg-mime default firefox.desktop text/html
  elif which chromium-browser > /dev/null; then
    echo "Restoring handler for text/html as Chromium"
    xdg-mime default chromium-browser.desktop text/html
  else
    echo "Could not find a handler, no handler set for text/html"
    xdg-mime default /bin/true text/html
  fi
fi

Gimp

Probably not as nice as Photoshop, but I'm not a designer and for me it gets the job done.

sudo apt install gimp

Development

VSCode

You'll know how to replace this with your own favorite editor.

curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg \
  && sudo install -o root -g root -m 644 packages.microsoft.gpg /usr/share/keyrings/ \
  && sudo sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list' \
  && sudo apt install apt-transport-https \
  && sudo apt update \
  && sudo apt install code \
  ;
# Afterwards I install the extension Settings Sync and enter the Gist ID (df2624fb06dc2d3b8890a28d4caa3820 in my case)
# to setup VSCode to my preferences. For uploading changes to the settings, you'll need a GitHub token.

If you want to allow incoming SSH connections:

sudo apt install openssh-server

Access to code, SSH Key for github and syncing your code dir from another machine

ssh-keygen -t rsa -b 4096 -C "${USER}@${HOSTNAME}"
# Press enter on all questions, then
cat ~/.ssh/id_rsa.pub
# and add it to https://github.com/settings/keys
# probably also add it to the machine that currently has
# your code in ~/.ssh/authorized_keys <-- and chmod it to 600,
# so you can sync it to your new machine via, e.g.:
rsync -a --progress --ignore-existing --exclude='node_modules/' --exclude='.Trash-*' "10.0.1.144:/${HOME}/code/" /home/kvz/code

Git

# Git LFS
cd /tmp \
  && curl -fsSLo script.sh https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh \
  && sudo bash script.sh \
  && sudo apt install git-lfs \
  && git lfs install \
  && cd -

# Avoid warning: Pulling without specifying how to reconcile divergent branches ..
git config --global pull.rebase false

Git Verified Commits

Dangerous, best not copy my setup but reference this guide.

# rm -rf ~/.gnupg
# Cross-platform macOs compatibility:
ln -nfs ~/Shared/Configs/gnupg ~/.gnupg
chmod 700 /home/kvz/.gnupg
sudo ln -nfs /usr/bin/gpg /usr/local/bin/gpg
sudo ln -nfs /usr/bin/pinentry-gnome3 /usr/local/bin/pinentry-mac

# List existing keys, pick key to sign commits with:
gpg --list-secret-keys --keyid-format LONG
# take short key and use as XXXXXXXX
git config --global user.signingkey XXXXXXXX
git config --global commit.gpgsign true
git config --global gpg.program /usr/local/bin/gpg

GitHub Desktop

I also still use the CLI, but for staging commits, there's no beating the GUI. Yes I did try git add -p. No it doesn't come close! Sorry! :smile:

# ran into multiple issues (such a segmentation faults
# and https://github.com/shiftkey/desktop/issues/59) with the default snap,
# So using this for now:
cd /tmp \
  && curl -fsSLo GitHubDesktop.deb https://github.com/shiftkey/desktop/releases/download/release-2.9.3-linux1/GitHubDesktop-linux-2.9.3-linux1.deb \
  && sudo apt install ./GitHubDesktop.deb \
  && cd -
# if you have GitHub 2FA and use HTTPS repositories (vs SSH) and get
# create a personal access token on GitHub, and use that as your password
# to make it persist, set: git config --global credential.helper store # (more convenient)
#                      or: git config --global credential.helper cache # (safer)

GitHub CLI

curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
  && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
  && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
  && sudo apt update \
  && sudo apt install gh \
  && gh auth login \
  && echo -e '\neval "$(gh completion -s bash) || true"' >> ~/.bash_profile \
  ;

Here's how I create todos from the CLI for different projects by just typing: gh todo-website. You'll want to change the values here of course, but maybe it can provide some inspiration.

gh alias set todo-meta 'issue create --repo=transloadit/team-internals --project="πŸ€– The Board" --body="n/a" --label="meta" --assignee="@me"' \
  && gh alias set todo-founder 'issue create --repo=transloadit/founder-internals --project="πŸ€– The Board" --body="n/a" --label="meta" --assignee="@me"' \
  && gh alias set todo-accounting 'issue create --repo=transloadit/accounting --project="πŸ€– The Board" --body="n/a" --label="accounting" --assignee="@me"' \
  && gh alias set todo-legal 'issue create --repo=transloadit/legal --project="πŸ€– The Board" --body="n/a" --label="legal" --assignee="@me"' \
  && gh alias set todo-website 'issue create --repo=transloadit/content --project="πŸ€– The Board" --body="n/a" --label="website" --assignee="@me"' \
  && gh alias set todo-content 'issue create --repo=transloadit/content --project="πŸ€– The Board" --body="n/a" --label="content" --assignee="@me"' \
  && gh alias set todo-nix 'issue create --repo=transloadit/transloadit-api2 --project="πŸ€– The Board" --body="n/a" --label="nix" --assignee="@me"' \
  && gh alias set todo-api2 'issue create --repo=transloadit/transloadit-api2 --project="πŸ€– The Board" --body="n/a" --label="api" --assignee="@me"' \
  && gh alias set todo-growth 'issue create --repo=transloadit/growth --project="πŸ€– The Board" --body="n/a" --label="growth" --assignee="@me"' \
  && gh alias set todo-botty 'issue create --repo=transloadit/botty --project="πŸ€– The Board" --body="n/a" --label="satellite" --assignee="@me"' \
  ;

Starship & powerline fonts

This gives me a cool prompt.

cd /tmp \
  && sudo apt install fonts-powerline fonts-firacode \
  && curl -fsSLo starship-v0.15.0-x86_64-unknown-linux-gnu.tar.gz https://github.com/starship/starship/releases/download/v0.15.0/starship-v0.15.0-x86_64-unknown-linux-gnu.tar.gz \
  && tar zxvf starship-v0.15.0-x86_64-unknown-linux-gnu.tar.gz \
  && sudo cp -af ./x86_64-unknown-linux-gnu/starship /usr/local/bin/starship \
  && cd -
# Now add to your ~/.bash_profile: [ -x /usr/local/bin/starship ] && eval "$(starship init bash)"

Shellcheck

Linting for Bash scripts.

sudo apt install cabal-install && cabal update && cabal install ShellCheck

Node.js

# Install Node 16
cd /tmp \
  && sudo rm -f /etc/apt/sources.list.d/nodesource.list* \
  && curl -fsSLo setup.sh https://deb.nodesource.com/setup_16.x \
  && sudo -E bash setup.sh \
  && sudo apt install nodejs \
  && cd -

# make sure apt does not produce warnings while updating, or the Node.js repo setup will silently bail out

# Install yarn
(curl -fsSL https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -) \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list \
  && sudo apt update \
  && sudo apt install yarn

# Log into npm if you need that
npm login

Go

sudo rm -f /etc/apt/sources.list.d/longsleep-ubuntu-golang-backports-* \
  && sudo add-apt-repository ppa:longsleep/golang-backports \
  && sudo apt update \
  && sudo apt install golang-go golang-go.tools \
  && mkdir ~/go ~/code \
  ;

Basic PHP & MySQL CLI

sudo apt install php-cli php-mbstring php-mysql mysql-client
# and enable extension=mbstring, extension=mysqlnd, extension=mysqli in $EDITOR /etc/php/*/cli/php.ini

DataGrip

Together with 1Password, DataGrip is the only software I installed that costs money. Although I was lucky enough to be donated a license for work done on my open source project Locutus.

sudo mkdir -p /opt \
  && cd /opt \
  && curl -fsSLo datagrip.tar.gz https://download.jetbrains.com/datagrip/datagrip-2019.2.4.tar.gz \
  && tar zxvf datagrip.tar.gz \
  && cd DataGrip-2019.2.4 \
  && ./bin/datagrip.sh \
  && cd -

You should be able to create a launcher from within the application itself. Choose "Tools", "Create desktop entry". This will create an item in the dash (<Ctrl><Space>), which you can then drag into the dock.

Edit: mxschumacher on Hacker News suggested to use Jetbrain's Toolbox instead.

Vagrant & VBox

echo "deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian $(lsb_release -cs) contrib" | sudo tee -a /etc/apt/sources.list \
  && curl -fsSL https://www.virtualbox.org/download/oracle_vbox_2016.asc | sudo apt-key add - \
  && curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - \
  && sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
  && sudo apt update \
  && sudo apt install virtualbox linux-headers-$(uname -r) vagrant \
  && vagrant plugin install vagrant-vbguest \
  && cd -

After a kernel/distribution upgrade you'll want to run:

sudo apt reinstall virtualbox-dkms virtualbox linux-headers-$(uname -r)

I had to install a non-signed kernel or I would run into an issue whenever starting VirtualBox.

Docker

sudo apt install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common \
&& (curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -) \
&& sudo apt-key fingerprint 0EBFCD88 \
&& sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable" \
&& sudo apt update \
&& sudo apt install docker-ce \
&& sudo usermod -aG docker kvz \
&& sudo systemctl enable docker \
;

# Login to docker Hub if you need that
docker login

echo "WARNING! REBOOTING HARD NOW. PRESS CTRL+C IF YOU ARE NOT SURE! Sleeping 10s" && sleep 10 & sudo reboot

Tweak Desktop

Fix copy-paste

10 years later, copy-paste still leaves a lot to be desired for people coming from other platforms. Different apps use different clipboards :scream:.There are different shortcuts to utilize the different clipboards :scream:. Clipboards reset when apps close :scream:. Even for copying these commands from Firefox to the terminal with keyboard shortcuts (like <Ctrl><Insert>, <Shift><Insert>, as <Ctrl>C has a different meaning in terminals), I recommend you get this fixed already. Luckily you can, with clipboard managers.

As a bonus, let's also install xclip which nice for copying from the CLI like: cat /etc/config |xclip

sudo apt install parcellite libcanberra-gtk-module xclip

I had to sudo reboot before this worked then press <Ctrl><Alt>P to bring up the menu, open preferences, make sure box 1 is checked, box 2 is unchecked.

Some linux veterans said they don't have any issues with multiple clipboards, and even enjoy it. And they know not to close an originating app so they don't hit that problem. But I feel for newcomers the appearance of a single clipboard that persists through app lifecycles would be a sane default. Looks at Mark Shuttleworth :eyes:.

Add emoji support

cd /tmp \
  && sudo apt install fonts-emojione \
  && curl -fsSLo noto-color-emoj.deb https://launchpad.net/~ubuntu-desktop/+archive/ubuntu/transitions/+files/fonts-noto-color-emoji_0~20170913-0ubuntu1~bionic1_all.deb \
  && sudo apt install ./noto-color-emoj.deb \
  && cd -
# then install GNOME Characters to easily browse emoji:
sudo apt install gnome-characters

Some apps will need a hand, e.g. for VSCode you could set (single config shared between Ubuntu & macOS, worked for me):

"editor.fontFamily": "Menlo, 'Droid Sans Mono', , monospace, 'Droid Sans Fallback', Monaco, Consolas, 'Droid Sans Mono', 'Inconsolata', 'Courier New', 'Droid Sans Fallback', 'Noto Color Emoji', 'Apple Color Emoji'"

Move around windows or resize them by holding <Alt> and dragging a window

sudo apt install compizconfig-settings-manager
cssm
# Enable the Move plugin. Set Initiate Move to <Alt>Button1.

Tip: the 'xev' tool lets you see what button number is associated with e.g. a two finger drag on a touchpad. You can also use this to let apps [open on certain areas of the screen](https://askubuntu.com/questions/107951/ how-to-set-a-specific-window-size-and-placement-for-all-windows-that-open-to-def) by default.

Better screenshots

Save screenshots in ~/Dropbox/Screenshots. And use annotation screenshot tool by default.

sudo apt install flameshot \
  && flameshot config -f '%Y-%m-%d_%H-%M-%S-screenshot' \
  && dconf write /org/gnome/gnome-screenshot/auto-save-directory "['file:///home/${USER}/Dropbox/Screenshots']" \
  && dconf write /org/gnome/gnome-screenshot/border-effect "['shadow']"
# https://askubuntu.com/a/1039949/2222
# Release the <PrtScr> binding by this command
gsettings set org.gnome.settings-daemon.plugins.media-keys screenshot ''
# Go to Settings -> Devices -> Keyboard and scroll to the end. Press + and you will create custom shortcut.
# Enter name: "flameshot", command: `/usr/bin/flameshot gui --path /home/kvz/Dropbox/Screenshots/`. # <-- replace 'kvz' with your username, no $HOME or ~ substitution supported
# Set shortcut to <PrtScr> (print).

Disable <PgUp> and <PgDn> in VSCode

Those buttons are awesfully close to the left and right cursor, that I use a lot while coding in VSCode, so disabling/changing the behavior there was sufficient for me:

  {
    "key": "ctrl+up",
    "command": "cursorPageUp",
    "when": "textInputFocus"
  },
  {
    "key": "ctrl+down",
    "command": "cursorPageDown",
    "when": "textInputFocus"
  },
  {
    "key": "pagedown",
    "command": "cursorRight",
    "when": "textInputFocus"
  },
  {
    "key": "pageup",
    "command": "cursorLeft",
    "when": "textInputFocus"
  },

One of those cases where retraining muscle memory took enough time to want to change the system instead.

Make the Apple Magick Trackpad 2 work on Ubuntu

Edit 2021-02-08: The Magic Trackpad 2 is now working, but you do need to increase finger sensitivity via xinput:

cat << EOF > ~/touchpad_settings.sh
#!/usr/bin/env bash
set -eux
deviceId=\$(xinput list |awk -F'id=' '/Apple Inc. Magic Trackpad/ {print \$2}' |awk '{print \$1}')
propId=\$(xinput list-props \${deviceId} |awk '/Synaptics Finger/ {print \$3}' |tr -d -c 0-9)
xinput set-prop \${deviceId} \${propId} 2, 2, 0

synclient ClickFinger3=2
synclient HorizTwoFingerScroll=1
synclient TapButton2=0
synclient TapButton1=1
EOF
chmod +x ~/touchpad_settings.sh
~/touchpad_settings.sh
gsettings set org.gnome.settings-daemon.peripherals.input-devices hotplug-command "${HOME}/touchpad_settings.sh"

Distilled from this reddit thread.

Make keyboard shortcuts, navigation, gestures, layout more like I had on macOS

This is highly personal because even on macOS I already personalized (where I stole much from Mathias Bynens' Dotfiles) so you'll probably only cherry-pick a few here.

# If you have an Apple keyboard and want the function keys to act like F1-F12 by default (disable Fn default behavior) give the following command in terminal:

echo 2 | sudo tee /sys/module/hid_apple/parameters/fnmode

# Disable many keybindings that manage windows to free them up for VSCode,
# except for a few ones I also had on macOS
dconf write /org/gnome/desktop/wm/keybindings/maximize "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/move-to-monitor-down "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/move-to-monitor-left "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/move-to-monitor-left "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/move-to-monitor-right "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/move-to-monitor-up "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/move-to-workspace-down "['<Super><Ctrl>Right','<Super><Ctrl>Down']"
dconf write /org/gnome/desktop/wm/keybindings/move-to-workspace-left "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/move-to-workspace-right "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/move-to-workspace-up "['<Super><Ctrl>Left','<Super><Ctrl>Up']"
dconf write /org/gnome/desktop/wm/keybindings/switch-applications "['<Ctrl>Tab','<Alt>Tab']"
dconf write /org/gnome/desktop/wm/keybindings/switch-applications-backward "['<Shift><Alt>Tab','<Shift><Ctrl>Tab']"
dconf write /org/gnome/desktop/wm/keybindings/switch-group "['<Ctrl>Above_Tab','<Alt>Above_Tab']"
dconf write /org/gnome/desktop/wm/keybindings/switch-group-backward "['<Shift><Ctrl>Above_Tab','<Shift><Alt>Above_Tab']"
dconf write /org/gnome/desktop/wm/keybindings/switch-input-source "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/switch-input-source-backward "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/switch-panels "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/switch-panels-backward "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/switch-to-workspace-down "['<Super>Right','<Super>Down']"
dconf write /org/gnome/desktop/wm/keybindings/switch-to-workspace-left "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/switch-to-workspace-right "['disabled']"
dconf write /org/gnome/desktop/wm/keybindings/switch-to-workspace-up "['<Super>Left','<Super>Up']"
dconf write /org/gnome/desktop/wm/keybindings/unmaximize "['disabled']"
dconf write /org/gnome/mutter/keybindings/switch-monitor "['XF86Display']"
dconf write /org/gnome/mutter/keybindings/toggle-tiled-left "['<Super><Ctrl><Alt>Left']"
dconf write /org/gnome/mutter/keybindings/toggle-tiled-right "['<Super><Ctrl><Alt>Right']"
dconf write /org/gnome/shell/keybindings/toggle-overview "['<Super>Space','<Ctrl>Space']"
dconf write /org/gnome/desktop/input-sources/xkb-options "['caps:escape']"
# ^-- to swap vs map both to escape: "['caps:swapescape']".

# Update 2020-12-28: After readers reporting about the Compose
# Key I decided to try and now to type the accented letter `Γ©`,
# I press compose (`<rAlt>`) then `'` then `e`. Not too bad at all
# and it takes just this one line to set up:
dconf write /org/gnome/desktop/input-sources/xkb-options "['compose:ralt']"
# The list of all the codes is in /usr/share/X11/locale/en_US.UTF-8/Compose
# and you can customize via `vim ~/.XCompose` `<Multi_key> <e> <m> <o> <s>: "✨"` then `ibus restart`

# More macOS-like tab navigation in the terminal
# Find all possible config keys via: gsettings list-recursively |grep Terminal
gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ next-tab "<Primary>braceright"
gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ prev-tab "<Primary>braceleft"
gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ move-tab-left "<Primary><Shift>Left"
gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ move-tab-right "<Primary><Shift>Right"
gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ close-tab "<Primary>w"
gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ new-tab "<Primary>t"

# Make the Dock more macOS-like
gsettings set org.gnome.shell.extensions.dash-to-dock extend-height false
gsettings set org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM
gsettings set org.gnome.shell.extensions.dash-to-dock transparency-mode FIXED
gsettings set org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 32
gsettings set org.gnome.shell.extensions.dash-to-dock unity-backlit-items true
# I once had all dash-to-dock icons dissappear. Resetting resolved it:
gsettings reset org.gnome.shell.extensions.dash-to-dock extend-height
gsettings reset org.gnome.shell.extensions.dash-to-dock dock-position
gsettings reset org.gnome.shell.extensions.dash-to-dock transparency-mode
gsettings reset org.gnome.shell.extensions.dash-to-dock dash-max-icon-size
gsettings reset org.gnome.shell.extensions.dash-to-dock unity-backlit-items

# Activate Gnome Activities Overview on hot corner <-- careful you may find this annoying
gsettings set org.gnome.shell enable-hot-corners true
# As of Ubuntu 19.10 this is:
gsettings set org.gnome.desktop.interface enable-hot-corners true

# (as of 19.10) Dark tabs for the Terminal to me look better regardless of the system theme
gsettings set org.gnome.Terminal.Legacy.Settings theme-variant "dark"

# Disable left super overview, bind to Super Up (use <Alt>F1 or hot corner)
gsettings set org.gnome.mutter overlay-key ""

# <Alt>left click to move windows (without dragging the titlebar)
gsettings set org.gnome.desktop.wm.preferences mouse-button-modifier "<Alt>"
# <Alt>right click to resize windows (without dragging the titlebar)
gsettings set org.gnome.desktop.wm.preferences resize-with-right-button true

# Disable <Alt><Ctrl>S minimizing windows (and freeing it up for VsCode Save-All)
gsettings set org.gnome.desktop.wm.keybindings toggle-shaded "['disabled']"

# Still click an app in the dock to open, but if it's open already, this makes a click minimize it
gsettings set org.gnome.shell.extensions.dash-to-dock click-action "minimize"

# Show weekday in clock
gsettings set org.gnome.desktop.interface clock-show-weekday true

# Disable <Alt> showing the menu/HUD, making windows very jumpy whenever you press a <Alt> involved key combo
gsettings set org.compiz.integrated show-hud "['']" # <-- No longer works on Ubuntu 19.10, does anybody know how to fix this?

# Move trash can from desktop to dock
gsettings set org.gnome.shell.extensions.dash-to-dock show-trash true
gsettings set org.gnome.shell.extensions.desktop-icons show-trash false

# Show directories above files
dconf write /org/gtk/settings/file-chooser/sort-directories-first true

# Enable Experimental Fractional Scaling
# This allows you to scale laptop screens in more finer grained steps than just 100%, 200%. After running this you can go to the display settings
# and choose: 125%, 150%, etc. On my 13" XPS, 125% looks much better.
# WARNING, CAN CAUSE LOAD/INSTABILITY
gsettings set org.gnome.mutter experimental-features "['x11-randr-fractional-scaling']"

You can list more options via e.g.:

gsettings list-recursively org.gnome.Terminal
gsettings list-recursively org.gnome.shell
gsettings list-recursively org.gnome.desktop.interface

You can reset a dconf setting via e.g.:

# Bring back capslock/escape mapping to default behavior
dconf reset /org/gnome/desktop/input-sources/xkb-options

You can explore more settings visually via:

sudo apt install dconf-editor
dconf-editor

Make open work

We're using open a lot in automation written orginally for macOS, in places where (bash) aliases aren't always available, so I symlinked it:

sudo ln -nfs /usr/bin/xdg-open /usr/bin/open

Bug workarounds / fixes

Remove ocra screenreader which was doing 100% CPU and making the system laggy and disable screenreader activating on what used to be Save-All in VSCode on macOS.

killall -9 orca \
  ; sudo apt purge orca \
  ; gsettings set org.gnome.settings-daemon.plugins.media-keys screenreader "['disabled']"

# Fix ENOSPC when watching many files
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

# Remove Amazon launcher
sudo rm /usr/share/applications/ubuntu-amazon-default.desktop

How to enable all APT repos again after upgrading to a new release

First remove old backed up sources lists:

sudo rm -f /etc/apt/sources.{list,list.d/}*{~,.save,.distUpgrade}

Then switch releases (e.g. rom hirsute to impish) and uncomment the repos:

for f in /etc/apt/sources.{list,list.d/}*; do
  [ -d "${f}" ] && continue
  echo "${f}"
  sudo sed -i \
    -e 's/hirsute/impish/g'\
    -e 's/^# \(.*\) # disabled on upgrade to.*/\1/g' \
  "${f}"
done

Not all 3rd party vendors will have repos for each Ubuntu release. The release may be too new, or the vendor may only support LTS releases while your upgrade may not be. To counter, now run:

sudo apt update

Find all the 404s, and change them back to the original release (e.g. focal) by editting the files inside /etc/apt, and re-running apt update until there are no more errors.

Games

Latest NVIDIA drivers

From https://github.com/lutris/docs/blob/master/InstallingDrivers.md which has warnings and compatibility disclaimer, read them.

sudo add-apt-repository ppa:graphics-drivers/ppa \
  && sudo dpkg --add-architecture i386  \
  && sudo apt update \
  && sudo apt install nvidia-driver-440 libnvidia-gl-440 libnvidia-gl-440:i386 \
  && sudo apt install libvulkan1 libvulkan1:i386 \
  ;

Lutris

sudo add-apt-repository ppa:lutris-team/lutris \
  && sudo apt-get update \
  && sudo apt-get install lutris \
  ;

Steam

# Steam
cd /tmp \
  && curl -fsSLo steam.deb https://steamcdn-a.akamaihd.net/client/installer/steam.deb \
  && sudo apt install ./steam.deb \
  && cd -

Age of Empires II

Start Steam, login, go to settings, advanced, check: Enable Steam Play for all Other titles. Latest Proto. Restart Steam. Now you can Install AOEII which is vital software to our remote company :)

StarCraft II

Parts taken and modified from https://www.reddit.com/r/starcraft/comments/5w0wyv/how_to_play_sc2_on_linux_a_full_walk_through/. Download the Battle.net installer https://www.blizzard.com/en-us/download/ and make it executable via:

chmod 755 ~/Downloads/Battle.net-Setup.exe

Get the latest Wine, and install ttf-mscorefonts-installer without which Battle.net will crash.

sudo dpkg --add-architecture i386 \
  && wget -O - https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add - \
  && sudo add-apt-repository "deb https://dl.winehq.org/wine-builds/ubuntu/ $(lsb_release -cs) main"
  && sudo apt install ttf-mscorefonts-installer \
  && sudo apt install wine \
  && sudo apt dist-upgrade \
  true
# Create a 32bit env:
WINEARCH=win32 WINEPREFIX=~/.wine32 winecfg
# Now go to libraries, and Add each of these:
# - api-ms-win-crt-math-l1-1-0
# - api-ms-win-crt-stdio-l1-1-0
# - dgbhelp
# - msvcp140
# - ucrtbase
# - vcruntime140
# Run installer
WINEARCH=win32 WINEPREFIX=~/.wine32 vblank_mode=0 wine ~/Downloads/Battle.net-Setup.exe
# Play
WINEARCH=win32 WINEPREFIX=~/.wine32 WINEDEBUG=-all vblank_mode=0 wine .wine/drive_c/Program\ Files/Battle.net/Battle.net.exe

FAQ

Why ; after that APT command?

It's a noop that lets me put a \ after each line (vs all lines but the last) which lets me more easily add/re-order lines. It's much like the preference trailing commas for all the elements of an array. If you still think that's just too weird, I'm okay with that :smile:

The reason I'm using && chaining at all is that a) programs like APT will read the STDIN and hence empty half of your copy-paste buffer and b) I want all commands to abort at the first sign of trouble.

Why didn't you just get an old Mac Book

Each new generation of hardware that allows our video encoding test suites to pass quicker, ramps up my productivity near-linearly.

Why didn't you get a Mac/Desktop

I need to sometimes pick up my machine to work at my co-founder/etc.

Why didn't you switch to Hackintosh

Now that's a good question. I didn't even properly look into it as I guess I feel Apple could at any time pull the plug on that, whether intentionally or no (by no longer including some driver needed for my non-apple-hardware, deploying some new kind of hardware-based signing, etc). Drop a line in the comments if I'm totally wrong about this?

Conclusion

If this makes you scared of trying something similar, good. Switching OSes is not for the faint-hearted. Especially to Linux. I read a Hacker News comment saying that

In a hotel (=on Mac), everything is stylish and cared for, but you have very little freedom to change things. At home (=on Linux), you need to do the dishes yourself but there's no external agenda. It's simply yours.

And even though there's enough to disagree with in analogy, it still resonated. I may still very well keep visiting hotels, I may very well buy Apple's next thing, but having the option now vs basically being forced is liberating.

As you noticed I have plenty of complaints, but no regrets about adding Linux to the mix. Two weeks in, allowing time to tweak to my habits/taste, I was feeling more productive than I was before. Big contributors there are: the OS being robust and snappy, not notifying me about the world as much, and it being finetuned to my routines more than macOS would encourage. Having GNU tools vs the minimalistic BSD versions helps, VM-less/faster Docker helps, and having APT to install all the things in a heartbeat is a godsent.

And say what you will about Electron being a memory hungry beast and so on, and yes that's true and if everything was written in Rust that'd be nice. But it is what allows me to make this jump now, at all.

Pretty much all my day-to-day tools are cross-platform now thanks to it, so I really even have the freedom to try Windows too. Although I was deep in Linux land when Ballmer said 'Linux is a cancer' and such, and so it will probably still take a few more years of Microsoft good-doing before I'm emotionally ready for something like that. Not having GPU/CUDA support in the 'Windows Subsystem for Linux', and seeing that Windows now offers ads in the start menu, as well as being a surveillance station by default, all don't help I'm afraid!

I'd love to hear what you think about all of this. Maybe I'm seeing it all wrong. I'd also like to hear what other tools you install to make your Linux box just right. I regard this post as a Work In Progress so it'll evolve with your feedback. Leave a note in the comments below, on Twitter, Hacker News, lobste.rs or Reddit.

Update 2019-12-03: Word is getting out that the 16" MBP that Apple just released addresses most painpoints, and has a working keyboard. By the time budget allows again to get a new machine.. Who knows.. I'm tempted.. I miss using Things! But I'm also getting into this Linux groove now. Perhaps a Dual boot? Does that work on a Mac? We'll see! Will update the post if something changes.