Running multiple Magento stores on multiple domains from a single index.php

For our eCommerce project, we are building multiple websites each with multiple languages, but all managed from one Magento install. We wanted to run each website from it’s own domain, with each store view as a subfolder for the language, such as (The base link urls are configured like this for each store view from the Magento admin panel):

  • http://store1.example.com/en/ (store name store1_en)
  • http://store1.example.com/fr/ (store name store1_fr)
  • http://store1.example.com/de/ (store name store1_de)
  • http://store1.example.com/es/ (store name store1_es)
  • http://store1.example.com/nl/ (store name store1_nl)
  • http://store2.example.com/en/ (store name store2_en)
  • http://store2.example.com/fr/ (store name store2_fr)
  • http://store2.example.com/de/ (store name store2_de)
  • http://store2.example.com/es/ (store name store2_es)
  • http://store2.example.com/nl/ (store name store2_nl)

Looking around the net for solutions, it seems the majority of suggestions are to duplicate the magento index.php and .htaccess into a folder for each language/store view. This would mean more files to maintain, and a more complicated structure. We also did not want to have to rely on .htaccess for the security and url rewriting, but rather maintain the rewrite configuration as well as the store URL to store name mapping in the main Apache config. We also didn’t want to have to extend the folder structure just because we added a new store view/language in the future.

I came up with a solution for this, utilising a slightly modified index.php which “runs” each store, does some querystring modifications, and an Apache configuration to handle the rewriting. This allows us to easily add another store view, just by altering the Apache config.

First of all here is our site structure. the js/media/skin folders are symbolic links to the parent magento folders (that is outside of the web accessible root)

site/
    magento/ (standard magento install)
    store/
          index.php
          js     -> ../magento/js
          media  -> ../magento/media
          skin   -> ../magento/skin
          report -> ../magento/report

Each virtualhost points to the store/ folder. It seemed safer to keep the main magento folder outside of the site root, and everything so far seems to work ok like this. Note there is no .htaccess. We will do the rewriting from the main Apache config.

Here is the example Apache config. I have split it into two files in this example. We run on a Debian system, and Apache has a layout with a conf.d and a sites-available/sites-enabled. We are also using mod_macro for the configuration, as this allows us to reduce configuration duplication.

File: /etc/apache2/conf.d/mageno

<Macro MagentoVHost $store $langs>
  Options +FollowSymlinks
  DocumentRoot /path/to/site/store
  SetEnv MAGENTO_STORE $store
  # For information on the next variable, see earlier blog post.
  # SetEnv MAGENTO_DEVURLS /path/to/urls.ini
  RewriteEngine On
  # we always have English as our default language
  RedirectMatch ^/$ /en/
  RewriteRule ^/($langs)/(.*)$ /index.php/$2 [E=MAGENTO_LANG:$1,L]
</Macro>

<Directory /path/to/site/store>
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule ^(.*)$ /index.php/$2 [L]
</Directory>

File: /etc/apache2/sites-available/store1.example.com

<VirtualHost *:80>
  ServerName store1.example.com
  # this store has 5 languages (store views)
  Use MagentoVHost store1 en|fr|es|de|nl
</VirtualHost>

<IfModule mod_ssl.c>
  <VirtualHost *:443>
    ServerName store1.example.com    # this store has 5 languages (store views)
    Use MagentoVHost store1 en|fr|es|de|nl

    SSLEngine on
    SSLCertificateFile /etc/apache2/ssl/your_certificate.pem

  </VirtualHost>
</IfModule>

Now a brief explanation on how the above works. All stores use a language in the url. If you visit the root,  the

RedirectMatch ^/$ /en/

line will redirect to the default store view (English). The virtualhost example above passes the store name to our macro. The macro then sets the variable MAGENTO_STORE to this. Depending on the language selected (from the chosen url) Apache will set an environment variable MAGENTO_LANG. So if we visited http://store1.example.com/de/ MAGENTO_STORE would be set to “store1” and MAGENTO_LANG would be set to “de”. Now we just need to process these in the main index.php that “Runs” the Magento store of our choice.

File: site/store/index.php
The following code replaced the last two lines in the default magento config

umask(0);
Mage::run();

# we use the url structure as /en/blah.html /fr/blah.html for each language
# language is set by mod_rewrite from the apache config
$lang = 'en';
if ( isset($_SERVER['MAGENTO_LANG']) ) {
  $lang = $_SERVER['MAGENTO_LANG'];
}

# store is set from the apache configuration depending on domain.
# this allows us to configure stores without having to modify multiple index.php files etc.
$store = '';
if ( isset($_SERVER['MAGENTO_STORE']) ) {
  $store = $_SERVER['MAGENTO_STORE'];
}
$store .= '_' . $lang;

