Skip to content

Instantly share code, notes, and snippets.

@alefi87
Last active October 21, 2018 11:18
Show Gist options
  • Save alefi87/bc778a7ca918d27821a1 to your computer and use it in GitHub Desktop.
Save alefi87/bc778a7ca918d27821a1 to your computer and use it in GitHub Desktop.
OS X 10.10 Yosemite, Apache, PHP 5.6, MySQL, Memcache, SSL setup with Homebrew

###Installing Apache 2.4 + PHP 5.6 + MySQL + SSL on Mac OS X Yosemite This is a TL;DR version of an upcoming blog entry for those who can read bash commands and scripts.

I prefer setting up the environment and leaving the original configuration files practically untouched. I only modify them to include my own files which include additional settings as well as overrides for the default ones. This way I have full control over the environment in just one folder.

I also like to work without the need to sudo commands, so I set up Apache without access to privileged ports 80 and 443. Instead, I add port forwarding 80->8080 and 443->8443.

By following this gist you will end up with the following folder structure:

~/workspace/
|_ environment/
  |_ certificates/
  |_ logs/
  |_ my.cnf
  |_ php.ini
  |_ httpd.conf

NOTE: this setup is for a brand new (or re-installed) OS X Yosemite. If you know what you are doing, you might still have use of parts of this gist.

###Homebrew

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

#verify
brew doctor

# tap required repos
brew tap homebrew/dupes
brew tap homebrew/versions
brew tap homebrew/homebrew-php
brew tap homebrew/apache

brew update && brew upgrade

###Prepare

brew install git openssl wget zlib curl

# create folders and empty files
mkdir -p ~/workspace/environment/{tmp,logs,certificates}
touch ~/workspace/environment/httpd.conf
touch ~/workspace/environment/php.ini
touch ~/workspace/environment/my.cnf
touch ~/workspace/environment/tmp/local.dev.conf
touch ~/workspace/environment/tmp/index.html
touch ~/workspace/environment/tmp/info.php

# add to PATH
# replace '.bash_profile' with .zshrc or whatever shell config file you use
echo -e "\nexport PATH=\"/usr/local/sbin:$PATH\"" >> ~/.bash_profile

# set a better hostname than "Alexanders-MacBook-Pro"
# change 'alefi-mbp' to the hostname you wish to use for your machine
sudo scutil --set HostName alefi-mbp

###Apache 2.4 ####Install

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

# install with brew
brew install httpd24 --with-brewed-openssl
ln -sfv $(brew --prefix httpd24)/homebrew.mxcl.httpd24.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist

At this point Apache should be up and running. Verify by visiting http://localhost:8080 and you should see It works!.

####Forward ports Running the following will allow to run on port 80 and 443 without root privilege. The commands will add a port forwarding rule to OS X that will be applied on every login.

sudo bash -c 'export TAB=$'"'"'\t'"'"'
cat > /Library/LaunchDaemons/local.httpdfwd.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
${TAB}<key>Label</key>
${TAB}<string>co.echo.httpdfwd</string>
${TAB}<key>ProgramArguments</key>
${TAB}<array>
${TAB}${TAB}<string>sh</string>
${TAB}${TAB}<string>-c</string>
${TAB}${TAB}<string>echo "rdr pass proto tcp from any to any port {80,8080} -> 127.0.0.1 port 8080" | pfctl -a "com.apple/260.HttpFwdFirewall" -Ef - &amp;&amp; echo "rdr pass proto tcp from any to any port {443,8443} -> 127.0.0.1 port 8443" | pfctl -a "com.apple/261.HttpFwdFirewall" -Ef - &amp;&amp; sysctl -w net.inet.ip.forwarding=1</string>
${TAB}</array>
${TAB}<key>RunAtLoad</key>
${TAB}<true/>
${TAB}<key>UserName</key>
${TAB}<string>root</string>
</dict>
</plist>
EOF'
sudo launchctl load -Fw /Library/LaunchDaemons/local.httpdfwd.plist

Verify by visiting http://localhost:80.

####Configure Apache

