Info

In 2021, I returned to macOS after several years on ChromeOS. I made these notes during setup. Some things have changed by 2024 and this document needs revision.

First, install software updates, migrate from another computer, etc.

System Preferences → Sharing → Computer Name → Edit… to set hostname to something short. Uncheck “Use dynamic global hostname”

Console setup

Install Homebrew from https://brew.sh/

Install iTerm2 https://iterm2.com/. The default dark colour palette is somewhat low contrast. Install a custom colour scheme such as Material Design colours. Update: Prefer Ghostty now.

Default shell in Big Sur is already zsh. Install oh-my-zsh https://ohmyz.sh/

brew install coreutils findutils, then set paths in ~/.oh-my-zsh/custom/path.zsh:

export PATH="/opt/homebrew/opt/coreutils/libexec/gnubin:/opt/homebrew/opt/findutils/libexec/gnubin:$PATH"

Install powerlevel10k for terminal prompt: brew install romkatv/powerlevel10k/powerlevel10k, follow instructions for oh-my-zsh, and use p10k configure to set up prompt

Colorize console commands. Make ~/.oh-my-zsh/colors.zsh:

export CLICOLOR=1  # This is for BSD ls (macOS default)
alias ls='gls --color=auto'  # This is for GNU ls
export LESS='-R'
export LESSOPEN='|pygmentize -g %s'
export GREP_OPTIONS='--color=auto'

brew install zsh-fast-syntax-highlighting then make ~/.oh-my-zsh/zsh-syntax-highlighting.zsh:

source /opt/homebrew/opt/zsh-fast-syntax-highlighting/share/zsh-fast-syntax-highlighting/fast-syntax-highlighting.plugin.zsh

Setup autocomplete: First, brew install zsh-completions, then add this to ~/.zprofile (brew provides its own autocompletions, so there are two folders):

FPATH="$(brew --prefix)/share/zsh/site-functions:$(brew --prefix)/share/zsh-completions:$FPATH"

Additional instructions at https://docs.brew.sh/Shell-Completion

Install bat as a replacement for cat and less with colour output: brew install bat

Install mosh: brew install mosh and Eternal Terminal: brew install MisterTea/et/et. Both require server-side installation too.

Install non-system Python: brew install python (is 3.13 at the time of writing) and virtualenvwrapper (pip3 install virtualenvwrapper), then setup virtualenvs for projects (using mkvirtualenv name and workon name). While modern Python workflows seem to have migrated to Pipenv and Poetry, I haven’t got my head around it yet.

Install direnv: brew install direnv, add it to plugin list in ~/.zshrc then setup for managing virtualenvs:

  1. Add to ~/.direnvrc:
layout_virtualenv() {
local venv_path="$1"
source ${venv_path}/bin/activate
}
 
layout_virtualenvwrapper() {
local venv_path="${WORKON_HOME}/$1"
layout_virtualenv $venv_path
}
  1. In the project folder, add a .envrc containing:
layout virtualenvwrapper my-project-virtualenv-name
unset PS1
  1. Bless the file to enable it: direnv allow .

Install zoxide with brew install zoxide and enable oh-my-zsh plugin. Use z folder-name to rapidly jump between folders.

Enabled plugins in ~/.zshrc: git direnv colorize zoxide

Enable Touch ID for sudo

With macOS Sonoma (macOS 14)

cd /etc/pam.d
sudo cp sudo_local.template sudo_local
vi sudo_local

Then uncomment the line that contains auth sufficient pam_tid.so:

# sudo_local: local config file which survives system update and is included for sudo
# uncomment following line to enable Touch ID for sudo
auth       sufficient     pam_tid.so

Use sudo-touchid prior to macOS Sonoma

brew install artginzburg/tap/sudo-touchid
sudo brew services start sudo-touchid

Even older instructions

Install pam_reattach: brew install fabianishere/personal/pam_reattach

sudo vim /etc/pam.d/sudo and add the first two lines here to the top:

# sudo: auth account password session
auth       optional       /opt/homebrew/lib/pam/pam_reattach.so
auth       sufficient     pam_tid.so
auth       sufficient     pam_smartcard.so
auth       required       pam_opendirectory.so
account    required       pam_permit.so
password   required       pam_deny.so
session    required       pam_permit.so

External keyboard

