Skip to content

Instantly share code, notes, and snippets.

@derekaug
Last active June 27, 2017 17:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save derekaug/5ca1c20597ca46147aff322aed82ecdf to your computer and use it in GitHub Desktop.
Save derekaug/5ca1c20597ca46147aff322aed82ecdf to your computer and use it in GitHub Desktop.
Setting up a LAMP stack / development environment on OSX

New Machine Setup

Preface

This is a living document, if I sent this your way and there's any changes you'd recommend or anything that's borked, don't hesitate to hit me up and tell me I suck at life.

Initial Setup

Set default to how all files (even hidden files) in Finder because it sucks not seeing hidden files in Finder when you know they are there:

defaults write com.apple.finder AppleShowAllFiles YES

Homebrew Install

Install Homebrew for package management, which is used for about every step in this process to some extent, so it is absolutely necessary. It also makes maintaining / updating packages super simple, as well as installing desktop applications without seeking everything out via your web browser.

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

Now it's time to tappa dat ass, basically these are extra git repositiories with formulae for building certain packages we'll be using in our environment install:

brew tap caskroom/cask
brew tap homebrew/bundle
brew tap homebrew/dupes
brew tap homebrew/versions
brew tap homebrew/php
brew tap homebrew/apache
brew tap homebrew/services

These will allow us to install various components that we need, but also the services is very important for helping us easily start / stop / restart different services along the way. Services may be one of my favorite things about this setup, instead of remember specific start up / restart commands for each service, you just need to go like this to restart Apache (after we get it installed, which we will do later):

brew services restart httpd24

Is great magic, as Craiggers would say.

Version Control Install

Get that Git goodness!

brew install git

Setup Git globals to your liking, here's mine:

git config --global user.name "Derek J. Augustine"
git config --global user.email derek.augustine@archrival.com
git config --global user.editor vim
git config --global push.default simple

For legacy projects (which are few and far between nowadays), we'll also install SVN because that's what we used back in the good ol' days.

brew install subversion	

Random Applications Install

These are just a few of the standard desktop applications I install, utilizing Homebrew's Cask system so I don't have to hunt down everything on the interwebz. These are mine, feel free to trim some fat / add you own.

brew cask install adobe-creative-cloud
brew cask install android-studio
brew cask install phpstorm
brew cask install sublime-text
brew cask install macdown
brew cask install iterm2
brew cask install google-chrome
brew cask install firefox
brew cask install 1password
brew cask install transmit
brew cask install virtualbox
brew cask install dropbox
brew cask install slack
brew cask install sourcetree
brew cask install sequel-pro
brew cask install spotify
brew cask install vlc
brew cask install skype
brew cask install java
brew cask install medis

You can search for casks by doing brew cask search [name].

The possibilities are endless here, but I really do love this feature and highly recommend it in general, not just for initial setups.

Someday I'll update this to using the Brewfile approach to make things a bit easier for the install process, but for now, this is what you get.

LAMP Stack install

MySQL Install

First we'll just knock out the MySQL install.

brew install mysql

That was easy enough, let's copy over the default config file.

cp -v $(brew --prefix mysql)/support-files/my-default.cnf $(brew --prefix)/etc/my.cnf

And make one adjustment to that file:

sed -i '' 's/^#[[:space:]]*\(innodb_buffer_pool_size\)/\1/' $(brew --prefix)/etc/my.cnf

The last step is running mysql_secure_config to set up the root password / default security things. Just step through the step by step guide that will get presented to you, making note of your root password. Most things you can probably answer no to (like the validate password plugin).

mysql_secure_install

That'll be it for MySQL until we setup our project(s) later.

PHP Install

We're going to install PHP 5.6, 7.0, and 7.1. We'll default to 7.1, so we'll install that one last.

brew install php56 php56-opcache php56-imagick php56-intl php56-mcrypt php56-memcached php56-xdebug
brew unlink php56
brew install php70 php70-opcache php70-imagick php70-intl php70-mcrypt php70-memcached php70-xdebug
brew unlink php70
brew install php71 php71-opcache php71-imagick php71-intl php71-mcrypt php71-memcached php71-xdebug

