Magento 2 Using PHP7, Nginx, and Ubuntu 14.04

Anyone that has dealt with Magento 1.x in the past no doubt has the war stories and scars to prove it. I am no different. It's a beast and I've sworn it off. Again and again. But with e-commerce, I've found it to be a circular argument. A recent project has brought me to the doorstep of Bigcommerce and I lament the drawbacks it has, and then I long for my Shopify days, and then, once again, ponder the power of Magento (plus, we're at version 2). I pop from one to the other, around and around, never satisfied or completely won over. I suppose there is something to be said about life in that statement, but no matter.

Since my previous build of Magento 1.8.x a year or two ago I have improved immensely as a developer and have continued to grow and refine these skills. Now, it is far less of a chore to spin up a quick box and test something out. It wasn't always that way for me, and in those times I relied on the community and those resources to help get me through. Here's a bit of return on that. I hope this small tutorial can get someone else through and perhaps connect a few dots. So let's start with our box.

Note: This should only be used for testing and playing. Nothing here is production ready, hardened, or best-in-class!

Note: If you are looking for a simple, modern LEMP stack, see my article Simple, Modern LEMP Using Vagrant.

Vagrant and Ubuntu 14.04

Let's begin with spinning up a bare-bones Vagrant box using Ubuntu 14.04. The Vagrantfile below will get you started, but feel free to modify it as you please. Also note that this step is optional. If you have a bare-bones Ubuntu 14.04 box, you can use it in place of this one.

Vagrant.configure(2) do |config|

    config.vm.box = "ubuntu/trusty64"
    config.vm.network "forwarded_port", guest: 22, host: 7842

    ## Set the IP below to your own, and edit your hosts file if you'd like
    config.vm.network "private_network", ip: "192.168.56.102"

    ## Feel free to modify the hostname below
    config.vm.hostname = "magento.vm"

    ## Modify the path below to your synched folder
    ## The path below is relative to this Vagrantfile
    config.vm.synced_folder "../source/magento/", "/var/www", type: "nfs"

    config.vm.provider "virtualbox" do |vb|
        # Customize the amount of memory on the VM:
        vb.memory = "4096"
        vb.cpus = "4"
        vb.name = "magento"
    end

end  

Go ahead and spin that up on the command line.

$ vagrant up
Let’s Install PHP7

Once you have a bare-bones Ubuntu server to SSH into, go ahead and do that.

$ vagrant ssh

Now that you are in the server, let's run a few commands to set up PHP7. A lot of these steps are from a great DigitalOcean article covering the same topic. Reference it for a more in-depth explanation. We need to begin by adding a repository to use with apt-get in order to install PHP7.

$ sudo add-apt-repository -y ppa:ondrej/php
$ sudo apt-get update

Once the repository is added and we have updated apt-get, let's install the package and the necessary PHP extensions that Magento2 requires (it's a long list).

$ sudo apt-get install -y php7.0-fpm php7.0-mysql php7.0-cli php7.0-mcrypt php7.0-curl php7.0-gd php7.0-intl php7.0-xsl php7.0-zip php7.0-mbstring

That should complete without issue and once you are done you can run php -v, and you will see something resembling:

PHP 7.0.4-1+deb.sury.org~trusty+1 (cli) ( NTS )  
Copyright (c) 1997-2016 The PHP Group  
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies  
with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies  

With that, we have PHP7! Now on to Nginx.

Serving with Speed

A quick note on why Nginx. I have found it to be fast, especially with Magento. That's it. I am not interested in much more than that in this case. So let's get it installed. Again I am using an additional repository in order to get the most recent stable version of Nginx (1.8.x at this time).

$ sudo add-apt-repository -y ppa:nginx/stable
$ sudo apt-get update

And install.

$ sudo apt-get install -y nginx

Congratulations, grab a beer! You should be able to visit the IP address from your Vagrantfile (192.168.56.102 in this tutorial) and be greeted with the default Nginx Welcome page.

Sneak a Quick One In

We are going to need MySQL for the Magento installation as well, and since there isn't much to getting that going, just run the following command to install it and set the root password.

$ sudo apt-get install -y mysql-server-5.6

While we're here, let's just quickly set up a database for Magento which we will need a bit later. Go ahead and drop in to MySQL.

$ mysql -u root -p

And on the MySQL prompt, enter:

create database magento;  
exit;  
Stay Composed

We are going to need Composer to run our installation of Magento via the command line. Let's run a quick installation of that as well.

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

One semi-final server-side command. Let's pop in a self-signed certificate so that we can reach the admin side of Magento over https.

$ sudo mkdir /etc/nginx/ssl
$ sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/magento-self.key -out /etc/nginx/ssl/magento-self.crt

Wow, okay, maybe another sip of beer. Take a breath and get ready, because now, finally, we get to Magento.

The Payoff, Step 1

As a glutton for punishment, I opt to install Magento2 entirely from the command line using Composer. As such, we need to secure a, ahem, secure key from Magento Connect to do that. Visit this link, log in to, or create, your account and follow the instructions. We will need to reference this key shortly.

Key in hand, let's continue. Navigate to the /var/www directory on the server. There will be a folder named html which holds the default Nginx page we celebrated earlier with our beer, but we will ignore that. From here we will run composer to download the Magento2 CE Metapackage into a new folder called magento.

$ composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition magento

You will immediately be prompted for your username. This is where we need the key we just created. Your username is the "Public Key" and the password is the "Private Key." You will be prompted as to whether you want you're credentials stored. Feel free to answer yes or no, but I suggest yes. After that… wait for Composer to do its thing. It will be a little bit, you may want some more of that beer. Perhaps a second. This is Magento after all. At the end of this, you should have a folder /var/www/magento.

But Wait!

Towards the end of the Composer install above, the command line may say "Could not fetch…"! Don't worry, just follow the provided instructions, but you will need a GitHub account. And we're back on track.

The Payoff, Step 2

Can you feel that? We're nearly there. Let's blindly set some permissions and ownership. Keep in mind that this is a test install and blindly copying and pasting commands to change permissions and ownership is not always prudent. In this case, let's go for it. Navigate to /var/www/magento and paste the following commands:

$ chown -R :www-data .
$ find . -type d -exec chmod 770 {} \; && find . -type f -exec chmod 660 {} \; && chmod u+x bin/magento

Note the period (".") at the end of the first line. Make sure that is included. These commands will take a little time to run in order to iterate over all the files and folders.

Now the cool part. Navigate in to the /var/www/magento/bin folder and let's run a command. This command is quite long and has a lot of options in it. Replace the all-cap placeholders with your own information.

./magento setup:install --base-url=http://YOUR-IP-OR-URL/ --db-host=localhost --db-name=magento --db-user=root --db-password=YOUR-MYSQL-ROOT-PASSWORD --admin-firstname=YOUR-FIRST-NAME --admin-lastname=YOUR-LAST-NAME --admin-email=THE-ADMIN-EMAIL --admin-user="THE ADMIN USERNAME" --admin-password=THE-ADMIN-PASSWORD --language=en_US --currency=USD --timezone=America/New_York --use-rewrites=1

And with that, we have Magento2! Note the URI at the end of the above command which denotes the Admin URI. We will need that to log in to the Admin section of our installation.

So go ahead and visit that IP or URL we have from the Vagrantfile.

Wait, What!?

Still see the default Nginx landing page? Sure do! We have two final steps to get this guy into working order. The first is the Nginx config file, and finally, we implement a quick cron job.

Config, Config, Config

Let's bang this out and get going. I’ll leave the details out of it, but run the following command to edit our default site config:

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

Delete everything that is in there, and replace it with the following (again, replace the all-caps with your information):

upstream fastcgi_backend {  
    server unix:/var/run/php/php7.0-fpm.sock;
}

server {  
    listen 443 ssl;
    server_name YOUR-IP-OR-URL;
    set $MAGE_ROOT /var/www/magento;
    set $MAGE_MODE default;
    ssl_certificate /etc/nginx/ssl/magento-self.crt;
    ssl_certificate_key /etc/nginx/ssl/magento-self.key;
    include /var/www/magento/nginx.conf.sample;
}

server {  
    listen 80;
    server_name YOUR-IP-OR-URL;
    set $MAGE_ROOT /var/www/magento;
    set $MAGE_MODE default;
    include /var/www/magento/nginx.conf.sample;
}

Now hit Nginx with a restart sudo service nginx restart and now you should be able to visit your IP or URL in the browser and be greeted with Magento2!

Cron, Cron, Cron

With our front-end up and running, take a peek at the Admin side of things. You can append the admin URI you noted at the end of the Magento installation and use the info you entered in that extra long Magento install command. You should be able to log in without problem, but you will see a warning immediately.

One or more indexers are invalid. Make sure your Magento cron job is running.  

Well, fact is, that cron job is not running! Let's make it run. Enter the following command.

Note: The user below is specific to Vagant, so if you aren't using Vagrant, enter the user that Magento is running under.

$ sudo crontab -u vagrant -e

Choose your editor of choice and then enter the following after the comments in the file:

*/1 * * * * /usr/bin/php -c /etc/php/7.0/cli/php.ini /var/www/magento/bin/magento cron:run > /var/www/magento/var/log/magento.cron.log&
*/1 * * * * /usr/bin/php -c /etc/php/7.0/cli/php.ini /var/www/magento/update/cron.php > /var/www/magento/var/log/update.cron.log&
*/1 * * * * /usr/bin/php -c /etc/php/7.0/cli/php.ini /var/www/magento/bin/magento setup:cron:run > /var/www/magento/var/log/setup.cron.log&

And that, my friend, is it. If you refresh the Admin side, the cron warning should be gone and you are the proud owner of a Magento2 installation. And now that you have all the information to get back up and running, feel free to blow this one up! Explore, change, break and see what’s under the hood. There's a lot to know.

Photo by kazuend at Unsplash