Raspberry Pi Dev Setup with Nginx + PHP7

How to develop Grav sites with a $35 computer

14 mins

Modified to bring instructions up to date for latest version of the Rasbian OS - released June 2018

A few years ago I setup a Raspberry Pi 2 Model B as a development web server. I took note of the steps involved and over the ensuing months, I've provided those notes to individuals on our Gitter chat looking to do the same thing. I recently purchased the latest Raspberry Pi 3 Model B which has the same form-factor, but has a faster 1.2Ghz quad core processor, built-in WIFI, and Bluetooth 4.1. I thought I would take this opportunity to update my notes, and turn them into a full blown tutorial as this seems to be a popular subject.

In this tutorial, we cover the basics to get Raspbian OS running on your Raspberry Pi computer. We will install the high-performance nginx 1.9 webserver, along with PHP 7.0 for optimal performance. We'll also cover installing the latest Netatalk 3 with spotlight support for easy file sharing with your Mac. So read on dear listener if you would like to discover the joy of building your own full linux-powered server on a $35 computer!

Initial Raspbian Installation

Raspbian is the best option for operating systems on the Raspberry Pi because it's the most supported and is based on Debian, a very popular Linux distribution. Those of you that have used Debian or Ubuntu will be very much at home with Raspbian. The current version called Rasbian Buster is equivalent to the latest Debian 9 release.

Rather than rehashing all the information available, I suggest you follow the installation procedures outlined on the Raspberry Pi site and install NOOBS onto an SD card. After you have created your bootable NOOBS installer, you can insert it in your Raspberry Pi and power it on. It will boot very quickly and then you can simply pick Raspbian from the installer and let it do it's thing.

When the installation is complete, you should be greeted by a clean desktop environment. Time to get some things setup and configured!

Raspbian Updates

Throughout this tutorial, I'm going to assume you are using a terminal so if you have not already done so, start up a terminal by clicking the terminal icon from the top menu bar of the desktop and it will launch a terminal instance for you.

Even though you just installed Raspbian, there are often updates to packages available so the first thing to do is make sure you are running the latest versions. Follow these steps:

$ sudo apt-get update
$ sudo apt-get dist-upgrade
$ sudo apt-get upgrade

You probably won't have any extra updates to perform after the dist-upgrade step, but better safe than sorry!

Raspbian Configuration

We can use the RASPI Config command to setup some important configuration options for our new Pi.

$ sudo raspi-config

Read the official docs for full details, but I like to set the following:

  • Change Password - pick a new unique password (default is raspberry)
  • Boot Option - I like to select console as I don't use the desktop at all
  • Interfacding Options - Enable SSH to allow remote access
  • Internationalisation Options - Change Locale to suite (I use en_US.UTF-8), Change Timezone to UTC (why?)

Choose your Editor

By default Raspbian comes with the GNU Nano Editor. It's a very capable editor and is great for newbies because it has on-screen help for commands. However, I've been a Vi kind of guy for many years, and just feel more comfortable using that. Vi has been around for years, and Vim is a new and improved version that is easily installable on Raspbian:

$ sudo apt-get install vim

Throughtout this guide I commonly will have vi commands for editing files. You can simply replace this with nano if you wish to use the default editor.

Changing the default Hostname

By default, Raspbian installs with the hostname raspberry. If you wish to change this to something more memorable, you just need to edit this value and then restart the hostname service:

$ sudo vi /etc/hosts
$ sudo vi /etc/hostname
$ sudo /etc/init.d/hostname.sh

Accessing Remotely

It's all well and good to use your new Raspberry Pi machine via the keyboard and monitor you have plugged into it, but it's much easier to simply access it remotely from your regular desktop. To do this your best friend is SSH (Secure Shell). In order to reach your Raspberry Pi, you will need to know the IP address. To do so simply type:

$ hostname -I

This will report the current IP address of the machine.

