Magento Base URLs and dev/staging installations

One of the earlier problems I came across when setting up Magento, was that the Base URLs for the websites/stores are stored in the database. We wanted a scenario where we can have a staging site, and a development site, and transfer the database between them. With the way Magento works, this would require updating the Base URLs each time, and means that we couldn’t easily share a single database between a local development copy and a shared development copy running from our svn.

My first idea to workaround this was to create a small tool, that updated the Base URLs stored in the database, however this didn’t solve the issue of sharing one database between different installs. I looked into the Magento code, and saw that there is a function Mage::getBaseUrl (which in turn calls Mage_Core_Model_Store->getBaseUrl). If I could override this function on the development copies, I could replace the live Base URLs stored in the database with whatever local address we were using.

One of the best places to find development information seems to be on other people’s blogs, and this was one of the reasons why we thought it a good idea to blog our development here. I found http://www.belanur.de/blog/2008/09/05/overriding-core-models-with-a-custom-module/ invaluable when it came to learn how to override classes/function in Magento.

On to the code. The code is split into 4 files. Two XML configurations, and the php with the new getBaseUrl call. The other file is a ini config file for specifying how the Base URLs should map to the development/staging URLs.

Assuming you have a working configured Magento install. The following paths are all referenced relative to the main Magento folder.

File: app/etc/modules/Maglife_All.xml
This file activates our module. Magento merges this xml with its own xml to create a config.

<?xml version="1.0"?>
<config>
    <modules>
      <Maglife_Core>
        <active>true</active>
        <codePool>local</codePool>
      </Maglife_Core>
    </modules>
</config>

File: app/code/local/Maglife/Core/etc/config.xml
This file specifies to Magento what the module does. In this case it says the model / class we want to override and points to the replacement file (the line Maglife_Core_Model_Store translates to the path Maglife/Core/Model/Store.php which contains our code). This is at least my current understanding as I haven’t found any comprehensive documentation on the various xml tags yet.

<?xml version="1.0"?>
<config>
    <global>
        <models>
            <core>
                <rewrite>
                    <store>Maglife_Core_Model_Store</store>
                </rewrite>
            </core>
        </models>
    </global>
</config>

File: app/code/local/Maglife/Core/Model/Store.php
This contains the actual code. We call the parent getBaseUrl function, and then if the ENV variable is set, we replace the base url with a url provided in the urls.ini file (passed in the MAGENTO_DEVURLS variable).

<?php

class Maglife_Core_Model_Store extends Mage_Core_Model_Store
{

    public function getBaseUrl($type=self::URL_TYPE_LINK, $secure=null)
    {
        $store_code = $this->getCode();
        $url = parent::getBaseUrl($type, $secure);
        if ($url_ini = @$_SERVER['MAGENTO_DEVURLS'])
        {
            if ($urls = parse_ini_file($url_ini))
            {
                $host = parse_url($url, PHP_URL_HOST);
                if (isset($urls[$host]))
                {
                    $url = str_replace('://'.$host.'/', '://'.$urls[$host].'/', $url);
                }
            }
        }
        return $url;
    }

}

?>

File: urls.ini (can call this anything you like)

livestore.example.com = staging-livestore.example.com
livestore2.example.com = staging-livestore2.example.com

Then in my apache config on the staging/dev site I have the line

SetEnv MAGENTO_DEVURLS /path/to/urls.ini

and that’s it. I can now copy our live database to the staging server for example, without having to manually alter the Base URL config data in the database. I hope this is some use to others.

