INSTALL LEMP (NGINX, PHP-FPM, MARIADB AND PHPMYADMIN) ON OS X MAVERICKS OR YOSEMITE

Resources

most of the resources from here, thanks to the blogger frdmn

http://blog.frd.mn/install-nginx-php-fpm-mysql-and-phpmyadmin-on-os-x-mavericks-using-homebrew/

other resources for mariadb instead of mysql

https://mariadb.com/kb/en/mariadb/building-mariadb-on-mac-os-x-using-homebrew/
https://mariadb.com/blog/installing-mariadb-10010-mac-os-x-homebrew

Prerequisites

The purpose is to run LEMP on MAC localhost for fast, robust and reliable local development environment
first get the latest Xcode, update from App Store

download Homebrew then check for the conflicts and update brew

$ ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)”
$ brew doctor
$ brew update && brew upgrade

PHP-FPM

Homebrew doesn’t have a default formula for PHP-FPM, so add this

$ brew tap homebrew/dupes
$ brew tap homebrew/php

install php-fpm source code

$ brew install –without-apache –with-fpm –with-mysql php56

Setup PHP CLI binary

$ echo ‘export PATH=”/usr/local/sbin:$PATH”‘ >> ~/.bash_profile
$ . ~/.bash_profile

setup auto start
Create a folder for LaunchAgents and symlink the start/stop service

$ mkdir -p ~/Library/LaunchAgents
$ ln -sfv /usr/local/opt/php56/homebrew.mxcl.php56.plist ~/Library/LaunchAgents/

start PHP-FPM

$ launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.php56.plist

make sure PHP-FPM is listening on port 9000

$ lsof -Pni4 | grep LISTEN | grep php

php-fpm 50144 msen 6u IPv4 0xacd828b2437ca351 0t0 TCP 127.0.0.1:9000 (LISTEN)
php-fpm 50145 msen 0u IPv4 0xacd828b2437ca351 0t0 TCP 127.0.0.1:9000 (LISTEN)
php-fpm 50146 msen 0u IPv4 0xacd828b2437ca351 0t0 TCP 127.0.0.1:9000 (LISTEN)
php-fpm 50147 msen 0u IPv4 0xacd828b2437ca351 0t0 TCP 127.0.0.1:9000 (LISTEN)

MARIADB

let’s look first what mariadb we can install, we can have 10.1.8 version, then install

$ brew info married
$ brew install mariadb

run the database installer

$ unset TMPDIR
$ cd /usr/local/Cellar/mariadb/10.1.8/
$ mysql_install_db

start MariaDB

$ mysql.server start
Starting MySQL
. SUCCESS!

secure the mariadb installation

$ mysql_secure_installation

root password: blablabla

connect to mariadb

$ mysql -u root -p

MariaDB [(none)]> show databases;

+--------------------+
 | Database |
+--------------------+
 | information_schema |
 | mysql |
 | performance_schema |
+--------------------+
3 rows in set (0.00 sec)

verify version

MariaDB [(none)]> select @@version;

or

MariaDB [(none)]> select version();

+----------------+
 | @@version |
+----------------+
 | 10.1.8-MariaDB |
+----------------+
1 row in set (0.00 sec)

list engines

MariaDB [(none)]> show engines;

exit

MariaDB [(none)]> exit;

if you need upgrade mariadb (ignore the warning messages such as Xcode is outdated)

$ brew update & brew upgrade
$ brew upgrade mariadb

PHPMYADMIN

first install autoconf

$ brew install autoconf

set $PHP_AUTOCONF

$ echo ‘PHP_AUTOCONF=”‘$(which autoconf)'”‘ >> ~/.bash_profile && . ~/.bash_profile

finally install phpmyadmin

$ brew install phpmyadmin

NGINX

install nginx

$ brew install nginx

setup auto start
since port 80 is used, start nginx as root

$ sudo cp -v /usr/local/opt/nginx/*.plist /Library/LaunchDaemons/
/usr/local/opt/nginx/homebrew.mxcl.nginx.plist -> /Library/LaunchDaemons/homebrew.mxcl.nginx.plist
$ sudo chown root:wheel /Library/LaunchDaemons/homebrew.mxcl.nginx.plist

test web server, start nginx for the first

$ sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.nginx.plist

default port 8080 instead of 80, go with 8080 for now

$ curl -IL http://127.0.0.1:8080

HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Thu, 05 Nov 2015 15:36:39 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sat, 08 Aug 2015 16:10:17 GMT
Connection: keep-alive
ETag: "55c629e9-264"
Accept-Ranges: bytes

stop nginx again

$ sudo launchctl unload /Library/LaunchDaemons/homebrew.mxcl.nginx.plist

NGINX CONFIGURATION

let’s do more nginx configuration

nginx folder is located at /usr/local/etc/nginx/ and nginx.conf file is also there

create the following folders which are going to be used in the configuration files

$ mkdir -p /usr/local/etc/nginx/logs
$ mkdir -p /usr/local/etc/nginx/sites-available
$ mkdir -p /usr/local/etc/nginx/sites-enabled
$ mkdir -p /usr/local/etc/nginx/conf.d
$ mkdir -p /usr/local/etc/nginx/ssl
$ sudo mkdir -p /var/www
$ sudo chown :staff /var/www
$ sudo chmod 775 /var/www

let’s remove the current nginx.conf, don’t worry the same file is there as nginx.conf.default in case you want to look at

we’ll download a custom one via curl from GitHub

$ rm /usr/local/etc/nginx/nginx.conf

nginx.conf on github looks very simple and lightweight, it has all the mac settings, paths and includes the sites enabled

worker_processes 1;
error_log /usr/local/etc/nginx/logs/error.log debug;

events {
worker_connections 1024;
}

http {
include mime.types;
default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

access_log /usr/local/etc/nginx/logs/access.log main;
sendfile on;
keepalive_timeout 65;
index index.html index.php;

include /usr/local/etc/nginx/sites-enabled/*;
}

let’s also download php-fpm config from github

$ curl -L https://gist.github.com/frdmn/7853158/raw/php-fpm -o /usr/local/etc/nginx/conf.d/php-fpm

which is this actually

location ~ \.php$ {
try_files $uri = 404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

NGINX CONF. CONTINUED
DOWNLOAD AND CREATE VIRTUAL HOSTS

create virtual host for the default

$ curl -L https://gist.github.com/frdmn/7853158/raw/sites-available_default -o /usr/local/etc/nginx/sites-available/default

the default server looks like this:

server {
listen 80;
server_name localhost;
root /var/www/;

access_log /usr/local/etc/nginx/logs/default.access.log main;

location / {
include /usr/local/etc/nginx/conf.d/php-fpm;
}

location = /info {
allow 127.0.0.1;
deny all;
rewrite (.*) /.info.php;
}

error_page 404 /404.html;
error_page 403 /403.html;
}

create virtual host for the default-ssl

$ curl -L https://gist.github.com/frdmn/7853158/raw/sites-available_default-ssl -o /usr/local/etc/nginx/sites-available/default-ssl

the default-ssl server looks like this:

server {
listen 443;
server_name localhost;
root /var/www/;

access_log /usr/local/etc/nginx/logs/default-ssl.access.log main;

ssl on;
ssl_certificate ssl/localhost.crt;
ssl_certificate_key ssl/localhost.key;

ssl_session_timeout 5m;

#ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

location / {
include /usr/local/etc/nginx/conf.d/php-fpm;
}

location = /info {
allow 127.0.0.1;
deny all;
rewrite (.*) /.info.php;
}

error_page 404 /404.html;
error_page 403 /403.html;
}

create virtual host for the phpmyadmin

$ curl -L https://gist.github.com/frdmn/7853158/raw/sites-available_phpmyadmin -o /usr/local/etc/nginx/sites-available/phpmyadmin

the phpmyadmin server looks like this

server {
listen 306;
server_name localhost;
root /usr/local/share/phpmyadmin;

error_log /usr/local/etc/nginx/logs/phpmyadmin.error.log;
access_log /usr/local/etc/nginx/logs/phpmyadmin.access.log main;

ssl on;
ssl_certificate ssl/phpmyadmin.crt;
ssl_certificate_key ssl/phpmyadmin.key;

ssl_session_timeout 5m;

ssl_protocols SSLv2 SSLv3 TLSv1;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

include /usr/local/etc/nginx/conf.d/php-fpm;
}

let’s clone an example virtual host from frdmn’s git (including 404, 403 and a phpinfo() rewrite)

$ git clone http://git.frd.mn/frdmn/nginx-virtual-host.git /var/www

remove /var/www/.git folder so that future projects won’t get tracked by git

$ rm -rf /var/www/.git

we actually only cloned 403, 404 and index html pages)

$ ls /var/www/
403.html 404.html index.html

SETUP SSL

create a folder under nginx for SSL certificates and private keys

$ mkdir -p /usr/local/etc/nginx/ssl

1ST WAY

generate 4096bit RSA keys and the self-sign the certificates in one command, remember we also pointed phpmyadmin to ssl

$ openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj “/C=US/ST=State/L=Town/O=Office/CN=localhost” -keyout /usr/local/etc/nginx/ssl/localhost.key -out /usr/local/etc/nginx/ssl/localhost.crt
$ openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj “/C=US/ST=State/L=Town/O=Office/CN=phpmyadmin” -keyout /usr/local/etc/nginx/ssl/phpmyadmin.key -out /usr/local/etc/nginx/ssl/phpmyadmin.crt

we now created the certificates and keys

$ ls -l /usr/local/etc/nginx/ssl/

total 32
-rw-r--r-- 1 msen admin 2090 Nov 5 10:25 localhost.crt
-rw-r--r-- 1 msen admin 3243 Nov 5 10:25 localhost.key
-rw-r--r-- 1 msen admin 2094 Nov 5 10:25 phpmyadmin.crt
-rw-r--r-- 1 msen admin 3247 Nov 5 10:25 phpmyadmin.key

2ND WAY

go first under ssl folder

$ cd /usr/local/etc/nginx/ssl

create the localhost.key file

$ sudo openssl genrsa -out localhost.key 4096

create the localhost csr file

$ sudo openssl req -new -key localhost.key -out localhost.csr

Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:TEXAS
Locality Name (eg, city) [Default City]:HOUSTON
Organization Name (eg, company) [Default Company Ltd]:NORTH AMERICAN UNIVERSITY
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:localhost
Email Address []:msen@na.edu

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

verify localhost csr file

$ openssl req -text -noout -verify -in localhost.csr

sign the key and output to server.crt file

$ sudo openssl x509 -req -days 730 -in localhost.csr -signkey localhost.key -out localhost.crt

repeat the same steps for phpmyadmin ssl

$ sudo openssl genrsa -out phpmyadmin.key 4096
$ sudo openssl req -new -key phpmyadmin.key -out phpmyadmin.csr
$ openssl req -text -noout -verify -in phpmyadmin.csr
$ sudo openssl x509 -req -days 730 -in phpmyadmin.csr -signkey phpmyadmin.key -out phpmyadmin.crt

CONFIG HINTS FOR SSL:

default ciphers is HIGH:!aNULL:!MD5

to full list of ciphers

$ openssl ciphers -v

DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1
AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1
EDH-RSA-DES-CBC3-SHA SSLv3 Kx=DH Au=RSA Enc=3DES(168) Mac=SHA1
EDH-DSS-DES-CBC3-SHA SSLv3 Kx=DH Au=DSS Enc=3DES(168) Mac=SHA1
DES-CBC3-SHA SSLv3 Kx=RSA Au=RSA Enc=3DES(168) Mac=SHA1
DES-CBC3-MD5 SSLv2 Kx=RSA Au=RSA Enc=3DES(168) Mac=MD5
DHE-RSA-AES128-SHA SSLv3 Kx=DH Au=RSA Enc=AES(128) Mac=SHA1
DHE-DSS-AES128-SHA SSLv3 Kx=DH Au=DSS Enc=AES(128) Mac=SHA1
AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1
DHE-RSA-SEED-SHA SSLv3 Kx=DH Au=RSA Enc=SEED(128) Mac=SHA1
DHE-DSS-SEED-SHA SSLv3 Kx=DH Au=DSS Enc=SEED(128) Mac=SHA1
SEED-SHA SSLv3 Kx=RSA Au=RSA Enc=SEED(128) Mac=SHA1
RC2-CBC-MD5 SSLv2 Kx=RSA Au=RSA Enc=RC2(128) Mac=MD5
RC4-SHA SSLv3 Kx=RSA Au=RSA Enc=RC4(128) Mac=SHA1
RC4-MD5 SSLv3 Kx=RSA Au=RSA Enc=RC4(128) Mac=MD5
RC4-MD5 SSLv2 Kx=RSA Au=RSA Enc=RC4(128) Mac=MD5
EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH Au=RSA Enc=DES(56) Mac=SHA1
EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH Au=DSS Enc=DES(56) Mac=SHA1
DES-CBC-SHA SSLv3 Kx=RSA Au=RSA Enc=DES(56) Mac=SHA1
DES-CBC-MD5 SSLv2 Kx=RSA Au=RSA Enc=DES(56) Mac=MD5
EXP-EDH-RSA-DES-CBC-SHA SSLv3 Kx=DH(512) Au=RSA Enc=DES(40) Mac=SHA1 export
EXP-EDH-DSS-DES-CBC-SHA SSLv3 Kx=DH(512) Au=DSS Enc=DES(40) Mac=SHA1 export
EXP-DES-CBC-SHA SSLv3 Kx=RSA(512) Au=RSA Enc=DES(40) Mac=SHA1 export
EXP-RC2-CBC-MD5 SSLv3 Kx=RSA(512) Au=RSA Enc=RC2(40) Mac=MD5 export
EXP-RC2-CBC-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=RC2(40) Mac=MD5 export
EXP-RC4-MD5 SSLv3 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export
EXP-RC4-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export

you can change your ciphers but it doesn’t matter actually

$ sudo vi /usr/local/etc/nginx/sites-available/default-ssl
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;

ENABLE VIRTUAL HOSTS

Let’s symlink the virtual hosts we want to enable into the sites-enabled folder

$ ln -sfv /usr/local/etc/nginx/sites-available/default /usr/local/etc/nginx/sites-enabled/default
$ ln -sfv /usr/local/etc/nginx/sites-available/default-ssl /usr/local/etc/nginx/sites-enabled/default-ssl
$ ln -sfv /usr/local/etc/nginx/sites-available/phpmyadmin /usr/local/etc/nginx/sites-enabled/phpmyadmin

START NGINX AND TEST

start Nginx again

$ sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.nginx.plist

test the pages

http://localhost → "Nginx works" page
http://localhost/info → phpinfo()
http://localhost/nope → " Not Found" page
https://localhost:443 → "Nginx works" page (SSL)
https://localhost:443/info → phpinfo() (SSL)
https://localhost:443/nope → "Not Found" page (SSL) -> because there is no such /nope path we setup so it gives error
https://localhost:306 → phpMyAdmin (SSL)

CONTROL SERVICES

let’s setup some aliases to simplify the service commands

$ curl -L https://gist.github.com/frdmn/7853158/raw/bash_aliases -o /tmp/.bash_aliases
$ cat /tmp/.bash_aliases >> ~/.bash_aliases
$ echo “source ~/.bash_aliases” >> ~/.bash_profile

reload the shell

$ source ~/.bash_profile

the https://gist.github.com/frdmn/7853158/raw/bash_aliases looks like:

alias nginx.start='sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.nginx.plist'
alias nginx.stop='sudo launchctl unload /Library/LaunchDaemons/homebrew.mxcl.nginx.plist'
alias nginx.restart='nginx.stop && nginx.start'
alias php-fpm.start="launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.php56.plist"
alias php-fpm.stop="launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.php56.plist"
alias php-fpm.restart='php-fpm.stop && php-fpm.start'
alias mysql.start="launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist"
alias mysql.stop="launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist"
alias mysql.restart='mysql.stop && mysql.start'
alias nginx.logs.error='tail -250f /usr/local/etc/nginx/logs/error.log'
alias nginx.logs.access='tail -250f /usr/local/etc/nginx/logs/access.log'
alias nginx.logs.default.access='tail -250f /usr/local/etc/nginx/logs/default.access.log'
alias nginx.logs.default-ssl.access='tail -250f /usr/local/etc/nginx/logs/default-ssl.access.log'
alias nginx.logs.phpmyadmin.error='tail -250f /usr/local/etc/nginx/logs/phpmyadmin.error.log'
alias nginx.logs.phpmyadmin.access='tail -250f /usr/local/etc/nginx/logs/phpmyadmin.access.log'

Now you can use short aliases instead of long launchtl arguments

$ nginx.start
$ nginx.stop
$ nginx.restart

to quickly tail the latest error or access logs:

$ nginx.logs.access
$ nginx.logs.default.access
$ nginx.logs.phpmyadmin.access
$ nginx.logs.default-ssl.access
$ nginx.logs.error
$ nginx.logs.phpmyadmin.error

check nginx config

$ sudo nginx -t
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: [warn] 1024 worker_connections exceed open file resource limit: 256
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

so we decrease the resource limit to 256

$ sudo vi /usr/local/etc/nginx/nginx.conf

events {
 worker_connections 256;
}

recheck nginx config

$ sudo nginx -t
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

php-fpm

$ php-fpm.start
$ php-fpm.stop
$ php-fpm.restart

check php-fpm config

$ php-fpm -t
[05-Nov-2015 12:28:55] NOTICE: configuration file /usr/local/etc/php/5.6/php-fpm.conf test is successful

PHP.INI

in case you need to update php.ini file

$ sudo vi /usr/local/etc/php/5.6/php.ini

INSTALL WGET

$ cd ~/Downloads/
$ curl -O http://ftp.gnu.org/gnu/wget/wget-1.15.tar.gz
$ tar -zxvf wget-1.15.tar.gz
$ cd wget-1.15
$ ./configure

following error might come up at the end which means it wget needs some type of SSL support GUNTLS is not averrable on your OS X system.

If so then use OpenSSL in the configuration as an alternative
configure: error: –with-ssl=gnutls was given, but GNUTLS is not available.

$ ./configure –with-ssl=openssl

you’ll see this output at the end

Version: 1.15
Host OS: darwin14.5.0
Install prefix: /usr/local
Compiler: gcc
CFlags: -O2 -Wall
LDFlags:
Libs: -lssl -lcrypto -ldl -lz -lpcre
SSL: openssl
Zlib: yes
Digest: yes
NTLM: yes
OPIE: yes
Debugging: yes

now compile

$ make

install wget

$ sudo make install

wget should be installed here: /usr/local/bin/wget

you could actually just run this 🙂

$ brew install wget

INSTALL PHPUNIT

we need to use later phpunit tests only on development environment

$ cd ~/Downloads
$ wget https://phar.phpunit.de/phpunit.phar
$ sudo chmod +x phpunit.phar
$ sudo mv phpunit.phar /usr/local/bin/phpunit

or move it to your local project folder because Intellisense didn’t work when I moved to /usr/local/bin/phpunit

$ sudo mv phpunit.phar /var/xtalk/
$ phpunit –version
PHPUnit 5.0.9 by Sebastian Bergmann and contributors.

If you are using PhpStorm IDE, from top Menu

  • PhpStorm -> Preferences -> Languages & Frameworks -> PHP -> PHPUnit
  • Select Path to phpunit.phar option
  • Path to phpunit.phar: /var/project_folder/phpunit.phar
  • Click OK

INSTALL XDEBUG FOR PhpStorm

in order to debug in PhpStorm, we need to download and install debug

$ brew install php56-xdebug
$ php -v
PHP 5.6.15 (cli) (built: Nov 4 2015 15:54:44)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies
with Xdebug v2.3.3, Copyright (c) 2002-2015, by Derick Rethans

you should see this

$ sudo vi /usr/local/etc/php/5.6/conf.d/ext-xdebug.ini
[xdebug]
zend_extension=”/usr/local/opt/php56-xdebug/xdebug.so”

then go to the PhpStorm Menu

  • PhpStorm -> Preferences -> Languages & Frameworks -> PHP
  • Next to Interpreter, click … icon
  • Interpreters dialog appears
  • Click Refresh button to get Debugger: Xdebug 2.3.3 recognized
  • Click OK
  • Click OK
  • You can apply the same steps for the default settings File -> Default Settings -> Languages & Frameworks -> PHP

now restart the services to take effect

$ nginx.restart
$ php-fpm.restart

HELLO WORLD

create an index page

$ sudo vi /var/www/index.php

<?php

echo “Hello World”;
?>

if you don’t want to accept index.html and only want to point index.php, then remove index.html

$ sudo vi /usr/local/etc/nginx/nginx.conf

index index.php;

$ sudo chown msen:staff /var/www/index.php
$ nginx.stop
$ nginx.start
$ mysql.server status
if mysql not running
$ mysql.server restart

test it

http://localhost/

if you see hello world..

YEEEYYYYY!!!
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s