January 14, 2016

This post is part two of a series on setting up an Amazon Web Service Instance for a WordPress site.  Part 1 covers the initial setup, security, and terminology of Amazon’s AWS.

Edited: Oct 12, 2016 to include newest versions of software.

If you’ve read the link above, you should have a newly created Amazon AWS account (running on Free Tier settings!) with an Ubuntu instance running and operational.  As it stands now, the instance is more like a brand new computer – there’s not much on it, and it really can’t do anything until we put some software on it.  This post covers the actual setup of Nginx, PHP(-FPM), MySQL, and a few other things we need to get the server up and serving websites.

Step 0: Update your System Packages

This should be a regular occurance for you as WordPress rarely sees conflict with the Linux system packages.

$ sudo apt-get update && sudo-apt-get upgrade

This command (minus the $ symbol, of course) will scan the package repositories for updates and will update them, prompting before the actual update runs. I like to reboot my system right after this, and you can do it from the command line:

$ sudo reboot

You’ll get kicked off, as you should since you just did a soft-reset, so ssh back in using the terminal:

$ ssh ubuntu@PUBLIC_HOSTNAME -i ~/.ssh/key-name.pem 

After this, your computer’s packages will be completely up to date. Now we can start installing our own.

Note: Linux uses a package management system to install software. Any dependencies – packages that are needed by other packages – should be installed with the commands we run. If you see a long list of packages being installed, don’t panic – that’s Linux making sure things are working correctly behind the scenes!

Step 1: Install Nginx

Nginx is, plain and simple, a web server. It routes incoming and outgoing connections to give people access to files, images, processed code, etc.  I like Nginx over Apache because the architecture is built to serve sites lean and fast. To install, run this from the command line:

$ sudo apt-get install nginx

We’re going to install the HTML5 Boilerplate’s Nginx Server Configs, which will take care of the heavy lifting of “tuning” our website out of the gate. These tweaks help with performance and security, so don’t skip out!

But, to do that, we need to install Git. Git is a version control system, and the files we need are stored on Github.

$ sudo apt-get install git
$ cd /etc
$ sudo mv nginx nginx-previous
$ sudo git clone https://github.com/h5bp/server-configs-nginx.git nginx

This installs Git, changes to the /etc directory (where all of the misc. packages are installed), moves the initial config into a new folder, and brings down the boilerplate files into a default configuration folder.

Next, we want to tell Nginx what “user” it’ll be running information under. Personally, I like “www-data” since Ubuntu already has information built in for it:

$ cd /etc/nginx
$ sudo nano nginx.conf

Look around for a line that looks similar to this:

# Run as a less privileged user for security reasons.
user nginx nginx;

And change it to:

# Run as a less privileged user for security reasons.
user www-data www-data;

We’re going to go ahead and set up our website’s “virutal host” directory. This ensures that 1) our files all live in one specific place and 2) allows us later on to install more WordPress sites and run them on one server – neat!

$ sudo mkdir -p /sites/site_domain_name.com/htdocs

Don’t put the www. in front of this – we’re just going for the root fully qualified domain name.

While we’re at it, let’s grab WordPress and go ahead and get it set up:

$ cd /sites/site_domain_name.com/htdocs
$ sudo wget https://wordpress.org/latest.tar.gz
$ sudo tar zxf latest.tar.gz
$ cd wordpress
$ sudo cp -rpf * ../
$ cd ..
$ sudo rm -rf wordpress/ latest.tar.gz

To walk through what we’re doing:

  • Changing into the directory we just created
  • Using WGET to “fetch” the latest version of WordPress
  • Using UnTar (similar to UnZip) to extract the files in the archive
  • Changing into the WordPress directory
  • Copying all of the files one folder lower (out of the WordPress directory)
  • Moving up to the root directory
  • Removing the wordpress folder (now empty) and the archive (not needed anymore).

We’ll come back here later once we’ve set up a few other things.

But first, we need to set this new directory up under the ownership of the nginx user:

$ sudo chown -R nginx:nginx /sites/

CHOWN (Change Ownership) does this easily enough, and we can hit every directory / file at once.

Back in the Nginx folder, we need to copy a few other configuration files from the old nginx configuration to the new one we just imported:

$ sudo cp /etc/nginx-previous/fastcgi_params /etc/nginx

This step is essential, as without it Nginx wouldn’t know how to run the PHP we’re installing later.

Each Nginx site has its own file that determines what happens when a user visits the site. We can set it up easily enough:

$ sudo nano /etc/nginx/sites-available/site_domain_name.com

This should bring up a blank text editor.

Note: Now would be the time that we introduce SSL certificates if we were using them. If you need them, great – I’ll do a follow up post that shows you how to install them easily.  For now, we’ll do a non-SSL site for ease of use.

Use this configuration to start things up:

# Define the microcache path.
fastcgi_cache_path /etc/nginx/cache levels=1:2 keys_zone=microcache:100m inactive=60m;

server {
 listen 80;
 listen [::]:80;

 root /sites/site_domain_name.com/htdocs;
 index index.php index.html index.htm;

 server_name site_domain_name.com www.site_domain_name.com;

 # Include the basic h5bp config set
 include h5bp/basic.conf;

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

 location ~ \.php$ {
     fastcgi_cache microcache;
     fastcgi_cache_key $scheme$host$request_method$request_uri;
     fastcgi_cache_valid 200 304 10m;
     fastcgi_cache_use_stale updating;
     fastcgi_max_temp_file_size 1M;
     fastcgi_pass 127.0.0.1:9000;
     fastcgi_index index.php;
     fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
     include fastcgi_params;

     # Local variables to track whether to serve a microcached page or not.
     set $no_cache_set 0;
     set $no_cache_get 0;

     # If a request comes in with a X-Nginx-Cache-Purge: 1 header, do not grab from cache
     # But note that we will still store to cache
     # We use this to proactively update items in the cache!
     if ( $http_x_nginx_cache_purge ) {
         set $no_cache_get 1;
     }

     # If the user has a user logged-in cookie, circumvent the microcache.
     if ( $http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
         set $no_cache_set 1;
         set $no_cache_get 1;
     }

     # fastcgi_no_cache means "Do not store this proxy response in the cache"
     fastcgi_no_cache $no_cache_set;
     # fastcgi_cache_bypass means "Do not look in the cache for this request"
     fastcgi_cache_bypass $no_cache_get;
 }
}

Suffice it to say there’s a LOT going on here, but this is the configuration for the site. It tells the server what to do when people visit, where to route connections, and so on.

Next, we have to “enable” the site by symlinking – creating a link relationship – to the “sites-enabled” folder in nginx:

sudo ln -s /etc/nginx/sites-available/site_domain_name.com /etc/nginx/sites-enabled/site_domain_name.com

This activates the site, but the server is still not running. We want to set it to run upon server startup:

$ sudo update-rc.d nginx defaults

Step 2: Setting an IP Address

Our Amazon AWS server techincally doesn’t have a public IP address yet, but it’s simple enough to create one.

Log into the Amazon AWS Console and click on the EC2 Link. In the Instance Console, look on the left side for Elastic IP addresses. These IP addresses are technically static, but you can remap them instantly to other containers should the need arise.

Amazon AWS

Hit the Allocate New Address button, and confirm. A blue bar with the IP address will pop up. The top blank, Instance, should be clicked on. Your running instance will pop up. Select it, watch the values populate, and hit Associate (and confirm). Congrats! Your server now has a public facing IP address, which means we can have our domain point to it once we’re done!

Amazon AWS

Nginx should be ready to go now. Start things up:

$ sudo service nginx start

Step 3: Installing PHP 7

If Nginx is the nervous system, then PHP is the brains behind it. PHP serves up any non-markup elements – variables, functions, and computations – that come into play on the web… at least on our server, anyway.

$ sudo apt-get install php7.0-fpm

This will bring in all of the packages and dependencies you need. We need to change the default user, so enter in:

$ sudo nano /etc/php7.0/fpm/pool.d/www.conf

Look for the lines that look like this:

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group will be used.
user = nginx
group = nginx

And replace them with this:

; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group will be used.
user = www-data
group = www-data

Once that’s done, we can start the PHP service:

$ sudo service php7.0-fpm start

…and make sure it starts every time we reboot!

$ sudo update-rc.d php7.0-fpm defaults

Step 4: Install MySQL

The engine, the brains, and now the memory center. MySQL is a “relational database” which is a fancy way of saying things are associated with other things. Installation will look familiar at this point:

$ sudo apt-get install mysql-server php7.0-mysql

It’ll ask you to fill in a root password – do so and don’t forget it! We can start this service immediately, as we want to run a few startup commands…

$ sudo service mysql start

…and (you guessed it) start it upon server boot!

$ sudo update-rc.d mysql start

Once that’s done, we can start the initial security lockdown for MySQL. I highly recommend this, as it removes a few unsafe features:

$ sudo /usr/bin/mysql_secure_installation

Enter your root password and use the defaults. Once you’re done, there’ll be no anonymous users, no remote logins, no “test” data, and the “privilege tables” will be refreshed to take the other settings into account.

Next, let’s log into MySQL and set up our initial WordPress database. We’re nearly there – this is the home stretch!

$ mysql -u root -p

