Ubuntu 16.04 / Apache2 / NGINX / PHP7.0 FPM / MariaDB / Varnish

Published on: Jul 4, 2016 2:33 pm  /   Published by:   /   Comments:

I’m a technical enthusiast! So I always try to keep myself up to date with latest technology trends and happenings. I came to know that having NGINX reverse proxy for Apache, improves the performance grade of the websites. So I decided to give it a test. I have configured many web servers earlier with Apache and PHP or Lighttpd and PHP modules. But this type of setup I was doing for the first time. I decided to configure a server with Linux Ubuntu 16.04 LTS, Apache2 as a web server, NGINX reverse proxy for Apache2, PHP7.0 FPM module for processing server-side PHP scripting, MariaDB server (a community-developed fork of the MySQL), and some other necessary modules to run the server independently. I will describe the whole procedure that I’ve followed. I will also list all the SSH commands that I’ve used while preparing the server.

Initial Server Setup and Configuration

I’ve used a 2GB dedicated server with Ubuntu 16.04 LTS version from DigitalOcean to test the setup. After logging in with “root” (or with a sudoer user), first, you have to check if the environment variables are set properly or not. This is to avoid some warnings during other modules installation. Many times, the locales are not set properly by the hosting providers while deploying the server. Run the following commands to configure it properly.
sudo locale-gen en_US.UTF-8
sudo dpkg-reconfigure locales

Then edit the locale and environment files to include default locale.
sudo nano /etc/default/locale and add these lines:
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
LC_MESSAGES=POSIX

Consequently, sudo nano /etc/environment and add these lines:
LC_ALL=en_US.UTF-8
LANG=en_US.UTF-8

Now you have configured the locale properly. It’s time to update the system for different modules and security patches. Run the following command.
sudo apt-get update && sudo apt-get upgrade

Furthermore, install a couple of commonly required components with the following commands.
sudo apt-get install curl
sudo apt-get install zip
sudo apt-get install git
sudo apt-get install memcached

The server probably will prompt that a ** System restart required ** message. If so, simply run the reboot command and log back in after a while. The message will disappear now. Finally, the initial setup is complete at this step.

Install and Configure Apache2 Web Server

Now it’s time to install and configure Apache as your main web server. First, install the Apache and Apache FastCGI module with the following commands.
sudo apt-get install apache2
sudo apt-get install libapache2-mod-fastcgi

Consequently, enable some necessary modules for Apache. Run the following command to enable the Rewrite, Expires, Deflate, Mime etc. modules. These are most commonly required for PHP applications, specifically, WordPress caching plugins.
sudo a2enmod alias rewrite expires headers filter mime deflate env setenvif fastcgi actions

Create User and Home Directory

Let’s assume your domain name is exampledomain.com. First of all, you should create a user with a home directory. Run the following commands.
sudo useradd -d /var/www/vhosts/exampledomain.com -m myuser
sudo passwd myuser

This will create the user+group “myuser” and will set home directory and password for it. sudo usermod myuser -s /bin/false will make sure the user do not have SHELL access enabled. Enabling SHELL access for FTP users is vulnerable to security.

Now add the www-data user to the myuser group. This will ensure that the Apache user can also write and execute files within the myuser user’s home directory.
usermod -a -G myuser www-data

Let’s create some more directories in order to proceed with the virtual host configuration. Here are the commands to follow.
cd /var/www/vhosts/exampledomain.com
sudo mkdir public_html
sudo mkdir logs

This will create the log and public_html folders within the home directory for the user. It is better to have publicly accessible files in a separate folder under home directory because of security reasons. That’s why the public_html directory is created. The logs directory is for storing apache and NGINX reverse proxy raw access log and error log files.

Set the ownership and some permissions as well to the user.
sudo chown myuser:myuser /var/www/vhosts/exampledomain.com -R
sudo chgrp myuser /var/www/vhosts/exampledomain.com -R
sudo chmod g+w /var/www/vhosts/exampledomain.com/public_html -R
sudo find /var/www/vhosts/exampledomain.com/public_html -type d -exec chmod 775 {} +
sudo find /var/www/vhosts/exampledomain.com/public_html -type f -exec chmod 664 {} +

