LEMP Stack Tutorial: Ubuntu + Nginx + MySQL + PHP-FPM Servers Are Impressively Simple Yet Powerful

By    |  July 16, 2014

If you’re a web developer of any sort, you’ve probably been overwhelmed to the point of frustration at least once during the past few years as more and more options continue to appear in the realm of web hosting and server configuration.

It was only a few years ago that practically the entire world was using the same Apache web server (with cPanel installed), and things like CDNs and DDOS attacks were not commonly discussed. But as web technology continues to grow at an exponential rate, independent designers and bloggers face growing learning curves in the world of web servers, as performance and scalability become evermore crucial in the face of fierce online competition for users’ respect.

In this tutorial, I will be showing you how to install a LEMP server stack from scratch. Although Apache (LAMP) servers will probably never die out – at least not for a while – the platform continues to lose ground to other players. In particular, many corporate + enterprise networks continue to choose Microsoft servers, and Nginx continues to grow rapidly among high traffic content portals and other websites.

How To Setup & Configure A LEMP Server

1. Choose A Linux Flavor. The first letter in L.E.M.P. stands for “Linux” – so before we begin configuring anything, we first must choose and install a linux distro. As this tutorial does NOT install any control panels such as cPanel/WHM, I highly recommend Ubuntu* as it is arguably the easiest distro to manage via shell (command line). Ubuntu, maintained by London-based Canonical Ltd., is renowned for its exceptional repositories and on-time release schedule, making server software updates impressively easy.

*Always use an LTS (Long Term Support) release when installing Ubuntu to a server for added stability and security. The most recent Ubuntu LTS version is Ubuntu 14.04

2. Root Login & Password. After you’ve installed Ubuntu to your server, login to your machine’s IP address via SSH using the root username (Note: if you are using Windows, connect to your server using a free SSH client such as Putty):

ssh root@

If you are logging in for the very first time, you’ll see a security message something like the one below. Simply type “yes” and hit enter to continue logging in:

The authenticity of host ' ('
can't be established. ECDSA key fingerpring is
12:34:45:1a:aa:12:33:4c:87:65:43:21:bb:3c:fa:c0. Are you sure you want
to continue connecting (yes/no)?

Depending on how you installed Ubuntu – i.e. if you installed it through your web hosting company’s automated server “imaging” interface – be sure to reset the default root password to something unique and secure if you haven’t done so already:

sudo passwd

3. Add New User. After you’ve secured your root password, its time to create a new user with root privileges so that we no longer need to use the root user on our server. The prompt will ask you for things like “name” and “phone number” etc for your new user – simply skip through all of these fields unless you have a use for them:

sudo adduser example

Make sure your root user account (or other) and password never expire:

sudo chage -E -1 -m 0 -M -1 -I -1 -W 99999 root

Next, we need to add “sudo” privileges to our new user, otherwise known as root privileges – this will allow our new user to do anything that root can do, as long as we prefix commands with “sudo” and input our password. The reason we don’t want to use root directly is to avoid accidentally inputting destructive commands – plus, we will later disable root SSH logins, creating additional security for our server.

sudo visudo

Inputting the above command will let you edit the configuration file as below. After you’re done editing, hit CONTROL + X to exit and type “Y” to confirm saving the changes:

# User privilege specification
root    ALL=(ALL:ALL) ALL
example    ALL=(ALL:ALL) ALL

4. SSH Hardening. Now that you’ve setup a new user with root privileges, we can lock down SSH a bit which will greatly improve our server’s security:

sudo nano /etc/ssh/sshd_config

The above command will bring you to another configuration file. Change the default port number for SSH to something between 1025 and 65536 to avoid common SSH attacks aimed at port 22. Although not foolproof, changing the port number adds an additional security layer against would-be attackers. After you’ve changed it, make sure you write it down or remember it, otherwise you’ won’t be able to connect to your server:

Port 55555

Next, disable SSH logins from user root to further protect your server:

PermitRootLogin no

Lastly, specify which users are allowed to login via SSH (WARNING: Check your spelling carefully! If you make a mistake on this step, you may lock yourself out!):

