In this article you will learn how to setup Drupal 8 with Nginx, PHP-FPM, MySQL and phpMyAdmin.

This article might not be complete, but you will find a lot of useful at least here. This article has been in my draft section since March 2017, and published at the end of December 2017, with little editing.

Prerequisites

  • Ubuntu 16.04 - 64bit version.
  • Root privileges.

You can get a cheap VPS for $10/mo from Linode. As I've few test Linodes already purchased I'm going to use one of them

Follow basic security guide, see: Securing Your Server

I will use Putty for Windows to access SSH

Secure your server

Create the user, replacing example_user with your desired username. You’ll then be asked to assign the user a password:

adduser example_user


Add the user to the sudo group so you’ll have administrative privileges:

adduser example_user sudo

Disallow root logins over SSH. This requires all SSH connections be by non-root users. Once a limited user account is connected, administrative privileges are accessible either by using sudo or changing to a root shell using su -.

sudo nano /etc/ssh/sshd_config

Under # Authetification section change to

# Authentication: ...

PermitRootLogin no

Update the Ubuntu system

sudo apt-get update

Install Nginx and PHP-FPM

Install Nginx with the following apt command:

sudo apt-get install nginx -y

Next, install php7.0-fpm with php-gd extension that is required by Drupal core:

sudo apt-get install php7.0-fpm php7.0-cli php7.0-gd php7.0-mysql php7.0-xml -y

Configure Nginx and PHP-FPM

In this step, we will configure Nginx to use php-fpm to serve HTTP requests for PHP pages. Go to the php-fpm directory "/etc/php/7.0/fpm" and edit the "php.ini" file:

sudo nano /etc/php/7.0/fpm/php.ini

Un-comment the cgi.fix_pathinfo line and change the value to "0"

When using nano command you can use CTRL+W to locate that line. Once changed press CTRL+O to save changes and CTRL+X to exit from nano editor

Now we should modify the default Nginx virtual host configuration. Edit the "default" file and enable the php-fpm directive.

sudo nano /etc/nginx/sites-available/default

Un-comment  location ~ \.php$ section, so it look like this

location ~ \.php$ {
include snippets/fastcgi-php.conf;
# With php7.0-cgi alone:
#fastcgi_pass 127.0.0.1:9000;
# With php7.0-fpm:
fastcgi_pass unix:/run/php/php7.0-fpm.sock;
}

CTRL+O and CTRL+X

Then test the Nginx configuration with the command "nginx -t" to ensure that it is valid:

nginx -t

If there is no error, restart nginx and the php-fpm service:

systemctl restart nginx
systemctl restart php7.0-fpm

PHP Info file (Optional)

Next, test that php-fpm is working properly with nginx by creating new php info file in the web directory "/var/www/html"

cd /var/www/html/
echo "<?php phpinfo(); ?>" > info.php

Visit the info.php file at the server IP  in a web browser. The result should be similar to the screenshot below.

PHP Version Info log

PHP Version Info log

Configure the VirtualHost for Drupal

We will install Drupal 8 in the directory "/srv/www/reinisfischer.com". Please replace my domain name in your installation with the domain name of the website that you want to use this Drupal installation for. So let's create the directory:

sudo mkdir -p /srv/www/reinisfischer.com/{public_html,logs}
sudo usermod -a -G www-data admin
sudo chown -R www-data:www-data /srv/www
sudo chmod -R 775 /srv/www
sudo nano /etc/nginx/sites-available/felicia.com

Paste the Nginx configuration for Drupal 8:

server {
    server_name reinisfischer.com;
    root /srv/www/reinisfischer.com/public_html; ## <-- Your only path $
    access_log /srv/www/reinisfischer.com/logs/access.log;
    error_log /srv/www/reinisfischer.com/logs/error.log;

    listen 80;
    listen [::]:80;


    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Very rarely should these ever be accessed outside of your lan
    location ~* \.(txt|log)$ {
        allow 192.168.0.0/16;
        deny all;
    }

    location ~ \..*/.*\.php$ {
        return 403;
    }

    location ~ ^/sites/.*/private/ {
        return 403;
    }

    # Block access to "hidden" files and directories whose names begin with a
    # period. This includes directories used by version control systems such
    # as Subversion or Git to store control files.
    location ~ (^|/)\. {
        return 403;
    }

    location / {
        # try_files $uri @rewrite; # For Drupal <= 6
        try_files $uri /index.php?$query_string; # For Drupal >= 7
    }

    location @rewrite {
        rewrite ^/(.*)$ /index.php?q=$1;
    }

    # In Drupal 8, we must also match new paths where the '.php' appears in the middle,
    # such as update.php/selection. The rule we use is strict, and only allows this pattern
    # with the update.php front controller.  This allows legacy path aliases in the form of
    # blog/index.php/legacy-path to continue to route to Drupal nodes. If you do not have
    # any paths like that, then you might prefer to use a laxer rule, such as:
    #   location ~ \.php(/|$) {
    # The laxer rule will continue to work if Drupal uses this new URL pattern with front
    # controllers other than update.php in a future release.
    location ~ '\.php$|^/update.php' {
        fastcgi_split_path_info ^(.+?\.php)(|/.*)$;
        #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
        include fastcgi_params;
        include snippets/fastcgi-php.conf;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_intercept_errors on;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    # Fighting with Styles? This little gem is amazing.
    # location ~ ^/sites/.*/files/imagecache/ { # For Drupal <= 6
    location ~ ^/sites/.*/files/styles/ { # For Drpal >= 7
        try_files $uri @rewrite;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }
}

CTRL+O and CTRL + X

The Drupal virtual host file has been created, now we have to activate it by creating a symlink to the file in the "sites-enabled" directory:

ln -s /etc/nginx/sites-available/reinisfischer.com /etc/nginx/sites-enabled/

Test the Nginx configuration and if there is no errors restart Nginx:

nginx -t
systemctl restart nginx

Install MySQL

sudo apt-get install mysql-server
​sudo mysql_secure_installation

Install phpMyAdmin

sudo apt-get install phpmyadmin

Hit ESC when the installation prompts you for auto-configuration, because there is no option for Nginx.

Make an easy accessible symlink

sudo ln -s /usr/share/phpmyadmin/ /srv/www/reinisfischer.com/public_html/phpmyadmin

Install and Configure Drupal

Enter the directory that we created earlier and download Drupal with wget. I'm using the latest Drupal 8.2.7. release as of March 23, 2017, make sure you are downloading latest version by visiting Drupal 8 download page and writing down the last numbers (version)

cd /srv/www/reinisfischer.com
sudo wget https://ftp.drupal.org/files/projects/drupal-8.2.7.tar.gz
sudo tar -xvzf drupal-8.2.7.tar.gz
sudo cp drupal-8.2.7/* public_html/ -R
sudo chown www-data:www-data public_html -R

Now visit your Drupal site in the web Browser, you should see following screen

Drupal 8 welcome screen

Drupal 8 welcome screen

Now, it's just time to connect database and set up your Drupal 8 website