The folder permission is set to 775 instead of usual 755 and file permission set to 664 instead of usual 644. This is to make sure the group can write and execute the files within the directory.

Setup Virtual Host for Apache

The virtual host configuration file instructs Apache to identify different domains or sub-domains. To set up a virtual host, you need to copy the default virtual host configuration file first. You can have one configuration file for all the virtual hosts. Or you can have different configuration files for each of the domains as well.
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/exampledomain.com.conf

Now you need to edit the newly created configuration file and update the directory paths etc.
sudo nano /etc/apache2/sites-available/exampledomain.com.conf

Add the following lines to the configuration file.

<VirtualHost *:80>
ServerName exampledomain.com
ServerAlias www.exampledomain.com
ServerAdmin [email protected]

DocumentRoot /var/www/vhosts/exampledomain.com/public_html

<Directory />
Options +FollowSymLinks
AllowOverride None
</Directory>

<Directory /var/www/vhosts/exampledomain.com/public_html>
Options -Indexes +FollowSymLinks +MultiViews
AllowOverride All
Order allow,deny
Allow from all
</Directory>

ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/

<Directory /usr/lib/cgi-bin>
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Order allow,deny
Allow from all
</Directory>

ErrorLog /var/www/vhosts/exampledomain.com/logs/error.log
LogLevel warn
CustomLog /var/www/vhosts/exampledomain.com/logs/access.log combined
</VirtualHost>

You can create a configuration file like this for each domain. Enable this virtual host configuration and restart the Apache.
sudo a2ensite exampledomain.com.conf

Then restart apache.
sudo service apache2 restart

If your domain is properly pointed to your server’s IP, you should see the default Apache page now when running the domain in a browser.

default-apache-ubuntu-page

Install and configure PHP

Run the following command to install PHP-FPM 7.0 and required PHP modules.
sudo apt-get install php-fpm php-mysql php-sqlite3 php-mcrypt php-mbstring php-gettext php-memcache php-memcached php-apcu php-opcache php-curl php-cli php-cgi php-gd php-imagick php-tidy

Once installed, update the php-fpm configuration file with the following. Remove any existing lines and have the following contents only.
sudo nano /etc/apache2/conf-available/php7.0-fpm.conf

<IfModule mod_fastcgi.c>
AddHandler php7.0-fcgi .php
Action php7.0-fcgi /php7.0-fcgi
Alias /php7.0-fcgi /usr/lib/cgi-bin/php7.0
FastCgiExternalServer /usr/lib/cgi-bin/php7.0 -socket /run/php/php7.0-fpm.sock -pass-header Authorization
<Directory /usr/lib/cgi-bin>
Require all granted
</Directory>
</IfModule>

Enable the php configuration for Apache with the following command.
sudo a2enconf php7.0-fpm

In the directory configuration, move index.php to the beginning of the line . Because, it will make sure that the index.php file gets executed first before the index.html file.
sudo nano /etc/apache2/mods-enabled/dir.conf and move index.php to the beginning of the line.

Restart the Apache web server.
sudo service apache2 restart

Finally, create a file in /var/www/vhosts/exampledomain.com/public_html with the PHP info.
echo "<?php phpinfo(); ?>" > /var/www/vhosts/exampledomain.com/public_html/info.php

Run the http://www.exampledomain.com/info.php in a browser. It will show the PHP info.

Install and Configure MariaDB and PhpMyAdmin

First, install the MariaDB server and secure the MySQL installation.
sudo apt-get install mariadb-server
sudo mysql_secure_installation

During the MariaDb installation, it will prompt for different inputs. Like root user password, administrator password, install default config or not etc. During the MySQL secure installation process, you can bypass changing the root user password if you already have a strong password. Rest of the answers will be “y”.

Let’s install PhpMyAdmin.
sudo apt-get install phpmyadmin

Enable the PhpMyAdmin alias in Apache config file. Edit the file sudo nano /etc/apache2/apache2.conf and add this line at the end of it Include /etc/phpmyadmin/apache.conf.

Edit the PhpMyAdmin Apache config file in order to allow .htaccess rules.
Edit the file using sudo nano /etc/phpmyadmin/apache.conf and add the following line AllowOverride All