AllowUsers example

If you want to lock down your SFTP users and block SSH, implement this under /etc/ssh/sshd_config at the very bottom of the file (seriously, the very bottom)

# Subsystem sftp /usr/lib/openssh/sftp-server
Subsystem sftp internal-sftp
Match User stupid
ChrootDirectory /home/stupid
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no

Once again hit CONTROL + X to exit and type “Y” to save changes. Now, restart SSH:

service ssh restart

Lastly it is recommended to set pretty much all servers across the world to be UTC timezone now, formerly known as either GMT or “Universal” time:

sudo dpkg-reconfigure tzdata

5. Install Nginx Server. Here’s where you start feeling happy that you chose Ubuntu, because all the software we will be installing is conveniently available in Ubuntu’s default repositories. So, we can use the Ubuntu “shortcut” command called apt:

sudo apt-get update
sudo add-apt-repository ppa:nginx/development
sudo apt-get update
sudo apt-get install nginx
sudo apt-get update
sudo apt-get upgrade

On all new 14.04+ versions of Ubuntu, Nginx will automatically run after installation is complete. You are literally done installing Nginx with a single command.

6. MySQL Installation. You are probably aware that MySQL is the most popular database software in the world. In recent years, other software such as MongoDB has become popular among developers because of its speed and simplicity. However, the newest 5.6 version of MySQL has drastically improved performance compared with the older version 5.5 (its also important to note that newest MySQL version (5.6+) defaults to innoDB tables, which provides automatic table repair and optimization… make sure your database is compatible). Unless you are an advanced developer, stick with MySQL:

sudo apt-get install mysql-server-5.6

During setup, you will need to set a “root” MySQL password. Don’t be confused; this is not related to the SSH password for user root but rather like a “superadmin” password for MySQL that uses the username root to connect to MySQL.

Note: In pre-5.6 versions of MySQL the sudo mysql_install_db command is required to properly finish setting up MySQL. However after version 5.6 the command is no longer needed and should be skipped to avoid creating server errors.

Next, run the below security script to remove insecure MySQL permissions:

sudo mysql_secure_installation

Type “Y” for all of the options, which will greatly improve MySQL security:

Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y

7. PHP-FPM Installation. So now we’ve got Nginx to serve our website files, and MySQL to store all of our data. But we need something to connect the dots and to generate dynamic content on the fly. Enter the magical world of PHP – specifically, PHP-FPM (fastCGI process manager) which allows Nginx to process PHP requests by passing them through FCGI. Lucky for us, this has added loading speed benefits:

sudo apt-get install php5-fpm php5-mysql

Some setups, like WordPress, now require the GD Library as well:

sudo apt-get install php5-gd

8. PHP Hardening. There’s a default setting when PHP is first installed that we must change in order to secure our server. First, enter the command below:

sudo nano /etc/php5/fpm/php.ini

