mountainlion

Installing NginX + PHP 5.4 on Mac OS X Mountain Lion for Symfony2

Sunday I upgraded my Macbook Pro to Mountain Lion. It mostly went without glitches.




I already wanted for some time to replace the built in apache with an NginX, for performance reasons.


On a sidenote, there is an awesome tool called Mountain Tweaks, which lets you tune some settings with one click. E.g. restore aluminium layout for calendar or disable this extremely annoying gatekeeper.


As I stumbled upon multiple problems on the way, I will write it down in this blog article.


I assume that homebrew is installed. Otherwise, google install instructions. Its a nice package manager and works (for me) better than macports.


I also recomment the binary version of MySQL. If you don’t have it, download it.


At first, download the current XCode version from the appstore.


Then, open XCode, go to preferences (CMD + ,) and update the commandline tools


For libpng to work, we need xquartz. Download and install it.





Note: Webroot and php stuff has to be writable to the user you’re working with, so if you’re working with root, don’t forget to set permissions afterwards

chown -R ereiche:staff /fucked/up/dir

Disable autostart of old apache.

sudo launchctl unload /Library/LaunchDaemons/org.apache.directory.server.plist

Link MySQL to where we need it:

sudo ln -s /usr/local/mysql/lib/libmysqlclient.18.dylib /usr/lib/libmysqlclient.18.dylib

By the way: if something doesn’t work as expected, its always a good idea to watch the system log

syslog -w

Now install autoconf, libjpeg and mcrypt.

brew install libjpeg mcrypt autoconf

Now create a directory to download all sourcecodes and go there

mkdir -p /usr/local/src
cd /usr/local/src

Get the latest PCRE, ICU4C, NginX & PHP:

wget 'ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.31.tar.gz'
wget 'http://download.icu-project.org/files/icu4c/49.1.2/icu4c-49_1_2-src.tgz'
wget 'http://de.php.net/distributions/php-5.4.7.tar.gz'
wget 'http://nginx.org/download/nginx-1.2.2.tar.gz'

Unpack them

tar xfz pcre-8.31.tar.gz
tar xfz icu4c-49_1_2-src.tgz
tar xfz php-5.4.7.tar.gz
tar xfz nginx-1.2.2.tar.gz

and compile them

cd /usr/local/src/pcre-8.31
./configure --enable-unicode-properties --enable-utf8
make
sudo make install

cd /usr/local/src/icu
sh source/configure --prefix=/usr/local
gnumake
sudo make install

The second line prevents an error while make. If it doesn’t help, look at this stackoverflow thread.

cd /usr/local/src/php-5.4.7
export EXTRA_LDFLAGS=-lresolv
./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 --with-gd \
 --with-jpeg-dir=/usr/local/Cellar/jpeg/8c/lib --with-png-dir=/usr/X11 \
 --enable-gd-native-ttf --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 --with-snmp=/usr \
 --enable-sockets --enable-fpm --with-mhash --with-mcrypt --with-xmlrpc \
 --enable-xmlwriter --enable-xmlreader --with-xsl=/usr \
 --enable-zip --with-pcre-regex=/usr/local --with-pdo-sqlite --enable-pdo \
 --with-pdo-mysql=/usr/local/mysql --with-freetype-dir=/usr/X11 --enable-dom \
 --enable-fileinfo --with-kerberos --enable-intl --with-curl --with-openssl=shared --with-zlib 
make

If you have problems with the make, see this PHP bug ticket.

sudo make install

cd /usr/local/src/nginx-1.2.2
./configure \
    --sbin-path=/usr/local/sbin/nginx \
    --conf-path=/usr/local/nginx/nginx.conf \
    --with-http_ssl_module \
    --with-pcre=../pcre-8.31

Now lets clean up some old stuff and link the binaries to the old places

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 /usr/local/bin/php.dSYM /usr/local/bin/php
sudo ln -s /usr/local/sbin/php-fpm.dSYM /usr/local/sbin/php-fpm
sudo mv /usr/bin/php /usr/bin/php.old
sudo ln -s /usr/local/bin/php /usr/bin/php
sudo mv /usr/bin/phpize /usr/bin/phpize.old
sudo ln -s /usr/local/bin/phpize /usr/bin/phpize
sudo mv /usr/bin/php-config /usr/bin/php-config.old
sudo ln -s /usr/local/bin/php-config /usr/bin/php-config
sudo mv /usr/sbin/php-fpm /usr/sbin/php-fpm.old
sudo ln -s /usr/local/sbin/php-fpm /usr/sbin/php-fpm