# replace the REQUEST_URI such as /en/blah.html with /blah.html
$_SERVER['REQUEST_URI'] = preg_replace(&quot;#^/$lang(/.*)#i&quot;,'$1',$_SERVER['REQUEST_URI']);

# we want our /lang/ urls to take priority over store querystrings
# but not if we are in the admin panel
if ( ! preg_match('#^/index.php/admin/#i',$_SERVER['REQUEST_URI']) ) {
  $_GET['___store'] = $store;
}

umask(0);
Mage::run($store,'store');

The comments in the code should explain how it works. We construct our store name from the store name and language. In our example this would be store1_de. The language is then stripped from the REQUEST_URI environment variable, as this breaks magento’s search engine URL processing. (So even though we are at the URL http://store1.example.com/de/somepage magento thinks we are at http://store1.example.com/somepage. Also note the code to override the ___store querystring parameter. We want our url path to specify which store we are in over any querystring magento chooses. This solves an issue I had where Magento would think we are in the wrong store. Perhaps due to the “current” store being stored in a cookie or a querystring parameter being appended by Magento. This parameter is also used on the administration side, so we don’t want to interfere with if we are in the admin panel. Finally we “run” the store of our choice.

Hopefully this has made sense. It might look rather complicated, but does allow for a flexible setup. If we wanted to add a new store view (language) to our example store1, we can simply add it from the magento admin panel, and modify the apache config. The index.php does not need to change.

39 thoughts on “Running multiple Magento stores on multiple domains from a single index.php”

  1. Nice. Thanks for sharing.

    I’m looking for a solution where I don’t need to modify the Apache config either.

    • You should be able to reproduce the set up I have, but use a .htaccess file instead of the apache config. try combining the rewrite rules (you might have to change the logic a bit) into a .htaccess and include it with the index.php.

  2. Hi,
    great tutorial.
    Just a question, what if you are starting a new magento installation ?
    Where do I need to start from ?
    I mean, installing magento under DocumentRoot, do a normal installation pointing to, for instance, http://localhost/magento and then, after installed it and stores configs through admin, do this multiple stores and domains configuration ?.

    Thanks.

    • Start by unpacking the full release (not the auto downloading one), and unpacking it somewhere. You can put it under document root, but I choose not to and rather symlink the directories that are needed to be “web accessible”. You can do the installation process first if you like from magento or after you can set up the structure. Just so long as you can get into the admin panel from /admin it should be fine. Might be easier to have a go at this with a fresh install, and see if you run into any troubles.

      • Thanks Jools.
        Actually I did a fresh installation and used 3 domains, magento.com for default store (otherwise, when I changed the Unsecure URL admin collapsed) and 2 domains for the solution you are suggesting and it worked fine.

        Right now I’m trying to realize how to copy data stores or how to upload magento data sample into store1_en for instance.

  3. Hi, great explanation , thanks.

    I’m trying to setup 2 stores sharing the same cart. I created the second store with a subfolder and index.php and .htaccess files.

    Since these are only 2 stores, I dont really need all the variables so I just manually entered the store name .

    Like this : ( Index.php )
    # replace the REQUEST_URI such as /en/blah.html with /blah.html
    $_SERVER[‘REQUEST_URI’] = preg_replace(“#^/myiphone(/.*)#i”,’$1′,$_SERVER[‘REQUEST_URI’]);

    if ( ! preg_match(‘#^/index.php/admin/#i’,$_SERVER[‘REQUEST_URI’]) ) {
    $_GET[‘___store’] = ‘myiphone’;
    }
    umask(0);
    Mage::run(‘myiphone’,’store’);

    The cart is not shared between the stores. I’ve tried everything I could think of , I also changed the cookie session management folder to /

    Everytime I switch between the stores it just empties my cart.

    Can you shed some light on this ? what am I doing wrong ?

    Thanks, Tal

  4. Yes , I want both on the same domain but one on the root and the other in a subfolder.

    Like this:
    www dot mylaptop dot co dot il
    www dot mylaptop dot co dot il /myiphone

    When using foxcookie, I can see the same cookie is used between the stores but all session data seems to be erased when I switch between the stores.

    • Both stores are under the same “website” ?

      So is it


      Website/
      Store 1/
      Store 1 View
      Store 2/
      Store 2 View

      or

      Website 1/
      Store 1/
      Store 1 view

      Website 2/
      Store 2/
      Store 2 view

      You might be better of taking this questions to the magentocommerce forums, as I believe it is related to yout set/config rather than my configuration stuff. I have had cart sharing working with the config as above (but actually in my case I didn’t want it so I split my sites up into different websites)

      • Hi Jools ,first of all thank you so much for helping and writing this blog.

        I have posted my question everywhere , at least in 3-4 places in the magento forums.

        I’ve read every single blog post/ forum I could find.

        I am a beginner programmer myself and have done quite a bit of magento tweaks and can’t seem to figure this out.
        I’m starting to think this has something to do with my templates.

        Anyway, it’s setup as 2 stores under the same website.
        the first option u suggested

        I’ve also watched the magento’s webinar at least twice. It seems that no one explains how to create a shared cart.

        By the way , If I set both base url’s to my main domain and forget about the subfolder. and I switch stores only through the magento switcher than it works perfectly.

        but this solution doesnt help me cause I want people to be able to search for the second store from the outside and advertise it’s location , not only switch using the switcher.

        Appreciate your help.

  5. Another thing, Can it be that this feature can only be implemented with “Add store code to url’s” ?

    I havent tried yet cause I dont want to break my links.

      • Ok , thanks.

        I’ll post a reply here if I solve it.

        One option I can think of now is to create a .htaccess redirect that will keep the links with the subfolder but tell magento that we are actually in the root with the store variable set.

        It sounds to me like a bad workaround and I don’t like the idea but I can’t think of anything else to try.

        If you have an idea , I’d appreciate if u post it. I’m following your blog.

  6. my rewrite solution above makes magento think it is running two stores from the same folder even though it isn’t.

  7. Another find is that on my local installation ( identical to my remote one ) running xampp on windows everything works fine when using your instructions.

    So I guess I will try to email my hosting provider although I’m pretty sure he will not have a clue.

    Tal

    • SOLVED!

      I copied the php.ini file in the root folder of magento to my second store subfolder and voila!

      What is probably happening is that this php.ini overrides some settings of the main php.ini of my host and apparently this doesn’t happen unless it’s in the root folder of the store.

      Thanks for all your help.

  8. How do you get two different domains to share cart contents with the session id. Any syntax help would be appreciated. Two websites, two stores, shared checkout.

    • I don’t think you can do that. To share the cart, each store must live under a single website, and run from the same domain. Of course you could have store.domain and store2.domain (in that case you might need to set the cookie domain differently in the admin panel).

  9. Do i have to add firstly the language folder like nl_NL ( for Dutch) for this on app/locale folder? .Or it needed only these changes.

  10. http://www.magento-mall.com/

    I want to develop the same site on my local machine (except design) but the functionality and url pattern should be same).
    PLease help me Jools.

    ANd shopping cart should share common in all store. and i have to implement in on my local machine and then to webserver.

    Please help Jools waiting for u r valuable answer with the steps to be followed to implement it on local machine.
    Thanks In advance

  11. I had the similar problem as Tal Mor, but in my case the solution was to put cookies path as “/” in Backend->System->Configuration->Web->Session Cookie management->Cookie Path

  12. Dear all,

    I would greatly appreciate your advice. I think I face an SEO issue with the configuration of my multi web sites. Here you are what I have :

    site.fr
    site.com
    site.de
    site.ru
    site.cn

    When I look the code source they all get their “stylesheet” from an other domain : site.info

    For example the site.com code source is :

    link rel=”stylesheet” type=”text/css” href=”http://www.site.info/skin/frontend/sitecom/site/css/reset.css” media=”all” />
    link rel=”stylesheet” type=”text/css” href=”http://www.site.info//skin/frontend/sitecom/site/css/boxes.css” media=”all” />

    When I look the magento mall example it is more like i should have somthing like that :

    link rel=”stylesheet” type=”text/css” href=”http://www.site.com/skin/frontend/sitecom/site/css/reset.css” media=”all” />
    link rel=”stylesheet” type=”text/css” href=”http://www.site.com/skin/frontend/sitecom/site/css/boxes.css” media=”all” />

    I do think that this is an SEO issue specilay for google. Would it be possible that google does not like the fact the some files of the code come from an other domain?

    I wonder that because I am very well rank (1st or 2nd place) for more than 150 keywords on Yahoo, Baidou and Yandex, but I stay at 2nd or 3rd page one google.

    What do you think of that?

    Thank you for your answer

    • not sure how google will treat the page linking css from the other site in terms of rank, but you should be able to make it pull in the css etc from the current URL. Please check you have set the baseurl for each website, to the correct domain in the Magento admin (/index.php/admin/system_config/edit/section/web/)

  13. Hi,

    I have Multiple Web Sites and Stores – each are diferent providers from different locations all over the world.

    I want the customer to be able to buy from any of those “Web Site” or “Store” – and to checkout from the main WebSite “Base”.

    -I need in the Global Cart, the total amount of purchases + all shipping fees.

    A idea?

  14. Hi,
    I am trying do another type of setup, for example my main url is

    company.com and I am selling from companystore.com , but when checkout I want it to checkout from company.com. The problem is the store can add product but when checkout it going to another URL and it shows cart is empty.

    Anyone knows the problem.

    regards

  15. Hey Jools, Bravo Brother. You did an excellent job on this tutorial. This is my complete first time setting up a multi-store site with Magento. I apologize for my ignorance, but you left out the magento configuration urls as well as the manage store settings.

    My site is in an infinite redirect loop.

  16. Another problem that I’ve been having: It seems that all of my Magento URLS are pointing back to the main domain. Anyway that I could pay you for a couple hours of your time?

  17. Hi Jools,

    Thanks for the post. I would like to know is this applicable for multiple website with single stores on each .
    for eg; Wesite1(Engllish)
    –> Wesite 1 store view(English)
    –> English Store
    Wesite2(Japanese)
    –> Wesite 2 store view(Japanese)
    –> Japanese Store

  18. There is also an other solution based only on .htaccess directives, Magento internal websites/stores precise settings, index.php customization, and parts of code snippets you reported 🙂 , plus is it possible also to set “fallback” websites/stores. Cheers and thanks!

Comments are closed.