# include our own conf file in apache main httpd.conf
echo -e "\n\nInclude $HOME/workspace/environment/httpd.conf" >> $(httpd -V|grep "SERVER_CONFIG_FILE"|awk '{print $2}'|tr -d \"\ |sed -n 's/SERVER_CONFIG_FILE=//p')

# point ServerRoot to ~/workspace for future conveniece
echo -e "ServerRoot $HOME/workspace\n\n" > ~/workspace/environment/httpd.conf

# restart apache
httpd -k restart

####Testing This will set up a virtual host in ~/workspace/environment/tmp/ to validate Apache configuration.

echo -e "<h1>Hello world</h1>" > ~/workspace/environment/tmp/index.html
echo -e "Include environment/tmp/local.dev.conf\n\n" >> ~/workspace/environment/httpd.conf
cat > ~/workspace/environment/tmp/local.dev.conf <<EOF
<VirtualHost *:8080>
    ServerName local.dev
    DocumentRoot environment/tmp/

    <Directory />
        Require all granted
    </Directory>
</VirtualHost>
EOF
httpd -k restart

Verify by visiting http://local.dev. You should see Hello world!.

###PHP 5.6 ####Install

# install
brew install php56
ln -sfv $(brew --prefix php56)/homebrew.mxcl.php56.plist ~/Library/LaunchAgents
launchctl load -Fw ~/Library/LaunchAgents/homebrew.mxcl.php56.plist

# create the (sometimes) missing directory where php by default looks for
# additional configuration files
[[ ! -d $(php --ini|grep "Scan for"|awk -F": " '{print $2}') ]] && sudo mkdir -p $(php --ini|grep "Scan for"|awk -F": " '{print $2}')
sudo ln -s $HOME/workspace/environment/php.ini $(php --ini|grep "Scan for"|awk -F": " '{print $2}')/php.ini

# configure php in our own php.ini
cat > ~/workspace/environment/php.ini <<EOF
; Defines the default timezone used by the date functions
date.timezone = "$(sudo systemsetup -gettimezone|awk -F"\: " '{print $2}')"
; Maximum amount of memory a script may consume (default 128MB)
memory_limit = 512M
; Maximum size of POST data that PHP will accept. (0 to disable the limit)
post_max_size = 100M
; Maximum allowed size for uploaded files.
upload_max_filesize = 50M
; Default timeout for socket based streams (seconds)
default_socket_timeout = 
; Maximum execution time of each script, in seconds
max_execution_time = 300
; Maximum amount of time in seconds each script may spend parsing request data. 
max_input_time = 60
; Log errors to specified file.
error_log = $(dscl . -read /Users/`whoami` NFSHomeDirectory | awk -F"\: " '{print $2}')/environment/logs/php-error_log
EOF

# avoid future perl and pecl permissions problem
# https://github.com/Homebrew/homebrew-php/issues/1039#issuecomment-41307694
chmod -R ug+w $(brew --prefix php56)/lib/php

# enable opcache which is bundled with php 5.6 (not earlier!)
cat >> ~/workspace/environment/php.ini <<EOF
; Determines if Zend OPCache is enabled
opcache.enable=0
; The OPcache shared memory storage size.
opcache.memory_consumption=256
EOF

# enable php in apache
cat <(cat <<EOF
# PHP

LoadModule php5_module $(brew --prefix php56)/libexec/apache2/libphp5.so
AddHandler php5-script .php
AddType text/html .php
<IfModule dir_module>
    DirectoryIndex index.php index.html
</IfModule>


EOF) ~/workspace/environment/httpd.conf > tmp.conf && mv tmp.conf ~/workspace/environment/httpd.conf

httpd -k restart

####Verify that PHP is working

echo -e "<?php phpinfo(); ?>" > ~/workspace/environment/tmp/info.php

Verify by visiting http://local.dev/info.php.

###Memcache (optional) ####Install

brew install memcached php56-memcache
ln -sfv $(brew --prefix memcached)/homebrew.mxcl.memcached.plist ~/Library/LaunchAgents
launchctl load -Fw ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist

httpd -k restart

####Verify

echo -e "<?php echo memcache_connect('127.0.0.1', 11211) ? 'Memcache OK' : 'Memcache FAILED'; ?>" > ~/workspace/environment/tmp/info.php

Verify by visiting http://local.dev/info.php. You should see Memcache OK.

###SSL ####Configure Add SSL configuration to our ~/workspace/environment/httpd.conf.

cat <(cat <<EOF
# SSL

LoadModule ssl_module libexec/mod_ssl.so
LoadModule rewrite_module libexec/mod_rewrite.so

Listen 8443
SSLCipherSuite HIGH:MEDIUM:\!aNULL:\!MD5
SSLPassPhraseDialog  builtin


EOF) ~/workspace/environment/httpd.conf > tmp.conf && mv tmp.conf ~/workspace/environment/httpd.conf

####SSL caching In order for SSL to work SSL caching must be enabled. This can be done either by using the default mod_socache_shmcb or mod_socache_memcache if you have installed Memcache in the previous part.

If Memcache is not installed:

cat <(cat <<EOF
# SSL caching

LoadModule socache_shmcb_module libexec/mod_socache_shmcb.so
SSLSessionCache "shmcb:/usr/local/var/run/apache2/ssl_scache(512000)"
SSLSessionCacheTimeout 300


EOF) ~/workspace/environment/httpd.conf > tmp.conf && mv tmp.conf ~/workspace/environment/httpd.conf

If Memcache is installed:

cat <(cat <<EOF
# SSL caching

LoadModule socache_memcache_module libexec/mod_socache_memcache.so
SSLSessionCache memcache:127.0.0.1:11211
SSLSessionCacheTimeout 300


EOF) ~/workspace/environment/httpd.conf > tmp.conf && mv tmp.conf ~/workspace/environment/httpd.conf

Now restart Apache:

httpd -k restart

####Add self-signed certificates See How to create a self-signed Certificate. These commands to the same, but without annoying prompts.

cd ~/workspace/environment/certificates
openssl genrsa -des3 -passout pass:x -out server.pass.key 1024
openssl rsa -passin pass:x -in server.pass.key -out server.key
rm server.pass.key
openssl req -new -key server.key -out server.csr -subj "/C=UK/ST=Warwickshire/L=Leamington/O=OrgName/OU=IT Department/CN=example.com"
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

####Verify

# replace previous virtual host with SSL-enabled one and 
# redirect traffic from HTTP to HTTPS
cat > ~/workspace/environment/tmp/local.dev.conf <<EOF
<VirtualHost *:8080>
    RewriteEngine On
    RewriteRule ^/(.*)$ https://%{HTTP_HOST}/$1 [L,R=301]
</VirtualHost>

<VirtualHost *:8443>
	ServerName local.dev
    DocumentRoot environment/tmp/

    <Directory />
    	Require all granted
    </Directory>

    SSLEngine on
	SSLCertificateFile environment/certificates/server.crt
	SSLCertificateKeyFile environment/certificates/server.key
</VirtualHost>
EOF

httpd -k restart

Verify by visiting http://local.dev/php.info. You should get redirected to HTTPS URL and get prompted with a certificate warning which is normal with self-signed certificates.

For some reason Chrome is giving me random trouble at this step which I cannot yet pin-point. So if you have used Chrome up until now, try a different browser - FireFox works like a charm for me.

MySQL

# install
brew install mysql
cp $(brew --prefix mysql)/support-files/my-default.cnf $(brew --prefix)/etc/my.cnf
# include our custom config file
echo -e "\n\n\!include $HOME/workspace/environment/my.cnf" >> $(brew --prefix)/etc/my.cnf

# configure mysql
cat > ~/workspace/environment/my.cnf <<EOF
[mysqld]
innodb_buffer_pool_size = 128M
max_allowed_packet = 1073741824
innodb_file_per_table = 1
EOF

# launch
ln -sfv $(brew --prefix mysql)/homebrew.mxcl.mysql.plist ~/Library/LaunchAgents/
launchctl load -Fw ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist

# secure the mysql installation
$(brew --prefix mysql)/bin/mysql_secure_installation

###Wrap up

# remove testing files and virtual host
rm -rf ~/workspace/environment/tmp
sed -i '' '/local.dev.conf/d' ~/workspace/environment/httpd.conf
httpd -k restart

###Where to go from here? My project structure looks like this:

~/workspace/
|_ environment/
  |_ certificates/
  |_ logs/
  |_ my.cnf
  |_ php.ini
  |_ httpd.conf
|_ projects
  |_ 001-random-project
    |_ _vhosts
    |_ _logs
    |_ htdocs

In my httpd.conf I include projects/001-random-project/_vhosts/*.conf. By having ServerRoot pointed at /Users/alexander/workspace I can use relative paths in my Apache .conf files.

Any configuration you need to do to Apache, PHP or MySQL may be done in the custom files in ~/workspace/environment/.

###If things go very wrong The following commands will remove Apache, PHP, MySQL, Memcache and the port forwarding. Use your brain! For example, if you haven't installed Memcache, don't try to remove it.

Kudos to beeftornado for brew rmtree.

brew tap beeftornado/rmtree && brew install beeftornado/rmtree/brew-rmtree

sudo launchctl unload /Library/LaunchDaemons/local.httpdfwd.plist
launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist
launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.php56.plist
launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist

unlink ~/Library/LaunchAgents/homebrew.mxcl.memcached.plist
unlink ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
unlink ~/Library/LaunchAgents/homebrew.mxcl.php56.plist
unlink ~/Library/LaunchAgents/homebrew.mxcl.httpd24.plist

brew rmtree httpd24
brew rmtree mysql
brew rmtree php56
brew rmtree memcached
brew rmtree php56-memcache

sudo rm /Library/LaunchDaemons/local.httpdfwd.plist
rm -rf $(brew --prefix)/etc/apache2
rm -rf $(brew --prefix)/etc/php
rm -rf $(brew --prefix)/etc/my.cnf
rm -rf /usr/local/var/mysql
@e0ipso
Copy link

e0ipso commented Sep 12, 2016

Replace:

error_log = $(dscl . -read /Users/`whoami` NFSHomeDirectory | awk -F"\: " '{print $2}')/environment/logs/php-error_log

By:

error_log = $(dscl . -read /Users/`whoami` NFSHomeDirectory | awk -F"\: " '{print $2}')/workspace/environment/logs/php-error_log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment