Guide: How to Install OroCRM on a Vagrant Box

Tweet

OroCRM is a CRM application we’ll be describing in a post dedicated to it tomorrow. This guide merely covers its installation and first run on a Vagrant Box – in particular, our good old Homestead Improved. If you need to get up and running with Homestead, see the original Quick Tip. If you want to follow along with tomorrow’s post on OroCRM, get a head start by installing it with the procedures below!

Installation

Before we begin, make sure your original Homestead Improved instance is working well, then destroy it. If you want symlink support and are on Windows, re-run the command prompt and/or Git Bash window through which you’ll be using Vagrant commands with Administrator privileges:

This is optional – symlinks are not required for Oro to work.

Step 1: Add a Site

In Homestead.yaml, add the site:

    - map: test.app
      to: /home/vagrant/Code/orocrm/web

The web subfolder is needed due to Symfony being the foundation Oro is built upon.

To make sure Symfony can write into its parent folders, we need to alter the mount mode of the shared folders. In scripts/homestead.rb update the following line from:

 config.vm.synced_folder folder["map"], folder["to"], type: folder["type"] ||= nil

to

      config.vm.synced_folder folder["map"], folder["to"], type: folder["type"] ||= nil, :mount_options => ["dmode=777,fmode=777"]

This is the last operation we’ll do outside the VM. Enter it now with vagrant ssh after running vagrant up.

Step 2: Clone

cd Code
git clone http://github.com/orocrm/crm-application.git orocrm

Step 3: Create the Database

mysql -u homestead -psecret
CREATE SCHEMA `oro_crm` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

Step 4: Configure Nginx and PHP

The configuration required for OroCRM in this case is as follows (replace the folder paths with your own if necessary). Put this into /etc/nginx/sites-available/test.app, replacing the original content:

server {
        listen 80;
        server_name test.app;
        root /home/vagrant/Code/orocrm/web;

        index app.php;

        access_log /var/log/nginx/test.app.access_log;
        error_log /var/log/nginx/test.app.error_log info;

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

        try_files $uri $uri/ @rewrite;
	    sendfile off;
	    
        location @rewrite { rewrite ^/(.*)$ /app.php/$1; }

        location ~ [^/]\.php(/|$) {
                fastcgi_split_path_info ^(.+?\.php)(/.*)$;
                if (!-f $document_root$fastcgi_script_name) {
                        return 404;
                }
                fastcgi_index app.php;
                fastcgi_read_timeout 10m;
                fastcgi_pass unix:/var/run/php5-fpm.sock;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
				include fastcgi_params;
		}
}

Don’t forget to restart Nginx with sudo service nginx restart.

Due to some bugs in either Composer, or the way the dependencies are set up, we need to raise the limit of RAM use for PHP’s command line instance to 1G. The VM we’re running has a reserved 2G, so that’s no problem.

sudo vim /etc/php5/cli/php.ini

Once in the file, hit the forward slash button if you’re using Vim to enter search mode, type “memory” and hit enter to get to the line that says 512M. Enter insert mode with “i” and replace “512M” with “1G”. Save and exit.

Next, we need to activate pathinfo in php-fpm, as per this StackOverflow answer.

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

Search for the line cgi.fix_pathinfo and set the value to 1. Also increase the maximum execution time for PHP scripts to 300 instead of 30 (search for max_execution), because Symfony apps are incredibly overbloated and need a long time on first requests to generate the cache they then use on subsequent runs.

Finally, there’s one more tweak we need to do.

sudo vim /etc/php5/mods-available/xdebug.ini

Add the line xdebug.max_nesting_level = 1000 to this file. We do this because Xdebug chokes out on the default nesting level of 100 when dealing with Symfony’s bloat. With this, we let it “go deeper”. Save and exit, and restart php5-fpm (sudo service php5-fpm restart).

We also need the php-intl extension installed, as with most Symfony projects.

sudo apt-get update
sudo apt-get install php5-intl

Step 5: Composer

First, let’s speed up Symfony. Go into app/AppKernel.php and add the following two methods to the class:

	public function getCacheDir()
    {
        if (in_array($this->environment, array('dev', 'test', 'prod'))) {
            return '/dev/shm/appname/cache/' .  $this->environment;
        }

        return parent::getCacheDir();
    }

    public function getLogDir()
    {
        if (in_array($this->environment, array('dev', 'test', 'prod'))) {
            return '/dev/shm/appname/logs';
        }

        return parent::getLogDir();
    }

As per this post, this moves the logs and cache folders outside the shared guest/host folder, and keeps the IO operations inside the VM. Symfony is notorious for super-high IO, and having those folders remain in their default place is a death sentence for any Symfony project on Vagrant.

Finally, let’s install the CRM’s dependencies.

