I end up installing and reinstalling Ubuntu a lot. As with many Linux users, I cannot not customize my installation. However, I use multiple devices with several accounts, some of which are not managed by me. This leads to a massive headache when trying to keep customizations in sync, especially when they keep changing as I learn new things.

This page is an attempt to consolidate all of my notes and helper scripts into the same place.

Installation

Actually installing Ubuntu is a very simple task. The folks at Canonical have put extraordinary amounts of effort to make installing Ubuntu both fast and simple.

Creating the Startup Disk

I only mention this because it has changed in recent years. You used to have to use UNetbootin to create a live USB from an ISO image. Nowadays you can use the builtin Startup Disk Creator to flash an ISO image to a USB drive. There's no need to install additional software, or run anything with sudo.

Select the ISO and USB drive you wish to flash, and click "Make Startup Disk". It will take some time, but is otherwise painless.

Note that the USB drive chosen may make a difference. I have learned that whenever I try to install from an image flashed to one of these flash drives, I get hit by this nasty bug. In short, the fix is to select "Try Ubuntu without installing" when prompted, and then delete /usr/lib/ubiquity/apt-setup/generators/40cdrom before running the installer.

Additionally, depending on the device I am installing Ubuntu on, there are some fixes that must be done before Ubuntu will install successfully.

On my Dell XPS 15 9560, I need to follow the instructions provided in this answer and install the Nvidia drivers before it will boot.

On my piecemeal desktop, I need to boot from a USB 2.0 port as discussed here.

Installing Ubuntu

This is a straightforward matter. The only thing worth mentioning is the installation type. You have several choices:

My choice depends on the device I am installing Ubuntu on. On several, I dual boot with other operating systems. On some, I use only Ubuntu. Your mileage may vary. Make sure to backup your data regardless of your choice.

First Steps

Bootstrap Software

Before anything else can be done, I need vim and git

sudo apt install vim git curl

SSH Keys

Before I can clone my dotfiles repository, I need to set up SSH keys for both github.com, gitlab.mcs.sdsmt.edu, and git.agill.xyz.

mkdir -p ~/.ssh
ssh-keygen -t rsa -b 4096 -f ~/.ssh/git
echo "AddKeysToAgent yes

Host github.com
    IdentityFile ~/.ssh/git

Host git.agill.xyz
    IdentityFile ~/.ssh/git

Host gitlab.mcs.sdsmt.edu
    IdentityFile ~/.ssh/git

Host anguish
    IdentityFile ~/.ssh/digitalocean

Host limbo
    IdentityFile ~/.ssh/limbo

Host agill.xyz
    IdentityFile ~/.ssh/limbo

Host linux103
    HostName linux103.mcs.sdsmt.edu
    User xxxxxxx
    IdentityFile ~/.ssh/opplab" > ~/.ssh/config

And then add the SSH keys to the proper accounts.

Dotfiles

Then I clone my dotfiles repository to ~/.config/dotfiles/ and symlink each of the dotfiles so that I don't have a git repository in my home folder.

git clone git@github.com:Notgnoshi/dotfiles.git ~/.config/dotfiles
~/.config/dotfiles/deploy.py ~
# Answer 'y' to 'Update dotfiles and plugins...' prompt
# Answer 'y' to 'Install fzf?' prompt
~/bin/configure.sh
source ~/.bashrc

This installation and configure process needs some work before I am completely happy with it. For one, I would like to forego ~/bin/ in favor of ~/.local/bin/ and I would like to remove the dependence on git.agill.xyz for a number of reasons. I would also like to rewrite the bin/configure.sh script to do everything that I'm listing on this page.

Software

Installing Pip as a User

For machines I do not have sudo privileges on, but still want an effective Python environment (Looking at you, school Linux lab), install Pip as a user.

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py --user

Installing to ~/.local/ as a User

The only thing needed to do here is add things to my path(s) so that I can build and install programs to ~/.local/ as a user. The following is set already in my ~/.bashrc, so there's no extra configuration to do.

# Add ~/bin/ to path
export PATH="$HOME/bin:$PATH"

# Add locally-installed binaries to path
export PATH="$HOME/.local/bin:$PATH"

# Add local header files to gcc path
export CPATH="$HOME/.local/include:$CPATH"

# Add local libraries to linker path
export LIBRARY_PATH="$LIBRARY_PATH:$HOME/.local/lib"

# Add local libraries to runtime path
export LD_LIBRARY_PATH="$LIBRARY_PATH"

Python Libraries

The Ubuntu repositories have an out-of-date version of Pip, so I prefer to install it without using Apt.

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
sudo -H python3 get-pip.py

Now, you're not supposed to install Python packages with sudo, so install them as a user

