Configure rewrite rules for Nginx & Prestashop v1.6 including multi-store

Apache vs Nginx

As we all know by now, there are two primary open source web servers available for you to use (between them they serve over 50% of the worlds websites).

Whilst Apache's rewrite rules are built in to Prestashop thanks to the extremely useful .htaccess methods, Nginx is not so simple to support out of the box. For many using Apache is not acceptable for their own reasons so therefore we need a manual method of replicating all the server redirects that Prestashop expects to use.


Nginx and Prestashop 1.6

For Nginx (pronounced engine-X) you need to do a little bit more than just tick a box in Prestashop. You need to configure the web servers config files themselves. Now this may sound daunting, but don't panic here's a step by step guide on getting it setup.

I am going to assume that your nginx configurations are located in a location of;
/etc/nginx

If this is not the case then adjust the locations accordingly.

Step 1

I am also going to assume you might want to use this config for different websites on the same server, so the best way to manage this is create a config file that can be shared between websites (or server definition blocks as they are known):

Create a folder

mkdir -p /etc/nginx/shopapps.d (the -p just means create any parent folders if required)

Then you need to copy the following configs into a file on the server, this could be done using nano editor (and copy/paste in your console) or an ftp or similar program such as winscp (for windows) or fetch for Apple Mac.


nano /etc/nginx/shopapps.d/prestashop.conf


    charset utf-8;
    client_max_body_size 200M;


    ######################################################
    ##  MultiSite Support
    ##   WORLD SITES
    ##  For Google optimisation reasons, this customer has a .co.uk domain for UK customers
    ##  and a .com for global visitors
    ##  the .com url will be in the following format:
    ##  NOTE:  This is a multisite url NOT a prestashop language URL
    ##  www.myshop.com/us   (USA)
    ##  www.myshop.com/fr   (France)
    ##  www.myshop.com/ca   (canada)
    ##  etc.  These URLs are then registered as country specific in Google Webmaster Tools.
    ##  NEXT:  if  multilingual is also required
    ##  the url format is:
    ##  www.myshop.com/ca/fr
    ##  www.myshop.com/ca/en
    ##  etc.
    #######################################################
    ##  only rewrite for a given domain
    ##  this could be moved to the server definition file instead of here...
    ##  however I have placed it here to save having two different
    ##  server definitions
    ##  
    if ($http_host ~ "^www.myshop.com$") {
        rewrite '^/([a-zA-Z]{2})$'     /$1/ redirect;
        rewrite '^/([a-zA-Z]{2})/(.*)'     /$2;
    }

    rewrite ^/api$ /api/ last;
    ##  ALL IMAGES REWRITE
    rewrite ^/([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$                 /img/p/$1/$1$2$3.jpg last;
    rewrite ^/([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$          /img/p/$1/$2/$1$2$3$4.jpg last;
    rewrite ^/([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$   /img/p/$1/$2/$3/$1$2$3$4$5.jpg last;
    rewrite ^/([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$            /img/p/$1/$2/$3/$4/$1$2$3$4$5$6.jpg last;
    rewrite ^/([0-9])([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$     /img/p/$1/$2/$3/$4/$5/$1$2$3$4$5$6$7.jpg last;
    rewrite ^/([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$          /img/p/$1/$2/$3/$4/$5/$6/$1$2$3$4$5$6$7$8.jpg last;
    rewrite ^/([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$   /img/p/$1/$2/$3/$4/$5/$6/$7/$1$2$3$4$5$6$7$8$9.jpg last;
    rewrite ^/([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])([0-9])(\-[_a-zA-Z0-9-]*)?(-[0-9]+)?/.+\.jpg$    /img/p/$1/$2/$3/$4/$5/$6/$7/$8/$1$2$3$4$5$6$7$8$9$10.jpg last;

    rewrite ^/c/([0-9]+)(-[_a-zA-Z0-9-]*)/[_a-zA-Z0-9-]*.jpg$   /img/c/$1$2.jpg last;
    rewrite ^/c/([a-zA-Z-]+)/[a-zA-Z0-9-]+.jpg$                 /img/c/$1.jpg last;
    rewrite ^/([0-9]+)(-[_a-zA-Z0-9-]*)/[_a-zA-Z0-9-]*.jpg$     /img/c/$1$2.jpg last;

    rewrite ^/images_ie/?([^/]+)\.(jpe?g|png|gif)$              /js/jquery/plugins/fancybox/images/$1.$2 last;


    rewrite '^/order/step([0-9]).html$'      /index.php?controller=order&step=$2   last;
    rewrite '^/quick-order$'                 /index.php?controller=order-opc       last;
    rewrite '^/password-recovery$'           /index.php?controller=password        last;


    if (!-e $request_filename){
        rewrite ^(.*)$ /index.php?q=$1 last;
    }

    location /api { 
        rewrite ^/api/(.*)$ /webservice/dispatcher.php?url=$1 break; 
    }

    # Do not log robots.txt or favicon.ico file requests
    location ~* ^/(favicon.ico|robots.txt)$ {
        access_log off;
        log_not_found off;
    }

    # Custom Prestashop 404 page
    error_page 404 /index.php?controller=404;

    #  Set long expirey values for CSS and Images (assuming you dont change them too often)
    location ~* ^.+.(gif|jpg|jpeg|png|wmv|avi|mpg|mpeg|mp4|htm|html|js|css|mp3|swf|ico|flv|xml) {
        access_log off;
        expires 30d;
    }


Step 2

Now we have created this file, we need to tell nginx to use it. This is done by including it from within a website's server block definition configs.


Server definition file

nano /etc/nginx/sites-avaiable/www.myshop.com.conf


    ## we only  want one access method into this store so rewrite myshop.com to www.myshop.com
    server { 
        listen         80; 
        server_name     myshop.com;     
        rewrite ^ http://www.myshop.com$request_uri? permanent; 
    }
    server {
        listen        80;
        server_name     www.myshop.co.uk 
                        www.myshop.com;

        server_name_in_redirect off;

        root            /var/websites/myshop.co.uk/public;
        index           index.php index.htm index.html  ;
        access_log      /var/log/nginx/access.myshop.co.uk.log;
        error_log       /var/log/nginx/error.myshop.co.uk.log debug;

        ##  Now include our shared config files
        include         shopapps.d/prestashop-new.conf;
        include         shopapps.d/drop.conf;
        include         shopapps.d/php.conf;
    }


This config is then made active by symlinking into into the sites-enabled folder:

cd /etc/nginx/sites-enabled ln -s ../sites-avaiable/www.myshop.com.conf

Other config Files

You will notice there are a number of other shared config files included under this website server definition. For reference below are their contents:

nano /etc/nginx/shopapps.d/drop.conf

This file is a must have to secure certain files on your website:


    location = /robots.txt  { allow all; access_log off; log_not_found off; }
    location = /favicon.ico { access_log off; log_not_found off; }      
    # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
    # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
    location ~ /\.          { deny all; }
    location ~ ~$           { access_log off; log_not_found off; deny all; }
    location = /CVS         { deny all;}

    location ~ (\.inc\.php|\.tpl|\.sql|\.tpl\.php|\.db)$ { deny all; }
    location ~ /\.ht { deny all; }

    # Deny access to any files with a .php extension in the uploads directory
    # Works in sub-directory installs and also in multisite network
    # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }
    location ~ ^/(README|INSTALL|LICENSE|CHANGELOG|UPGRADING)$ {
        deny all;
    }
    location ~ ^/(bin|SQL)/ {
        deny all;
    }


nano /etc/nginx/shopapps.d/php.conf

On my server I use nginx and php-fpm running as a socket to manage php requests as i find this the most efficient method in respect to resources on the server.


    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index    index.php;
        fastcgi_read_timeout 7200;  # 2 hours for big cron jobs...
        include fastcgi_params;
    }

Barring any typo's on my part, you should now have a working config supporting Prestashop 1.6 & muti-site on nginx.

Now you just need to restart the server...

Step 3

Restart the server

On Ubuntu the commands are:

nginx -t && service nginx reload

This is actually two commands on one line. The first part nginx -t tests the configuration, if the console reports any errors then deal with them appropriately. Then service nginx reload actually reloads the nginx server.


Want to know more - Then why not subscribe to our mailing list?

* indicates required
Which information are you interested in?