On your regular computer, you can simply create a /etc/hosts entry with this IP and a suitable name. Usually this should match the hostname you just set. Then you can access your Pi remotely via:

$ ssh pi@raspberry

Enter the password you set in the configuration step, or if you have not set the password yet, it will be raspberry. More details can be found in the docs.

It is strongly advised to use SSH Keys rather than passwords. There is a great tutorial on how to set up Passwordless SSH Access in the offical docs.

Updating Firmware (Optional)

Your Raspbian installation also included a pretty recent copy of the Raspberry Pi firmware. However, sometimes there are important updates, so it really doesn't hurt to update this to the latest version:

$ sudo rpi-update
$ sudo reboot

Change the Shell (Optional)

By default, Raspbian ships with the very capable bash shell. However, I personally prefer zsh which has many useful features. On top of this I like to use Oh My ZSH! which is a handy ZSH configuration tool that comes packed with custom plugins, themes, etc.

To install this just follow these steps:

$ sudo apt-get install zsh git
$ wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - | zsh
$ chsh -s `which zsh`

Then simply log out and back in to see your new shell in all it's glory! I like to change the theme to nice clean multi-line version. To do so simply edit the ~/.zshrc file and change the theme to one of the many supported themes (My personal favroite is the dst theme).

Install PHP 7.2

Raspbian being based on Debian Stretch ships with PHP 7.0 by default. This works fine, but there is a new and better supported PHP 7.2 release available. Released in November of 2017, PHP 7.2 is the current latest released version of PHP, and will be supported until November 2019 with security updates until November 2020.

As with most PHP-centric projects, Grav commonly sees 2X performance increases when running under PHP 7.2 (compared to PHP 5.6) and that combined with the reduction in memory, makes it an ideal candidate for the Raspberry Pi.

To install this newer PHP version however, we must tap into the testing branch of Raspbian, commonly known by the codename buster. We must credit a new buster.list file used by Aptitude (apt-get):

$ sudo vi /etc/apt/sources.list.d/10-buster.list

Add this line:

deb http://mirrordirector.raspbian.org/raspbian/ buster main contrib non-free rpi

Now, by adding this and referencing -t buster in our apt-get commands, it wil use the newer versions of files available in the buster release which is not considered 100% stable. To facilitate this we need to create a buster preferences file:

$ sudo vi /etc/apt/preferences.d/10-buster

And paste in the follwing:

Package: *
Pin: release n=stretch
Pin-Priority: 900

Package: *
Pin: release n=buster
Pin-Priority: 750

Save this file and update:

$ sudo apt-get update

You can see which release versions are available with which priority by using sudo apt-cache policy. You can also see specific versions of packages with sudo apt-cache policy <package_name>

Now you are ready to install PHP 7.2 from the buster release including all the common PHP packages:

$ sudo apt-get install -t buster php7.2 php7.2-curl php7.2-gd php7.2-fpm php7.2-cli php7.2-opcache php7.2-mbstring php7.2-xml php7.2-zip

After this has been completed, you can quickly test to make sure things have been installed by simply typing:

$ php -v
PHP 7.2.9-1 (cli) (built: Aug 19 2018 06:56:13) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.9-1, Copyright (c) 1999-2018, by Zend Technologies

Installation of nginx 1.13

While it's trivial to install nginx 1.10 with Raspbian, we want to use a faster, more up to date, and secure version of nginx here, and luckily there's a nginx 1.13 version available in the buster release.

$ sudo apt-get install -t buster nginx

You can easily see what version would install by simulating an install: sudo apt-get install -t buster -s <packagename>

Once fully installed (accept any defaults when prompted), we should now tweak our PHP 7.2 FPM pool to be better optimized:

$ sudo vi /etc/php/7.2/fpm/conf.d/90-pi-custom.ini

And add:

cgi.fix_pathinfo=0

upload_max_filesize=64m
post_max_size=64m
max_execution_time=600

Now, we want to modify our PHP 7.2 FPM pool to use our pi user and group, so edit the config file:

$ sudo vi /etc/php/7.2/fpm/pool.d/www.conf

And and change the user and group references:

user = pi
group = pi

Next we want to create a new nginx configuration for our grav test site:

$ sudo vi /etc/nginx/sites-available/grav

In this file paste:

server {
    #listen 80;
    index index.html index.php;

    ## Begin - Server Info
    root /home/pi/www/grav;
    server_name localhost;
    ## End - Server Info

    ## Begin - Index
    # for subfolders, simply adjust:
    # `location /subfolder {`
    # and the rewrite to use `/subfolder/index.php`
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    ## End - Index

    ## Begin - PHP
    location ~ \.php$ {
        # Choose either a socket or TCP/IP address
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        # fastcgi_pass 127.0.0.1:9000;

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }
    ## End - PHP

    ## Begin - Security
    # deny all direct access for these folders
    location ~* /(.git|cache|bin|logs|backups|tests)/.*$ { return 403; }
    # deny running scripts inside core system folders
    location ~* /(system|vendor)/.*\.(txt|xml|md|html|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
    # deny running scripts inside user folder
    location ~* /user/.*\.(txt|md|yaml|php|pl|py|cgi|twig|sh|bat)$ { return 403; }
    # deny access to specific files in the root folder
    location ~ /(LICENSE.txt|composer.lock|composer.json|nginx.conf|web.config|htaccess.txt|\.htaccess) { return 403; }
    ## End - Security
}

Now we need to ensure the default site is not loaded and we load this new grav site instead:

$ cd /etc/nginx/sites-enabled/
$ sudo rm default
$ sudo ln -s ../sites-available/grav

Then simply restart nginx and php-fpm to ensure the new changes are picked up:

$ sudo service nginx restart
$ sudo service php7.2-fpm restart

Installing Grav

The nginx configuration is expecting our Grav site to be located in /home/pi/www/grav, so now we need to create that folder structure:

$ cd ~;mkdir www;cd www

Then download Grav release package you wish to install. We are going to use the Blog Skeleton in our example, but you can use any release package or skeleton:

$ wget https://getgrav.org/download/skeletons/blog-site/latest -O grav-blog.zip
$ unzip grav-blog.zip
$ mv grav-skeleton-blog-site grav

Adjust the naming of the these files to reflect the Grav release package or skeleton you are using

At this point, and if you followed all the steps properly, you should be able to point your browser at your Raspberry Pi with either the IP or the hostname you setup in your /etc/hosts file. For example: http://raspberry.

Problems?

If you have a problem reaching the webserver, there are a few things to check:

  1. You have a symbolic link called grav in your /etc/nginx/sites-enabled folder
  2. The grav file looks correct and matches the example pasted above
  3. If you receive a 'Bad Gateway' error, then check to ensure the /var/run/php/php7.2-fpm.sock file exists and is referenced correctly in the /etc/nginx/sites-available/grav file.

Advanced - Install PHP 7.2 APCu + Yaml

A couple of useful PHP packages that can inmprove performance are not available in the regular repositories, but they can be installed using PECL.

To accomplish this we first need to install PECL, then update the PECL repo data:

$ sudo apt-get install php7.2-dev
$ sudo pecl channel-update pecl.php.net

APCu

To install APCu, simply run this command:

$ sudo pecl install apcu

If you get an error during this process regarding Archive\Tar.php you can fix this by editing the file and editing the line provided in the error that looks like this:

$v_att_list = & func_get_args();

with this:

$v_att_list = func_get_args();

Then run the PECL command again.

To add APCu to the PHP configuration you need to edit the php.ini file:

sudo vi /etc/php/7.2/fpm/php.ini

And add an entry under the [PHP] block at the top of the file:

extension=apcu.so

Then restart php-fpm with:

$ sudo service php7.2-fpm restart

YAML

This one is also pretty easy simple to install:

$ sudo apt-get install libyaml-dev
$ sudo pecl install yaml

To add Yaml to the PHP configuration you need to edit the php.ini file:

sudo vi /etc/php/7.2/fpm/php.ini

And add an entry under the [PHP] block at the top of the file:

extension=yaml.so

Then restart php-fpm with:

$ sudo service php7.2-fpm restart

Advanced - Install Netatalk 3 (Optional)

Now you have a 100% functional Linux server that is perfect for web development. However, it's more convenient to be able to access your new server with a shared network folder from your main development machine. If you are using a Mac like I am, then you are going to want to install Netatalk 3 which is a Linux implementation of the Apple AFP network protocol. The problem however, is that by default Raspbian (even the buster release) only provides a very old version that doesn't work well with modern versions of OS X.

If you are using a Windows machine, you will need to install Samba rather than Netatalk, but this is a pretty straightforward process that has been documented elsewhere.

The solution is to download the source of the latest Netatalk 3 server software, and build it for your Raspbery Pi. Perform the following steps:

$ sudo apt-get install -t buster build-essential libevent-dev libssl-dev libgcrypt-dev libkrb5-dev libpam0g-dev libwrap0-dev libdb-dev libtdb-dev libmariadbclient-dev avahi-daemon libavahi-client-dev libacl1-dev libldap2-dev libcrack2-dev systemtap-sdt-dev libdbus-1-dev libdbus-glib-1-dev libglib2.0-dev libio-socket-inet6-perl tracker libtracker-sparql-1.0-dev libtracker-miner-1.0-dev
$ cd ~;mkdir src;cd src
$ wget https://downloads.sourceforge.net/project/netatalk/netatalk/3.1.11/netatalk-3.1.11.tar.bz2
$ tar -xvf netatalk-3.1.11.tar.bz2; cd netatalk-3.1.11
$ ./configure \
        --with-init-style=debian-systemd \
        --without-libevent \
        --without-tdb \
        --with-cracklib \
        --enable-krbV-uam \
        --with-pam-confdir=/etc/pam.d \
        --with-dbus-daemon=/usr/bin/dbus-daemon \
        --with-dbus-sysconf-dir=/etc/dbus-1/system.d \
        --with-tracker-pkgconfig-version=1.0
$ make
$ sudo make install

Assuming everying built correctly you need to edit the configuration file:

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

Modify the existing file with the following content:

;
; Netatalk 3.x configuration file
;

[Global]
; Global server settings

[Homes]
        basedir regex = /home

; [My AFP Volume]
; path = /path/to/volume

After this point you should be good to go to restart the service:

$ sudo service netatalk restart

Now you should see your server show up in the sidebar of Finder. Simply connect with your pi user and password.

FYI, you can validate that things are setup correctly by typing:

$ sudo /usr/local/sbin/afpd -V

You should see output similar to the following:

afpd 3.1.11 - Apple Filing Protocol (AFP) daemon of Netatalk

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version. Please see the file COPYING for further information and details.

afpd has been compiled with support for these features:

          AFP versions: 2.2 3.0 3.1 3.2 3.3 3.4
         CNID backends: dbd last tdb mysql
      Zeroconf support: Avahi
  TCP wrappers support: Yes
         Quota support: Yes
   Admin group support: Yes
    Valid shell checks: Yes
      cracklib support: Yes
            EA support: ad | sys
           ACL support: Yes
          LDAP support: Yes
         D-Bus support: Yes
     Spotlight support: Yes
         DTrace probes: Yes

              afp.conf: /usr/local/etc/afp.conf
           extmap.conf: /usr/local/etc/extmap.conf
       state directory: /usr/local/var/netatalk/
    afp_signature.conf: /usr/local/var/netatalk/afp_signature.conf
      afp_voluuid.conf: /usr/local/var/netatalk/afp_voluuid.conf
       UAM search path: /usr/local/lib/netatalk//
  Server messages path: /usr/local/var/netatalk/msg/