pip install --upgrade --user pylint pycodestyle pydocstyle nose black virtualenv \
    pygments ipython jupyter jupyterlab parsedatetime parse-torrent-name         \
    nbstripout nb_pdf_template
python3 -m nb_pdf_template.install --minted
mkdir -p ~/.jupyter
echo "c.PDFExporter.latex_command = ['xelatex', '-8bit', '-shell-escape','{filename}']" > ~/.jupyter/jupyter_nbconvert_config.py
echo "c.LatexExporter.template_file = 'classicm'" >> ~/.jupyter/jupyter_nbconvert_config.py

Apt Packages

Previously mentioned, there are essential packages that a prerequisites for anything else.

sudo apt install vim git curl

Here are commands essential to development work.

sudo apt install gcc g++ clang clang-format clang-tidy gdb valgrind make cmake  \
    shellcheck doxygen graphviz python3-dev optipng

Here are packages for LaTeX development

sudo apt install texlive-full chktex pdf2svg pandoc

Here are essential utilities.

sudo apt install htop nmap traceroute screen screenfetch linux-tools-common    \
    linux-tools-generic openssh-server tree iperf net-tools nfs-common pv

And tools necessary for further customization.

sudo add-apt-repository ppa:numix/ppa
sudo add-apt-repository ppa:mikhailnov/pulseeffects
sudo apt install gnome-tweak-tool chrome-gnome-shell numix-gtk-theme           \
    numix-icon-theme-circle pulseeffects

Nvidia drivers

sudo add-apt-repository ppa:graphics-drivers
sudo apt install nvidia-driver-415

Visual Studio Code and Extensions

I install Visual Studio Code and configure the excellent Settings Sync extension, which manages the rest of my extensions and settings using a private GitHub gist.

curl -L https://go.microsoft.com/fwlink/?LinkID=760868 -o code.deb
sudo apt install ./code.deb
code --install-extension shan.code-settings-sync

Follow the instructions here to set up a new gist, or download settings from an existing gist. Unfortunately, I have not found a way to perform these steps from the commandline.

Spotify and Discord

There are two ways to install Spotify for Ubuntu as mentioned here.

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 931FF8E79F0876134EDDBDCCA87FF9DF48BF1C90
echo deb http://repository.spotify.com stable non-free | sudo tee /etc/apt/sources.list.d/spotify.list
sudo apt-get update
sudo apt-get install spotify-client

And then to install Discord,

curl -L "https://discordapp.com/api/download?platform=linux&format=deb" -o discord.deb
sudo apt install ./discord.deb

Games

You used to have to do a lot of work in order to nicely install Minecraft on Linux, such as downloading a thumbnail, creating a startup script, and then creating ~/.local/share/applications/minecraft.desktop. Now there is a Debian installer available straight from the minecraft website. Note that this requires Java.

sudo add-apt-repository ppa:webupd8team/java
sudo apt install oracle-java8-installer libpango1.0-0
curl -L https://launcher.mojang.com/download/Minecraft.deb -o minecraft.deb
sudo apt install ./minecraft.deb

Installing Steam is much more straightforward.

sudo apt install steam

Customization

The absolute very first thing I do is clean everything but Documents, Downloads, and Desktop from my home folder.

rm -rf examples.desktop Desktop Videos Music Public Templates

Then I go through the system settings and tweak things to my preferences.

Ubuntu Settings

gsettings set org.gnome.shell favorite-apps "['firefox.desktop', 'org.gnome.Nautilus.desktop']"
gsettings set org.gnome.desktop.peripherals.touchpad natural-scroll false
gsettings set org.gnome.settings-daemon.plugins.color night-light-enabled true
gsettings set org.gnome.desktop.interface clock-format '12h'
gsettings set org.gtk.Settings.FileChooser clock-format '12h'
gsettings set org.gnome.desktop.notifications show-in-lock-screen false
gsettings set org.gnome.desktop.privacy remember-recent-files false
gsettings set org.gnome.desktop.datetime automatic-timezone true
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 3600
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type 'nothing'
gsettings set org.gnome.settings-daemon.plugins.power ambient-enabled true
gsettings set org.gnome.shell.extensions.dash-to-dock dash-max-icon-size 36

Gnome Extensions

I install the following Gnome Shell Extensions

Gnome Tweak Tool

After installing all of the extensions, I configure them and a few more settings with Gnome Tweak Tool.

gsettings set org.gnome.desktop.wm.preferences num-workspaces 4
gsettings set org.gnome.desktop.wm.preferences focus-mode 'sloppy'
gsettings set org.gnome.settings-daemon.plugins.xsettings hinting 'full'
gsettings set org.gnome.desktop.interface icon-theme 'Numix-Circle'
gsettings set org.gnome.desktop.interface show-battery-percentage true
gsettings set org.gnome.desktop.interface clock-show-date true
gsettings set org.gnome.mutter workspaces-only-on-primary false
gsettings set org.gnome.desktop.background show-desktop-icons false
gsettings set org.gnome.shell.extensions.dash-to-dock isolate-workspaces true

