Skip to content

Instantly share code, notes, and snippets.

@dvlden
Last active February 24, 2025 08:05
Show Gist options
  • Save dvlden/28ba472c6129a5d962d5 to your computer and use it in GitHub Desktop.
Save dvlden/28ba472c6129a5d962d5 to your computer and use it in GitHub Desktop.
My complete macOS Workspace Setup Tutorial!

Setting up workspace for web development...

If you are planning to use everything from this guide, do it in exact order, otherwise install only what you need...


Try my automated macOS setup... It will configure all of these automatically for you. If you don't want everything, feel free to clone repo and modify what you want/need!

dvL-den macOS Setup

macOS

install (command line tools only, not complete xcode)

xcode-select --install


install

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"


taps

declare -a taps=(
  'buo/cask-upgrade'
  'caskroom/cask'
)

for tap in "${taps[@]}"; do
  brew tap "$tap"
done

upgrade and update

brew upgrade && brew update


common commands (the ones that you might use day-to-day)

COMMAND DESCRIPTION
install Install formula
uninstall / rm / remove Uninstall formula
reinstall Uninstall and then install formula
update Fetch the newest version of Homebrew and all formulae
upgrade Upgrade outdated, unpinned brews
search Display all locally available formulae for brewing
list / ls List all files in the Homebrew prefix not installed by Homebrew
prune Remove dead symlinks from the Homebrew prefix
cleanup For all installed or specific formulae, remove any older versions from the cellar
doctor Check your system for potential problems
tap Migrate tapped formulae from symlink-based to directory-based structure
unlink Remove symlinks for formula from the Homebrew prefix
HINT: to learn more about each command and its use, enter brew help [COMMAND] command, and it will display all details about specific command and each flag it has... If you'd like to learn more, see complete list of commands

install

brew install cask


install apps (optional)

declare -a cask_apps=(
  '1password'
  'adguard'
  'adobe-creative-cloud'
  'alfred'
  'bartender'
  'droplr'
  'firefox'
  'flume'
  'google-backup-and-sync'
  'google-chrome'
  'iterm2'
  'opera'
  'screenflow'
  'sip'
  'skype'
  'slack'
  'sublime-text'
  'tableplus'
  'telegram'
  'transmit'
  'webstorm'
)

for app in "${cask_apps[@]}"; do
  brew cask install "$app"
done

common commands (the ones that you might use day-to-day)

COMMAND DESCRIPTION
audit verifies installability of Casks
cat dump raw source of the given Cask to the standard output
cleanup cleans up cached downloads and tracker symlinks
create creates the given Cask and opens it in an editor
doctor checks for configuration issues
edit edits the given Cask
fetch downloads remote application files to local cache
home opens the homepage of the given Cask
info displays information about the given Cask
install installs the given Cask
list with no args, lists installed Casks; given installed Casks, lists staged files
outdated list the outdated installed Casks
reinstall reinstalls the given Cask
search searches all known Casks
style checks Cask style using RuboCop
uninstall uninstalls the given Cask
zap zaps all files associated with the given Cask

install

brew install mas


install apps (optional)

declare -a mas_apps=(
  # '824183456'   # Affinity Photo
  # '824171161'   # Affinity Designer
  '1091189122'  # Bear
  # '736584830'   # Folx GO
  # '775737590'   # iA Writer
  '441258766'   # Magnet
  # '1063631769'  # Medis
  # '967805235'   # Paste
  '1176895641'  # Spark
  '583827028'   # WinZip
)

for app in "${mas_apps[@]}"; do
  mas install "$app"
done

common commands (the ones that you might use day-to-day)

COMMAND DESCRIPTION
account Prints the primary account Apple ID
help Display general or command-specific help
install Install from the Mac App Store
list Lists apps from the Mac App Store which are currently installed
outdated Lists pending updates from the Mac App Store
reset Resets the Mac App Store
search Search for apps from the Mac App Store
signin Sign in to the Mac App Store
signout Sign out of the Mac App Store
upgrade Upgrade outdated apps from the Mac App Store
version Print version number

install

brew install zsh zsh-completions zsh-autosuggestions zsh-syntax-highlighting
sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

make config file & open it

touch ~/.my-zshrc && subl ~/.my-zshrc


add into config file

# Load extensions
source /usr/local/share/zsh-autosuggestions/zsh-autosuggestions.zsh
source /usr/local/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

# Activate plugins
plugins=(git zsh-completions)

