Categories
Server Software Technology

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

Using NGINX reverse proxy along with the Apache webserver improves the performance of the websites significantly! So, I decided to give it a try. I have configured a lot of webservers earlier with Apache and PHP or Lighttpd and PHP modules. However, I was doing this type of setup for the first time!

I decided to configure a server with Linux – Ubuntu 16.04 LTS, Apache2 as a webserver, 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. In this article, 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

First of all, I’ve used a 2GB dedicated server with Ubuntu 16.04 LTS version from DigitalOcean to test the setup. After logging in to the server 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. Therefore, 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 the following lines:
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
LC_MESSAGES=POSIX

Consequently, run this command sudo nano /etc/environment and add the lines mentioned below:
LC_ALL=en_US.UTF-8
LANG=en_US.UTF-8

Hence, you have configured the locales 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 very commonly required components with the following commands.
sudo apt-get install curl -y
sudo apt-get install zip -y
sudo apt-get install git -y
sudo apt-get install memcached -y

Probably, the server will prompt 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 steps are complete and we are ready to move on to the next stage.

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 -y
sudo apt-get install libapache2-mod-fastcgi -y

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 the 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.

nginx reverse proxy
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 webserver.
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 -y
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 -y

Now, we have to enable the PhpMyAdmin alias in the Apache config file. Therefore, edit the file sudo nano /etc/apache2/apache2.conf and add this line at the end of it Include /etc/phpmyadmin/apache.conf.

Also, edit the PhpMyAdmin Apache config file in order to allow .htaccess rules. To do so, edit the file using sudo nano /etc/phpmyadmin/apache.conf and add the following line AllowOverride All if not exists. Otherwise, just modify it from AllowOverride None to AllowOverride All.

Furthermore, 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.

Finally, 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 set up the NGINX reverse proxy now. We will configure NGINX to work just like a proxy server over Apache webserver. So NGINX reverse proxy will pass all the static and dynamic requests to Apache. Follow the steps below to setup the 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 -y

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;
# The following are important to pass the IP to the Apache
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;
}
}

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

Finally, restart both the Apache webserver and NGINX reverse proxy server.
sudo service apache2 restart
sudo service nginx restart

As a result, the NGINX should be running as a reverse 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. The 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 of all, 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 -y

The Varnish is now installed on your server. It’s time to configure Varnish.
sudo nano /etc/default/varnish and make the following changes. Make a note that 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

Finally, restart the 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.

By Supratim Roy

I'm a technology enthusiast with over fifteen years of hands-on work experience in the IT industry. My specialization in web development technology, allows me to quickly adopt innovative approaches and leading-edge technology solutions.

After passing the HS, I joined B.Com. under the CU. From the second year, I started studying computer courses. After graduating in Computer Applications (BCA) from Indira Gandhi National Open University (IGNOU), I started my career as a Jr. Software Dev. in 2005. After four years, in 2009, I got the opportunity to pursue a master's degree. In 2011, I completed MCA from Sikkim Manipal University (SMU). I carried out the journey of my carrier as Jr. Software Dev., Sr. Software Dev., TL, and PM. Now I'm working as the VP of Technology & Product at CodeClouds.

I use my technical knowledge, skill, expertise, and previous experience to analyze the requirements of the clients and understand their business philosophy. I try to deliver quality solutions and products in a timely manner with a high percentage of accuracy. I also prepare and manage project specifications, scope documentation, workflow, data diagram, and development documentation. I lead a team of around 50 highly talented members in a well-formed and structured way.

I love listening to music and watching the action, adventure, thriller, horror movies, and Discovery, Animal Planet, and Nat Geo TV channels. Photography is also one of my hobbies, however, I'm really an amateur! I like to read technical articles, journals, and documentaries about Indian Himalayas and wildlife. I'm passionate about adventure sports. I encourage peoples to love adventure sports.

I've traveled to many places and trekked in several parts of the Himalayas in India and Nepal. I'm a member of "MTG - Miles To Go" - a nature lover's association in Kolkata. I've done the Rock Climbing course from Parvat Abhiyatri Sangha affiliated with Anandabazar Patrika. I also participate in several community initiatives taken by an NGO.

Leave a Reply