Uncomment (remove the # symbol) and change the following line as below:

memory_limit = 256M
max_input_vars = 3000
post_max_size = 64M
upload_max_filesize = 256M

Performing this step will keep PHP from attempting to execute “nearest match” files when a path or file is missing. This prevents hackers from crafting malicious PHP requests in order to execute files they shouldn’t be allowed to access. Now, restart PHP:

sudo service php5-fpm restart

9. Configure Nginx Server Block. All of our server components are installed by now – however, Nginx still hasn’t been told to “handle” all of our dynamic content via PHP-FPM. For that, we use a “server block” which is similar to Apache virtual hosts:

sudo nano /etc/nginx/sites-available/default

I won’t spend time explaining all the various options and settings for Nginx server blocks. The below example is optimized for websites using WordPress as their CMS, and it provides both security and speed benefits:

The server block example above also specifies expires max on static files for improved cache control. It also properly configures @font-face directives to avoid display errors with Firefox/IE browsers. In the above example, /var/www is the default “web root” directory which is recommended for most websites. Now, restart Nginx one more time:

sudo service nginx restart

10. Setup MySQL Database. Even if you are migrating from another server, its usually easiest to simply setup a new MySQL database and later import your data into it:

sudo mysql -u root -p
CREATE USER 'example'@'localhost' IDENTIFIED BY 'newpassword';
CREATE USER 'example'@'' IDENTIFIED BY 'newpassword';
GRANT ALL PRIVILEGES ON wordpress.* TO 'example'@'localhost';
GRANT ALL PRIVILEGES ON wordpress.* TO 'example'@'';

11. Migrate Server Data. If you are migrating your data from another server, simply use mysqldump to dump your old database into a single .sql file:

sudo mysqldump -u root -p [database name] > dump.sql

And use the powerful tar command to bundle all files in your old web directory:

sudo tar -czf migrate.tar.gz *

Use encrypted SCP to securely send your database and tarball to your new server:

sudo scp dump.sql user@
sudo scp migrate.tar.gz user@

On your new server, go to your web root i.e. /var/www and unzip the tarball:

sudo tar -xzf migrate.tar.gz

Now, restore your innoDB MySQL database to your freshly installed MySQL 5.6:

sudo mysql -u root -p newdatabase < /path/to/dump.sql

12. Cleanup & Finish. We are nearly finished, but there are a few things we need to double check. First of all, make sure to configure your wp-config.php or other database configuration file depending on the CMS you are using. Also, let's make sure that Nginx owns the web root so that your CMS can update and edit files properly, and lastly, fix up any potential file + directory permission errors:

sudo chown root:root /home/example
sudo chmod 755 /home/example
sudo mkdir /home/example/www
sudo addgroup wordpress
sudo adduser example wordpress
sudo adduser www-data wordpress
sudo chown -R example:wordpress /home/example/www
sudo find /home/example/www/ -type d -exec chmod 775 {} \;
sudo find /home/example/www/ -type f -exec chmod 664 {} \;
sudo find /home/example/www/wp-content/cache/ -type d -exec chmod 777 {} \;
sudo find /home/example/www/wp-content/cache/ -type f -exec chmod 777 {} \;
sudo chmod 660 /home/example/www/wp-config.php
sudo chmod -R g+s /home/example/www/
sudo service nginx restart

For good measure, add this to wp-config.php:

/* make sure WordPress has enough memory */
define('WP_MEMORY_LIMIT', '64M');
/* make sure WordPress admin has enough memory */
define('WP_MAX_MEMORY_LIMIT', '256M');
/* avoid annoying FTP prompt screens on updates/installs */
define('FS_METHOD', 'direct');

Finally, enable all the gzip options on Nginx to compress your files and to speed up rendering times. On the newest versions of Nginx, the default options are usually fine:

sudo nano /etc/nginx/nginx.conf

Simply uncomment all of the default gzip options in order to activate them (below). And, like always, hit CONTROL + X to exit the nano editor and type "Y" to save changes:

CONGRATULATIONS! We're done. From here, you can install your favorites firewall(s) if you wish, such as fail2ban etc. Whenever possible, avoid installing an FTP server, email server, name server, or control panel to greatly speed up your server and avoid quite a few inherent security risks that accompany these unnecessary applications.

sudo service nginx restart

Comments? Leave your intelligent feedback down below or consider following CollegeTimes on Facebook or Twitter to stay updated or to get in touch!

Share This Story:

Page ID #55112  -  Last updated on

Please scroll down to leave a comment.

One Comment on “LEMP Stack Tutorial: Ubuntu + Nginx + MySQL + PHP-FPM Servers Are Impressively Simple Yet Powerful”  (RSS)

  1. Good article. Thank you.
    NGINX configuration for Drupal is here

Leave a Reply

Your email address will not be published.*


You may use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Howdy! I'm Jesse, the editor here at CollegeTimes. I hope you find our articles useful, interesting, and inspiring as you make life decisions. Feel free to follow me on Google+, Facebook, or LinkedIn, or get in touch anytime. If you have a unique story tip or article idea for CollegeTimes please email us now at info@collegetimes.tv. You may remain anonymous and/or off the record. Cheers!