If you have an external keyboard, macOS may insist the function keys (F1-F12) are mapped to the same shortcuts as on the in-built keyboard, blocking access to actual function keys. To override, install Karabiner-Elements, accept all permission requirements (Accessibility, Extension) and use these settings:

  • Function keys → For all devices: Map all F1-F12 keys to function keys, not the (default) shortcuts
  • For the in-built keyboard, map them back to media keys.
  • If you have a newer Mac, F6 may be mapped to a DND shortcut (🌙 icon) that Karabiner doesn’t recognise (issues #2901 and #3851). If you don’t need Karabiner for anything other than function keys, the easy fix is to go to Settings → Devices and remove the internal keyboard (turn off “modify events”).

Terminal

If you prefer Kitty or Ghostty for your terminal, they set custom identifiers in $TERM that can mess up SSH connections. Remote connections won’t have their xterm-kitty and xterm-ghostty in their terminfo databases. You’ll need additional configuration (see for Kitty and for Ghostty).

If you don’t need their special terminal features on a remote host, you reset $TERM instead. Add to ~/.ssh/config:

Host *
  SetEnv TERM=xterm-256color

Eternal Terminal doesn’t support setting $TERM, so add an alias to ~/.oh-my-zsh/custom/aliases.zsh:

[[ "$TERM" =~ "xterm-(ghostty|kitty)"]] && alias et='TERM=xterm-256color et'

GUI

Install Multitouch, Rectangle Pro, Charmstone (optional) and Raycast.

System Preferences → Trackpad → More Gestures → Swipe between full-screen apps = change to use four fingers

Setup Multitouch:

  1. Three finger tap = middle click
  2. Three finger click = middle click
  3. Three finger swipe left = apps with tabs, switch tab left
  4. Three finger swipe right = apps with tabs, switch tab right

Setup Rectangle Pro: mostly default settings, start at login

Setup Raycast: mostly default settings, maybe swap shortcut with Spotlight

Fix keyboard navigation to be a bit more Windows-like. Make ~/Library/KeyBindings/DefaultKeyBinding.dict containing:

{
"\UF729"  = (moveToBeginningOfLine:); // home
"\UF72B"  = (moveToEndOfLine:); // end
"$\UF729" = (moveToBeginningOfLineAndModifySelection:); // shift-home
"$\UF72B" = (moveToEndOfLineAndModifySelection:); // shift-end
"^\UF729" = (moveToBeginningOfDocument:); // ctrl-home
"^\UF72B" = (moveToEndOfDocument:); // ctrl-end
"^$\UF729" = (moveToBeginningOfDocumentAndModifySelection:); // ctrl-shift-home
"^$\UF72B" = (moveToEndOfDocumentAndModifySelection:); // ctrl-shift-end
"^\UF702" = (moveWordBackward:); // ctrl-left
"^$\UF702" = (moveWordBackwardAndModifySelection:); // ctrl-shift-left
"^\UF703" = (moveWordForward:); // ctrl-right
"^$\UF703" = (moveWordForwardAndModifySelection:); // ctrl-shift-right
}

Console dev setup

Postfix

Postfix is pre-installed, but has to be configured to (a) relay email and (b) auto-start SMTP server.

Setup relayhost. Add to /etc/postfix/main.cf:

relayhost = [smtp.myserver.tld]:587
smtp_generic_maps = hash:/etc/postfix/generic
# Use TLS/SASL authentication
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_mechanism_filter = plain
smtp_use_tls = yes
smtp_tls_security_level = encrypt

Add to /etc/postfix/generic:

my-username@my-laptop-host    [email protected]

sudo postmap /etc/postfix/generic

Add to /etc/postfix/sasl_passwd:

[smtp.myserver.tld]:587 login:password

Then:

sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd

Next, setup Postfix to auto-start. Make /Library/LaunchDaemons/org.postfix.custom.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "[http://www.apple.com/DTDs/PropertyList-1.0.dtd](http://www.apple.com/DTDs/PropertyList-1.0.dtd)">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>org.postfix.custom</string>
  <key>Program</key>
  <string>/usr/libexec/postfix/master</string>
  <key>ProgramArguments</key>
  <array>
    <string>master</string>
  </array>
  <key>QueueDirectories</key>
  <array>
    <string>/var/spool/postfix/maildrop</string>
  </array>
  <key>AbandonProcessGroup</key>
  <true/>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>
</dict>
</plist>

Then sudo launchctl load /Library/LaunchDaemons/org.postfix.custom.plist

PostgreSQL, Redis, NodeJS

PostgreSQL: brew install postgresql and brew services start postgresql

Postgres.app is no longer recommended. They haven’t released M1 or Universal binaries yet (July 2021).

Your user account will be the root user of PostgreSQL in this setup, while in production it won’t be. The CREATE EXTENSION command is straightforward when root, but in production will require switching privileges, such as with a sudo su - postgres -c "psql database < commands.sql"

Redis: brew install redis and brew services start redis

NodeJS: brew install node

GUI dev setup

Install VS Code, GitHub Desktop, Sublime Text, Sublime Merge