Set up a Nginx, MariaDB, and PHP-FPM (LEMP) Server for Drupal

Posted on 18 Sep 2017 by Oleksii Raiu
LEMP Server Logo

This is a tutorial to install LEMP with Drupal with OPCache, Varnish, and Apache Solr. This will result in a ready production website, covering 99.9% of Drupal based website needs.

1. Create an admin user.

$ adduser site_admin
$ usermod -a -G sudo,root,www-data site_admin

2. Install MariaDB.

MariaDB server is better than a standard MySQL for it’s optimizations, and must be installed early on to avoid conflicts.

$ apt install software-properties-common
$ apt-key adv --recv-keys --keyserver hkp:// 0xF1656F24C74CD1D8
$ add-apt-repository 'deb [arch=amd64,i386,ppc64el] xenial main'
$ apt update
$ apt install mariadb-server

Edit /etc/mysql/my.cnf, set innodb_buffer_pool_size = 512M

3. Install nginx.

$ echo "deb $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/nginx-stable.list
$ sudo apt-key adv --keyserver --recv-keys C300EE8C
$ sudo apt update
$ sudo apt install nginx

Edit /etc/nginx/nginx.conf, add under http section: client_max_body_size 256M;

4. Install PHP and libraries.

$ apt install curl zip unzip ssl-cert php7.1-common php7.1-gd php7.1-mbstring php7.1-mcrypt php7.1-mysql php-phpseclib php-tcpdf php7.1-xml php7.1-cli php7.1-fpm php7.1-bcmath php7.1-json php7.1-readline php7.1-bz2 php7.1-zip php-imagick php7.1-curl php-geoip php-mail php-oauth unzip php-zip

Set php-fpm user to current in /etc/php/7.1/fpm/pool.d/www.conf

Set php-fpm daemon in /etc/php/7.1/fpm/pool.d/www.conf
pm.max_children = 50

5. Install PHPMyAdmin.

When installing PHPMyAdmin we don’t want to pull apache with it. Prerequisites have been installed in the previous step.

$ sudo apt --no-install-recommends install phpmyadmin

6. Install Drush:

$ wget
$ chmod +x drush.phar
$ mv drush.phar /usr/bin/drush
$ drush init


7. Install Git and git-flow:

$ apt install git
$ apt install git-flow

8. Install Composer.

$ curl -sS | php
$ chmod +x composer.phar
$ mv composer.phar /usr/bin/composer


9. Install htop.

$ apt install htop

10. Install Fish.

$ apt install fish

Check where fish is installed before going on.

$ which fish
$ chsh -s /usr/bin/fish
$ curl -L | fish
$ omf install agnoster

11. Tune PHP.

In /etc/php/7.0/fpm/php.ini file:

memory_limit = -1
post_max_size = 64M
upload_max_filesize = 64M
max_execution_time = 60
max_input_vars = 32000

In /etc/php/7.0/fpm/conf.d/10-opcache.ini file:


If using php5.6, set always_populate_raw_post_data = -1 in php.ini

12. Tune redis.

Drupal module.

Edit /etc/redis/redis.conf and set:

databases 1
maxmemory 1024mb
loglevel warning
maxmemory-policy allkeys-lru

D7: In settings.php:

$conf['redis_client_interface'] = 'PhpRedis'; // Can be "Predis".
$conf['redis_client_host'] = '';
$conf['lock_inc'] = 'sites/all/modules/contrib/redis/';
$conf['path_inc'] = 'sites/all/modules/contrib/redis/';
$conf['cache_backends'][] = 'sites/all/modules/contrib/redis/';
$conf['cache_default_class'] = 'Redis_Cache';
$conf['cache_class_cache'] = 'Redis_Cache';
$conf['cache_class_cache_bootstrap'] = 'Redis_Cache';
$conf['cache_class_cache_menu'] = 'Redis_Cache';
$conf['cache_class_cache_block'] = 'Redis_Cache';
$conf['cache_class_cache_content'] = 'Redis_Cache';
$conf['cache_class_cache_filter'] = 'Redis_Cache';
$conf['cache_class_cache_form'] = 'Redis_Cache';
$conf['cache_class_cache_page'] = 'Redis_Cache';

D8: In settings.php:

$settings['redis.connection']['interface'] = 'PhpRedis';
$settings['redis.connection']['host'] = ''; $settings['cache']['default'] = 'cache.backend.redis';
$settings['cache']['bins']['bootstrap'] = 'cache.backend.chainedfast';
$settings['cache']['bins']['discovery'] = 'cache.backend.chainedfast';
$settings['cache']['bins']['config'] = 'cache.backend.chainedfast';
$settings['container_yamls'][] = 'modules/redis/';

In services.yml:

$settings['container_yamls'][] = 'modules/redis/';

Run redis-cli info and verify it works.

13. Setup varnish.

Install varnish:

apt install varnish

Configure /etc/default/varnish file:

Set DAEMON_OPTS -a to listen to port 80.

Configure /etc/varnish/default.vcl:…

Edit the nginx virtualhost to listen to port 8080.

Edit /etc/varnish/secret. Set it to admin/config/development/varnish

Fix the systemd issue:

$ cp /lib/systemd/system/varnish.service /etc/systemd/system/

Edit /etc/systemd/system/varnish.service and set -a to :80. Reboot the server.

Install drupal module:

Add settings.php:

$conf['cache_backends'][] = 'sites/all/modules/contrib/varnish/';
$conf['cache_class_cache_page'] = 'VarnishCache';
$conf['page_cache_invoke_hooks'] = FALSE;
$conf['omit_vary_cookie'] = TRUE;
$conf['reverse_proxy_header'] = 'HTTP_X_FORWARDED_FOR';
$conf['reverse_proxy_addresses'] = array('');

14. Final preparations.

14a. Cron.

0 * * * *   idm     /usr/bin/curl -s http://localhost/cron.php?cron_key=hNkEIUmRyEQ7wTZxQHemFJyVh-2V1M4YBOsZ0RC2_vQ > /dev/null

14b. MX Record and DNS for www subdomain.

14c. Clean the apt archives.

$ apt clean

15. Install Apache Solr.

Install unzip (required for solr):

$ apt install unzip

Install Java:

$ apt install python-software-properties
$ apt install default-jdk

Install Solr:

$ cd ~
$ wget
$ tar xzf solr-5.5.3.tgz solr-5.5.3/bin/ --strip-components=2
$ sudo bash ./ solr-5.5.3.tgz

Check if Solr is running:

$ sudo service solr status

Check if Solr UI is running:

15a Password-protect Solr

Edit /opt/solr/server/etc/jetty.xml
Add before the closing configure tag:

    <Call name="addBean">
        <New class="">
          <Set name="name">Solr Realm</Set>
          <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/</Set>
          <Set name="refreshInterval">0</Set>

Edit /opt/solr/server/solr-webapp/webapp/WEB-INF/web.xml
Add before the closing web-app tag:

      <web-resource-name>Solr authenticated application</web-resource-name>

    <realm-name>Solr Realm</realm-name>

Create or edit /opt/solr/server/etc/
Add the line:

admin: solr_password_here,core1-role.

Copy over the configs and create the core folder structure:

$ mkdir /opt/solr/server/solr/drupal
$ mkdir /opt/solr/server/solr/drupal/conf/
$ mkdir /opt/solr/server/solr/drupal/data/
$ ln -s /opt/solr/server/solr/drupal /var/solr/data/drupal
$ cp <search_api_module_path>/search_api_solr/solr-conf/5.x/*.* /opt/solr/server/solr/drupal/conf/
$ chown -R solr /opt/solr/server/solr/drupal

Restart Solr:

$ service solr restart

Create a core with name and folder of drupal in Solr UI.

16. Checkups.

  • Check www to non www redirect.
  • Check file system permissions.