1

I got an nginx vHost that hosts:

  • a CMS in /
  • a magento shop in /store

Things are running fine except one thing:

Removing index.php from the URL. At the moment the following URLs are working

example.com/store/index.php/my-funny-test-product.html and (as there are a few subshops in magento) 
example.com/store/index.php/city/my-funny-test-product.html

Now I have to build a redirect so that the index.php can be stripped off the URL.

example.com/store/my-funny-test-product.html or example.com/store/city/my-funny-test-product.html

I got it to work on my local Apache with this .htaccess

RewriteEngine on
RewriteBase /store/

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l

RewriteRule .* index.php [L]

Based on this I built the following rewrite

location /store {
   rewrite ^/store /store/index.php;
}

Now example.com/store/my-funny-test-product.html works but CSS images and the like are broken! I tried adding if (!-e $request_filename) to fix that but then got an nginx 40x error.

How can I achieve a working rewrite of example.com/store/my-funny-test-product.html and example.com/store/city/my-funny-test-product.html to the subfolder /store without breaking css & co and without having index.php in the URL?

Here's the full vhost config

    ## The whole setup stays close with the magento recommendations
    ## http://www.magentocommerce.com/wiki/1_-_installation_and_configuration/configuring_nginx_for_magento

server {
    listen myip:80;
    server_name .example.com;

    root /var/www/mydomain/public_html;

    location / {
        index index.html index.php;
        try_files $uri $uri/ @handler;  
    }

    ## here comes my rewrite stuff to remove index.php from the subfolder ##
   location /store {
       rewrite ^/store /store/index.php;
   }

    ## followed by some deny rulesets not relevant here ##

    location @handler { ## Magento common front handler
        rewrite / /index.php;
    }

    location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
        rewrite ^(.*.php)/ $1 last;
    }

    location ~ .php$ { ## Execute PHP scripts
        if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss

        expires        off; ## Do not cache dynamic content
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_param  HTTPS $fastcgi_https;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_param  MAGE_RUN_CODE default; ## Store code is defined in administration > Configuration > Manage Stores
        fastcgi_param  MAGE_RUN_TYPE store;
        include        fastcgi_params; ## See /etc/nginx/fastcgi_params
    }
AD7six
  • 2,920
  • 2
  • 21
  • 23
Tsolen
  • 23
  • 1
  • 7
  • Why are you trying to use rewrite at all instead of just `try_files` ? – AD7six Nov 22 '14 at 11:22
  • @AD7six Good point. I'll give it a try. Can you suggest something for this specific case? – Tsolen Nov 22 '14 at 11:29
  • `try_files` approach is for situations, where you are not sure where exaclty does the file exist. When you are sure some location does not have the specific script, it's useless and counterproductive to patch this with `try_files` (resulting in a bunch of redundant syscalls that nobody isn't need of) and you should point the nginx to a path where the file definitely is. probably with a rewrite. so the first method was right, and @AD7six personally neglects the Occam's Razor approach. – drookie Nov 22 '14 at 12:24
  • @EugeneM.Zheganin the code in the question currently uses `try_files` **and** rewrites I refer to this: `try_files $uri $uri/ @handler;` + `location @handler { rewrite / /index.php; }` is that your preferred Occam's Razor solution? There are more rules, but that should simply be `try_files $uri $uri/ /index.php;` or equivalent/very similar. Also note the purpose of the rewrite rules `here comes my rewrite stuff to remove index.php from the subfolder` - that's asking for an index directive. I encourage you to provide an answer if you still think I'm in some way suggesting complexity is better. – AD7six Nov 22 '14 at 12:33
  • Someone may say that it's amusing watching you help people shooting their legs (not me, though). The original post was too long to hope to understand it precisely, and to erroneous to post the answer immidiately, my concern was more about what you propose in comments. If we talk about the `location @handler { rewrite / /index.php; }` nonsense - its funny (now it is) that you pretend to complement this crippled logic. My opinion - this (and all other similar occurences) should be removed, because a single `index index.php` on `server {}` level will do all the work. – drookie Nov 22 '14 at 12:42
  • Maybe I should add that magento resides in /store while the root (/) is populated by a CMS. That runs fine with magento's default handler. So there was no need to change that. – Tsolen Nov 22 '14 at 12:45
  • @EugeneM.Zheganin I asked a question, I didn't provide an answer or recommendation. Are you using/familiar with any front-controller applications? Which ones, and what nginx config do you recommend? – AD7six Nov 22 '14 at 12:49
  • Your config makes references to store and shop - it's not really clear what you expect because of that. If all you want is to install magneto in a subfolder -that is one location block and one try_files directive. – AD7six Nov 22 '14 at 12:53
  • I saw various types of routing/controllers aproach (and I'm working as engineer to support all those numerous types). I personally prefer the `if (!-e $request_filename) { rewrite` technique for the reasons above (least redundancy). I am also aware that `try_files` technique is ultimately popular and lots of articles exists which try to prove it's the only right way. I think that this "right way" only leads to disk iops saturation. It's not critical when we talk about small vps with 2 users per year, but this is all about learning to build scalable things. – drookie Nov 22 '14 at 12:56
  • Sorry for the confusion guys. I'm new to SE and just wanted to provide all the info I got to get this resolved asap. I've been trying to get that (I bet simple) task done the whole day now ... I will clean up the question now. Maybe you can help me get things sorted out – Tsolen Nov 22 '14 at 13:00
  • @EugeneM.Zheganin (last question) what's your opinion of exactly that being [listed as a bad practice](http://wiki.nginx.org/Pitfalls#Check_IF_File_Exists)? – AD7six Nov 22 '14 at 13:09
  • My opinion on this is simple:`if`s are Igor's Sysoev personal foe and he's trying to avoid them as often as possible. This comes from http://wiki.nginx.org/IfIsEvil - the same root cause of nested ifs not being implemented. My thoughs about why ifs are better than `try_files` are clear and (I hope) evident. His are unclear, and if "IfsAreEvil" would be published here, they would be downvotes probably - because he stated no reason at all. I suppose the main reason is the code logic being non-perfect. Still if are better in a situation where nginx is proven to to what it should and not segfault. – drookie Nov 22 '14 at 13:17
  • Once he said that nested locations are evil, so what ? After some years nginx got nested locations. Same story will happen with condition handling. If your ifs are not doing what they should - failover to `try_files`, but it's more expensive. Plus, I never saw such cases in my experience (I'm not saying it's impossible). My main technique is "be simple". – drookie Nov 22 '14 at 13:21
  • 1
    You're trying to solve the wrong problem. Instead, you should configure Magento to not generate the links with `index.php` in the first place. – Michael Hampton May 22 '16 at 09:33

2 Answers2

1

Now example.com/store/my-funny-test-product.html works but CSS images and the like are broken!

Use try files

Requests for css files (or, any actual files in /var/www/example.com/public_html/store) aren't working at the moment because the requeset is routed unconditionally to /store/index.php. The minimal change necessary to make that work - is to use try_files:

## here comes my rewrite stuff to remove index.php from the subfolder ##
location /store {
    # rewrite ^/store /store/index.php; NO
    try_files $uri /store/index.php;
}

In this way, if the following file exists:

/var/www/example.com/public_html/store/css/style.css

Then the following url will return its content:

http://example.com/store/css/style.css

And any request starting with /store that does not directly map to a file will be passed to /store/index.php.

AD7six
  • 2,920
  • 2
  • 21
  • 23
-1

Then add the following code to this newly created .htaccess file

Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /

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

RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s(.*)/index\.php [NC]
RewriteRule ^ %1 [R=301,L]
Aishee
  • 1
  • 1