# Custom vars
SPARK=$HOME/.spark-installer
COMPOSER=$HOME/.composer/vendor/bin
LOCAL_NODE_BIN=node_modules/.bin

# Custom paths
PATH=/usr/local/sbin:$PATH
PATH=$SPARK:$PATH
PATH=$COMPOSER:$PATH
PATH=$LOCAL_NODE_BIN:$PATH

# Set default editor
EDITOR='subl -w'

# Load my aliases
if [ -f ~/.aliases ]; then
  . ~/.aliases
fi

# Load my functions
if [ -f ~/.functions ]; then
  . ~/.functions
fi

local ret_status="%(?:%{$fg_bold[green]%}△ :%{$fg_bold[red]%}▽ )"
PROMPT='${ret_status} %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)'

add custom config into main config

echo ". ~/.my-zshrc" >> "$HOME/.zshrc"


make aliases file & open it

touch ~/.aliases && subl ~/.aliases


add into aliases file

# Helpful
alias s='cd ~/Sites'
alias art='php artisan'
alias path='echo -e ${PATH//:/\\n}'
alias copy_ssh="pbcopy < $HOME/.ssh/id_rsa.pub"
alias reload="exec ${SHELL} -l"
alias afk="/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend"
alias flush_dns="sudo killall -HUP mDNSResponder"
alias chdirs="find . -type d -exec chmod 755 {} \;"
alias chfiles="find . -type f -exec chmod 644 {} \;"

# Common files for editing
alias edit_hosts='subl /etc/hosts'
alias edit_httpd='subl /usr/local/etc/httpd/httpd.conf'
alias edit_vhosts='subl /usr/local/etc/httpd/extra/httpd-vhosts.conf'
alias edit_php='subl /usr/local/etc/php/7.2/php.ini'

# System
alias update='mas upgrade; brew cleanup; brew upgrade; brew update; brew cu -a -y; composer global update; npm update -g; npm install -g npm'
alias show_files='defaults write com.apple.finder AppleShowAllFiles -bool true && killall Finder'
alias hide_files='defaults write com.apple.finder AppleShowAllFiles -bool false && killall Finder'
alias show_desktop="defaults write com.apple.finder CreateDesktop -bool true && killall Finder"
alias hide_desktop="defaults write com.apple.finder CreateDesktop -bool false && killall Finder"
alias enable_gate="sudo spctl --master-enable"
alias disable_gate="sudo spctl --master-disable"

# IP
alias ip='dig +short myip.opendns.com @resolver1.opendns.com'

# NPM
alias nom='rm -rf node_modules/ && npm cache verify && npm install'

# Github
alias wip="git add .;git commit -m 'wip'"
alias nah='git reset --hard;git clean -df'

# Composer
alias dump='composer dump-autoload -o'

# Chrome
alias kill_chrome="ps ux | grep '[C]hrome Helper --type=renderer' | grep -v extension-process | tr -s ' ' | cut -d ' ' -f2 | xargs kill"

# Dummy
alias shrug="printf '¯\_(ツ)_/¯' | pbcopy"
alias flipt="printf '(╯°□°)╯︵ ┻━┻' | pbcopy"
alias fight="printf '(ง'̀-'́)ง' | pbcopy"

make functions file & open it

touch ~/.functoons && subl ~/.functions


add into functions file

# Make directory and enter it
function mkd () {
  mkdir -p "$@" && cd "$_";
}

# Copy site and its contents
function copy_site () {
  wget -e robots=off -p -k "$1"
}

function copy_site_r () {
  wget -e robots=off -r -p -k "$1"
}

# Extract most know archives with one command
extract () {
  if [ -f $1 ] ; then
    case $1 in
      *.tar.bz2)   tar xjf $1     ;;
      *.tar.gz)    tar xzf $1     ;;
      *.bz2)       bunzip2 $1     ;;
      *.rar)       unrar e $1     ;;
      *.gz)        gunzip $1      ;;
      *.tar)       tar xf $1      ;;
      *.tbz2)      tar xjf $1     ;;
      *.tgz)       tar xzf $1     ;;
      *.zip)       unzip $1       ;;
      *.Z)         uncompress $1  ;;
      *.7z)        7z x $1        ;;
      *)     echo "'$1' cannot be extracted via extract()" ;;
    esac
  else
    echo "'$1' is not a valid file"
  fi
}

# Determine size of a file or total size of a directory
function fs() {
  if du -b /dev/null > /dev/null 2>&1; then
    local arg=-sbh
  else
    local arg=-sh
  fi

  if [[ -n "$@" ]]; then
    du $arg -- "$@"
  else
    du $arg .[^.]* *
  fi
}

