Install Nginx and PHP on OS X Mountain Lion (10.8)
Time Investment: 1.25 hours
The Skinny on Nginx
If you haven’t already heard of it, Nginx is a web server that has a reputation for extreme speed and efficiency. It has gained wide acceptance and usage amongst many people, including systems administrators who are responsible for the availability of high-traffic websites. Like Apache, Nginx’s basic function is to serve web content over HTTP and HTTPS. Also like Apache, Nginx can be configured to serve numerous other unique purposes such as load-balancing, etc. However, what sets Nginx apart from Apache is it’s performance under heavy loads. Nginx accomplishes this because it handles incoming requests using an event model while Apache uses a process model. Even under the heaviest loads, Nginx consumes only a fraction upon a fraction of the memory and CPU that Apache would to handle identical traffic profiles.
The Skinny on PHP-FPM
PHP-FPM stands for PHP – FastCGI Process Manager. It is an alternative PHP FastCGI implementation. PHP-FPM is faster and more efficient at serving PHP than alternatives such as mod_php in Apache (it should be noted that Apache can be configured to use PHP-FPM too). It can do this because it only has to worry about PHP when needed. In contrast, mod_php gets loaded for every request whether PHP is needed or not. Additionally, mod_php inherits all the other Apache modules needed to service the request. Beyond resource inefficiency, this has lifecycle implications too. PHP-FPM can terminate processes and pass results back as soon as it’s done with any PHP-level processing. mod_php must live out the entire process of the HTTP request which means Apache has to hang onto unused resources even if it doesn’t need them. This is a real killer on high traffic sites.
Our Focus: Nginx + PHP-FPM on OS X Mountain Lion (10.8)
Even if you use Nginx and PHP-FPM as an alternative to Apache/mod_php just in your development environment, you will probably notice an overall system performance gain. I did. This was especially true during heavy development when using tools such as Eclipse, Netbeans, XCode, etc.
In this article, I’ll focus on getting Nginx setup in an environment to support PHP-based application development. In the followup, we’ll focus on Python. This post is written from my notes and what I found to be true OS X Mountain Lion (10.8), however things are only slightly different for OS X Lion (10.7) and the difference mainly lies in the libpng library (at least it was the only one I experienced).
Assumptions
I am assuming you have a clean install of OS X Mountain Lion. If you already have some of the components necessary to get everything running you can simply skip and move on. If you already have Apache running, you can either turn it off in System Preferences or use launchctl
to unload the corresponding launch/plist file. Also, I’m assuming you have TextMate installed as your preferred text editor. Use whatever editor makes you happy.
Install XCode 4.4
As of this writing, if you have access to OS X Mountain Lion, you are probably a member of Apple’s Mac Developer program or listed under a corporate account that affords you those privileges. At any rate, to make any of this happen on Mountain Lion, you will need XCode 4.4 (Developer Preview) in order to install the necessary Unix command line tools. I should also note that this is where you will experience a difference between Lion and Mountain Lion. Apple no longer distributes XCode as a package that installs all the Unix tools along with the installation of all the other XCode utilities and SDK’s. Instead, they have opted to distribute a software bundle which requires you to opt for installation of the Unix command line tools separately through a preferences option in XCode. To do this, open XCode and go to > “Preferences”. Click on the “Downloads” icon and select the components tab as shown in the figure below:
Install XQuartz
To compile PHP successfully, you will need libpng
. The easiest way to solve this dependency is to use the libraries that are included in the X11/XQuartz distribution. To install XQuartz, go to: http://xquartz.macosforge.org/trac/wiki/X112.7.0.
Download the latest version and install it.
Install Homebrew
I use Homebrew to manage some of my packages and dependencies. I prefer Homebrew as an alternative to Fink or MacPorts because I like how it stays out of your way and is highly flexible when you do want to use it. If you don’t want to use or install Homebrew, you will need to make sure you install libjpeg, mcrypt and mysql whichever way you feel comfortable. If you want to use Homebrew, roll on:
|
Install libjpeg and mcrypt using Homebrew
To compile PHP, you will need libjpeg, libpng and mcrypt. Because we are on OS X, we will address libpng separatley. For now, install libjpeg and mcrypt using Homebrew:
brew
install
libjpeg mcrypt
|
Creating a work area
When you download and install packages or libraries from source, it’s good to keep them consolidated in one place. I like to use the same location as I do on our Linux and FreeBSD servers so /usr/local/src
it is. Go ahead and issue the following command in your console to create that location if it doesn’t exist already:
mkdir
-p
/usr/local/src
|
Install PCRE
With PCRE, we are going to download and compile it ourselves. When you install PCRE, make sure you install the current stable release (8.21 as of this writing). Do not attempt to use 8.3. You will encounter problems compiling PHP later if you do. Below are the steps to download, compile and install PCRE 8.21:
cd
/usr/local/src
curl -O
ftp
:
//ftp
.csx.cam.ac.uk
/pub/software/programming/pcre/pcre-8
.21.
tar
.gz
tar
xzvf pcre-8.21.
tar
.gz
cd
pcre-8.21
.
/configure
--
enable
-unicode-properties
--
enable
-utf8
make
sudo
make
install
|
Install ICU libs
Another dependency is the ICU libs. Below are the steps to download, compile and install icu:
mdkdir
/usr/local/src
curl -O http:
//download
.icu-project.org
/files/icu4c/4
.8.1.1
/icu4c-4_8_1_1-src
.tgz
tar
-xzf icu4c-4_8_1_1-src.tgz
cd
icu
sh
source
/configure
--prefix=
/usr/local
gnumake
sudo
make
install
|
Compile IMAP libraries for PHP
One last major dependency we need to address are the IMAP libs. In this case, we will not be installing them. We will just compile them and create some symbolic links so the compiler can use them when it compiles PHP. To do this, follow these steps:
cd
/usr/local/src
curl -O
ftp
:
//ftp
.cac.washington.edu
/imap/imap
.
tar
.Z
tar
xzvf imap.
tar
.Z
cd
imap-2007f
make
osx
ln
-s c-client include
mkdir
lib
cd
lib
ln
-s ..
/c-client/c-client
.a libc-client.a
|
Installing MySQL using Homebrew
Finally, with all that out of the way, we can worry about MySQL. In this case, I use Homebrew (mainly because I’m lazy and they auto-generate a plist file I can use easily). Hey, if I can save 5 – 10 minutes, why not? Below are the steps to install MySQL using Homebrew:
brew
install
mysql
unset
TMPDIR
mysql_install_db --verbose --user=`
whoami
` --basedir=
"$(brew --prefix mysql)"
--datadir=
/usr/local/var/mysql
--tmpdir=
/tmp
mkdir
-p ~
/Library/LaunchAgents
cp
/usr/local/Cellar/mysql/5
.5.19
/homebrew
.mxcl.mysql.plist ~
/Library/LaunchAgents/
launchctl load -w ~
/Library/LaunchAgents/homebrew
.mxcl.mysql.plist
/usr/local/Cellar/mysql/5
.5.19
/bin/mysql_secure_installation
|
Compile and install PHP
Before we go any further, OS X Mountain Lion ships with php 5.3.8. If you want to use the default version of php and php-fpm, you can do so by skipping this step and proceeding to configuring PHP-FPM as a LaunchDaemon. PHP-FPM lives in /usr/sbin
. You can use the exact same plist file that is specified in the next step. If you want to compile and install php 5.3.10, follow the steps below:
cd
/usr/local/src
curl -O http:
//us2
.php.net
/distributions/php-5
.3.10.
tar
.bz2
tar
xzvf php-5.3.10.
tar
.bz2
cd
php-5.3.10
.
/configure
--prefix=
/usr/local
--mandir=
/usr/share/man
--infodir=
/usr/share/info
--sysconfdir=
/private/etc
--
enable
-cli
--with-config-
file
-path=
/usr/local/php/etc
--with-libxml-
dir
=
/usr
--
enable
-xml
--
enable
-exif
--
enable
-
ftp
--
enable
-intl
--with-gd
--with-jpeg-
dir
=
/usr/local/Cellar/jpeg/8c/lib
--with-png-
dir
=
/usr/X11
--
enable
-gd-native-ttf
--with-imap=
/usr/local/src/imap-2007f
--with-imap-ssl
--
enable
-magic-quotes
--
enable
-mbstring
--
enable
-mbregex
--
enable
-json
--with-mysql=mysqlnd
--with-mysqli=mysqlnd
--with-pdo-mysql=mysqlnd
--with-mysql-sock=
/tmp/mysql
.sock
--with-iodbc=
/usr
--
enable
-shmop
--with-snmp=
/usr
--
enable
-sockets
--
enable
-fpm
--with-mhash
--with-mcrypt
--with-xmlrpc
--
enable
-xmlwriter
--
enable
-xmlreader
--with-xsl=
/usr
--
enable
-zend-multibyte
--
enable
-zip
--with-pcre-regex=
/usr/local
--with-pdo-sqlite
--
enable
-pdo
--with-pdo-mysql
--with-freetype-
dir
=
/usr/X11
--
enable
-dom
--
enable
-fileinfo
make
sudo
make
install
|
At this point PHP is installed. However, the php distribution that shipped with OS X is still in /usr/bin which is in your system path first. An easy way to activate your new installation is to move the old binaries by renaming them andcreate symlinks in /usr/bin and /usr/sbin that point to the binaries that were compiled. Using this method, you can easily revert back to the original binaries that shipped by simply deleting the symlinks. You can complete that process like this:
sudo
cp
/private/etc/php-fpm
.conf.default
/private/etc/php-fpm
.conf
sudo
mkdir
/usr/local/php/etc
sudo
cp
/private/etc/php
.ini.default
/usr/local/php/etc/php
.ini
sudo
ln
-s php.dSYM php
sudo
ln
-s php-fpm.dSYM php-fpm
sudo
mv
/usr/bin/php
/usr/bin/php
.old
sudo
ln
-s
/usr/local/php/bin/php
/usr/bin/php
sudo
mv
/usr/bin/phpize
/usr/bin/phpize
.old
sudo
ln
-s
/usr/local/php/bin/phpize
/usr/bin/phpize
sudo
mv
/usr/bin/php-config
/usr/bin/php-config
.old
sudo
ln
-s
/usr/local/php/bin/php-config
/usr/bin/php-config
sudo
mv
/usr/sbin/php-fpm
/usr/sbin/php-fpm
.old
sudo
ln
-s
/usr/local/php/sbin/php-fpm
/usr/sbin/php-fpm
|
Configure launchd to start php-fpm during boot
Part of the power of PHP-FPM is the level of granularity in which you can manage your configurations. Because it allows you to configure pools differently, you can think of PHP-FPM much like an application server with each pool configured and tweaked for a specific purpose. We will setup PHP-FPM to look for pool configurations in /usr/local/php/fpm/pool.d
. If you need to configure pools differently for different applications, you can create multiple unique configurations in this sub-directory. PHP-FPM will load them and you can configure Nginx to hand it’s process off upstream to the proper pool. Since we are using a Unix based OS, we are going to configure php-fpm to listen on a Unix socket to squeeze out extra performance. Alternatively, you can also use TCP in situations where Unix sockets aren’t an option. You can also configure PHP-FPM to listen on both at the same time. To get this all setup, we must first make two directories: 1) /usr/local/php/var/run
and 2) /usr/local/php/fpm/pool.d
.
/usr/local/php/var/run
is where the pid file will be stored while the php-fpm daemon is running and as mentioned above, /usr/local/php/fpm/pool.d
is where the pool configurations will reside. Let’s make those directories now:
mkdir
-p
/usr/local/php/var/run
mkdir
-p
/usr/local/php/fpm/pool
.d
|
After you have created the directories, we need to make a basic config file for PHP-FPM. The master config file will reside at: /private/etc/php-fpm.conf
. Let’s create the file:
mate
/private/etc/php-fpm
.conf
|
Now, paste the following into php-fpm.conf
and save:
1
2
3
4
5
6
7
8
9
10
11
|
;;;;;;;;;;;;;;;;;;
; Global Options ;
;;;;;;;;;;;;;;;;;;
[global]
pid = /usr/local/php/var/run/php-fpm.pid
; run in background or in foreground?
; set daemonize = no for debugging
daemonize = yes
include=/usr/local/php/fpm/pool.d/*.conf
|
Notice the last line: include=/usr/local/php/fpm/pool.d/*.conf
. We need to make sure to place at least one pool configuration file there so PHP-FPM will configure one pool when it starts.
mate
/usr/local/php/fpm/pool
.d
/pool
.conf
|
Now, paste the following text into pool.conf
and save:
1
2
3
4
5
6
7
8
9
10
11
12
|
[www]
user=(REPLACE WITH YOUR USER NAME)
group=staff
pm = dynamic
pm.max_children = 10
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
listen = /tmp/php-fpm.sock
;listen = 127.0.0.1:9000
php_flag[display_errors] = off
|
The last thing in our lineup for getting PHP-FPM setup is to make sure it starts up every time the system restarts. Just create a new plist file for the LaunchDaemon:
mate
/Library/LaunchDaemons/net
.php.php-fpm.plist
|
Now, copy the following code into TextMate and save the net.php-fpm.plist
file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<?
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
>
<
key
>KeepAlive</
key
>
<
true
/>
<
key
>Label</
key
>
<
string
>net.php.php-fpm</
string
>
<
key
>LaunchOnlyOnce</
key
>
<
true
/>
<
key
>NetworkState</
key
>
<
true
/>
<
key
>ProgramArguments</
key
>
<
array
>
<
string
>/usr/sbin/php-fpm</
string
>
</
array
>
<
key
>RunAtLoad</
key
>
<
true
/>
<
key
>ServiceDescription</
key
>
<
string
>PHP FastCGI Process Manager</
string
>
<
key
>StandardErrorPath</
key
>
<
string
>/var/log/system.log</
string
>
</
dict
>
</
plist
>
|
Once the file has been saved, make sure you load it:
sudo
launchctl load -F
/Library/LaunchDaemons/net
.php.php-fpm.plist
|
For a quick sanity check, go ahead and issue the following command to make sure the php-fpm process is running:
ps
aux |
grep
php-fpm
|
You should see output similar to the output below:
your_username 91743 0.0 0.0 2432764 600 s000 R+ 11:56PM 0:00.00
grep
php-fpm
your_username 91730 0.0 0.0 2454736 480 ?? S 11:55PM 0:00.00
/usr/sbin/php-fpm
your_username 91729 0.0 0.0 2454736 480 ?? S 11:55PM 0:00.00
/usr/sbin/php-fpm
your_username 91728 0.0 0.0 2454736 480 ?? S 11:55PM 0:00.00
/usr/sbin/php-fpm
your_username 91727 0.0 0.0 2454736 480 ?? S 11:55PM 0:00.00
/usr/sbin/php-fpm
your_username 91726 0.0 0.0 2454736 476 ?? S 11:55PM 0:00.00
/usr/sbin/php-fpm
root 91725 0.0 0.0 2454736 720 ?? Ss 11:55PM 0:00.01
/usr/sbin/php-fpm
|
Also, just to be sure, let’s check that PHP-FPM is listening on a Unix socket:
netstat
-n -a |
grep
php-fpm
|
You should see output similar to the output below:
ffffff801bb62ce8 stream 0 0 ffffff8023afd078 0 0 0
/tmp/php-fpm
.sock
|
Compiling and Installing Nginx
Installing Nginx is fairly straightforward. You can either download and compile it yourself, or you can choose to use Homebrew. In this case, I prefer compiling it myself.
curl -O http:
//nginx
.org
/download/nginx-1
.1.16.
tar
.gz
tar
xzvf nginx-1.1.16.
tar
.gz
cd
nginx-1.1.16
.
/configure
--sbin-path=
/usr/local/sbin/nginx
--conf-path=
/usr/local/nginx/nginx
.conf
--with-http_ssl_module
--with-pcre=..
/pcre-8
.30
make
make
install
|
Setting Yourself Up For Success With Nginx Configuration
I like to setup Nginx’s configuration structure similar to the way Ubuntu handles both Apache and Nginx to help streamline and decouple the different configurations. I have a master nginx.conf
file that pulls in other configuration components as necessary. For site configurations, I create two directories under /usr/local/etc/nginx
called sites-enabled
and sites-available
. The sites-available directory contains one to many configuration files, each representing one virtual host configuration. The sites-enabled directory contains symbolic links to the files in the sites-available directory. When nginx.conf is loaded it will in turn load all the symlinked files in the sites-enabled directory for active configurations when it starts up. Using this approach, you can turn off a virtual host by simply removing the symlink.
Create the directories:
mkdir
/usr/local/nginx/sites-enabled
mkdir
/usr/local/nginx/sites-available
|
Open the existing nginx.conf
file:
mate
/usr/local/nginx/nginx
.conf
|
Replace the entire contents of the current nginx.conf file with the following contents:
nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
worker_processes
2
;
events {
worker_connections
1024
;
}
http {
include mime.types;
default_type text/plain;
server_tokens off;
sendfile on;
tcp_nopush on;
keepalive_timeout
1
;
gzip on;
gzip_comp_level
2
;
gzip_proxied any;
gzip_types text/plain text/css text/javascript application/json application/x-javascript text/xml application/xml application/xml+rss;
index index.html index.php;
upstream www-upstream-pool{
server unix: /tmp/php-fpm.sock;
}
include sites-enabled/*.dev;
}
|
The “upstream” directive in the code above provides Nginx a mapping to an upstream process that we can refer to later when we want to pass fastcgi requests. In this manner, you could easily create and configure multiple upstreams and delegate to them as needed on a per app basis or even on a per URI basis if you wanted to break your application down into logical groups of functionality that required different resource configurations. Pretty simple! Now, we just need to make sure we create a default configuration file for hosts to load that need to support php and requests upstream to PHP-FPM:
mate
/usr/local/nginx/fastcgi_php_default
.conf
|
Copy and paste the following code into fastcgi_php_default.conf
ans save:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
fastcgi_intercept_errors on;
location ~ .php$
{
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_param
SCRIPT_FILENAME
$document_root
$fastcgi_script_name
;
fastcgi_param
QUERY_STRING
$query_string
;
fastcgi_param
REQUEST_METHOD
$request_method
;
fastcgi_param
CONTENT_TYPE
$content_type
;
fastcgi_param
CONTENT_LENGTH
$content_length
;
fastcgi_param
SCRIPT_NAME
$fastcgi_script_name
;
fastcgi_param
REQUEST_URI
$request_uri
;
fastcgi_param
DOCUMENT_URI
$document_uri
;
fastcgi_param
DOCUMENT_ROOT
$document_root
;
fastcgi_param
SERVER_PROTOCOL
$server_protocol
;
fastcgi_param
HTTPS
$https
if_not_empty;
fastcgi_param
GATEWAY_INTERFACE
CGI
/
1
.
1
;
fastcgi_param
SERVER_SOFTWARE
nginx/
$nginx_version
;
fastcgi_param
REMOTE_ADDR
$remote_addr
;
fastcgi_param
REMOTE_PORT
$remote_port
;
fastcgi_param
SERVER_ADDR
$server_addr
;
fastcgi_param
SERVER_PORT
$server_port
;
fastcgi_param
SERVER_NAME
$server_name
;
fastcgi_param
PATH_INFO
$fastcgi_path_info
;
fastcgi_param
PATH_TRANSLATED
$document_root
$fastcgi_path_info
;
fastcgi_read_timeout
300
;
fastcgi_pass www-upstream-pool;
fastcgi_index index.php;
}
fastcgi_param
REDIRECT_STATUS
200
;
|
The next thing we need to accomplish is setting up a test host. We will need to create a document root for the site files and then a configuration file for Nginx to load. On my machine, I keep all my projects in a “Repo” folder in my home directory. I’m going to setup a document root for “mytestsite.dev” under the Repo folder and create an index.php file for the test site:
mkdir
-p ~
/Repo/mytestsite
.dev
echo
"<?php phpinfo(); ?>"
>> ~
/Repo/mytestsite
.dev
/index
.php
|
Now, let’s create the host configuration file for Nginx:
mate
/usr/local/nginx/sites-available/mytestsite
.dev
|
Paste the following configuration into mytestsite.dev
and save:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
server {
listen
80
;
server_name mytestsite.dev;
root ~/Repo/mytestsite;
access_log logs/access_mytestsite.log;
error_log logs/error_mytestsite.log;
location / {
index index.php;
try_files
$uri
$uri
/ /index.php?q=
$uri
&
$args
;
}
include fastcgi_php_default.conf;
}
|
Now, create the plist to add Nginx as a LaunchDaemon:
mate
/Library/LaunchDaemons/net
.nginx.nginx.plist
|
Paste this into the editor and save it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<?
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
>
<
key
>Label</
key
>
<
string
>net.nginx.nginx</
string
>
<
key
>RunAtLoad</
key
>
<
true
/>
<
key
>KeepAlive</
key
>
<
true
/>
<
key
>ProgramArguments</
key
>
<
array
>
<
string
>/usr/local/sbin/nginx</
string
>
<
string
>-g</
string
>
<
string
>daemon off;</
string
>
</
array
>
<
key
>WorkingDirectory</
key
>
<
string
>/usr/local</
string
>
</
dict
>
</
plist
>
|
Just ike mysql and php-fpm, load the plist so that launchd starts up Nginx every time you reboot:
sudo
launchctl load -F
/Library/LaunchDaemons/net
.nginx.nginx.plist
|
Setup Your Hosts File
The last step in the process is to create a record in your hosts file that points “mytestsite.dev” to your localhost. It’s simple:
sudo
mate
/etc/hosts
|
Now, add a line and save the hosts
file:
127.0.0.1 mytestsite.dev
|
Again, let’s do a quick test by trying to ping the host:
ping
-t 4 mytestsite.dev
|
You should see a response like this:
Ok, now let’s fire up a browser and go to http://mytestsite.dev and you should see:
Final Thoughts
That should do it. You should be ready to roll and have a dev environment on your Mac using Nginx as the primary web server.
转自:http://www.group7even.com/blog/2012/02/23/installing-nginx-php-fpm-on-os-x-mountain-lion-10-8/