11 January 2013

Installing Magento in a Subdirectory

I had a situation recently where I wanted to get Magento running under a subdirectory of web root, with Magento requests being seamlessly rewritten from a subdomain to the Magento install, but I didn't want the subdirectory to appear in the URL.

It's easy enough to get Magento running from a subdirectory if you don't mind having that subdirectory appearing in the URL itself directly after the host.  You just copy Magento to the subdirectory, access it from http://domain.com/subdirectory and install as normal.  This means however that your base URL's then include that subdirectory, and all URLs are generated with it.

If you want to have Magento run from a subdirectory without any indication of this being the case (so no directory in the url), you will find that you come across all kinds of wierd and wonderful solutions from huge, $_POST data disabling .htaccess rewrites (meaning you can no longer save in admin, add any items to the cart etc), to the addition of RewriteBase declarations that cripple any other domains you have running from the web root directory, to moving index.php and .htaccess files to web root and making all kinds of changes to index.php to add in the subdirectory.

Well with a bit of time, and some local development environment debugging, the solution actually boils down to 1 rewrite rule in a web root .htaccess file and one line added to index.php.  You don't need to move any Magento files anywhere.

So lets start by installing the store, copy Magento to the subdirectory, and run the installation like normal from http://domain.com/subdirectory or whatever your address might be.  Once installation is complete login to admin and I tend to disable and clear cache to stop potential caching issues confusing results.  You can do this under System -> Cache Management.  Then navigate to System -> Configuration -> Web and remove the subdirectory you will see appended to the Secure and Insecure Base URL's (ensure the Base URL's still finish with a trailing slash).  Save the changes (which will break the store, don't worry).

Now create .htaccess if one isn't already there under web root and add the following into it, replace subdomain.domain.com with your subdomain and domain, and magento with your subdirectory:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^subdomain\.domain\.com$
RewriteCond %{REQUEST_URI} !^/magento/
RewriteRule ^(.*)$ /magento/$1
This is a simple rewrite that just rewrites all requests for the subdomain called subdomain to the magento subdirectory.

NOTE: If you aren't using a subdomain, just alter the HTTP_HOST line to instead be:
RewriteCond %{HTTP_HOST} ^www\.domain\.com$
or:
RewriteCond %{HTTP_HOST} ^domain\.com$
depending on what your web address is.

Next we need to make a change to a $_SERVER variable used to build the request URI by an underlying Zend method before the request is dispatched by the front controller.  The class is Zend_Controller_Request_Http, and about halfway down you will see the methods setBaseUrl() and setRequestUri().  Without going into too much unnecessary detail, these methods end up creating an invalid request string by running a substr() of $_SERVER['REQUEST_URI'] and the string length of $_SERVER['SCRIPT_NAME'].  When not running from a subdirectory this is fine, as it just ends up stripping off index.php from the REQUEST_URI, but when running from a subdirectory, $_SERVER['SCRIPT_NAME'] reflects the actual script location from web root, so whereas normally it would just contain /index.php, now it contains /magento/index.php.  The end result of this is that more than just /index.php gets stripped off the REQUEST_URI, this creates an invalid path, and Magento loads a 404 error page.

All we need to do to correct this is add the following inside <?php ?> tags at the top of index.php within the subdirectory:
$_SERVER['SCRIPT_NAME'] = '/index.php';
And that's it, you should now have a fully functional, seamlessly rewritten Magento store running from a subdirectory.