Now create a .htaccess file in the PhpMyAdmin directory to password protect it. sudo nano /usr/share/phpmyadmin/.htaccess and add the following lines to it.
AuthType Basic
AuthName “Restricted Files”
AuthUserFile /etc/apache2/.phpmyadmin.htpasswd
Require valid-user

Now create the user and password for the directory protection.
sudo htpasswd -c /etc/apache2/.phpmyadmin.htpasswd myusername. It will prompt you to enter a password for the user, “myusername” in this case.

Restart the Apache to enable the changes.
sudo service apache2 restart

Sometimes, you will see, that the PhpMyAdmin is having login issues. However, you might be using the correct root password! Please follow the steps below if you face this issue.
sudo service mysql stop
sudo mysqld_safe --skip-grant-tables &
mysql -uroot
use mysql;
UPDATE user SET plugin="";
UPDATE user SET password=PASSWORD("my_root_password") WHERE user="root";
FLUSH PRIVILEGES;
quit
sudo service mysql restart

It should be working properly now.

NGINX reverse proxy

It’s time to setup the NGINX reverse proxy now. We will configure NGINX to work just as a proxy server over Apache web server. So NGINX reverse proxy will pass all the static and dynamic requests to Apache. Follow the steps below to setup NGINX reverse proxy.

First of all, stop the Apache server to free the 80 port.
sudo service apache2 stop

Now, install NGINX
sudo apt-get install nginx

Therefore, edit the Apache2 config file sudo nano /etc/apache2/ports.conf and make it listen on port 8080 instead of 80.
Listen 8080

In addition, create the NGINX reverse proxy configuration file for your domain. sudo nano /etc/nginx/sites-available/exampledomain and add the following lines below.
server {
listen 80;
listen [::]:80;

root /var/www/vhosts/exampledomain.com/public_html;

index index.php index.html;

server_name exampledomain.com *.exampledomain.com;

access_log /var/www/vhosts/exampledomain.com/logs/access_nginx.log;
error_log /var/www/vhosts/exampledomain.com/logs/error_nginx.log;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:8080;

proxy_buffering on;
proxy_buffer_size 1k;
proxy_buffers 24 4k;
proxy_busy_buffers_size 8k;
proxy_max_temp_file_size 2048m;
proxy_temp_file_write_size 32k;
}

location ~ /\.ht {
deny all;
}
}

Finally, enable the configuration for your domain.
sudo ln -s /etc/nginx/sites-available/exampledomain /etc/nginx/sites-enabled/exampledomain

Restart both Apache web server and NGINX reverse proxy server.
sudo service apache2 restart
sudo service nginx restart

Now the NGINX should be running as a proxy server on top of Apache.

Varnish cache

In addition, you can add one more layer over the NGINX. That is the Varnish cache system. Varnish is a full-page cache mechanism. If you want to run some dynamic sites like WordPress or Drupal or Magento, you have to use proper VCL rules, though.

First, stop the NGINX reverse proxy service. Because Varnish also listens to port 80. So we have to move NGINX reverse proxy service port to something different. Run the following commands.
sudo service nginx stop
sudo apt-get install varnish

Varnish is now installed on your server. It’s time to configure Varnish.
sudo nano /etc/default/varnish and make the following changes. Note the port here has been changed to 80.

DAEMON_OPTS=”-a :80 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s malloc,256m”

Make some default VCL rules as well.
sudo nano /etc/varnish/default.vcl and add the following.

backend default {
.host = “127.0.0.1”;
.port = “8888”;
}

sudo nano /lib/systemd/system/varnish.service and change the port to 80.

ExecStart=/usr/sbin/varnishd -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m

Restart Varnish cache.
sudo systemctl daemon-reload
sudo systemctl restart varnish.service

Now the Varnish cache is running on port 80. Therefore, we need to update the NGINX reverse proxy service port. Follow the steps below. Edit the NGINX virtual host file sudo nano /etc/nginx/sites-available/exampledomain and update the port to 8888.

server {
listen 8888;
listen [::]:8888;

In addition, restart the NGINX reverse proxy service.
sudo service nginx restart

Summary

So, the Apache web service is running on port 8080. Consequently, the NGINX reverse proxy service is running on port 8888. And finally, the Varnish cache service is running on port 80.