In this blog post I'd like to share some snippets of my presentation at the last San Francisco Magento Meetup.

Starting from a blank server we're going to install MySQL, php-fpm and nginx, then create a simple "Hello World" module. The purpose of this presentation was not to show how to setup a production server, but to show how to get a development environment up and running in no time and what tools are out there to help you with that.

Prerequisites

In this tutorial we're going to use Virtualbox and Vagrant. Installing this should be easy. So if you aren't already using it grab a copy and install it on your computer.

Creating a vagrant box

Now let's create a Ubuntu based virtual machine. I'm using precise32 in this example, but you could also use precise64 or any other base box you can find on http://www.vagrantbox.es/ (If you're running into problem with a 64bit box check if 64bit virtualization is enabled in your BIOS.)

vagrant box add precise32 http:// files.vagrantup.com/precise32.box vagrant init precise32

(I added an extra space between http:// and files... so this isn't rendered as a link in this blog post. Please remove this extra space after pasting...)

Edit the vagrantfile

Vagrant created a file called Vagrantfile in the current directory. We want to add another port forwarding rule there so we'll be able to access Magento using localhost later.

config.vm.network :forwarded_port, guest: 80, host: 80

If you're running Skype port 80 is probably blocked. Shutdown Skype or choose another port here.

Start the vagrant box

Starting the vagrant box is easy. Just type vagrant up and wait a couple of minutes. Try vagrant ssh to log into the box after it finished booting. Depending on your setup this doesn't work, but vagrant will tell you how to configure your ssh client (e.g. Putty) to log into the box. Logging in to 127.0.0.1:2222 with username "vagrant" and password "vagrant" will probably work.

Become root

You shouldn't work as root on a real server, but for this presentation we're breaking this rule and continue working as root from now on. Type the following command:

sudo su

Install some packages

First of all let's install a bunch of packages to get everything we need from the Ubuntu package repositories:

apt-get update && apt-get install vim curl nginx php5-fpm mysql-server mysql-client php5-cli php5-mysql php5-mcrypt php5-gd php5-curl php-apc -y

Install some tools

Let's also install two of my favorite tools. We're going to need them later:

curl -o /usr/bin/modman https://raw.github.com/colinmollenhour/modman/master/modman && chmod +x /usr/bin/modman   
curl -o /usr/bin/n98-magerun.phar https://raw.github.com/netz98/n98-magerun/master/n98-magerun.phar && chmod +x /usr/bin/n98-magerun.phar

Create a database

While installing the packages Ubuntu asked for a root password for the MySQL server. Log in and create the database that we're going to use for Magento:

mysql -uroot -proot   
CREATE USER 'play'@'localhost' IDENTIFIED BY 'play';   
GRANT USAGE ON *.* TO 'play'@'localhost' IDENTIFIED BY 'play' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;   
CREATE DATABASE IF NOT EXISTS play DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;   
GRANT ALL PRIVILEGES ON `play`.* TO 'play'@'localhost';   
FLUSH PRIVILEGES;

Prepare webroot

Now let's create a directory that we're going to use as webroot:

mkdir -p /var/www/magento/htdocs

Enable php in nginx

Depending on the Ubuntu version php-fpm is configured to listen to an ip address or to a unix socket by default. In precise32 this is the ip addres.

Go to /etc/nginx/sites-enabled/default and uncomment the lines that come with nginx's default configuration. Then restart nginx with service nginx restart.

Test php

Let's verify that php and nginx are working correctly. Create a simple file:

echo '<?php phpinfo();' > /var/www/magento/htdocs/info.php

... and hit 127.0.0.1/info.php. You should see the phpinfo() output now.

Configure nginx for Magento

When run Magento with Apache a mod_rewrite rule takes care of redirecting all urls to index.php. In nginx this works slightly different:

Edit /etc/nginx/sites-enabled/defaultand restart nginx with service nginx restart afterwards:

server {  
    listen 80;  
    listen [::]:80 default_server ipv6only=on;  

    root /var/www/magento/htdocs;  
    index index.html index.php;  
    server_name localhost;  

    location / {  
        try_files $uri $uri/ @handler;  
    }  

    location @handler { ## Magento uses a common front handler  
        rewrite / /index.php;  
    }  

    location ~ \.php$ {  
        fastcgi_split_path_info ^(.+\.php)(/.+)$;  
        # fastcgi_pass unix:/var/run/php5-fpm.sock;  
        fastcgi_pass     127.0.0.1:9000;  
        fastcgi_index index.php;  
        include fastcgi_params;  
    }  
}

Installing Magento

Now let's install Magento using n98-magerun. Run this command and follow the interactive instructions (use '.' as the destination directory):

cd /var/www/magento/htdocs  
n98-magerun.phar install

Fix permissions

We did everything so far being root, remember? Nginx (like Apache) runs PHP as the www-data user. So let's fix the permissions:

sudo chmod -R ug+rw /var/www && sudo chgrp -R www-data /var/www

Hit Magento

Now hit Magento here 127.0.0.1 and verify links are working too.

Make nginx secure

We started with a very simple nginx configuration. This is fine for a local devbox that is not accessible from anywhere else than your host system, but should never by configured like this on a production system. Try hitting

[127.0.0.1/app/etc/local.xml](http://127.0.0.1/app/etc/local.xml)

and you'll see nginx delivering your local.xml including the plain text database credentials.

In order to prevent this let's add some more lines to the server{} block in /etc/nginx/sites-enabled/default:

location /app/                       { deny all; }  
location /includes/                  { deny all; }  
location /lib/                       { deny all; }  
location /media/downloadable/        { deny all; }  
location /pkginfo/                   { deny all; }  
location /report/config.xml          { deny all; }  
location /var/                       { deny all; }  
location  /.                         { deny all; }

Modman

OK, now let's kickstart our first module. I'd like to use the modman script for everything I do with Magento. By default modman assumes you'll put your .modman folder inside your webroot. I prefer putting it one level up and configuring modman to take this extra level into account by adding a .basedir file to the .modman folder: (All modules stay compatible without any changes).

mkdir -p /var/www/magento/.modman  
echo "htdocs/" > /var/www/magento/.modman/.basedir

Redis

Before we start our own module let's install and configure Redis real quick. This way we'll also get familiar with modman.

First install redis (and git):

apt-get install redis-server git -y

Now install Colin Mollenhour's brilliant Redis cache backend (yes, that's the same guy that create modman):

cd /var/www/magento/.modman  
git clone --recursive  https://github.com/colinmollenhour/Cm_Cache_Backend_Redis.git

Finally got to app/etc/local.xml and configure Magento to use the new cache backend. This snippet is taken from the module's readme file and works great out of the box:

<cache>  
    <backend>Cm_Cache_Backend_Redis</backend>  
    <backend_options>  
        <server>127.0.0.1</server> <!-- or absolute path to unix socket -->  
        <port>6379</port>  
        <persistent></persistent> <!-- Specify a unique string like "cache-db0" to enable persistent connections. -->  
        <database>0</database>  
        <password></password>  
        <force_standalone>0</force_standalone>  <!-- 0 for phpredis, 1 for standalone PHP -->  
        <connect_retries>1</connect_retries>    <!-- Reduces errors due to random connection failures -->  
        <read_timeout>10</read_timeout>         <!-- Set read timeout duration -->  
        <automatic_cleaning_factor>0</automatic_cleaning_factor> <!-- Disabled by default -->  
        <compress_data>1</compress_data>  <!-- 0-9 for compression level, recommended: 0 or 1 -->  
        <compress_tags>1</compress_tags>  <!-- 0-9 for compression level, recommended: 0 or 1 -->  
        <compress_threshold>20480</compress_threshold>  <!-- Strings below this size will not be compressed -->  
        <compression_lib>gzip</compression_lib> <!-- Supports gzip, lzf and snappy -->  
    </backend_options>  
</cache>

Deploy the module using this command:

cd /var/www/magento  
modman deploy-all 

Delete all files from the cache directory (rm -rf /var/www/magento/htdocs/var/cache/*) and verify that no files are being written after hitting Magento with caches being enabled. Type redis-cli info to verify that a Redis database was automatically created and contains some data (will show something like db0:keys=XX,expires=YY)

Kickstart Hello, World module

First let's create some basic folders:

cd /var/www/magento/.modman  
mkdir -p Meetup_HelloWorld/app/etc/modules  
mkdir -p Meetup_HelloWorld/app/code/community/Meetup/HelloWorld/etc  
mkdir -p Meetup_HelloWorld/app/code/community/Meetup/HelloWorld/controllers

Now let's add a file to app/etc/modules/:

vi Meetup_HelloWorld/app/etc/modules/Meetup_HelloWorld.xml

<?xml version="1.0" encoding="UTF-8"?>  
<config>  
    <modules>  
        <Meetup_HelloWorld>  
            <active>true</active>  
            <codePool>community</codePool>  
        </Meetup_HelloWorld>  
    </modules>  
</config>

... the module's config.xml:

vi Meetup_HelloWorld/app/code/community/Meetup/HelloWorld/etc/config.xml

<?xml version="1.0" encoding="UTF-8"?>  
<config>  

    <modules>  
        <Meetup_HelloWorld>  
            <version>0.0.1</version>  
        </Meetup_HelloWorld>  
    </modules>  

    <frontend>  
        <routers>  
            <meetup_helloworld>  
                <use>standard</use>  
                <args>  
                    <module>Meetup_HelloWorld</module>  
                    <frontName>meetup</frontName>  
                </args>  
            </meetup_helloworld>  
        </routers>  
    </frontend>  
</config>

... and the actual controller file

vi Meetup_HelloWorld/app/code/community/Meetup/HelloWorld/controllers/IndexController.php

<?php  

class Meetup_HelloWorld_IndexController extends Mage_Core_Controller_Front_Action {  

    public function indexAction() {  
        $this->getResponse()  
            ->setHeader('Content-Type', 'text/plain')  
            ->setBody('Hello, World!');  
    }  

}

Now, we have to create a modman configuration file (vi Meetup_HelloWorld/modman):

app/etc/modules/*       app/etc/modules/  
app/code/community/Meetup/HelloWorld/ app/code/community/Meetup/HelloWorld

... and deploy the module using this command:

cd /var/www/magento  
modman deploy-all

Now, let's clear the cache...

cd /var/www/magento/htdocs  
n98-magerun.sh cache:flush

... and hit our new controller in the frontend:

127.0.0.1/meetup/index/index

Add layout

Our current controller is pretty boring and bypasses Magento's layout concept. Change the content of the indexAction method to this to show the text embedded into the default layout:

$this->loadLayout();  
$block = $this->getLayout()->createBlock('Mage_Core_Block_Text')->setText('Hello, World!');  
$this->getLayout()->getBlock('content')->append($block);  
$this->renderLayout();

Have fun!

Comments

This website uses disqus for the commenting functionality. In order to protect your privacy comments are disabled by default.

Enable Comments