smrkem
smrkem

Reputation: 173

Trouble with mod_rewrite, subdomain and codeigniter

I have a codeigniter installation at example.com/ci. I have a subdomain foo.example.com. The document root for the foo subdomain is set to be home/public_html/ci.

I'm using the following rule in .htaccess to send requests for foo.example.com to example.com/ci/city/foo.

 RewriteCond %{HTTP_HOST} !^(www)\. [NC]
 RewriteCond %{HTTP_HOST} ^(.*)\.example\.com [NC]
 RewriteRule (.*) http://example.com/ci/city/%1/$1 [L]

It all works like I want it to except that the address bar url changes from foo.example.com to example.com/ci/city/foo. I would like it to remain foo.example.com. There is no R=301 in the RewriteRule (used to be but I removed it). The .htaccess file is in the ci/ folder and the rule is above all the codeigniter stuff.

The redirect works perfectly and the url remains foo.example.com with (Jon Lin's answer)

RewriteCond %{HTTP_HOST} !^(www)\. [NC]
 RewriteCond %{HTTP_HOST} ^(.*)\.example\.com [NC]
 RewriteCond %{REQUEST_URI} !/city/
 RewriteRule (.*) /city/%1/$1 [L]

but the codeigniter default controller is called instead of the foo method in the city controller.

Any help is appreciated.

Upvotes: 1

Views: 918

Answers (4)

aphoe
aphoe

Reputation: 2716

This worked for me

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /file_path/to/subdomain
    RewriteCond $1 !^(index\.php|images|robots\.txt)
    RewriteRule ^(.*)$ /index.php/$1 [L]
    RewriteCond %{REQUEST_URI} ^application.*
        RewriteRule ^(.*)$ /index.php?/$1 [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)$ index.php?/$1 [L]
    </IfModule>

    <IfModule !mod_rewrite.c>
        ErrorDocument 404 /index.php
    </IfModule> 

Upvotes: 0

smrkem
smrkem

Reputation: 173

I got it to work correctly using the following rewrite rule

   RewriteCond %{HTTP_HOST} !^(www)\. [NC]
 RewriteCond %{HTTP_HOST} ^(.*)\.example\.com [NC]
 RewriteCond %{REQUEST_URI} !/city/
 RewriteRule (.*) /city/%1/$1 [L]

and by setting

$config['uri_protocol'] = 'ORIG_PATH_INFO';

in the codeigniter config file. Thanks for all the help.

Upvotes: 1

Aken Roberts
Aken Roberts

Reputation: 13457

Your mileage may vary with this (might need to finesse it to fit your server and conditions), but doing some testing on my Mac, here's what I had mild success with:

Directory Structure

public_html/
  ci/
    application/
    system/
    .htaccess
    index.php

I'm assuming that you have other stuff in your root public_html directory. So I'm letting the .htaccess focus on the CodeIgniter-related stuff by leaving it in the ci dir.

.htaccess

DirectoryIndex index.php

RewriteEngine on

RewriteCond %{HTTP_HOST} ^(.*)\.ciwildsub\.dev [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php/city/%1/$1 [L,QSA]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L,QSA]

It's fairly self explanatory, but the first block is your subdomain check. I didn't bother excluding www but you may want to (as I said, your mileage may vary). The second block is a standard CodeIgniter index.php removal.

These rules will only apply to sub.example.com or example.com/ci/ URLs, since as I said, I assume your root has stuff that shouldn't be disturbed by rewrites.

CodeIgniter Config

$config['uri_protocol'] = 'PATH_INFO';

Because of the way Apache handles a URL like example.com/index.php/controller/method, it bypasses the index.php and handles it like any other directory segment. Also, mod_rewrite doesn't necessarily stop at the [L] tag -- it stops processing the .htaccess at that point, passes through the RewriteRule, and then runs that URL through the .htaccess. Setting PATH_INFO helps make sure CodeIgniter pulls the current URI correctly, and our .htaccess doesn't get stuck in a validation loop.

I will note, though, that I'm not entirely happy with what I see in my RewriteLog output -- there has to be a way to optimize this further, I'm just not sure of it yet (I'm done tinkering with this for today!). Sorry if any of the explanation here is a little out of whack - I'm not a server admin or mod_rewrite expert, I've just had fun tinkering with this. If I manage to find a better solution, I'll be sure to update this.


Looks like the END flag would be perfect for situations like this (to prevent [L] loops), but it's only available in Apache 2.3.9+. The search continues.

Upvotes: 1

Jon Lin
Jon Lin

Reputation: 143886

When your rewrite rule's target has an http://example.com in it, a 302 redirect is implicit regardless of whether an R flag is used or not. You need to provide the URI path based on the subdomain's document root, so I'm assuming you want something like:

RewriteCond %{HTTP_HOST} !^(www)\. [NC]
RewriteCond %{HTTP_HOST} ^(.*)\.example\.com [NC]
RewriteCond %{REQUEST_URI} !/city/
RewriteRule (.*) /city/%1/$1 [L]

If the subdomain's document root is in the /ci/ directory.

The other option is to use the P flag to reverse proxy the request:

RewriteCond %{HTTP_HOST} !^(www)\. [NC]
RewriteCond %{HTTP_HOST} ^(.*)\.example\.com [NC]
RewriteRule (.*) http://example.com/ci/city/%1/$1 [L,P]

Upvotes: 2

Related Questions