Set Up a Complete LEMP Stack Server for WordPress with EasyEngine v4

Hello,

One of my other non-game related hobbies is creating websites. I have created a lot of them. All of my websites are now hosted on several VPSs of some popular providers, such as Vultr, Linode, OVH, and so on. At first shared hosting was my go-to choice whenever I wanted to set up a new website. However, as my websites were getting bigger, I realized that I could not push my websites to their full potential, due to the limited hosting capacity. So, I switched to self-managed VPS, and I have never looked back.

CSGONOOB.net is now hosted on a self-managed VPS of VULTR 😉

The not-so-great thing when it comes to set up a new server manually is the number of steps I have to go through to make that server run properly.

Luckily, some brilliant folks have addressed this issue and have created some auto installers that make my life (and so many others) so much easier!

One of those great auto installers which I prefer to use is EasyEngine v4.

EasyEngine v4 is a Linux shell-script used to deploy a LEMP Stack (Linux, NGINX, MySQL, & PHP) on a Linux server, with auto-optimized configurations. The server created by EasyEngine is a WordPress-ready server, with free Let’s Encrypt SSL, Redis Cache (a server caching method – this is also another reason to love EasyEngine, no caching plugins required), and Zend OPCache. All the ingredients needed for a fast loading, high traffic WordPress website.

Basically, EasyEngine will do all the hard work. All you have to do is typing a few command lines for better security and backup solutions.

I’m writing this post because I want to document those command lines, which are something I have to do every time I set up a new server.

Currently, EasyEngine v4 officially supports Ubuntu 14.04, 16.04, 18.04 and Debian 8.

In this post, I’ll set up a LEMP Stack server using EasyEngine v4 on Ubuntu 16.04. Also, I’m using MobaXterm to connect to my servers through SSH.

Please note: I’m not a server admin. These are just what I often do to set up servers for my WordPress websites. All of my websites are running well with fast loading time and good security. If you have any suggestions, please leave a reply below.

1. Update the server:

apt-get update

apt-get upgrade

apt full-upgrade

2. Add SSH key:

mkdir ~/.ssh && touch ~/.ssh/authorized_keys

chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys

Open that file authorized_keys (located in /root/.ssh/). Then add the public key into the file. Save it.

Now go to /etc/ssh/ , open sshd_config.

Uncomment/Change PubkeyAuthentication to Yes, AuthorizedKeysFile, PasswordAuthentication to No.

Also, change SSH Port to 2222 (or any port you want).

Restart SSH service:

service sshd restart

3. Setup UFW Firewall

UFW Firewall is often installed by default on Ubuntu, you can check that with this command:

ufw status

Now you have to make UFW Firewall allow all outgoing connections and deny all incoming connections by default. Later you will choose which connections to be allowed, then turn on the firewall.

If your SSH port is the default 22:

ufw allow ssh

If your SSH port has been changed (2222, for example):

ufw allow 2222

ufw allow 80/tcp

ufw allow 443/tcp

ufw logging on

Now enable the firewall:

echo "y" | ufw enable

You can re-check the firewall rules with:

ufw status verbose

4. Install fail2ban

Fail2ban scans log files (e.g. /var/log/apache/error_log) and bans IPs that show the malicious signs — too many password failures, seeking for exploits, etc. Generally, Fail2Ban is then used to update firewall rules to reject the IP addresses for a specified amount of time, although any arbitrary other action (e.g. sending an email) could also be configured. Out of the box, Fail2Ban comes with filters for various services (apache, courier, ssh, etc).

The default fail2ban options are good enough, no need further configurations. If you want other features, read this tutorial by DigitalOcean.

Install fail2ban:

apt-get install fail2ban

5. Install Google Authenticator

Install Google Authenticator on Ubuntu:

apt-get install libpam-google-authenticator

google-authenticator

Answer any prompts within the script.

Now open sshd in this directory /etc/pam.d/ and add this below the last line:

auth required pam_google_authenticator.so

Open sshd_config in /etc/ssh/, change ChallengeResponseAuthentication to Yes.

Add this below the last line:

AuthenticationMethods publickey,password publickey,keyboard-interactive