58 comments:

  1. This was the perfect solution to my problem! Thanks a million! After spending a miserable afternoon trying every RewriteCond/Rule combination imaginable, I didn't realize the problem was in the index.php itself.

    Thanks and take care.

    ReplyDelete
  2. Amazingly simple solution that works at my test environment right now. Will be testing it today. Compared to all other posts about this subject, this seems to be the most clean and simple one.

    ReplyDelete
    Replies
    1. Great, glad it worked for you. Yes there are certainly a lot of wierd and wonderful 'solutions' to this problem out there!

      Delete
  3. hey about this
    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^subdomain\.domain\.com$
    RewriteCond %{REQUEST_URI} !^/magento/
    RewriteRule ^(.*)$ /magento/$1

    what if i dont have a subdomain ?
    should i just put the sub-directory name in there

    ReplyDelete
    Replies
    1. Hi Antony,

      Just omit the subdomain in the HTTP_HOST line so you end up with:

      RewriteCond %{HTTP_HOST} ^domain\.com$

      or

      RewriteCond %{HTTP_HOST} ^www\.domain\.com$

      Delete
  4. works like a charm
    thanks man
    Anto

    ReplyDelete
    Replies
    1. hey Hussey, however, i was trying to delete the Magento stuff from the root after i set up the redirection to the sub directory and it comes up with an error about missing files from app folder
      looks like the redirection still has dependency on the initial root magento installation

      any thoughts ?

      Delete
    2. Hi Antony,

      No there won't be any reliance on Magento files in the original website root with the rewrite in place. If you are getting errors about missing files I would say they are either actually missing (perhaps not all moved into the subdirectory?) or it's down to changes to your local fileset. I would do some debugging around the area indicated by the error, you can probably get to the bottom of the problem pretty quickly.

      Delete
  5. This is great but how would this work with both HTTP and HTTPS, I've tried this

    RewriteEngine On
    RewriteCond %{HTTP_HOST} ^subdomain\.domain\.com$
    RewriteCond %{REQUEST_URI} !^/magento/
    RewriteRule ^(.*)$ /magento/$1

    RewriteCond %{HTTPS_HOST} ^subdomain\.domain\.com$
    RewriteCond %{REQUEST_URI} !^/magento/
    RewriteRule ^(.*)$ /magento/$1

    ReplyDelete
    Replies
    1. Hi Phil,

      $_SERVER['HTTP_HOST'] actually applies the same for both secure and insecure connections. To determine if a connection is secure or not you need to be looking at variables like $_SERVER['HTTPS'] and $_SERVER['SERVER_PORT'].

      Delete
  6. Thanks, my issue with SSL turned out to not be related at all to these rewrite rules.
    The error I was getting with ssl connections was;
    Error 310 (net::ERR_TOO_MANY_REDIRECTS): There were too many redirects.

    The answer was solved by my hosting provider;

    The cause here is Magento being confused by our SSL loadbalancer. I've applied this fix which should fix its SSL detection:

    http://naruzo.typepad.com/blog/2011/01/ssl-with-magento-behind-a-load-balancer.html

    ReplyDelete
    Replies
    1. Thanks for the update, hopefully the fix will prove useful to others too.

      Delete
  7. Thanks for the heads up. Looks helpful and works except - the images inside /media/ is not showing up. Gives 404 error.

    Also - in some areas it shows double front slashes like `//media/`

    Any ideas? TIA :)

    ReplyDelete
    Replies
    1. All this solution does is a simple forwarding of requests to the subdirectory. If you are having issues with certain urls I would suggest that those problems probably exist without this solution in place.

      Delete
  8. It work perfectly. Thanks.
    Just one question, it work nice in domain.com, but throwing a forbidden message on www.domain name.
    Any ideas?
    Thanks

    ReplyDelete
    Replies
    1. The solution should work equally well with both domain.com and www.domain.com setups. Make sure whichever one you are using matches the base url defined for the store. You may also want to check your domain configuration to make sure www. is properly catered for.

      Delete
  9. This was a life saver! Thanks a million

    ReplyDelete
  10. My site is installed @ example.com/magento
    I added .htaccess file with code listed in solution above.
    I changed Base and secure url. to example.com

    Question is do I edit the index.php file in the magento folder or create a new on in root folder..

    ANd when I edit the top line of the php file, do I close the already <php? or is it already closed.. thanks in advance...

    ReplyDelete
  11. when I go to example.com now I still get the apache test page .. Thats why I think its something Im missing....

    ReplyDelete
    Replies
    1. Hi there,

      You don't need to move any of the Magento files outside of the /magento to site root, so index.php should be edited inside the /magento directory. The .htaccess you find inside the /magento directory should not be changed or moved, you just add an extra one as outlined above in the root directory.

      Delete
  12. This doesnt work as soon as you try login to admin?

    ReplyDelete
    Replies
    1. This solution does nothing more than simply rewriting all requests to the subdrectory - admin and frontend requests are treated identically. I would suggest you double check the changes and also try it on a clean install as a proof of concept.

      Delete
  13. I'm about to move my dev site to the root and like this very simple and elegant solution.

    This should definitely be in the magento wiki - all the other weird and wonderful solutions need health warnings :-)

    ReplyDelete
    Replies
    1. Yes there are some very wierd and wonderful solutions out there that's for sure!

      Delete
  14. It all works great for me - I'm using the www version with magento in a subdirectory.

    The only problem I'm getting is when I try the none www version it's reporting as 404 page not found.

    Is there another .htaccess command to redirect all none www to the www version? Or have I done something else wrong? I've checked the settings in magento secure and unsecure are both showing the http://www. version

    Many thanks, John

    ReplyDelete
    Replies
    1. The solution should work identically whatever your stores base url, so if you are getting different results with and without www. I would just double check your setup - something is probably not configured quite right.

      Delete
  15. Hello

    I have followed the guidance, but I don't get the desired result.

    I had already an .htaccess file in the root. I have added the below to to complete the file that was already in place.

    RewriteCond %{HTTP_HOST} ^domain\.com$
    RewriteCond %{REQUEST_URI} !^/magento/
    RewriteRule ^(.*)$ /magento/$1

    I have then added $_SERVER['SCRIPT_NAME'] = '/index.php'; just after the opening <?php essentially like this

    <?php
    $_SERVER['SCRIPT_NAME'] = '/index.php';

    The issue is that for some reason when I go in the url 'domain.com' now i get 'domain.com/magento/downloader and essentially not able to access back and front office

    I am unsure if this is due to an error of mine or if I missed something in particular.

    Have you ever experienced this? Do you know how I could address this?

    Many thanks
    Luca

    ReplyDelete
    Replies
    1. You should try the solution on a clean install of Magento as a proof of concept before applying it to an install which has been modified. It is a proven solution so I would suggest that other modifications to your install are causing the issues you are seeing.

      Delete
    2. Many thanks that was a clean install but I will try with a new one and keep you posted.
      Regards
      Luca

      Delete
  16. Well done. Amazingly worked in a single shot.

    ReplyDelete
  17. Has anyone received "No input file selected" when trying to access the admin after trying this? My front-end works fine from what I've found so far. However, I can't access my admin by just typing http://www.my-domain.cxm/customadmin. It keeps putting /index.php/ before /customadmin/. I can remove /index.php/ out of the URL and then it'll work for one re-direct, then it goes back to "No input file selected." I can keep doing this until I see the dashboard which gives me hope, but that's as far as I can get because /index.php/ is getting generated in all admin links.

    ReplyDelete
    Replies
    1. That error is fairly widely discussed and shouldn't be related to these changes. Have a look here for instance - http://www.magentocommerce.com/wiki/groups/227/error/no_input_file_specified

      Delete
    2. I host with SiteGround so none of the "no input... / GoDaddy" fixes applied to me. I tried them anyways, but still nothing worked. However... a very cool support technician there assisted me and saw that I needed some slightly different re-writes due to my hosting account setup on SiteGround.

      This original solution at first also caused a huge red flag with SiteGround because I was notified of high resource consumption coming from my account. They shut the website down with 403s because it was so high! Although in the end, again, their support staff was able to assist me even further and figure out that a few additional changes needed to be made to the configuration of our hosting account since we have a dedicated IP address with them, and the caching system that's used there.

      Unfortunately while this solution works for many people, there are out-of-the-ordinary cases like ours where it needed a few extra things. Not much though, and I really do appreciate the original solution because now I can finally get rid of the hundreds (literally) of links/pages that search engines keep picking up due to magento generated links/urls. I feel free!!!

      For anyone else having issues, I implore you to contact your web hosting provide to see if they are willing to give any insight as to why its not working for you.

      Delete
    3. If the solution for you is generic enough to be applied to other SiteGround hosted accounts, perhaps you could post it here? I'd be interested to know how it differs for your setup and it could prove useful for others also having issues with the same hosting.

      Delete
  18. This is in the mod_rewrite.c section of my .htaccess in /public_html/... (my root).

    ############################################
    ## Rewrite everything for main website to subfolder

    RewriteCond %{HTTP_HOST} ^domain.c0m$ [NC,OR]
    RewriteCond %{HTTP_HOST} ^www.domain.c0m$
    RewriteCond %{REQUEST_URI} ^/index.php
    RewriteRule ^(.*)$ /magento/?$1 [QSA,L]

    RewriteCond %{HTTP_HOST} ^domain.c0m$ [NC,OR]
    RewriteCond %{HTTP_HOST} ^www.domain.c0m$
    RewriteCond %{REQUEST_URI} !^/magento/
    RewriteRule ^(.*)$ /magento/$1 [QSA,L]

    The interesting thing with this is that the second re-write rule by itself (which is the main one mentioned in this blog) worked with no problem on the front-end. It just didn't allow me to get to the back-end. I kept getting the "No input file specified" message. SiteGround added the additional re-write rule displayed with "index.php". I do get "index.php" in my urls in magento admin, but no "magento" at all. This was fine for me.


    This is in the mod_rewrite.c section of my .htaccess in /public_html/magento/...

    ############################################
    ## you can put here your magento root folder
    ## path relative to web root

    RewriteBase /magento/

    ############################################
    ## rewrite everything else to index.php

    RewriteRule ^(.*)$ /index.php?$1 [L]

    This .htaccess is the standard one from Magento. SiteGround only modified the Rewrite Base line and the "rewrite everything else to index.php" line.


    Depending on your setup, you may have to also add the following to your root .htaccess in order to perform mass edits. Its already included in the standard Magento .htaccess thats in my sub-folder, but it wasn't getting executed from that .htaccess some reason.


    # Turn the filtering engine On or Off
    SecFilterEngine Off



    And since we have a static IP address and are using their memcache service, they had to do some wizardry on their end in order remove the high resources consumption error/alert that was getting flagged on our account. I have no clue what they did there, but now they have a solved case to look back on if it occurs again! lol

    The modification for the ../public_html/magento/index.php file worked fine as specified in this blog.

    ReplyDelete
    Replies
    1. Thanks for coming back with this detail, it's probably a bit too specific to the hosting to put into the main post, but hopefully it will help someone out should they run into a similar issue with SiteGround.

      Delete
  19. I have spent hours and hours on this and you have now solved my issues. Thank you!

    ReplyDelete
  20. Even for me as an newbie it worked!
    Thank you Hussey!

    ReplyDelete
  21. This solution works if the primary domain is installed worldpress.
    I installed worldpress in domain.com
    Magento is installed in domain.com/online
    Sorry for bad English

    ReplyDelete
  22. After i did this , i can accées my frontend site directly with the url www.mydoami.com , but in fottunatelly i can't acees the back office any more.
    Please, is there a solution ?

    ReplyDelete
    Replies
    1. Can you try the solution on a clean install? The solution is proven to work correctly across a wide range of setups so I would most suspect something specific to your install as being the issue. Also just worth double checking you have done everything correctly.

      Delete
  23. Thanks. I spent ages reading lots of posts and trying various rewritecond rules before seeing your solution. It should be somewhere obvious on the magento site. Have you tried this with multiple domain websites running off the single magento install?

    ReplyDelete
    Replies
    1. I haven't tried it not, but I don't have any reason believe it wouldn't work correctly.

      Delete
  24. Dear Hussey Coding Limited,

    thank you very much for this post..

    i spend countless hours -- and still !!!! cannot figure it out...

    here is my situation.. SiteGround is my hosting provider and i read this post very carefully - someone else who is hosted on SiteGround provided guidance...

    my setup is as follows:

    1) my .htaccess file in document root is exactly like the prior SiteGround user suggested:

    RewriteEngine On

    RewriteCond %{HTTP_HOST} ^domain.c0m$ [NC,OR]
    RewriteCond %{HTTP_HOST} ^www.domain.c0m$
    RewriteCond %{REQUEST_URI} ^/index.php
    RewriteRule ^(.*)$ /magento/?$1 [QSA,L]

    RewriteCond %{HTTP_HOST} ^domain.c0m$ [NC,OR]
    RewriteCond %{HTTP_HOST} ^www.domain.c0m$
    RewriteCond %{REQUEST_URI} !^/magento/
    RewriteRule ^(.*)$ /magento/$1 [QSA,L]

    2) my .htaccess file inside magento folder has 2 modifications (just like the other siteground user suggested)
    RewriteBase /magento/
    RewriteRule ^(.*)$ /index.php?$1 [L]

    3) finally i added the following line to magento/index.php:
    $_SERVER['SCRIPT_NAME'] = '/index.php';

    *** results ***
    front end works fully
    i am able to login to admin.. everything seems to work
    but now when i go to Catalog -> Manage Categories

    all the categories forms load -- but they are missing data...
    when i go back to original setup (i.e. running magento from document root instead of subdirectory) -- everything works again

    Any idea??

    ReplyDelete
    Replies
    1. I can't comment on advice others give on achieving this, all I can say is that if you follow the steps I outline above on a clean install Magento will work correctly.

      Delete
  25. Didn't work for me.
    Front page fine, but catalogue search etc all 404s.

    ReplyDelete
    Replies
    1. This is a proven solution, sounds more like you don't have rewrites enabled to me (could be either in Magento or in your virtual host). If the homepage is working correctly that suggests to me requests are getting rewritten correctly to the subdirectory.

      Delete
  26. Hi,
    did not wirk for me.
    My local linux server hostname is dev-pmc, and I create website with ispconfig, it name is dev1.pmctire.loc
    this is what I put in .htaccess

    Options +FollowSymLinks
    RewriteEngine on
    RewriteCond %{HTTP_HOST} ^dev-pmc$
    RewriteCond %{REQUEST_URI} !^/dev1.pmctire.loc/
    RewriteRule ^(.*)$ /dev1.pmctire.loc/$1

    when I call my page http://dev-pmc/dev1.pmctire.loc/
    this my error
    file does not exist:/var/www/skin

    thanks for help

    ReplyDelete
    Replies
    1. It sounds like your issue is with your server virtual host configuration rather than this solution. Get things working normally then try with a subdirectory.

      Delete
  27. Hi Hussey - Thank you for your post. This works perfectly, but is there method to remove index.php from the uri? Not to have it displayed. The way my test site displayed the uri was "MyDomain.com/prodCategory/product-style-a", now it's showing it as "MyDomain.com/index.php/prodCategory/product-style-a". Again is there a way to remove "index.php" from the path?

    ReplyDelete
    Replies
    1. That's not actually related to this - do a search for removing index.php from urls and you will have plenty of results come up.

      Delete
  28. Hi Hussey,
    Your solution works like as a charm, but I would suggest to use this .htaccess version under the web root so you don't have to specifiy the domain and the subdomain:

    RewriteEngine On
    RewriteRule ^$ /subdirectory/ [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/subdirectory/
    RewriteRule ^(.*)$ /subdirectory/$1

    ReplyDelete
    Replies
    1. You can use an .htaccess without a domain but it was included so that you can distinguish more accurately between requests.

      Delete