Edit php.ini's to have default timezone set and setup some other defaults, fix permissions for PEAR / PECL libraries, and set OpCache memory limits:

(export USERHOME=$(dscl . -read /Users/`whoami` NFSHomeDirectory | awk -F"\: " '{print $2}') ; sed -i '-default' -e 's|^;\(date\.timezone[[:space:]]*=\).*|\1 \"'$(sudo systemsetup -gettimezone|awk -F"\: " '{print $2}')'\"|; s|^\(memory_limit[[:space:]]*=\).*|\1 512M|; s|^\(post_max_size[[:space:]]*=\).*|\1 200M|; s|^\(upload_max_filesize[[:space:]]*=\).*|\1 100M|; s|^\(default_socket_timeout[[:space:]]*=\).*|\1 600|; s|^\(max_execution_time[[:space:]]*=\).*|\1 300|; s|^\(max_input_time[[:space:]]*=\).*|\1 600|; $a\'$'\n''\'$'\n''; PHP Error log\'$'\n''error_log = '$USERHOME'/Sites/logs/php-error_log'$'\n' $(brew --prefix)/etc/php/5.6/php.ini) 
(export USERHOME=$(dscl . -read /Users/`whoami` NFSHomeDirectory | awk -F"\: " '{print $2}') ; sed -i '-default' -e 's|^;\(date\.timezone[[:space:]]*=\).*|\1 \"'$(sudo systemsetup -gettimezone|awk -F"\: " '{print $2}')'\"|; s|^\(memory_limit[[:space:]]*=\).*|\1 512M|; s|^\(post_max_size[[:space:]]*=\).*|\1 200M|; s|^\(upload_max_filesize[[:space:]]*=\).*|\1 100M|; s|^\(default_socket_timeout[[:space:]]*=\).*|\1 600|; s|^\(max_execution_time[[:space:]]*=\).*|\1 300|; s|^\(max_input_time[[:space:]]*=\).*|\1 600|; $a\'$'\n''\'$'\n''; PHP Error log\'$'\n''error_log = '$USERHOME'/Sites/logs/php-error_log'$'\n' $(brew --prefix)/etc/php/7.0/php.ini)
(export USERHOME=$(dscl . -read /Users/`whoami` NFSHomeDirectory | awk -F"\: " '{print $2}') ; sed -i '-default' -e 's|^;\(date\.timezone[[:space:]]*=\).*|\1 \"'$(sudo systemsetup -gettimezone|awk -F"\: " '{print $2}')'\"|; s|^\(memory_limit[[:space:]]*=\).*|\1 512M|; s|^\(post_max_size[[:space:]]*=\).*|\1 200M|; s|^\(upload_max_filesize[[:space:]]*=\).*|\1 100M|; s|^\(default_socket_timeout[[:space:]]*=\).*|\1 600|; s|^\(max_execution_time[[:space:]]*=\).*|\1 300|; s|^\(max_input_time[[:space:]]*=\).*|\1 600|; $a\'$'\n''\'$'\n''; PHP Error log\'$'\n''error_log = '$USERHOME'/Sites/logs/php-error_log'$'\n' $(brew --prefix)/etc/php/7.1/php.ini) 
chmod -R ug+w $(brew --prefix php56)/lib/php  
chmod -R ug+w $(brew --prefix php70)/lib/php
chmod -R ug+w $(brew --prefix php71)/lib/php  
/usr/bin/sed -i '' "s|^\(\;\)\{0,1\}[[:space:]]*\(opcache\.enable[[:space:]]*=[[:space:]]*\)0|\21|; s|^;\(opcache\.memory_consumption[[:space:]]*=[[:space:]]*\)[0-9]*|\1256|;" $(brew --prefix)/etc/php/5.6/php.ini   
/usr/bin/sed -i '' "s|^\(\;\)\{0,1\}[[:space:]]*\(opcache\.enable[[:space:]]*=[[:space:]]*\)0|\21|; s|^;\(opcache\.memory_consumption[[:space:]]*=[[:space:]]*\)[0-9]*|\1256|;" $(brew --prefix)/etc/php/7.0/php.ini
/usr/bin/sed -i '' "s|^\(\;\)\{0,1\}[[:space:]]*\(opcache\.enable[[:space:]]*=[[:space:]]*\)0|\21|; s|^;\(opcache\.memory_consumption[[:space:]]*=[[:space:]]*\)[0-9]*|\1256|;" $(brew --prefix)/etc/php/7.1/php.ini   

We'll need to enable short_open_tags and setup error_reporting like we want it as well:

/usr/bin/sed -i '' "s/short_open_tag[[:space:]]*=[[:space:]]*.*/short_open_tag = On/g" $(brew --prefix)/etc/php/5.6/php.ini
/usr/bin/sed -i '' "s/error_reporting[[:space:]]*=[[:space:]]*.*/error_reporting = E_ALL \& ~E_NOTICE/g" $(brew --prefix)/etc/php/5.6/php.ini
/usr/bin/sed -i '' "s/short_open_tag[[:space:]]*=[[:space:]]*.*/short_open_tag = On/g" $(brew --prefix)/etc/php/7.0/php.ini
/usr/bin/sed -i '' "s/error_reporting[[:space:]]*=[[:space:]]*.*/error_reporting = E_ALL \& ~E_NOTICE/g" $(brew --prefix)/etc/php/7.0/php.ini
/usr/bin/sed -i '' "s/short_open_tag[[:space:]]*=[[:space:]]*.*/short_open_tag = On/g" $(brew --prefix)/etc/php/7.1/php.ini
/usr/bin/sed -i '' "s/error_reporting[[:space:]]*=[[:space:]]*.*/error_reporting = E_ALL \& ~E_NOTICE/g" $(brew --prefix)/etc/php/7.1/php.ini

At the end of all this debauchery, we'll need to start the fpm module for the version of PHP we want to use, in our case, PHP 7.1.

brew services start php71

Apache Install

First, let's remove system Apache from the launchctl daemons, because we're using Homebrewed Apache and system Apache will get in the way:

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

Now, we'll install Apache 2.4:

brew install -v homebrew/apache/httpd24 --with-homebrew-openssl --with-mpm-event

Next, we'll configure Apache. In all honesty, I set it up, got it working, and forgot it, so I don't have any handy sed commands for getting it going. But I do have my current configuration for reference. Also, I prefer vim as my default editor, you can use whatever you prefer!

vim $(brew --prefix)/etc/apache2/2.4/httpd.conf

Here's a link to mine for reference: httpd.conf

I'll highlight some of the key things to make sure to enable, for instance, make sure the following modules are uncommented:

LoadModule proxy_module libexec/mod_proxy.so
LoadModule proxy_fcgi_module libexec/mod_proxy_fcgi.so
LoadModule alias_module libexec/mod_alias.so
LoadModule rewrite_module libexec/mod_rewrite.so

I also set the User / Group to the following to help resolve permission issues on development setups:

User derek.augustine  # current user
Group staff			  # general group	

I also make sure the document root contains where all my development sites will live reside:

DocumentRoot "/Users/derek.augustine/Sites"
<Directory "/Users/derek.augustine/Sites">
### ...
</Directory>

The last thing I do is setup where my virtual hosts configuration will live (we'll setup that file next), this is at the end of my file.

Include /Users/derek.augustine/Sites/httpd-vhosts.conf

That should be most of the changes, feel free to change / configure anything else within that you see fit.

Next, we'll setup our virtual hosts file. Let's download a base virtual host template to use as a starting point, I like to put it at the root of where my sites will live so it's easily accessible. I like to save my virtual hosts file at the root of where my sites live, which in my case is at ~/Sites/ so my virtual hosts file is located at ~/Sites/httpd-vhosts.conf.

curl https://gist.githubusercontent.com/derekaug/bb5248a9e02d2dfe3434a8d779c8b221/raw/e3edc22929e747bff69d73c799de18bc1568ea6c/httpd-vhosts.conf > ~/Sites/httpd-vhosts.conf

You will need to replace the following placeholders within this file:

{PORT} => your HTTP port, mine is 8005
{USERNAME} => your username for your machine, mine is derek.augustine
{DOMAIN} => your public domain (you may need to request one), mine is derek.archrival.com

After your virtual hosts are setup, we should be able to start Apache using brew services.

brew services start httpd24

Hosts & DNSMasq

First, you'll need to edit your host file to add your public domain (mine is derek.archrival.com).

sudo vim /etc/hosts

Here's what mine looks like, edit yours to match what your public domain.

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1       localhost
255.255.255.255 broadcasthost
::1             localhost

127.0.0.1       derek.archrival.com
::1             derek.archrival.com

On top of that, I use DNSMasq so any time I add a new development virtual host I don't have to edit my hosts file. Basically, this is in place to handle any request with .dev as a top-level domain. First, we'll install it with Homebrew.

brew install dnsmasq

Next, we'll setup the initial config. This is using .dev as the top-level domain. If you'd prefer something else, feel free to change .dev to whatever.

echo 'address=/.dev/127.0.0.1' > $(brew --prefix)/etc/dnsmasq.conf
echo 'listen-address=127.0.0.1' >> $(brew --prefix)/etc/dnsmasq.conf
echo 'port=35353' >> $(brew --prefix)/etc/dnsmasq.conf
echo 'addn-hosts=/etc/hosts' >> $(brew --prefix)/etc/dnsmasq.conf

Now the service can be started up.

brew services start dnsmasq

We'll need to setup the resolver now. Most UNIX-like operating systems have a configuration file called /etc/resolv.conf which controls the way DNS queries are performed, but OSX also allows us to configure additional resolvers by creating configuration files in the /etc/resolver/ directory. We'll add a resolver for .dev (or whatever you choose to use).

sudo mkdir -v /etc/resolver
sudo bash -c 'echo "nameserver 127.0.0.1" > /etc/resolver/dev'
sudo bash -c 'echo "port 35353" >> /etc/resolver/dev'

To ensure this is setup to and working now, we'll just fire off a quick ping. First, to make sure we didn't break DNS system-wide:

ping -c 1 www.google.com

And next, to test our .dev TLD:

ping -c 1 ass-warp.dev

If the pings succeed, and resolve to the correct places we should be done here.

Loose Ends

Composer

Let's install Composer (package management for PHP). To keep it simple we'll just use Homebrew to do this too:

brew install composer

Node Install

Node.js for our client-side stuffz:

brew install node

This may be getting ahead of our selves, but while we're here we might as well get grunt and gulp installed globally.

Global NPM Packages

Here's a few of the build tools / cli tools that we use frequently and need installed globally.

npm install -g grunt-cli
npm install -g gulp-cli
npm install -g @angular/cli

zsh

zsh is my preferred shell and I'm fairly convinced it will be yours too if you just give it a shot. It has a good chunk of plugins to make things easy.

brew install zsh
sudo vim /etc/shells

Add this to end of file:

/usr/local/bin/zsh

And to change your default shell to zsh

chsh -s /usr/local/bin/zsh
compaudit | xargs chmod g-w
sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

TODO: finish zsh configuration / plugin installation

Switching PHP Versions

Generally, you won't need to do this and should probably just stick on the latest PHP build as the software we're building will strive to be on the latest version of PHP. But, sometimes you may get pulled on another project that lives on an older server. Since we have multiple versions of PHP installed, and we're using PHP-FPM, switching is "fairly" simple. For instance, switching from PHP 7.1 to 5.6 can be handled by running the following commands:

brew services stop php71         # stop the PHP-FPM server for PHP 7.1
brew unlink php71                # unlink PHP 7.1
brew link php56                  # link PHP 5.6
brew services start php56        # start PHP-FPM server for PHP 5.6
brew services restart httpd24    # restart Apache

And switching back:

brew services stop php70
brew unlink php70
brew link php56
brew services start php56
brew services restart httpd24	
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment