
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://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
$ add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://nyc2.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu xenial main'
$ apt update
$ apt install mariadb-server
Edit /etc/mysql/my.cnf, set innodb_buffer_pool_size = 512M
3. Install nginx.
$ echo "deb http://ppa.launchpad.net/nginx/stable/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/nginx-stable.list
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --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 http://files.drush.org/drush.phar
$ chmod +x drush.phar
$ mv drush.phar /usr/bin/drush
$ drush init
Refer: http://docs.drush.org/en/master/install/
7. Install Git and git-flow:
$ apt install git
$ apt install git-flow
8. Install Composer.
$ curl -sS https://getcomposer.org/installer | php
$ chmod +x composer.phar
$ mv composer.phar /usr/bin/composer
Refer: http://symfony.com/doc/current/cookbook/composer.html
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 https://github.com/oh-my-fish/oh-my-fish/raw/master/bin/install | 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:
opcache.enable=1
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.max_accelerated_files=16000
opcache.memory_consumption=128
opcache.interned_strings_buffer=32
opcache.fast_shutdown=1
If using php5.6, set always_populate_raw_post_data = -1 in php.ini
12. Tune redis.
Drupal module.
https://www.drupal.org/project/redis
Configure:
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'] = '127.0.0.1';
$conf['lock_inc'] = 'sites/all/modules/contrib/redis/redis.lock.inc';
$conf['path_inc'] = 'sites/all/modules/contrib/redis/redis.path.inc';
$conf['cache_backends'][] = 'sites/all/modules/contrib/redis/redis.autoload.inc';
$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'] = '127.0.0.1'; $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/example.services.yml';
In services.yml:
$settings['container_yamls'][] = 'modules/redis/example.services.yml';
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:
https://www.drupal.org/docs/7/caching-to-improve-performance/varnish-4x…
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:
https://www.drupal.org/project/varnish
Add settings.php:
$conf['cache_backends'][] = 'sites/all/modules/contrib/varnish/varnish.cache.inc';
$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('127.0.0.1');
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 http://archive.apache.org/dist/lucene/solr/5.5.3/solr-5.5.3.tgz
$ tar xzf solr-5.5.3.tgz solr-5.5.3/bin/install_solr_service.sh --strip-components=2
$ sudo bash ./install_solr_service.sh solr-5.5.3.tgz
Check if Solr is running:
$ sudo service solr status
Check if Solr UI is running:
http://your_server_ip:8983/solr
15a Password-protect Solr
Edit /opt/solr/server/etc/jetty.xml
Add before the closing configure tag:
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Solr Realm</Set>
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
<Set name="refreshInterval">0</Set>
</New>
</Arg>
</Call>
Edit /opt/solr/server/solr-webapp/webapp/WEB-INF/web.xml
Add before the closing web-app tag:
<security-constraint>
<web-resource-collection>
<web-resource-name>Solr authenticated application</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>core1-role</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Solr Realm</realm-name>
</login-config>
Create or edit /opt/solr/server/etc/realm.properties
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.