Open file sshd in /etc/pam.d/, comment out @include common-auth to #@include common-auth (add #).

Restart ssh service:

service ssh restart

6. Change Timezone:

dpkg-reconfigure tzdata

Choose the correct timezone, then set NTP on:

timedatectl set-ntp on

Re-check with this command:

timedatectl

7. Automatically backup server with EasyEngine v4

I will create a cronjob for Rclone to automatically back up my server, including files and database.

First, install Rclone. This is for Linux 64bit:

cd /root/

wget https://downloads.rclone.org/v1.42/rclone-v1.42-linux-amd64.zip

unzip rclone-v*.zip

\cp rclone-v*-linux-amd64/rclone /usr/sbin/

rm -rf rclone-*

Now type in the console:

rclone config

Choose n to create a new remote. Set remote for remote’s name.

Choose 11 for Google Drive.

Leave blank for Client ID and Client Secret.

Choose 1 for Scope that rclone should use when requesting access from drive.

Leave blank for ID of the root folder and Service Account Credentials JSON file path.

Choose n for Use auto config?

Copy and paste the URL that Rclonde gives you into a browser. Give Rclone the permission to your Google Drive by clicking Allow.

Give Google Drive permission to Rclone

Copy/paste the verification code into the console. Enter.

Choose n for Configure this as a team drive?

Choose y to confirm and then q to quit the config.

Now create a bash file to backup website’s files and database:

nano /root/backup.sh

Copy/paste this into the file:

#!/bin/bash
SERVER_NAME=RLYLIT_BACKUP

TIMESTAMP=$(date +"%F")
BACKUP_DIR="/root/backup/$TIMESTAMP"
MYSQL_USER="root"
MYSQL_PASSWORD=`cat /opt/easyengine/services/docker-compose.yml | grep MYSQL_ROOT_PASSWORD | awk -F'=' '{print $2}'`
MYSQL=/usr/bin/mysql
MYSQLDUMP=/usr/bin/mysqldump
SECONDS=0
DOCKERDatabaseID=`docker ps | grep -e 'services_global-db' | cut -c1-12;`

mkdir -p "$BACKUP_DIR/mysql"
databases=`docker exec $DOCKERDatabaseID bash -c "mysql -h localhost --user=$MYSQL_USER --password=$MYSQL_PASSWORD -e 'show databases;'" | tr -d "| " | grep -v Database`

echo "Starting Backup Database";

for db in $databases; do
if [[ "$db" != "information_schema" ]] && [[ "$db" != "performance_schema" ]] && [[ "$db" != "mysql" ]] && [[ "$db" != _* ]] ;
then
#uncomment this next line if you want to know which DB the script is on.
#echo "Dumping database: $db"
sudo docker exec $DOCKERDatabaseID bash -c "/usr/bin/mysqldump -u $MYSQL_USER -p$MYSQL_PASSWORD --databases $db" > $BACKUP_DIR/$db.sql
fi
done

