OS-X, NGINX, and Symfony2 – What a Party!
Google on OS-X, nginx, and Symfony2 and you’ll pull up a ton of posts. However I find them all confusing or missing pieces. Maybe I’m getting slow…maybe I’m not the command line guru…but in this post I will give you my take on how to setup these tools on OS-X Mavericks. Why? Well – I’m looking for speed and I suppose a challenge to wrack my brain with.
What is My Motivation?
I was serious – basically I’m looking for improvements on the ‘ol LAMP/OAMP stack. I have a program that is going to require some advanced processing power so I’m looking at how to scale better with PHP and web services. Apache has never been a great performer at scale. Most hosting companies have switched to nginx at the web tier for this reason. Since my personal machine is a MBP, I’ll be working with OS-X. I suppose for a server OS I would probably pick CentOS or something like that. I have VirtualBox installed so I could save myself some time and simply use that, but that’s no fun.
A note of caution: I am setting this up on my dev laptop, not a production server. Security is critical and I have not “battle tested” this configuration.
Where to get Started
Here’s the stuff we’re working with:
- nginx
- PHP
- PHPFastCGI
- Symfony2
- HHVM – for the truly brave 🙂
There are a lot of references out there on the internet for how to do this, but I found them lacking. Here’s a few of the better posts that I used to piece all of this together:
- http://blog.frd.mn/install-nginx-php-fpm-mysql-and-phpmyadmin-on-os-x-mavericks-using-homebrew/
- http://www.leaseweblabs.com/2013/05/symfony2-under-nginx-on-ubuntu-12-04/
- http://symfony.com/doc/current/cookbook/configuration/web_server_configuration.html
- https://gist.github.com/leon/3019026
- http://wiki.nginx.org/Symfony
That’s a lot of places to poke around, right? Right.
The first place to start is with OS-X. You’ll need to have XCode installed with the command line tools…probably means you need to be an active Apple developer. I’m going to rely on homebrew as a package manager so you’ll need that. To use homebrew you’ll need curl…here’s a good guide for how to get this setup.
The next step is to get PHP installed with the right stuff. We need to tap a couple of kegs (boy that sounds great, right?):
brew tap homebrew/dupes
brew tap josegonzalez/homebrew-php
Now we should have the package index we need. Tell brew to install PHP with the components we need:
brew install --without-apache --with-fpm --with-mysql php55
That will download and install everything you’ll need. Brew is pretty cool. What it did was download and install all the things you need in /usr/local/Cellar/ and then created the symlinks you need in /usr/lcoal/bin so that now your PHP environment is all ready to go. PHP should be installed in /usr/local/Cellar/php55. The .ini configuration files will be in /usr/local/etc/php/5.5 you can get to them via command line or with Finder using the “go to” option in Finder.
Part of the PHP install you just performed is FPM. To get it setup for autostart you need to add some things to your OS-X profile. The names below can vary depending on what exact version you have installed. At the time of writing I’ve installed 5.5.9 – if the file does not exist look in the Cellar and change out the name. The plist file should have references to FPM in it.:
mkdir -p ~/Library/LaunchAgents
cp /usr/local/Cellar/php55/5.5.9/homebrew-php.josegonzalez.php55.plist ~/Library/LaunchAgents/
Then you can start and stop the FPM server with:
launchctl load -w ~/Library/LaunchAgents/homebrew-php.josegonzalez.php55.plist
launchctl unload -w ~/Library/LaunchAgents/homebrew-php.josegonzalez.php55.plist
To see if the FPM server is running properly this command is helpful:
lsof -Pni4 | grep LISTEN | grep php
Installing MySQL
There are a variety of ways to get MySQL installed – including using brew, but I choose the easy solution of using the downloadable binary from the MySQL community. I also like the MySQLWorkBench for doing all my admin work. Its a decent GUI for OS-X actually – only beef I have is that it does not check for updates automatically. I’m not going to run through how to configure all security stuff – just know that you should do it.
To start/stop/restartMySQL use:
mysql.server start
mysql.server stop
mysql.server restart
Getting nginx Working
The first step – if you have apache httpd installed and running…turn it off…my instructions will use nginx on port 80. 🙂 For better security you could run it on some port like 9878. To run on 80 you need root/sudo rights. I will also not configure it with autostart because I will probably switch back and forth between nginx and apache. To install it is quite simple:
brew install nginx
The default doc root is /usr/local/var/www and the configuration files are in /usr/local/etc/nginx. There are a ton of ways to setup nginx. Checkout the first link above if you want to learn a ton for how to make working with it easy. What I did for my config was set it up to point at the same www root that apache does so that I can test development with both on the same code. To do that I modified the main config file with the following:
- I set the error logging directory to a folder in my home directory to make it easy to get to the logs.
- In the http section I did the same for the access logs.
- In the http section I changed the port to 80 and set the root directory to /Library/WebServer/Documents. I added index.php as an allowed type.
- I’m running FastCGI so I added this block in the http section:
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
root /Library/WebServer/Documents;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
} - I added a section to deny access to .htaccess files (since they will be there because I’m sharing the directories with apache:
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
I didn’t bother to configure HTTPS yet. With all that done you should be able to start nginx with a simple command line:
sudo nginx
Pretty easy to stop and restart it as well
sudo nginx -s stop|restart
Throw a php file with the ‘ol info call in it and make sure it loads up.
Configuring OS-X, nginx, and Symfony2 with FPM
Installing Symfony2 is pretty well documented – so go ahead and get it installed (I recommend composer). One thing that can make it easier is to simply shut off nginx and start apache so that you can do the initial Symfony2 install with confidence. After getting it installed you should be able to bring up the Symfony2 config page at localhost/yourApp/app_dev.php
You can see that I did something different. I have a single “master” composer file in the directory above so that all my S2 project share the same revs.
Also keep in mind that I am setting this to use /Library/WebServer/Documents as the www root. On OS-X this means I have to sudo all the changes. This can be a PITA, but it is also secure so just get used to being king of “sudo” or hack your box by messing with groups or whatever.
Once you have the basics working you can create a virtual server in nginx to make things work nice using a local entry in your hosts file. Go ahead and add s2.local as a 127.0.0.1 entry in your hosts file (on OS-X this is in /etc).
Now create two directories: sites-available and sites-enabled in /usr/local/etc/nginx. Add a file called s2.local, or whatever name you added to hosts file, to the sites-available directory. Add the following content to this file and save it:
#/usr/local/etc/nginx/sites-available/s2.local
server {
# Listen on port 80
listen 80;
# Server name being used (exact name, wildcards or regular expression)
server_name s2.local;
# Document root, make sure this points to your Symfony2 /web directory
root /Library/WebServer/Documents/s2-nginx/web;
index app_dev.php;
# Handle static files, redirect to app.php if not found
location / {
try_files $uri /app_dev.php$is_args$args;
}
# Pass the PHP scripts to FastCGI server
location ~ ^/(app|app_dev|config)\.php(/|$) {
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
# Logging
error_log /Users/beren/logs/s2.local-error.log;
access_log /Users/beren/logs/s2.local-access.log;
}
Now, symlink the s2.com file to the sites_enabled folder:
sudo ln -s /usr/local/etc/nginx/sites-available/s2.com /usr/local/etc/nginx/sites-enabled/s2.com
Restart FPM and nginx. Voila!
In the above I’m assuming that this is for a dev server. If you want this for production you need to modify the index from app_dev.php to just app_php and the location line in the same way.
With all this done you should be ready to go with Symfony2 development on PHP. You can keep on creating new apps and virtual servers like I did above add/remove them by removing the symlink. Pretty neat I think. I think it does take some getting used to with this setup, but once you get the hang of it, it is pretty nice.
Hopefully you found this helpful. I’ll keep coming back and adding more details over time along with any improvements I come up with. I’m working on getting Xdebug working with this using PHPStorm.