38 thoughts on “Magento Base URLs and dev/staging installations”

  1. Great post, exactly what we are looking for!!

    One note though. In Store.php you terminate the file with php closing tags. Magento complains about headers already being sent if this si the case. Take out the ?> and all is fine!

  2. Hi Richard. Glad you found the article helpful.

    Usually when you get a PHP error about headers having already been sent, it is because there is some trailing whitespace (a space, tab or linebreak) after the closing PHP tags, not because of the tag itself. We’ve certainly encountered no issues with the code as we have it here. Thanks for your comment!

  3. Ah, that could well have been the problem.

    Looking forward to reading your future posts.

    Now back to trying to get an iframe injected in the one page checkout!!

  4. Hello Richard! This sounds like a very good thing to be able to do, but I have run into a few problems. As far as I can tell, I followed your instructions exactly.

    First of all, I got the “Cannot send headers” error, which I fixed.

    Now I see that the urls.ini file is in the wrong place. Where exactly should it go? Here’s the message:

    Warning: parse_ini_file() [function.parse-ini-file]: open_basedir restriction in effect. File(/path/to/urls.ini) is not within the allowed path(s): (/var/www/vhosts/ (…blah blah blah…) /httpdocs:/tmp) in /var/www/vhosts/(…blah blah blah…) /httpdocs/magento/app/code/local/Maglife/Core/Model/Store.php on line 12
    Trace:
    #0 [internal function]: mageCoreErrorHandler(2, ‘parse_ini_file(…’, ‘/var/www/vhosts…’, 12, Array)

    And while I have your attention, here’s another problem that is unrelated, but maybe you know the answer. I haven’t been able to access the Admin backend from my staging subdomain. (I noticed this before I tried to implement your code.) Basically, all I did was backup the live site to my hard disk, and then upload it to the staging subdomain. I also set the permissions, and the front end comes up fine, or at least it used to!) but the backend isn’t there.

    Thank you!

    Claire

  5. I see what I did wrong — I added the following line verbatim to the apache config on my server, but didn’t include the actual path. (duh)

    SetEnv MAGENTO_DEVURLS /path/to/urls.ini

    So this seems to work fine, Thanks! But I still can’t get the backend to come up.

  6. I’m getting a 404 Not Found, although the files are there. I also noticed that the frontend isn’t functioning properly. It looks good, but if you click a product you also get a 404 error. I better upload it all again, just to make sure nothing was left behind.

    Also, I have the admin set to run in SSL. Will this url staging reroute apply to https as well?

    Thanks!

    • Yeh should work for ssl also. Not sure why you can’t get to the admin panel. I can only think there is a mismatch between the baseurl stored in magento and the reference to it in the ini file ?

      tried accessing it from /index.php/admin ?

      if that works then it might be the rewrite / friendly urls not working on your system.

  7. Jools, Yes! That worked. hmmmm..

    I have mod_rewrite on my server, but haven’t yet enabled it in Magento. If I set Use Web Server Rewrites to “yes,” will it take care of this problem?

    • To access the admin panel from /admin you will need to have mod_rewrite running or have some other redirect. once you login magento will take you to index.php/admin anyway.

      You will need mod_rewrite enabled on the webserver to utilise the “web server rewrites” facility of magento (used for frontend catalog etc)

  8. I turned that on and cleared the cache, but it didn’t change anything. I’m running 1.3.1 and need to upgrade the site soon to get that subdomain security bug fix. Although upgrading sounds like a pretty iffy proposition, judging from all the problems people are having — all the more need for a good staging environment!

  9. Jools,

    Thanks much for the code. I ran into an error while using the product custom option file upload on the front end. Magento changes the current working directory and causes an error:

    Warning: parse_ini_file(./urls.ini) [function.parse-ini-file]: failed to open stream: No such file or directory in /Applications/MAMP/htdocs/x/app/code/local/Maglife/Core/Model/Store.php on line 19″;i:1;s:1509:”#0 [internal function]: mageCoreErrorHandler(2, ‘parse_ini_file(…’, ‘/Applications/M…’, 19, Array)
    #1 /Applications/MAMP/htdocs/x/app/code/local/Maglife/Core/Model/Store.php(19): parse_ini_file(‘./urls.ini’)

    So the fix for me was to add in the whole path:

    if ($url_ini = Mage::getBaseDir() . ‘/’ . @$_SERVER[‘MAGENTO_DEVURLS’])

    I of course removed the period and forward slash from the ./urls.ini in .htaccess as well.

    Thanks!

    -Tony

    • I dont keep my urls.ini inside the magento working folder, and use an absolute path to it, so your change isn’t needed in this case. However your change is useful if you want to keep it relative to the magento install folder. Thanks.

  10. I’ve tried your version, but i get a strange error:

    Can’t retrieve entity config: core/store_group

    I haven’t found any documentation on what it means, there’s two that have similar problem, but no solution anywhere…

    • You get this error after applying the dev/staging url changes? removing them makes the store work as normal ? What version of magento are you running ?

    • Hello

      I’m testing a full restore of my live magento site to a temp server. I backed up the full /magento/ folder excluding cached dirs etc into a tar package. I restore the files and database to my temp server but whenever I try and load the site I get the error

      Can’t retrieve entity config: core/store_group

      I’m pulling my hair out because I can’t identify where the problem is, base urls are set correctly but this error seems to be happening before the DB connect, if I set the local.xml connect credentials to rubbish the error still appears. A google search bought me here and I wondered if you could shed anymore light on it?

      You can see the problem temporarily i.e. today 21.07.2010 here.

      http://ec2-184-72-23-67.us-west-1.compute.amazonaws.com/

  11. Jools

    You are really well informed and are really talented. I have read the above but I too new to work out what i need to do. I am new to magento and code for that matter. I have installed a working copy of magento but am not sure on how to set up a staging site and run multiple websites from multiple domains with one magento install. Would be grateful for a dummies guide.

  12. Hi..

    Regarding the SetEnv MAGENTO_DEVURLS /path/to/urls.ini

    ..dose any one have an idea where the ‘Apache Config’ folder is located?

    My ‘staging’ site is located on a subdomain of our web site, hosted with a web hosting company and cPanel is our file manager.

    No where in our ‘home directory’ can we find the ‘Apache’ ‘Config’ folder in which we think we include the … SetEnv MAGENTO_DEVURLS /path/to/urls.ini some where with-in.

    Do we need to create these folders? Where about is the …urls.ini line entered?

    Any help / clarification about this would be grate and very much appreciated.

    Thanks

    • If you’re on shared hosting, you can enter those same settings in an .htaccess file in the root of your development server.

      Also, you’ll need to make sure that if you do this, that your webhost has ‘mod_env’ enabled, you can check this, by using phpinfo().

  13. Hi there, i’m hoping you can help me.

    Site works fine right now with Server Rewrites off. When I turn them on, the index page works fine but as soon as I go to a category page I get a 500 error. (I’ve searched everywhere to fix this problem and have tried all the htaccess tricks and all)

    Here’s the interesting part…if I change http to https (I have SSL enabled), the friendly URL works fine, and I don’t get the 500 error.

    In other words:

    1. http://domain.com/index.php/category.html WORKS
    2. https://domain.com/index.php/category.html WORKS
    3. https://domain.com/category.html WORKS
    4. http://domain.com/category.html DOES NOT WORK

    …and of course all links of the home page are to http

    Any help would be greatly appreciated…i’ve spent hours looking for a solution to no avail.

  14. Thanks for this great post!

    I’ve set everything up on our server, front-end is working perfectly, everything is behaving as it should. The only problem that I have is that whenever I try to access the Magento admin panel, it directs me to our live-site admin URL, instead of the staging admin URL.

    I’ve refreshed all caches, checked all settings for this extension in comparison to the post, can’t seem to narrow down the problem though.

    Any ideas on what the cause of this can be?

    • Did you ever solve this? I am hoping this is a good way to work with staging and production catalogs, but I would like to be sure that this is a viable solution before diving in headfirst…

    • I am in the same position as the others. I modified your code to not use an external file, but am suffering from the same problem of the backend not working.

      I used firefox LiveHTTPheaders to see that /index.php/[admin_front_name] keeps getting a 302 response – to the same URL.

      In my case, https:// is the protocol in the database and web/secure/use_in_adminhtml is set to 1.

      Any idea on how to fix this?

      • I would need more details of your modification. you can contact me privately @ jools [at] oxfordinspire.co.uk and I can try and help. The solution I posted here does work, and I still use it in a setup myself.

  15. Hmm, I can’t get any traction on this at all. I’ve been through the solution many times and understand the steps but it doesn’t seem to have any effect on my site. I’m expecting to see the URL in the address bar update with the location specified in my url.ini file, is that correct?

    I’m running MAMP Pro and have the rewrite_module enabled.

  16. Hi there,
    will be glad to share for everybody more simplier sollution:
    just delete records for baseUrl from core_config_data 😉

    Have a nice dev
    Thanks

    • Thanks. Glad it was of use – I wrote the article some years ago – I should probably do some updates, as I have probably changed stuff since this was written. I’ll take a look at your module – cheers.

Comments are closed.