Search form

Ubuntu 16.04 Web Server with Nginx, MariaDB, Redis, and Drupal 7

The Drupal 8 version of this article can be found here.

As of today, April 21, 2016, Canonical has released Ubuntu 16.04 Server, supported until 2021. Ubuntu 16.04 has some nice enhancements, and some changes that will affect sysadmins and developers: it ships with Python 3 as the default Python, plus PHP 7, MySQL 5.7, Nginx 1.9, Apache 2.4.18, and MariaDB 10.0.27. Let's see if we can make it work with Nginx, PHP-FPM, MariaDB, and Drupal 7, using the Redis key-value store as the backend cache instead of Drupal's cache tables.

Ubuntu 16.04 Security

As with any production server, you should enable unattended security updates, harden or disable SSH, then add a firewall (ufw), fail2ban, remote logging, and ideally an IDS like OSSEC for monitoring filesystem checksums. For now at least I'd ensure that unattended upgrades are set up:

root@ubuntu:/# cat /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

root@ubuntu:/# head /etc/apt/apt.conf.d/50unattended-upgrades
// Automatically upgrade packages from these (origin:archive) pairs
Unattended-Upgrade::Allowed-Origins {
        "${distro_id}:${distro_codename}-security";
//      "${distro_id}:${distro_codename}-updates";
//      "${distro_id}:${distro_codename}-proposed";
//      "${distro_id}:${distro_codename}-backports";
};

Ubuntu 16.04 Packages and Version Numbers

Ubuntu 16.04 offers current stuff in its main repos:

root@ubuntu:/# apt-cache madison nginx
     nginx | 1.9.15-0ubuntu1 | http://us.archive.ubuntu.com/ubuntu xenial/main amd64 Packages
     nginx | 1.9.15-0ubuntu1 | http://us.archive.ubuntu.com/ubuntu xenial/main i386 Packages

root@ubuntu:/# apt-cache madison php
     php | 1:7.0+35ubuntu6 | http://us.archive.ubuntu.com/ubuntu xenial/main amd64 Packages
     php | 1:7.0+35ubuntu6 | http://us.archive.ubuntu.com/ubuntu xenial/main i386 Packages

root@ubuntu:/# apt-cache madison php-fpm
     php-fpm | 1:7.0+35ubuntu6 | http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 Packages
     php-fpm | 1:7.0+35ubuntu6 | http://us.archive.ubuntu.com/ubuntu xenial/universe i386 Packages

root@ubuntu:/# apt-cache madison mariadb-server
     mariadb-server |  10.0.24-7 | http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 Packages
     mariadb-server |  10.0.24-7 | http://us.archive.ubuntu.com/ubuntu xenial/universe i386 Packages

root@ubuntu:/# apt-cache madison mysql-server
     mysql-server | 5.7.11-0ubuntu6 | http://us.archive.ubuntu.com/ubuntu xenial/main amd64 Packages
     mysql-server | 5.7.11-0ubuntu6 | http://us.archive.ubuntu.com/ubuntu xenial/main i386 Packages

root@ubuntu:/# apt-cache madison redis-server
     redis-server |  2:3.0.6-1 | http://us.archive.ubuntu.com/ubuntu xenial/universe amd64 Packages

It's worth noting here that both Drupal (update 08 July, 2016: fixed in Drupal 7.50) and WordPress have some known issues with PHP 7. In normal usage I haven't encountered any problems, but if you're concerned about this you can use Ondřej Surý's PPA to install PHP 5.6 instead:

root@ubuntu:/# add-apt-repository ppa:ondrej/php
root@ubuntu:/# apt-get update
root@ubuntu:/# apt-get install php5.6

Set Up Nginx, MariaDB, and PHP-FPM

root@ubuntu:/# apt-get install nginx php mariadb-server

This installs PHP-FPM automatically. Next we need to install a MariaDB-compatible PHP database connector, and some PHP extensions for Drupal:

root@ubuntu:/# apt-get install php-gd php-xml php-mbstring php-mysqli

PHP 7 on Ubuntu 16.04 includes the Zend OPcache:

root@ubuntu:/# php -v
PHP 7.0.4-7ubuntu2 (cli) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

Set a root password for MariaDB:

root@ubuntu:/# mysql -uroot
MariaDB [(none)]> use mysql;
Database changed
MariaDB [mysql]> UPDATE user SET PASSWORD=PASSWORD("my-password") WHERE user='root';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Ensure PHP-FPM is listening on the correct socket:

root@ubuntu:/# vi /etc/php/7.0/fpm/pool.d/www.conf
# look for the listen directive
listen = /run/php/php7.0-fpm.sock

Finally, let's edit /etc/nginx/sites-available/default and tell Nginx to pass PHP requests along to PHP-FPM. I'm just using the default site and location (/var/www/html) here in the interest of getting this up and running quickly.

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.php;
        #index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                # setting up rewrite here for Drupal's clean_urls
                try_files $uri @rewrite;
                # $uri/ =404;
        }

        # define rewrite
        location @rewrite {
                rewrite ^ /index.php last;
        }

        #
        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;
        }
}

Finally, chown your web directories (/var/www/html) so they're accessible to the Debian/Ubuntu web user (www-data:www-data).

root@ubuntu:/# chown -hR www-data:www-data /var/www/html

Installation of Drupal

No need to do anything unusual here, so just follow the standard guidelines from Drupal.org. I typically use the Minimal install to start with a basic set of modules. If Drupal reports any errors, you may need to install one or more additional extensions for your version of PHP.

Installation of Redis

Now that Drupal is up and running, let's install Redis and a PHP connector for it (we're using the PhpRedis extension here):

root@ubuntu:/# apt-get install php-redis redis-server

You can start Redis manually by running redis-server, and if it's daemonized (this is the default) it'll run automatically on startup:

13515:M 21 Apr 13:06:50.023 # Server started, Redis version 3.0.6
13515:M 21 Apr 13:06:50.023 * The server is now ready to accept connections on port 6379

The Redis default settings are sufficient for our purposes, although the official documentation explains everything in detail.

Next, install and enable the Redis Drupal module, and add some directives to your site's settings.php (per the Redis module's readme.txt) to tell Drupal to use Redis for caching instead of the Drupal cache tables:

$conf['redis_client_interface'] = 'PhpRedis';
$conf['lock_inc']               = 'sites/all/modules/redis/redis.lock.inc';
$conf['path_inc']               = 'sites/all/modules/redis/redis.path.inc';
$conf['cache_backends'][]       = 'sites/all/modules/redis/redis.autoload.inc';
$conf['cache_default_class']    = 'Redis_Cache';

There's no need to override the default hostname here unless you specified a Unix socket or you're running the Redis server on a different machine. You can see Redis working by running the Redis monitor as you click around your Drupal site:

1461263488.591916 [0 127.0.0.1:38376] "HGETALL" "9e7becd0db04b05520cc75f45400fd26:cache_menu:links:navigation:tree-data:en:9bd1605e2280833450478f9083b7f8714c2fa28f1012455e2744e5af1a13eec5"
1461263488.592534 [0 127.0.0.1:38376] "HGETALL" "9e7becd0db04b05520cc75f45400fd26:cache_menu:links:management:page:admin/people:en:1:0"

So now you're running Drupal with a highly scalable web server, opcode caching, a key-value database store, and the high-performance Percona-XtraDB storage engine, on an Ubuntu 16.04 system supported by security updates until 2021.

root@ubuntu:/# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1486/nginx -g daemo
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      905/sshd
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      1179/mysqld
tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      943/redis-server 12
tcp6       0      0 :::80                   :::*                    LISTEN      1486/nginx -g daemo
tcp6       0      0 :::22                   :::*                    LISTEN      905/sshd

Drupal Status Page on Ubuntu 16

For SSL, particularly with Varnish added in, look here.

Categories: