Tutorial: The complete guide from nothing to the next WordPress.com PART 1

Be the next WordPress.com or Edublogs.org, but better! The complete guide for beginners to set up their server.

In these series I'll be explaining you step by step, line by line on how I set up my new server cluster to be like WordPress.com.
This will eventually allow easy expansion, super fast websites and high availability.
This will mean you can make WordPress available for everyone in the best way using your WPMU skills!

Why this tutorial?
The reason for this tutorial is because I've struggled many months with my hosting network to get it all set up correctly in cPanel. And it works - Brilliantly. As you can see on http://status.hostmijnpagina.nl my homepage loads within 0.14 seconds. A clean mapped page even within 0.09 seconds and a VIP database page loads within 0.12 seconds.
But it stops there, because cPanel is slow with updating its core and is based upon Apache - Apache is great but will decrease the speed of the WordPress non-cached pages a LOT when you want a fast front-end. This means that as a logged-in user a basic page loads in about 3 seconds on a fiber connection.

So what's the verdict?
We want to use ISPConfig, Nginx and mod_spdy, as well save ourself 1GB of RAM and a lot of processing power. At the same time we to be able to load balance, which is only possible on DNS and mail level in cPanel.
We want our pages to load within 0.05 seconds on a fiber connection with HTTPS for cached pages. That's about 12 times faster than WordPress.com does. We also want upgradeablitity and redundancy.
We want our pages to load within 0.4 seconds on a fiber connection with HTTPS for logged in users, that's about 3 to 4 times faster than WordPress.com offers and 8 times faster than an optimized cPanel server does.
We want WPMUdev Domain Mapping SSO plugin's script to load within 0.1 second, that's 6 to 20 times faster than on an optimized cPanel server.

How do we achieve this?
Simply put, we externalize and split all the processes which are needed.
The basic and most easily split is the DNS server, this server requires the least power and can easily be put in conjunction with other servers.
Something that's harder is the mailserver, however this is easily achieved using cPanel together with its DNS services. The mail server requires more CPU power because you'll need to configure anti-spam and virus scanning.
The hardest part will be the splitting of the databases. However this is easily achieved with WPMUdev's Multi-DB plugin. You can assign the server's location and passwords in the configuration of this plugin.
The most important part will be PHP process load balancing. This is achieved through splitting the server and copying the content on the servers to each other. With an interval of 1 minute this will be achieved best.
The problem that follows is that the uploads will be slowing this server down greatly, so we'll externalize the wp-uploads folder to one of the server's Hard Drive Disk (40TB raid 10 :smiley:)
Now that'll be slow and so we need to fix that by using a CDN which pulls the uploads from the Hard Drive Disk.
Finally we have multiple servers running our WordPress MU installation. Without further configuration needed. Maybe you'll need to install another server and update your DNS settings or upgrade your SSD/HDD. Besides that, everything should keep working.

This part of the guide is based upon the following sources:
https://www.howtoforge.com/perfect-server-centos-7-x86_64-nginx-dovecot-ispconfig-3
http://codex.wordpress.org/Nginx
http://kbeezie.com/securing-nginx-php/

But then with WordPress MultiSite and TLS, SPDY, memcached, external DNS, Multi-DB and Domain Mapping in mind.
This will ensure the fastest server with the lowest amount of resources (4GB RAM, 2 cores) and will have upgradeablitity and load balancing in mind.

We will also keep in mind that we are going to use WPMUDev's Multi-DB plugin, with that we're going to externalize our database and up the performance of our main server.
Only ISPConfig will be installed on the local database, ISPConfig allows you to create FTP users and maintain the database.
The rest will be installed on an external CPanel server. That server will host the Nameserver, mailserver and the databases.
With that we can easily plug in our Domain Mapping extension to the DNS server with a plugin linked below.

Disclaimer: This has all been done on TransIP's BladeVPS server and configurations might differ for some people. However because of the minimal installs we keep everything in mind here.
If you do have a problem regarding the connection and other server-related problems, please ask your hosting provider first before you place your comments here. They have much better understanding of your server's configuration.

Another Disclaimer: I'm not a seasoned Linux user, so I can't help you in-dept. This tutorial describes exactly what I've done and which worked for me.

REQUIREMENTS

  1. Server 1: 2 Cores + 4GB RAM VPS with CentOS 7 installation image
  2. Server 2: 2 Cores + 4GB RAM VPS with cPanel
  3. Optional Server 3: 2 Cores + 4GB RAM VPS with CentOS 7 installation image (load balancing
  4. Your domain you'd like to use to be pointed at the server(s) through DNS. Including the *.yourdomain.com
  5. Putty (Windows) or Terminal (Mac/Linux)
  6. A keyboard, basic Linux knowledge and about an hour or 2 of your time

Before we begin, I'd like to say that I'm using a "console" view of the server. This is a virtual screen sent to my computer so I can configure the server. In step 2 of part one we make sure we can use SSH, from step 3 you can simply use SSH so you can copy+paste and use the CTRL+W (find) function without closing your browser's window.

Part 1: CentOS 7 Basic setup for ISPconfig

STEP 1. Install Centos7 Minimal
Once you're in the installation screen, select your Date & Times, Keyboard and Language. Most of the time the defaults are correct.
For the software, the image should be correct and the Software Selection should be clicked.
Inside the Software Selection select Minimal Install on the left and Compatibility Libraries and Development Tools on the right. Then select Done in the top left.
In the System selection select your hard drive/ssd and keep all values default.
The Network & Hostname should be kept untouched because your VPS host has already set these values.
If you however must change this the settings should be simple: Select the eth0 connection and select the Configure button on the bottom right, in general the top 2 values should be on (automatically connect and all users may connect). Select Save.

Begin Installation
DO NOT create a user, don't even try to click that button.
DO create a root password, this password will be used to log in as root. If you missed this option then you can always change the root password later.

You'll be asked to update the system, hit Enter (defaults to Yes).

When installed, log into root and issue this command, this will allow you to edit files without the Vi command (which is god-likely annoying and counter intiutive):
yum -y install nano wget

We also would like to locate our files with the locate command.
yum -y install mlocate
We will index the filetree to mlocate using the following command: (use this command as often as you'd like to find something after an installation)
updatedb

Edit your host file so it will allow your control panel to be connected to your IP before the DNS is set up:
nano /etc/hosts

Make it look like this, only add your IP and desired "hosting" subdomain, make it look professional and don't use swear words because your users might see this subdomain in their mail:
Change 123.456.789.012 with your server's IP, and connectisp.yourdomain.com connectisp to your desire. Change yourdomain.com to your domain of course.

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
123.456.789.012 connectisp.yourdomain.com connectisp

Step 2. Setting up your connections and activating SSH
At this point we're going to disable the firewalls because they're too much of a hassle. If you wish to re-enable them just reverse these steps and open the ports and allow applications you need.
systemctl stop firewalld.service
systemctl disable firewalld.service

We're going to use NetworkManager-tui to configure our firewall later on.
yum -y install net-tools NetworkManager-tui

Disable SELinux
nano /etc/selinux/config
Change this line:
SELINUX=enforcing
To:
SELINUX=disabled

Then reboot with this command:
reboot

Now you can connect to your server using SSH. Login as root.

Step 3. Installing the basic requirements
Install Epel
yum -y install epel-release
yum update
Install Network Time Protocol to make your server's time in sync with the world.
yum -y install ntp
Install and activate MariaDB (+ server)
yum -y install mariadb mariadb-server
systemctl enable mariadb.service
systemctl start mariadb.service

Step 4. Configuring MariaDB
mysql_secure_installation
Hit Enter for current root password
Hit Enter for Set root password (Defaults to the capital letter [Y])
Set your password, make it long and secure - MAKE SURE YOU SAVE THIS PASSWORD ELSEWHERE because you will need it later - Be sure not to include punctiation as it might mess up ISPConfig's installtion
Type in the password again.
Keep hitting enter because the default options are the most secure and will work perfectly - After that you've installed MariaDB and return to the default command line interface.

Step 5. Basic Mail server & Enable MariaDB & PostFix (super-lightweight alternative to sendmail)
This will ensure WordPress can send mails. No mailing recieving system will be installed because that will be done on cPanel. You can ignore any errors here.
yum -y install postfix
systemctl enable mariadb.service
systemctl start mariadb.service
systemctl stop sendmail.service
systemctl disable sendmail.service
systemctl enable postfix.service
systemctl restart postfix.service

Step 6. Preparing Nginx with a lot of goodies and installing it
Installing the OpenSSL development package to prevent errors.
yum -y install openssl-devel

Install nginx (full package)
yum -y install nginx

Stop Apache (if it was enabled)
systemctl stop httpd.service
systemctl disable httpd.service

Enable nginx
systemctl enable nginx.service
systemctl start nginx.service

You can now connect to your website.
You can even use a subdomain and it will work :slight_smile:.

If not, be sure that you're able to connect to your server through the IP address.
If that doesn't work, it's best to start over or to troubleshoot your problems with your hosting provider.
If it does work, make sure your DNS settings for your domain are pointing to your server.
Both the home directory as the * (ANAME) need to point to your server for WPMU to work.

https:// won't work for now.

Check if nginx is running:
service nginx status

If you see a green light, nginx is working!

Step 7. Installing PHP 5.6
We'll be using the following list of php modules to get ISPConfig and WordPress MU working in its fullest glory.

rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
yum --enablerepo=remi,remi-php56 -y install php php-common php-opcache php-pecl-memcache php-pecl-memcached php-fpm php-cli php-mysql php-gd php-ldap php-zlib php-pear php-xml php-xmlrpc php-iconv php-mbstring php-fileinfo php-curl php-xmlreader php-xmlwriter php-spl php-openssl php-ftp php-ssh2 php-pspell php-mcrypt php-soap php-tidy php-imap

Edit php.ini
nano /etc/php.ini

Change the following things in the file (default = 1st line, new = 2nd line):
Disable PHP info:

expose_php = On
expose_php = Off

Up the memory limit:

memory_limit = 128M
memory_limit = 256M

Up the upload limit for WP uploads (I used 100M which is massive, use lower if your space is limited):

post_max_size = 8M
post_max_size = 100M

Change the timezone for ntp ( http://php.net/manual/en/timezones.php ), use your server's location. Be sure to remove the ; before

;date.timezone =
date.timezone = "Europe/Amsterdam"

Another one for upload_max_filesize

upload_max_filesize = 2M
upload_max_filesize = 100M

You can now save the php.ini file.

Enable and start php-fpm:
systemctl enable php-fpm
systemctl restart php-fpm

Because ISPConfig uses fcgi, we need to do step 8.

Step 8. Disabling Apache and Installing FastCGI
To make fast-cgi work next to php-fpm, we need to do a few things.
yum -y install fcgi-devel
cd /usr/local/src/
git clone git://github.com/gnosek/fcgiwrap.git
cd fcgiwrap
autoreconf -i
./configure
make
make install
yum -y install spawn-fcgi

Now FastCGI is installed, we need to modify its configuration to make everything work with nginx.
nano /etc/sysconfig/spawn-fcgi

Add the following lines to the document:

FCGI_SOCKET=/var/run/fcgiwrap.socket
FCGI_PROGRAM=/usr/local/sbin/fcgiwrap
FCGI_USER=apache
FCGI_GROUP=apache
FCGI_EXTRA_OPTIONS="-M 0770"
OPTIONS="-u $FCGI_USER -g $FCGI_GROUP -s $FCGI_SOCKET -S $FCGI_EXTRA_OPTIONS -F 1 -P /var/run/spawn-fcgi.pid -- $FCGI_PROGRAM"

Save file

Add nginx to the apache group
usermod -a -G apache nginx

Make sure everything starts up correctly and start FastCGI
chkconfig spawn-fcgi on
systemctl start spawn-fcgi

Step 9. Installing pureFTP
Straightforward.
yum -y install pure-ftpd
systemctl enable pure-ftpd.service
systemctl start pure-ftpd.service

Encrypting the passwords.
nano /etc/pure-ftpd/pure-ftpd.conf
Remove the # in front of "# TLS 1"
Save.

Create a random SSL cert for the FTP server
yum -y install openssl
mkdir -p /etc/ssl/private/
openssl req -x509 -nodes -days 7300 -newkey rsa:2048 -keyout /etc/ssl/private/pure-ftpd.pem -out /etc/ssl/private/pure-ftpd.pem
Fill in the fields. e.g.:

NL
Noord-Holland
Amsterdam
Host Mijn Pagina
internet
connectisp.example.com
webmaster@example.com

Change the cert's permission
chmod 600 /etc/ssl/private/pure-ftpd.pem

Restart the pure-ftp service
systemctl restart pure-ftpd.service

Now you can connect to your server through FTP using TLS. However, there are no FTP users yet. We'll set those up later.

Step 10. Installing a BIND DNS server
BIND is perfect for a local DNS service. It's lightweight and just works. No future configuration needed. The real DNS server will be hosted on the cPanel server later.

Install BIND
yum -y install bind bind-utils

Backup old configuration and create a new configuration
cp /etc/named.conf /etc/named.conf_bak
cat /dev/null > /etc/named.conf

Edit the new configuration and edit it
nano /etc/named.conf
Fill in the following in the named.conf file:

//
// named.conf
//
// Provided by Red Hat bind package to configure the ISC BIND named(8) DNS
// server as a caching only nameserver (as a localhost DNS resolver only).
//
// See /usr/share/doc/bind*/sample/ for example named configuration files.
//
options {
        listen-on port 53 { any; };
        listen-on-v6 port 53 { any; };
        directory       "/var/named";
        dump-file       "/var/named/data/cache_dump.db";
        statistics-file "/var/named/data/named_stats.txt";
        memstatistics-file "/var/named/data/named_mem_stats.txt";
        allow-query     { any; };
        recursion no;
};
logging {
        channel default_debug {
                file "data/named.run";
                severity dynamic;
        };
};
zone "." IN {
        type hint;
        file "named.ca";
};
include "/etc/named.conf.local";

Save file. This file now makes sure it'll accept every connection to your DNS server locally.

Create a local named.conf file so ISP config can use it later
touch /etc/named.conf.local

And enable the service and start it:
systemctl enable named.service
systemctl status named.service
systemctl start named.service
If this doesn't work hit the following keycombination: CTRL+Z and try running the above 2 commands again, don't work so fast next time :slight_smile:

Step 11. Installing Jailkit, fail2ban and rkhunter
This adds extra security to the server. Do your own research or just follow the commands below.
cd /tmp
wget http://olivier.sessink.nl/jailkit/jailkit-2.17.tar.gz
tar xvfz jailkit-2.17.tar.gz
cd jailkit-2.17
./configure
make
make install
cd ..
rm -rf jailkit-2.17*

yum -y install fail2ban

systemctl enable fail2ban.service
systemctl start fail2ban.service

yum -y install rkhunter

Step 12. Install ISPConfig
Make sure Apache is stopped and never activated
systemctl stop httpd.service
systemctl disable httpd.service

Restart nginx
systemctl restart nginx.service

Download and unpack ISPConfig
cd /tmp
wget http://www.ispconfig.org/downloads/ISPConfig-3-stable.tar.gz
tar xfz ISPConfig-3-stable.tar.gz
cd ispconfig3_install/install/

Now install
php -q install.php

Fill in accordingly (ENTER = hit your enter key) [default value]:

en
ENTER [standard]
connectisp.yourdomain.com (this SHOULD BE your subdomain configured earlier as default (what's between the [ and ] is default
ENTER [localhost]
ENTER [root]
your mariadb password set up in Step 4
ENTER [dbispconfig]
ENTER [utf8]
nginx (most important step!!!)

Now you're getting a mailman fatal error and warnings. This is OK and can be ignored.

ENTER [XX]
ENTER []
ENTER [Default City]
ENTER [Default Company Ltd]
ENTER []
ENTER []
ENTER []
ENTER [8080]
ENTER [y]

Generating private key.

ENTER [XX]
ENTER []
ENTER [Default City]
ENTER [Default Company Ltd]
ENTER []
ENTER []
ENTER []
ENTER [] (password)
ENTER [] (optional company)

Writing key and restarting services.

Now everything's set up for ISPConfig and Nginx.

You can connect to ISPconfig through these urls:
https://connectisp.yourdomain.com:8080
https://123.123.123.123:8080

The username and passwords are:
admin
admin

Change the password in System -> CP Users -> admin -> Password -> save

Step lostcountlol. Edit nginx.conf
nano /etc/nginx/nginx.conf
Edit worker_process to the amount of cores the server has.
worker_process 2
Edit worker_connections to a big value (multiplications of 128 to be safe).
worker_connections 8192
Lower keepalive (seconds)
keepalive_timeout 7

More configuration can be done here but that's up to you.

Step stilllostcountlol. Add a website!
In your ISPconfig, hit Sites (far right).
Then Add new website
Leave all empty except
Domain: yourdomain.com
Auto Subdomain: *.
SSL: X

In the SSL tab, add your SSL cert, key and bundle for the domain.
SSL Action: Save Certificate

Statistics -> Webstatistics Program: None

Backup: Your prefered options
Options ->
pm.max_children: 10000
pm.start_servers: 50
pm.min_spare_servers: 50
pm.max_spare_server: 90
pm.max_requests: 650

And SAVE!

Now your website will display a welcome message.

Step stilllostcountlol+1. Enable SPDY!
Edit the vhost of your file
updatedb
nano /etc/nginx/sites-available/yourdomain.com.vhost
Edit the following line:
listen *:443 ssl;
To:
listen *:443 ssl spdy;
Save.
systemctl restart nginx

It's time to upload WordPress.

Step stilllostcountlol+2. Create an FTP user
Straightforward, but anyway:
Select your domain
Select a username (default+username)
Select a Password (make it strong!)
Repeat it
Edit the options to your liking (not needed)
SAVE.

Connect to the server with your favorite FTP client.

You can see a few folders there. You will need to make sure that the ssl files are 644 400 400 respectively (ISPConfig made sure of this)
The web folder allows you to upload files. Keep the error folder for now. Delete the index.html file.
Upload a fresh copy of WordPress in there (don't use the wordpress folder, just everything what's inside it). You can get your copy for a lot of cache from https://wordpress.org/download/

Commence the music!

Now go to https://yourdomain.com - You can see SPDY is activated.. how? https://spdycheck.org/
Brilliant!

Now you can install WordPress! But don't..... what? Let's continue to part 2.

PART 2 AVAILABLE SOON :smiley: (Setting up a cPanel mail + DNS + DB server)