How to setup a LEMP stack on Ubuntu 18.04 LTS with Nginx, PHP7.2 and MariaDB and some extra goodies

In this tutorial we will be covering how to successfully create a LEMP stack on a new Ubuntu 18.04 LTS server.

First step: Setup a empty install of Ubuntu 18.04 LTS. The easiest way to do this is to create a $5 DigitalOcean droplet.

Once the server has been setup, SSH into the server.

You should see something like this:


Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-29-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

System information as of Thu Aug 2 18:48:08 SAST 2018

System load: 0.0 Processes: 95
Usage of /: 72.1% of 24.06GB Users logged in: 0
Memory usage: 36% IP address for eth0: ***.***.***.***
Swap usage: 1% IP address for eth1: ***.***.***.***

Get cloud support with Ubuntu Advantage Cloud Guest:
http://www.ubuntu.com/business/services/cloud

* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch

1 package can be updated.
1 update is a security update.


Last login: Tue Jul 31 18:11:41 2018 from ***.***.***.***
[email protected]:~$

Next we will update the server packages.


apt-get update
apt-get upgrade

Now we can install some basic packages

apt-get install -y build-essential curl fail2ban gcc git make supervisor ufw unattended-upgrades unzip whois zsh

Setup the UFW firewall

ufw allow 22
ufw allow 80
ufw allow 443
ufw --force enable

Remove the Default Apache2 package

sudo apt autoremove -y
sudo apt remove apache2.* -y

Install Nginx

sudo apt install nginx -y

Setup DHParams

openssl dhparam -out /etc/nginx/dhparams.pem 2048

Install PHP 7.2

sudo apt install -y php php7.2-curl php7.2-fpm php7.2-mbstring php7.2-bcmath php7.2-dom php7.2-zip

Install Composer

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

Update the Default Nginx Package

rm /etc/nginx/sites-available/default
touch /etc/nginx/sites-available/default
cat > /etc/nginx/sites-available/default << EOF
server {
server_name _all;
root /<ROOT_PATH_FOR_YOUR_WEBSITES>/default/;

listen 80 default_server;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparams.pem;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;

error_log /<ROOT_PATH_FOR_YOUR_WEBSITES>/php_errors.log error;
access_log off;

index index.php index.html;

charset utf-8;

location ~ /.well-known {
allow all;
}

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }

error_page 404 /index.php;

location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 180;
}
location ~ /\.ht {
deny all;
}
}
EOF

Setup the default site

mkdir /home/ubuntu/www
mkdir /home/ubuntu/www/default
cat > /home/ubuntu/www/default/index.php << EOF
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hello</title>
<link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Raleway', sans-serif;
font-weight: 100;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.content {
text-align: center;
}
.title {
font-size: 84px;
}
</style>
</head>
<body>
<div class="flex-center position-ref full-height">
<div class="content">
<div class="title">
Hello
</div>
</div>
</div>
</body>
</html>
EOF

Restart the services

service php7.2-fpm restart
service nginx restart
service nginx reload

Install NodeJS, NPM, PM2 and GULP

sudo apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages nodejs
sudo apt-get install npm -y
npm install -g pm2
npm install -g gulp

Install Redis Server

apt-get install -y redis-server
sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf
service redis-server restart

Install Zip

sudo apt-get install -y zip

Install LetsEncrypt

sudo apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages letsencrypt

Install MariaDB

export DEBIAN_FRONTEND=noninteractive
debconf-set-selections <<< "mariadb-server-10.1 mysql-server/data-dir select ''"
debconf-set-selections <<< "mariadb-server-10.1 mysql-server/root_password password YOUR_PASSWORD!"
debconf-set-selections <<< "mariadb-server-10.1 mysql-server/root_password_again password YOUR_PASSWORD!"

sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
sudo add-apt-repository 'deb [arch=amd64] http://mirror.zol.co.zw/mariadb/repo/10.3/ubuntu bionic main'
sudo apt update -y
sudo apt install mariadb-server mariadb-client -y

sed -i '/^bind-address/s/bind-address.*=.*/bind-address = */' /etc/mysql/my.cnf
mysql --user="root" --password="YOUR_PASSWORD!" -e "GRANT ALL ON *.* TO [email protected]'127.0.0.1' IDENTIFIED BY 'YOUR_PASSWORD!;"

service mysql restart
mysql --user="root" --password="YOUR_PASSWORD!" -e "CREATE USER 'ubuntu'@'%' IDENTIFIED BY 'YOUR_PASSWORD!';"
mysql --user="root" --password="YOUR_PASSWORD!" -e "GRANT ALL ON *.* TO 'ubuntu'@'127.0.0.1' IDENTIFIED BY 'YOUR_PASSWORD!' WITH GRANT OPTION;"
mysql --user="root" --password="YOUR_PASSWORD!" -e "GRANT ALL ON *.* TO 'ubuntu'@'%' IDENTIFIED BY 'YOUR_PASSWORD!' WITH GRANT OPTION;"
mysql --user="root" --password="YOUR_PASSWORD!" -e "FLUSH PRIVILEGES;"

# Set Character Set
echo "" >> /etc/mysql/my.cnf
echo "[mysqld]" >> /etc/mysql/my.cnf
echo "character-set-server = utf8" >> /etc/mysql/my.cnf


# Conclusion
Now that you have a working LEMP stack on Ubuntu 18.04, go forth and build something amazing. Feel free to contact me with feedback or queries.