tar -jcf $BACKUP_DIR/DBs-$TIMESTAMP.tar.bz2 $BACKUP_DIR/*.sql

rm -f $BACKUP_DIR/*.sql

echo "Finished";
echo '';

echo "Starting Backup Website";

tar -jcf $BACKUP_DIR/siteFiles-$TIMESTAMP.tar.bz2 /opt/easyengine/sites/* --dereference

echo "Finished";
echo '';

size=$(du -sh $BACKUP_DIR | awk '{ print $1}')

echo "Starting Uploading Backup";
/usr/sbin/rclone --transfers=1 move $BACKUP_DIR "remote:$SERVER_NAME/$TIMESTAMP" >> /var/log/rclone.log 2>&1
# Clean up
rm -rf $BACKUP_DIR
/usr/sbin/rclone -q --min-age 1w delete "remote:$SERVER_NAME" #Remove all backups older than 2 day
/usr/sbin/rclone -q --min-age 1w rmdirs "remote:$SERVER_NAME" #Remove all empty folders older than 2 day
/usr/sbin/rclone cleanup "remote:" #Cleanup Trash
echo "Finished";
echo '';

duration=$SECONDS
echo "Total $size, $(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."

You can change delete and rmdirs value to how long you wish to keep the backups. I keep them for 1w only.

Now press Ctrl+O then Enter to save the file, Ctrl+X to quit the text editor.

Chmod the file:

chmod +x /root/backup.sh

Create a cronjob to automatically create a backup every day:

EDITOR=nano crontab -e

Paste this into the console:

0 4 * * * /root/backup.sh > /dev/null 2>&1

Save and close. From now, the server should automatically create backups daily at 4 A.M, then upload them to Google Drive, and remove backup files on local storage.

8. Setup automatic update on Ubuntu 16.04

Install unattended-upgrades on Ubuntu 16.04:

apt update

apt install unattended-upgrades

Open file 50unattended-upgrades in /etc/apt/apt.conf.d/

Comment out everything but security updates. You will have something like this:

Unattended-Upgrade::Allowed-Origins {
// "${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
// Extended Security Maintenance; doesn't necessarily exist for
// every release and this system may not have it installed, but if
// available, the policy for updates is such that unattended-upgrades
// should also install from here by default.
// "${distro_id}ESM:${distro_codename}";
// "${distro_id}:${distro_codename}-updates";
// "${distro_id}:${distro_codename}-proposed";
// "${distro_id}:${distro_codename}-backports";
};

Scroll down to the second block, it’s blacklisted packages configuration. We can define which packages are allowed for an update and which are not. Sometimes, we do not want some packages to be updated because it’s critical to the system for whatever reason.

Our blacklist configuration should be similar to the one shown below:

Unattended-Upgrade::Package-Blacklist {
"vim";
// "libc6";
// "libc6-dev";
// "libc6-i686";
};

However, with EasyEngine v4, your whole LEMP Stack is on Docker. So all the updates to the EasyEngine system will be handled by the EasyEngine team. Thus you don’t need to worry about what package to block.

Now open 20auto-upgrades. If that file doesn’t exist, create it with this command:

nano /etc/apt/apt.conf.d/20auto-upgrades

Add these:

APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "3";
APT::Periodic::Unattended-Upgrade "1";

Restart the server with:

reboot

9. Create swap (optional, recommended)

You should create a swap for your server for better performance. Some VPS providers automatically create swap for you whenever you deploy a new server, like Linode. To check if swap has been created on your server:

swapon -s

If you see nothing or something like this, there is no swap on the server.

No swap has been created

To create a swap:

dd if=/dev/zero of=/swapfile bs=1024 count=1024k

mkswap /swapfile

swapon /swapfile

echo /swapfile none swap defaults 0 0 >> /etc/fstab

chown root:root /swapfile

chmod 0600 /swapfile

For better server performance, we need to configure Swappiness:

sysctl vm.swappiness=10

nano /etc/sysctl.conf

Add this below the last line:

vm.swappiness = 10

Save it. Now your server is ready to install EasyEngine v4.

10. Install EasyEngine v4 and WordPress

Install EasyEngine v4:

wget -qO ee rt.cx/ee4 && sudo bash ee

Install WordPress. This command will install a create a WordPress website with the latest version of WordPress, Redis cache (that means you don’t need any WordPress caching plugins), Let’s Encrypt SSL, latest version of PHP, custom website title, custom database name & user, custom WordPress database prefix, an admin email & username & password of your choice. Remember to point your domain to the server. Also if you are using Cloudflare, turn it off by switching to gray cloud icon. You can get more commands by visiting the official command page.

ee site create litless.com --type=wp --cache --title=SiteTitle --admin-user=yourusername --admin-pass=yourpassword [email protected] --php=latest --dbname=yourdbname --dbuser=yourdbuser --dbpass=yourdbpassword --dbprefix=yourdbprefix --version=latest --ssl=le

Answer any prompts within the script.

After that, your WordPress website is ready to use. You can enable admin tools with this command:

ee admin-tools enable example.com

Then navigate to example.com/ee-admin/ in the browser. There you’ll see a list of admin-tools.

To disable admin tools:

ee admin-tools disable example.com

To get the admin username & password:

ee auth list global

Get site info:

ee site info example.com

Leave a Reply

avatar
  Subscribe  
Notify of