Enter your root password. Next, we’re going to create a database and user, associate them with each other, and reload the privilege table.

> CREATE DATABASE sitename;
> CREATE USER 'username'@'localhost' IDENTIFIED BY 'secure_password';
> GRANT ALL ON sitename.* TO 'username'@'localhost';
> FLUSH PRIVILEGES;
> exit;

If these look familiar to you – as in you’ve seen WordPress’s install screen before – then you know you have most of what you need to install WordPress.

But, before we do that, we need to associate that IP address with your domain name.

If you don’t have a domain, head over to NameCheap (affiliate link) and pick one up. They value privacy over anything else, and even include WhoIs Guard (their private registration) free for a year!

Once you’ve done that (or logged into your own domain registrar), you’ll want to change the A record (the ‘@’record, and possibly the ‘www’ record) to the IP address you created earlier.  Every domain registrar is different – so you may have to poke around on their forums if you’re unsure.

Set the TTL (Time to Live) to between 5 and 10 minutes – no sense waiting all night, right?

Once that’s done, go pour yourself a celebratory drink, because we’re at the finish line.

Step 5: Set up WordPress

Visit your domain. If you’ve followed all the instructions correctly and didn’t receive any error messages, you should see the WordPress installation screen.  Take your username, sitename, and secure_password variables you defined above and enter them in. For the host, type in ‘localhost’.

And that’s it! WordPress is now running on your very own slice of the web, powered by Amazon’s amazing AWS Elastic Instance.

You’ve set up your own server, added PHP7, MySQL, and Nginx, installed WordPress from the command line, and are now ready to reap the benefits of a server that is truly your own.

If you have any questions, I’ll do my absolute best to answer them below.  If I’ve missed a step, or you’ve got some handy-dandy tips for first-time sysadmins, leave those below as well!

  • Osazeme Usen

    when I run
    sudo service nginx start, I get this error
    Starting nginx: nginx: [emerg] open() “/usr/share/nginx/logs/error.log” failed (2: No such file or directory)[FAILED] ..

    How do I go about this?

    • I’d check your configuration files /etc/nginx/sites-available/yourdomain.com and make sure that that same directory is created and linked to correctly in the config (I think it was /sites/yourdomain.com/htdocs).

      • Osazeme Usen

        thanks alot

        And when I fixed the first error , I still get this

        nginx: [emerg] getpwnam(“www”) failed in /etc/nginx/nginx.conf:5 [FAILED]
        [ec2-user@ip-172-31-44-40 etc]$ Starting nginx: nginx: [emerg] getpwnam(“www-data”) failed in /etc/nginx/nginx.conf:5

        just when I attempt to fix this by setting www-data www-data to nobody, I get another error message when I attempt to start nginx.

        Starting nginx: nginx: [emerg] invalid parameter “key_zone=microcache:100m” in /etc/nginx/sites-enabled/yourdomain.com:2

        How do I fix this one??

        • Check your nginx configuration (/etc/nginx/nginx.conf) and make sure you’ve defined the username and group correctly. It should be “www-data” on Ubuntu, but if you’ve used a different install, or have a different “web user” username, use that (it may be apache, nginx, or www-data depending on which linux you’re using.

          I’d check to make sure you copy/pasted the server configuration in, and check spaces. Can you pastebin your /etc/nginx/sites-available/yourdomain.conf file so I can take a look?

          • Osazeme Usen

            It was totally my fault. I installed it on the wrong instance.. I tried linux, its supposed to be ubuntu. I’ll follow the process as stated.
            thanks for taking your time to write this guide.

  • Osazeme Usen

    Sorry for this newbie question but I wasn’t able to figure this part out.
    I am currently trying to run this tutorial on the right instance.
    when I run this sudo chown -R nginx:nginx /sites/ , I get this error chown: invalid user: `nginx:nginx’ …

    I also ran compgen -u | less and compgen -g | less to display list of all users and groups. nginx wasn’t included. Should I create this user and group?

    • User and group is www-data:www-data… Look in the nginx config file and change the options to have nginx run as that user.

  • Osazeme Usen

    I think I followed all steps correctly. I have one more newbie question and I hope this will be the last. how do I remove this error?

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.

    For online documentation and support please refer to
    nginx.org.

    Commercial support is available at
    nginx.com.

    Thank you for using nginx.

    • That’s the default page. You want to make sure that your virtual hosts are set up correctly if you are seeing that. Right now, the domain is not pointing to the right folder. Double check to make sure you edited your configuration files. Then, reload Nginx.

      • Osazeme Usen

        pls I need to be clear on this. Does wordpress files have to be in htdocs folder?
        Can chmod cause this error?? .. Am going through the config line by line with little success