As explained in our parent article, we love Nginx. In order to create similar working environments on both your local machine as your server(s), we've written 2 sibling articles as close aligned as possible.
OSX comes with Apache pre-installed. Lovely.
Now we need to ignore that. As with every http server flavour, Nginx has its on set of quirks. After years of .htaccess hacking, we're sure you'll find some use in the latter tricks and modifications.
Setup
For your local convenience
If you don't have HomeBrew installed, go get it already: homebrew article. If you have, it doesn't hurt to update to the latest version.
$ brew update
$ brew upgrade --all
The actual install of Nginx on OSX takes seconds:
$ brew install nginx
To make sure everything went fine, you can run $ brew doctor
The configuration is located at /usr/local/etc/nginx/nginx.conf
, and will need some tweaking if you want to use Nginx as default webserver and maybe add php.
Auto start
We'll want Nginx to listen to the default port 80, which requires root credits. Let's set this up, softlink the plist to the auto start directory and launch a root'ed process.
First check if the /Library/LaunchAgents
exists, you might need to create it:
$ mkdir -p /Library/LaunchDaemons
$ sudo cp /usr/local/opt/nginx/*.plist /Library/LaunchDaemons
$ sudo chown root:wheel /Library/LaunchDaemons/homebrew.mxcl.nginx.plist
$ sudo launchctl load -w /Library/LaunchDaemons/homebrew.mxcl.nginx.plist
If you haven't tweaked the config files yet, you can test the process with curl on the default Nginx port.
curl -IL http://localhost:80
Let's abort the service for now. Yes, you can just run nginx
, the -s
stand for "Signal the master process" and accepts stop, quit, reopen
or reload
.
$ sudo nginx -s stop
Server-like config
You probably want your local environment behaving as close as possible as your server setup. Let's add some folders first. Be careful with the rights, if you already have /var/www, ignore those actions, or you might have to re-commit ALL your git repos stored there.
$ cd /usr/local/etc/nginx
$ mkdir -p sites-available sites-enabled conf.d global
$ sudo mkdir -p /var/www
$ sudo chown :staff /var/www
$ sudo chmod 775 /var/www
Now let's clean out the main config file. It looks a bit different then the server version.
You can simply clean and replace.
$ sudo nano /usr/local/etc/nginx/nginx.conf
worker_processes 1;
events {
worker_connections 768;
}
http {
include mime.types;
default_type application/octet-stream;
types_hash_max_size 2048;
sendfile on;
keepalive_timeout 45;
error_log /usr/local/var/log/nginx/error.log debug;
access_log /usr/local/var/log/nginx/access.log;
include conf.d/*.conf;
include sites-enabled/*;
}
We configure more project-specific settings next.
NODE
Nginx is very suited to proxy your local url's to Node, like Ghost.
You of course need Node installed: frontend article.
PHP-FPM
You'll probably going to use php along the line. PHP-FPM is our poison of choice, as it is on the server. Prepare the brew, or ignore this install if you're a Node- or Python-head.
$ brew tap homebrew/dupes
$ brew tap josegonzalez/homebrew-php
Install without Apache. This can take a couple of minutes. This article is based on php5.5, your machine might have an alternative version - edit accordingly.
$ brew install --without-apache --with-fpm --with-mysql php55
All you need now is an auto-start, make sure you link the right version (replace the 5.5.xx by your temporary one). Then launch PHP-FPM.
$ ln -s /usr/local/Cellar/php55/5.5.xx/homebrew.mxcl.php55.plist ~/Library/LaunchAgents/
$ launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.php55.plist
To confirm a responsive port 9000, lsof -Pni4 | grep LISTEN | grep php
should put out something like this:
php-fpm 68817 user 6u IPv4 0x3d7bc2124072d59b 0t0 TCP 127.0.0.1:9000 (LISTEN)
php-fpm 68818 user 0u IPv4 0x3d7bc2124072d59b 0t0 TCP 127.0.0.1:9000 (LISTEN)
php-fpm 68819 user 0u IPv4 0x3d7bc2124072d59b 0t0 TCP 127.0.0.1:9000 (LISTEN)
php-fpm 68820 user 0u IPv4 0x3d7bc2124072d59b 0t0 TCP 127.0.0.1:9000 (LISTEN)
Config Files
We have a couple of boilerplate configuration files for easy vhost addition.
General
Some global configurations are stored in global/general.conf
and included in some of our vhosts. Go ahead and create it.
$ nano /usr/local/etc/nginx/global/general.conf
# Global configuration http file.
# Designed to be included in any server {} block.
listen 80;
rewrite ^(.+)/+$ $1 permanent;
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Deny all attempts to access hidden files such as .htaccess or .DS_Store
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
deny all;
}
# Directives to send expires headers and turn off 404 error logging.
location ~* ^.+\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|tar|mid|midi|wav|bmp|rtf)$ {
expires max;
log_not_found off;
access_log off;
}
PHP FastCGI
If you're using PHP, You'll need to pass the scripts to the FastCGI server listening on the port 9000.
This setup varies between your local and server environment. Obviously, ignore this file if you're never going to use PHP. We've added it in the global/laravel.conf
file. You might want to store it in conf.d/php-fpm.conf
otherwise, for default addition.
server {
location ~ \.php$ {
try_files $uri = 404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
Important: You should have cgi.fix_pathinfo = 0;
in your php.ini at all times.
Laravel
Laravel and Nginx play well together. This global conf is tailored to be included in all your Laravel (and Lumen) projects as global/laravel.conf
.
# Laravel php rules.
# Designed to be included in any server {} block.
# Use alongside global/general.conf
index index.php;
try_files $uri $uri/ @rewrite;
location @rewrite {
rewrite ^/(.*)$ /index.php?_url=/$1;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /usr/local/etc/nginx/fastcgi.conf;
break;
}
Wordpress
Wordpress is one of the older kids who's actually more used to play with Apache, so we'll need to set up some specific rules to keep it's behaviour predicatble. Nano global/wordpress.conf
:
# WordPress single blog rules.
# Designed to be included in any server {} block.
# Use alongside global/general.conf
index index.php;
# Deny access to any files with a .php extension in the uploads directory
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
# Add trailing slash to */wp-admin requests.
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
Vhosts
Your projects
Your vhost file is basicly your website directive, stored in sites-available
. The configuration varies wildly, depending on your flavour of choice. We've added some examples.
Create project
As you might have guessed, you should start with creating your project root.
$ mkdir /var/www/html/project
Add vhosts
To add a vhost site, it's a good practise to add a file to sites-available and link it in sites-enabled. We'll describe the file's content later on.
$ nano /usr/local/etc/nginx/sites-available/project
$ ln -s /usr/local/etc/nginx/sites-available/project /usr/local/etc/nginx/sites-enabled/project
The possible configurations (to be included in the above):
Static project
Static projects (eg. a Grunt-generated web app) are usually pre-compiled and nimble in use. This should be reflected in the config file too.
server {
server_name project.local;
root /var/www/html/project/staging;
include /usr/local/etc/nginx/global/general.conf;
index index.html;
location / {
try_files $uri $uri.html $uri/ /index.html;
}
}
Ghost project
If you want to add a ghost blog, you just need to proxy your site to the running ghost server.
Your file contents will look like this (port 2368 is your default Ghost port):
server {
listen 80;
server_name project.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:2368;
proxy_redirect off;
}
}
Laravel project
To set up a Laravel (or Lumen) project, the nginx configuration file needs a couple of extra lines. We use php-fpm
in this example.
server {
server_name project.com;
root /var/www/html/project/public;
# Laravel configuration
include global/general.conf;
include global/laravel.conf;
}
Wordpress project
Who hasn't hosted a Wordpress website before, right? The default vhost entry points to the project root (we use project/www) and include the previously explained configurations.
server {
server_name project.com;
root /var/www/html/project/www;
# Wordpress configuration
include global/general.conf;
include global/wordpress.conf;
}
And as always, reload your nginx files.
$ sudo nginx -s reload
Notes
Set your custom local url
It’s very simple to point custom made urls to your local environment. Open /etc/hosts
as admin and add a name to your liking:
$ sudo nano /etc/hosts
> 127.0.0.1 project-api.local
Add some aliases
We've enabled a set of services we probably want to start/stop/reload in the future. OSX has aliases for just that.
$ nano /tmp/.aliases
### Service Aliases - Nginx
alias nginx.logs.error='tail -200f /usr/local/var/log/nginx/error.log'
alias nginx.logs.access='tail -200f /usr/local/var/log/nginx/access.log'
### Service Aliases - PHP-FPM
alias php-fpm.start="sudo launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.php55.plist"
alias php-fpm.stop="sudo launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.php55.plist"
alias php-fpm.restart='php-fpm.stop && php-fpm.start'
Let's add it to your user profile and reload.
$ cat /tmp/.aliases >> ~/.profile
$ source ~/.profile