Prepare PHP FPM

mkdir -p /usr/local/php/var/run
mkdir -p /usr/local/php/fpm/pool.d
mkdir -p /usr/local/nginx/sites-enabled
mkdir -p /usr/local/nginx/sites-available
touch /private/etc/php-fpm.conf
touch /usr/local/php/fpm/pool.d/pool.conf
touch /Library/LaunchDaemons/net.php.php-fpm.plist
touch /usr/local/nginx/fastcgi_php_default.conf
touch /usr/local/nginx/sites-available/localhost
touch /usr/local/nginx/sites-available/symfony.local
touch /Library/LaunchDaemons/net.nginx.nginx.plist

I assume that your web root is under /Users/YOURUSERNAME/Sites/, as it’s Macs default storage for websites.

mkdir -p ~/Sites/symfony.local/
touch ~/Sites/index.php

After you open VIM, just press [i] to enter/paste text. To save & close, press [ESC] [:] [x] [ENTER]

vim /private/etc/php-fpm.conf
;;;;;;;;;;;;;;;;;;
; 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

vim /usr/local/php/fpm/pool.d/pool.conf
[www]
user=[ENTER 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
php_flag[display_errors] = on
security.limit_extensions = .php .html .css .js

vim /Library/LaunchDaemons/net.php.php-fpm.plist
<?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>ProgramArguments</key>
    <array>
        <string>/usr/sbin/php-fpm</string>
        <string>-c</string>
        <string>/usr/local/php/etc/php.ini</string>
        <string>--fpm-config</string>
        <string>/private/etc/php-fpm.conf</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceDescription</key>
    <string>PHP FastCGI Process Manager</string>
    <key>StandardErrorPath</key>
    <string>/var/log/system.log</string>
    <key>Debug</key><false/>
    <key>RunAtLoad</key><true/>
    <key>KeepAlive</key><false/>
    <key>UserName</key><string>[ENTER YOUR USER NAME]</string>
</dict>
</plist>

vim /usr/local/nginx/nginx.conf
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;
   include sites-enabled/*;
   upstream www-upstream-pool{
      server unix:/tmp/php-fpm.sock;
   }
}

vim /usr/local/nginx/fastcgi_php_default.conf
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;

vim ~/Sites/index.php
<?php phpinfo();

As I said, I assume your Symfony2 installation lies in ~/Sites/symfony.local/ , so adapt the paths.

vim /usr/local/nginx/sites-available/localhost
server {
   listen 80;
   server_name localhost eric.local;
   root /Users/ereiche/Sites/;
   access_log logs/access_localhost.log;
   error_log logs/error_localhost.log;
 
   location / {
      index index.php;
      try_files $uri $uri/ /index.php?q=$uri&$args;
   }
 
   include fastcgi_php_default.conf;
}

WATCH OUT! If you want SSL support, you need /usr/local/nginx/server.key and /usr/local/nginx/server.crt. You can create a CSR and get a certificate at CaCert if your domain is reachable from outside (dyndns?). Otherwise, just don’t add the second server block:

vim /usr/local/nginx/sites-available/symfony.local
server {
        listen 80;
        server_name symfony.local;

        root /Users/ereiche/Sites/symfony.local/web/;
        rewrite ^/app_dev\.php/?(.*)$ /$1 permanent;
        location / {
                index app_dev.php;
                try_files $uri @rewriteapp;

        }

        location @rewriteapp {
                rewrite ^(.*)$ /app_dev.php/$1 last;
        }

        location ~ ^/(app|bundles\/stfalcontinymce\/vendor\/tiny_mce\/plugins\/cyberim\/index|app_dev|config)\.php(/|$) {
                include fastcgi_params;
                fastcgi_pass   unix:/tmp/php-fpm.sock;
                fastcgi_split_path_info ^(.+\.php)(/.*)$;
                fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
                fastcgi_param  HTTPS              off;
        }
}
server {
        listen 443;
        server_name symfony.local;

        ssl         on;
        #ssl_protocols       SSLv3 TLSv1;
        ssl_certificate     /usr/local/nginx/server.crt;
        ssl_certificate_key /usr/local/nginx/server.key;

        root /Users/ereiche/Sites/symfony.local/web/;
        rewrite ^/app_dev\.php/?(.*)$ /$1 permanent;
        location / {
                index app_dev.php;
                try_files $uri @rewriteapp;

        }

        location @rewriteapp {
                rewrite ^(.*)$ /app_dev.php/$1 last;
        }

        location ~ ^/(app|bundles\/stfalcontinymce\/vendor\/tiny_mce\/plugins\/cyberim\/index|app_dev|config)\.php(/|$) {
                include fastcgi_params;
                fastcgi_pass   unix:/tmp/php-fpm.sock;
                fastcgi_split_path_info ^(.+\.php)(/.*)$;
                fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
                fastcgi_param  HTTPS              on;
        }
}

vim /Library/LaunchDaemons/net.nginx.nginx.plist
<?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>

Add your new vhost to local DNS redirect (localhost should already be there)

vim /etc/hosts
127.0.0.1       symfony.local

Edit your PHP file as you wish.

vim /usr/local/php/etc/php.ini

Make sure this line is there

cgi.fix_pathinfo=1

(Yes, I know Nginx wiki says otherwise)
Maybe increase memory limit.


Install APC extension

sudo /usr/local/bin/pecl install APC-beta

Install xdebug extension

sudo /usr/local/bin/pecl install xdebug

Add the following lines at the end of your php.ini file (Replace PHPSTORM with your IDE key):

vim /usr/local/php/etc/php.ini

(Note: I disabled APC because it seems unstable for me)

;extension=apc.so
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so

[xdebug]
xdebug.remote_enable=on
xdebug.default_enable=on
xdebug.remote_autostart=off
xdebug.idekey=PHPSTORM
xdebug.remote_port=9000
xdebug.remote_host=localhost
xdebug.profiler_enable=0
xdebug.profiler_enable_trigger=1
xdebug.profiler_output_name=xdebug-profile-cachegrind.out-%H-%R
xdebug.profiler_output_dir="/tmp/xdebug/"
xdebug.var_display_max_children = 128
xdebug.max_nesting_level=100
xdebug.var_display_max_data = 2048
xdebug.var_display_max_depth = 32
debug.remote_connect_back=1

Start PHP

sudo launchctl load -F /Library/LaunchDaemons/net.php.php-fpm.plist

Check if it worked

ps aux | grep php-fpm
netstat -n -a | grep php-fpm

The result should be something like that:

ereiche> ps aux | grep php-fpm
ereiche        78330   0,0  0,7  2514652  43584   ??  S     4:49pm   0:01.05 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78329   0,0  0,8  2579948  47620   ??  S     4:49pm   0:07.54 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78327   0,0  0,6  2514396  37960   ??  S     4:49pm   0:00.88 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78322   0,0  0,7  2514396  41884   ??  S     4:49pm   0:00.92 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78275   0,0  0,7  2516444  45772   ??  S     4:42pm   0:03.21 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78264   0,0  0,7  2578908  46064   ??  S     4:42pm   0:01.99 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78263   0,0  0,8  2547164  47724   ??  S     4:42pm   0:08.11 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78262   0,0  0,8  2556380  47676   ??  S     4:42pm   0:03.11 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78261   0,0  0,7  2578900  44824   ??  S     4:42pm   0:01.23 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78260   0,0  0,7  2514644  41008   ??  S     4:42pm   0:01.34 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        78259   0,0  0,0  2510544    548   ??  Ss    4:42pm   0:00.31 /usr/sbin/php-fpm -c /usr/local/php/etc/php.ini --fpm-config /private/etc/php-fpm.conf
ereiche        80122   0,0  0,0  2432768    616 s005  R+    6:09pm   0:00.00 grep --color=auto php-fpm
ereiche> netstat -n -a | grep php-fpm
20a9841426c86645 stream      0      0 20a984142fb9eec5                0                0                0 /tmp/php-fpm.sock

Enable vhosts

cd /usr/local/nginx/sites-enabled
ln -s ../sites-available/localhost .
ln -s ../sites-available/symfony.local .

Finally, launch NginX

sudo launchctl load -F /Library/LaunchDaemons/net.nginx.nginx.plist

Open your browser and check if http://symfony.local & http://localhost works.

References:

Kommentar verfassen