cd orocrm
export COMPOSER_PROCESS_TIMEOUT=3000; composer install --prefer-dist --no-dev

The “export” command before the “install” command is there to make sure Composer keeps going even if it encounters an insanely large repo. The prefer dist option means the dependencies aren’t downloaded as sources under version control, but as just sources or a phar package even. When --prefer-sources is used (default), the entire version tree is downloaded too, which slows down the download and increases the amount of disk space required, which is pointless if you don’t intend to hack away on the actual dependencies.

During installation (which will take upwards of 30 minutes easily due to the sheer bloat of Symfony’s dependencies), you will be asked for your username and password for Github due to their anonymous download rate limitation policy. This is nothing to be concerned about. At the end of the download, you’ll be asked for some configuration params regarding the database, mailer, etc.

Then, run php app/console oro:install --env dev to install the app completely or visit http://test.app:8000 in your host machine’s browser. This will take another 10 minutes or so, but it’s the final step. For some reason, setting the --env flag here to “prod” fails with a class not found error, but works with “dev”, so I’m using that. If you give it a go and solve the problem, do let me know please.

You might have to activate the WebSockets server and the crontab, too, though these are optional:

php app/console clank:server --env prod
php app/console oro:cron --env prod

Step 6: Demo [optional]

OroCRM comes with a set of demo data you can import into your instance so you have something to play around with. This is identical to what you can find on their demo page, but more flexible, as it allows you to alter the source code, extend the app, and properly play around in it.

To install demo data, just run the following while inside the orocrm folder:

php app/console oro:migration:data:load --fixtures-type=demo --env=prod

Conclusion

Was it too complicated? Perhaps. Then again, not many framework and app devs optimize their apps for VM installations just yet, so it’s no surprise. There’s not much the Oro team can do, anyway, seeing as they depend on some of the largest frameworks out there (Zend and Symfony both get installed during Composer Install, and in --prefer-sources mode the entire folder finally amounts to 420MB, which is ludicrous for a web app of any caliber; --prefer-dist wraps it up around 190MB).

I hope they’ll find ways to make the procedure lighter, or that they’ll at the very least focus on making version 2.0 much Vagrant-friendlier from the get-go and more multi-platform – especially since it’s now public knowledge that Symfony apps frequently have problems on Vagrant. Have you given this installation procedure a go yet? Let me know if you get stuck somewhere, and we’ll try and work through it together.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • KerryJTruong

    Google is paying 80$ per hour! Work for few hoursand have more time with friends & family! On tuesday I got a great new Land Rover Range Rover>>CLICK NEXT TAB FOR MORE INFO AND HELP</b

  • http://knpuniversity.com/ weaverryan

    Hey Bruno!

    You said the installation takes 30 minutes. That actually sounds like a potential bug (or at the very least, a developer experience issue we can tell the ORO guys about to help them). Even if you have a TON of dependencies, a Composer install should take only a few minutes, and those are due to Composer doing it’s complex dependency calculations. The Symfony bloat comment was unfortunate as I think the true cause is something else that ideally we can fix :).

    Anyways, if you have some ideas/thoughts about the 30 minutes part and some issues that could potentially be created with ORO or Composer, that would be awesome. I’m also happy to help create these issues if we can start to figure out “why”. I’ve never installed Oro, but I’ve never seen a Composer install talk longer than 5 minutes, so I’m thinking it’s not Oro, but maybe something related to the VM. If you have any thoughts, I’d love to hear them.

    Thanks for the post – I love scanning through it looking for the “problem areas” so that all layers (Composer, Symfony, Oro) can be made better. I hope you have time to keep playing with more stuff!

    Cheers!

    • http://www.bitfalls.com/ Bruno Skvorc

      Hey Ryan, thanks for the comment!

      The 30 minutes were actually required when I omitted “no-dev”, with “no-dev” it sped up drastically. I’ll do some more testing tonight and report back with more accurate figures.

      • http://knpuniversity.com/ weaverryan

        That’s interesting. Obviously including the “dev” repos would mean that you’re downloading more dependencies, but I wouldn’t expect it to make a material difference in time (e.g. maybe 5 minutes instead of 3 or 4). I’m interested – let me know what you find out and thanks!

  • Nicholas Loomans

    You always say to restart nginx, is there a reason to favour that over an `nginx -s reload`?

    • http://www.bitfalls.com/ Bruno Skvorc

      Not really, both approaches have the same effect

      • Nicholas Loomans

        I guess at this point they do, yeah.

      • http://sergeif.me/ Sergei Filippov

        Hi Bruno,

        Overall there is a difference between restarting and reloading nginx:

        Restart = load in all new configuration files that may have been added since last restart of the process

        Reload = load in only configuration files that have been loaded as part of the last process start

        Always run “nginx -t” to test the configuration validity before running reload or restart. ;)