install package-control

get installation code


packages

  • Preferences > Package Settings > Package Control > Settings – User
  • Copy/Paste contents from below and save the file
  • Reopen application and wait until everything is installed
{
  "bootstrapped": true,
  "installed_packages":
  [
    "A File Icon",
    "AdvancedNewFile",
    "ApacheConf",
    "AutoFileName",
    "Autoprefixer",
    "Babel",
    "BracketHighlighter",
    "ColorPicker",
    "DA UI",
    "DocBlockr",
    "EditorConfig",
    "Emmet",
    "GitGutter",
    "HyperClick",
    "JavaScript Completions",
    "Laravel Blade Highlighter",
    "Markdown Preview",
    "MarkdownEditing",
    "Material Theme",
    "Minify",
    "Package Control",
    "PackageResourceViewer",
    "PHP Companion",
    "PHP CS Fixer",
    "Sass",
    "SFTP",
    "SnippetMaker",
    "SublimeCodeIntel",
    "SublimeLinter",
    "SublimeLinter-phpcs",
    "Terminal",
    "Vue Syntax Highlight"
  ]
}

preferences

  • Download and install the font that you want to use (e.g. Operator Mono or Fira Code)
  • Preferences > Settings (cmd ,)
  • On the right pane, paste the contents from below and save the file
  • Reopen application
{
	"bold_folder_labels": true,
	"color_scheme": "Packages/DA UI/DA Dark.tmTheme",
	"copy_with_empty_selection": false,
	"create_window_at_startup": false,
	"drag_text": false,
	"detect_indentation": false,
	"enable_tab_scrolling": false,
	"ensure_newline_at_eof_on_save": true,
	"find_selected_text": true,
	"folder_exclude_patterns":
	[
		".svn",
		".git",
		".hg",
		"CVS",
		"composer",
		"node_modules"
	],
	"font_face": "Fira Code",
	"font_size": 14,
	"highlight_line": true,
	"highlight_modified_tabs": true,
	"indent_to_bracket": true,
	"line_padding_bottom": 6,
	"line_padding_top": 6,
	"margin": 8,
	"match_brackets_content": false,
	"match_selection": false,
	"match_tags": false,
	"open_files_in_new_window": false,
	"preview_on_click": false,
	"shift_tab_unindent": true,
	"show_full_path": false,
	"theme": "DA.sublime-theme",
	"translate_tabs_to_spaces": true,
	"trim_trailing_white_space_on_save": true
}
HINT: Type whoami in terminal to see your username, you will need it for this config file... (replace "nn" occurrences)

stop and unload system-installed apache

sudo apachectl stop >/dev/null
sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist 2>/dev/null

install

brew install httpd


open main config

bash -c 'exec env ${EDITOR:=nano} /usr/local/etc/httpd/httpd.conf'


modify main config

FIND & UNCOMMENT
rewrite_module
vhost_alias_module
httpd-vhosts
ServerName www.example.com:8080
OCCURRENCES FIND REPLACE OCCURRENCE TO REPLACE
1 Listen 8080 Listen 80 All
1 User _www User nn All
1 Group _www Group staff All
2 /usr/local/var/www /User/nn/Sites All
3 AllowOverride None AllowOverride All 3rd
1 ServerName www.example.com:8080 ServerName localhost All
FIND ADD WHERE
rewrite_module LoadModule php7_module /usr/local/opt/[email protected]/lib/httpd/modules/libphp7.so after search occurrence
<IfModule dir_module> <FilesMatch \.php$> SetHandler application/x-httpd-php </FilesMatch> after search occurence's closed tag

open virtual-hosts config

bash -c 'exec env ${EDITOR:=nano} /usr/local/etc/httpd/extra/httpd-vhosts.conf'


modify virtual-hosts config (replace existing contents)

Define USER nn
Define PATH "/Users/${USER}/Sites"

<VirtualHost *:80>
    ServerName localhost
    DocumentRoot ${PATH}
</VirtualHost>

<VirtualHost *:80>
    ServerAlias *.test
    UseCanonicalName Off
    VirtualDocumentRoot "${PATH}/%1"
</VirtualHost>

<VirtualHost *:80>
    ServerAlias *.public
    UseCanonicalName Off
    VirtualDocumentRoot "${PATH}/%1/public"
</VirtualHost>

restart

sudo apachectl -e info -k restart