I also install PulseEffects to play with my sound settings. It might be necessary to run PulseEffects before setting these settings.

gsettings set com.github.wwmm.pulseeffects.sinkinputs.deesser post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.multibandcompressor post-messages false
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.deesser post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.maximizer post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.gate post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.loudness post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.compressor post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs plugins "['autogain', 'bass_enhancer', 'limiter', 'gate', 'multiband_gate', 'compressor', 'multiband_compressor', 'convolver', 'exciter', 'crystalizer', 'stereo_tools', 'reverb', 'equalizer', 'deesser', 'crossfeed', 'loudness', 'maximizer', 'filter']"
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.multibandcompressor post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.autogain post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.exciter post-messages false
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.equalizer post-messages false
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.multibandgate post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.multibandgate post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.bassenhancer amount 10.0
gsettings set com.github.wwmm.pulseeffects.sinkinputs.bassenhancer post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.bassenhancer state true
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.compressor post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.crossfeed post-messages false
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.pitch post-messages false
gsettings set com.github.wwmm.pulseeffects enable-all-apps true
gsettings set com.github.wwmm.pulseeffects use-dark-theme true
gsettings set com.github.wwmm.pulseeffects.sinkinputs.crystalizer post-messages false
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.gate post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.stereotools post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.limiter post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.convolver post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.filter post-messages false
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.filter post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.reverb post-messages false
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.webrtc post-messages false
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.reverb post-messages false
gsettings set com.github.wwmm.pulseeffects.sinkinputs.equalizer post-messages false
gsettings set com.github.wwmm.pulseeffects.sourceoutputs.limiter post-messages false

Network Settings

If I'm installing on a Laptop, I add my local NFS shares using my NAS's static local IP. But before I can do that, I need to make the directories where the shares will be mounted.

mkdir -p /mnt/{assets,documents,images,plex,projects}
# Synology NAS NFS shares. Note that this is a laptop, and these are local
# IPs. Also note that noauto means they won't be mounted on startup.
192.168.1.112:/volume1/ASSETS       /mnt/assets      nfs user,noauto 0 0
192.168.1.112:/volume1/DOCUMENTS    /mnt/documents   nfs user,noauto 0 0
192.168.1.112:/volume1/IMAGES       /mnt/images      nfs user,noauto 0 0
192.168.1.112:/volume1/PLEX         /mnt/plex        nfs user,noauto 0 0
192.168.1.112:/volume1/PROJECTS     /mnt/projects    nfs user,noauto 0 0

If I'm installing something that will always be connected to my local network, I add the following instead

# Synology NAS NFS shares
192.168.1.112:/volume1/ASSETS       /mnt/assets      nfs defaults 0 0
192.168.1.112:/volume1/DOCUMENTS    /mnt/documents   nfs defaults 0 0
192.168.1.112:/volume1/IMAGES       /mnt/images      nfs defaults 0 0
192.168.1.112:/volume1/PLEX         /mnt/plex        nfs defaults 0 0
192.168.1.112:/volume1/PROJECTS     /mnt/projects    nfs defaults 0 0

I also add any static local IPs to /etc/hosts and add an associated SSH key and entry in ~/.ssh/config.

School VPN and Network Drives

I have been able to figure out how to connect to the school VPN and network drives from an Ubuntu operating system, and have received repeated requests to share this knowledge, as it is not officially supported by the school. First, create a new PPTP VPN.

Update: It appears that either the Ubuntu 18.10 VPN utility is broken, or the school ITS department has it configured improperly. Running telnet techvpn.sdsmt.edu 1723 times out.

Then enter the following information in the Identity tab.

The username is your student ID number and the password is either your email password, D2L password, or WebAdvisor password, I'm not sure. Then configure the following settings in the Advanced menu.

Note that MSCHAP and MSCHAPv2 are the only boxes checked in the list of available authentication methods.

Then to connect to the shared F Drive, connect to a server in Nautilus with the address smb://speedy.sdsmt.edu/sdsmtshare/. When you click "connect", you will need to enter your username and password (the same as for the VPN).

To connect to your personal H Drive, the address is smb://speedy.sdsmt.edu/student_id$/ (note the $!)

Misc Config

I like enabling insults on incorrect sudo password attempts. It adds needed levity when it's nearing a deadline and I can't build a PDF because LaTeX is a bitch about SVG images.

# Add 'Defaults insults' to '/etc/sudoers'
# Will complain about readonly, but use :wq! to force write.
sudo vim /etc/sudoers
# sudo visudo will open in nano (eww)