How to: Set-up and configure a Web Server running Nginx and PHP-FPM
An installation how to guide from Stock Ubuntu 16.04 to Web Server (PHP-FPM, Nginx, Git, Varnish and AWS Logs).
Table of Contents
This is a quick guide on going from a stock Ubuntu 16.04 server to a ready to go web server, with PHP-FPM, Nginx, Git, Varnish and AWS Logs. If you find this guide useful please take a moment to say so in the comments.
This guide doesn't cover in detail the configuration of either Nginx or Varnish as these are subjects that could easily warrant their own, separate guides.
Stating the obvious, but at the time of writing these steps worked, obviously things change so I can't guarantee these steps will still work in the future.
To start with I selected the Ubuntu 16.04 HVM 64-bit AMI at Amazon Web Services (AWS). These steps can be followed on the smallest (free tier eligible) instance size, currently the t2.micro instance.
Back to topConfigure the server timezone
Run this simple wizard to configure the server timezone:
dpkg-reconfigure tzdata
Back to topInstalling Nginx and PHP-FPM
So connect to your new instance using SSH.
First we need to add some PPA repositories so when we install Nginx and PHP we're getting the very latest versions:
add-apt-repository ppa:nginx/stable
add-apt-repository ppa:ondrej/php
Download the latest package lists from the repositories:
apt-get update
Upgrade any packages that can be:
apt-get upgrade
Any upgrades that are kept back can be installed as follows:
apt-get dist-upgrade
Install Nginx and then PHP-FPM
apt-get install nginx
apt-get install php7.2-fpm
Back to topInstall PHP Extensions
You might have particular PHP extensions you need but here's a starting point:
apt-get install php7.2-curl php7.2-gd php7.2-mcrypt php7.2-xmlrpc php7.2-mbstring
Now is also a good time to install ImageMagick if you need it.
Personal preference but I usually run PHP under a different user than the default www-data user.
Next, create a user under which PHP-FPM will run:
useradd worker
Back to topLogfile storage
Create the logs storage folder
Create the /logs folder, we'll point the Nginx and PHP logs at this folder:
mkdir /logs
In the /etc/nginx/nginx.conf file set:
error_log /logs/error.log warn;
Back to topSetting up a website
Create a directory where your websites will be stored:
mkdir /websites
Create a folder for your (first) website:
cd /websites
mkdir example.com
Set the ownership of the websites directory and it's sub-directories to the "worker" user we created:
chown -R worker:worker /websites
Back to topInstalling Git
Install Git
apt-get install git-core
Create a key for use with Git:
cd ~
When you run the next command you can just press enter repeatedly to accept the defaults, if you don't want/need to supply a passphrase:
ssh-keygen -t rsa
To output the public key so you can copy and paste it easily run:
cat ~/.ssh/id_rsa.pub
Copy and paste the public key into your Git service.
Back to topClone the website's files from a Git repository
Clone the website's files into this directory (the Github URL below doesn't actually work, it's just an example for you to replace with the correct path to your Git repo):
cd /websites/example.com
git clone git@github.com:enovatedesign/example.git .
Now's a good time to grant any particular write permissions your website may require.
Back to topSet-up the Nginx virtual host
The next step is to create the Nginx virtual hosts file. I'm not going to cover Nginx configuration at this point as that warrants a guide of its own.
Create/duplicate an existing Nginx configuration file for the new site:
These steps simply copy the default virtual hosts file that comes with a fresh Nginx installation and opens the new file in the Nano text editor for you to tweak:
cd /etc/nginx/sites-available
cp default example.com
nano example.com
Once the virtual hosts configuration file is complete we need to symlink it to the "sites-enabled" folder:
ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
Next, we can test the configuration to make sure everything is present and correct:
nginx -t
All going well, we can ask Nginx to reload its configuration so it picks up the newly enabled virtual hosts file:
service nginx reload
Back to topConfigure PHP-FPM
Next we need to configure PHP to run as the user we added:
Edit the /etc/php/7.1/fpm/pool.d/www.conf file, changing the lines so they read as follows:
user = worker
group = worker
listen.owner = worker
listen.group = worker
Then restart the PHP-FPM service:
service php7.1-fpm restart
PHP should now be working correctly. If it isn't then check your Nginx log file for any errors.
It's recommended to make a few edits to the php.ini as required, I usually make a point of editing the following lines:
Please note: Comment out line 3 as shown so the default kicks in or replace it with the default's value.
max_execution_time = 300
memory_limit = 256M
;error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
error_log = /logs/php_errors.log
upload_max_filesize = 8M
date.timezone = Europe/London
Back to topSet-up AWS Logs
This is worth doing as it allows you to save the server's logs into AWS CloudWatch, which then allows you to retain your logs even if you terminate the instance. It also provides the added benefit of being able to set-up log metrics, which can then trigger alarms and in turn notifications, such as when a certain number of 404 or 500 HTTP status codes are returned within a certain period of time.
I've covered this in more detail in the recent AWS CLoudWatch Logs blog post.
Back to topInstall Varnish (optional)
Varnish is a fantastic piece of software, it caches your web pages to RAM so requests are served at lightning speed straight from RAM without even touching the disk. Even with a t2.micro instance you should be able to achieve response times close to 200ms (as reported by Pingdom from multiple locations worldwide)
Again, the Varnish documentation has this well covered, but I have included the steps below too (note the change from "precise" to "trusty"):
The steps are:
curl https://repo.varnish-cache.org/ubuntu/GPG-key.txt | apt-key add -
echo "deb https://repo.varnish-cache.org/ubuntu/ trusty varnish-4.0" >> /etc/apt/sources.list.d/varnish-cache.list
apt-get update
apt-get install varnish
This will install and start the Varnish service.
Back to topConfigure Varnish
We currently have Nginx running on port 80 so we need to swap things around so Nginx will form the back-end server for Varnish running on port 8080 and Varnish will run on port 80. This also allows us to request websites on port 8080 if we ever need to try to debug something to see what our back-end server (Nginx in this case) is serving to Varnish.
First stop the Nginx service:
service nginx stop
Edit the file /etc/default/varnish
Switch Varnish to port 80 by changing the port reference here:
DAEMON_OPTS="-a :6081 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,256m"
To 80, thus:
DAEMON_OPTS="-a :80 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,256m"
Restart Varnish:
service varnish restart
Next you need to edit the Nginx virtual hosts file to change it from listening on port 80 to port 8080 instead:
nano /etc/nginx/sites-available/example.com
Start Nginx:
service nginx start
Next we need to configure Varnish to use Nginx (which is now running on port 8080) as the back-end server.
Again, covering the configuration of Varnish via VCL files is beyond the scope of this guide so I have simply included the code necessary to define a basic Nginx back-end server running on the same server on port 8080.
So we need to edit the file /etc/varnish/default.vcl to include the back-end server definition:
backend default {
.host = "127.0.0.1";
.port = "8080";
}
Back to topTesting
To test the new instance I normally adjust my computer's hosts file to point a domain name that matches an Nginx virtual host through to the server.
You should be able to request the domain with the port number to compare the direct output from Nginx to that served by Varnish:
- http://www.example.com:8080/ (Nginx)
- http://www.example.com/ (Varnish)
You should be able to identify if Varnish is running by inspecting the headers. Requests served from Varnish normally include an "Age" header that stores the time in seconds since that item was cached.
If you've found this guide useful please let me know in the comments.
You might also like...