start daemon for the first time and run on system startup

sudo brew services start httpd


common commands (the ones that you might use day-to-day)

COMMAND DESCRIPTION
start Start the Apache httpd daemon
stop Stop the Apache httpd daemon
restart Restart the Apache httpd daemon
graceful Gracefully restarts the Apache httpd daemon
graceful-stop Gracefully stops the Apache httpd daemon
configtest Run a configuration file syntax test

watch error log (tail is not apachectl command, but it's very useful)

tail -f /usr/local/var/log/apache2/error_log


install

brew install dnsmasq


rewrite config

cat > "$(brew --prefix)/etc/dnsmasq.conf" <<EOF
address=/.test/127.0.0.1
address=/.public/127.0.0.1
EOF

add resolvers

sudo mkdir -p /etc/resolver
sudo bash -c 'echo "nameserver 127.0.0.1" > /etc/resolver/test'
sudo bash -c 'echo "nameserver 127.0.0.1" > /etc/resolver/public'

start

sudo brew services start dnsmasq


modify wi-fi dns

System Preferences > Network > Wifi > Advanced > DNS

127.0.0.1

test

dig sample.test @127.0.0.1

# you should be able to find following in the output
;; ANSWER SECTION:
sample.test.   0 IN  A 127.0.0.1

install

brew install php


install dependency manager (composer)

brew install composer


open config file

bash -c 'exec env ${EDITOR:=nano} /usr/local/etc/php/*/php.ini'


find and replace

FIND MODIFY / REPLACE
;date.timezone uncomment and add desired timezone (e.g. Europe/Belgrade)
post_max_size set it to 25M
upload_max_filesize set it to 20M
HINT: You can find timezones here: List of Supported Timezones

install

brew install mysql


start

brew services start mysql


config (optional)

By default, MySQL will install with user root and no password. If you want to configure that, run following command...

mysql_secure_installation

Since you will be required to set the password to root and you may not need it (if this is localhost for development), you may set it to toor and afterwards disable the password again, with the commands below.

mysql -u root -p
toor

ALTER USER 'root'@'localhost' IDENTIFIED BY '';
FLUSH PRIVILEGES;

install

brew install node (it installs npm too)



install packages (my favourites)

npm i -g @vue/cli npm-check-updates


common commands (the ones that you might use day-to-day)

COMMAND DESCRIPTION
adduser Add a registry user account
dedupe / ddp Reduce duplication
deprecate Deprecate a version of a package
init Interactively create a package.json file
install / i Install a package
install-test / it Install and Test combined
list / ls List installed packages
login Add a registry user account
logout Log out of the registry
outdated Check for outdated packages
prune Remove extraneous packages
publish Publish a package
run Run arbitrary package scripts
search / s / se Search for packages
test / t / tst Test a package
uninstall / un Remove a package
unpublish Remove a package from the registry
update / up Update a package
HINT: to learn more about each command and its use, enter npm help [COMMAND] command, and it will display all details about specific command and each flag it has... If you'd like to learn more, see complete list of commands

install

brew install git


config (replace with your data)

git config --global user.name "Nenad Novaković"
git config --global user.email "[email protected]"
git config --global core.editor "subl -n -w"
git config --global color.ui true

https config

git config --global credential.helper osxkeychain


ssh config

# Generate key
ssh-keygen -t rsa -C "[email protected]"

# Copy key
cat ~/.ssh/id_rsa.pub | pbcopy

# Add to Github
[Github SSH keys](https://github.com/settings/ssh)

# Test connection
ssh -T [email protected]

# > Hi dvlden! You've successfully authenticated, but GitHub does not provide shell access.

common commands (the ones that you might use day-to-day)

COMMAND DESCRIPTION
clone Clone a repository into a new directory
init Create an empty Git repository or reinitialize an existing one
add Add file contents to the index
mv Move or rename a file, a directory, or a symlink
reset Reset current HEAD to the specified state
rm Remove files from the working tree and from the index
log Show commit logs
show Show various types of objects
status Show the working tree status
branch List, create, or delete branches
checkout Switch branches or restore working tree files
commit Record changes to the repository
diff Show changes between commits, commit and working tree, etc
merge Join two or more development histories together
tag Create, list, delete or verify a tag object signed with GPG
pull Fetch from and integrate with another repository or a local branch
push Update remote refs along with associated objects
HINT: to learn more about each command and its use, enter git help [COMMAND] command, and it will display all details about specific command and each flag it has... If you'd like to learn more, see complete list of commands
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment