skip to Main Content

I’m moving a site from apache to nginx and stuck with the following configuration.

I have site http://example.com/ which shows the main (English) version.
Also, I have a few more languages which could be opened using correspondent subdirectories.
http://example.com/de http://example.com/fr, http://example.com/es or http://example.com/es/ (with a trailing slash).

These subdirectories are virtual (non-existing), but should open the same pages from the root directory. A php script handles the language representation.

Now English site works fine, however, other languages don’t work.
I can open http://example.com/es/ (only with a trailing char) and it opens the main page, however, all other pages could not be accessed (e.g. http://example.com/es/test.html which is a seo friend url). I already reviewed lots of similar questions and answers on SO but non of them are helpful.
Here is my configuration:

server {
    ....
    root /var/www;
    index index.php index.html index.htm;
  
    location / {
            rewrite ^/(de|fr|it|es)/(.*)$ /$2;
            try_files $uri $uri/ @fallback;
    }

    location @fallback {
            rewrite  ^(.*)$ /seo.php?$args last;
    }

    location ~* .(jpeg|ico|jpg|gif|png|css|js|pdf|txt|tar|gz|wof|csv|zip|xml|yml) {
            access_log off;
            try_files $uri @static;
            expires 14d;
            add_header Access-Control-Allow-Origin *;
            add_header Cache-Control public;
            root /var/www;
    }

    location @static {
            rewrite ^/(w+)/(.*)$ /$2 break;
            access_log off;
            rewrite_log off;
            expires 14d;
            add_header Cache-Control public;
            add_header Access-Control-Allow-Origin *;
            root /var/www;
    }

    location /backend/ {
            
            rewrite  ^(.*)$ /backend/index.php last;
    }

    location ~ .php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+.php)(/.+)$;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
    }
}

It previously worked on apache as follows:

RewriteRule ^(de|fr|it|es)/(.*)$ $2
RewriteCond %{REQUEST_URI} !^/(backend|template)/
RewriteCond %{REQUEST_FILENAME} !.(gif|jpeg|png|js|css|swf|php|ico)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ seo.php [L]

2

Answers


  1. Obviously Apache is transforming /es to /es/ before applying the rewrite. nginx will not do that unless the directory actually exists.

    However, it is easily remedied by tweaking the regular expression, and making the trailing slash optional.

    Try this:

    rewrite ^/(?:de|fr|it|es)(?:/(.*))?$ /$1;
    

    The (:? ) construct is a non capturing group.

    EDIT:

    If you want the trailing slash to be added “visibly”, then you will need a redirect. For example:

    rewrite ^/(de|fr|it|es)$ /$1/ permanent;
    rewrite ^/(?:de|fr|it|es)/(.*)$ /$1 last;
    
    Login or Signup to reply.
  2. Thank you so much @Richard Smith 🙂

    I am using an Angular 13 app with an Nginx server for a Blog and the expected URL is –

    **English content (Default)**
        www.site.com/blog/en
        www.site.com/blog/en/the-world-is-waiting-for-you-2022
    **Hindi language content**    
        www.site.com/blog/hi
        www.site.com/blog/hi/the-world-is-waiting-for-you-2022
    

    My Nginx Configuration:

    # if request is /blog
    location ~* /blog {
        # http to https redirection
        if ($http_x_forwarded_proto = 'http' ) {
            return 301 https://$host$request_uri;
        }
        # execute default file
        index index.html;
        # root folder where angular code 'blog' folder exists
        root /site/stage.example.in;
        # if url has language code /blog/en, /blog/hi, ... 
        # then rewrite request to index.html
        rewrite ^/(?:en|hi)(?:/(.*))?$ /$1;
        # check file, folder/, point /blog/index.html
        try_files $uri $uri/ @blogfallback;
        # my error and access log
        access_log /site/stage.example.in/logs/access.log;
        error_log /site/stage.example.in/logs/error.log;
    }
    # from /blog/en or /blog/hi last rule execution
    location @blogfallback {
        rewrite ^(.*)$ /blog/index.html?$args last;
    }
    

    Inside blog folder-

    blog
     ├── assets
     │   ├── fonts
     │   │   ├── montserrat-medium-webfont.ttf
     │   │   └── roboto-v18-latin-regular.woff2
     │   ├── images
     │   │   ├── master.jpg
     │   │   ├── home
     │   │   │   └── icons
     │   │   │       └── sample.png
     │   │   ├── icons
     │   │   │   ├── static_icons
     │   │   ├── search_hover_icon.png
     │   │   ├── static
     │   │   │   ├── blog
     │   │   │   │   ├── save-icon.png
     │   │   │   │   ├── banner_1366x290.jpg
     │   │   │   │   └── share-icon.png
     │   └── json
     │       ├── listing.json
     │       ├── common.json
     │       └── details.json
     ├── favicon.ico
     ├── index.html
     ├── main.33y3y.js
     ├── polyfills.sgsg53t.js
     ├── runtime.353gghegh.js
     ├── scripts.36sgsg.js
     └── styles.ss4647.css
    

    The angular app needs to execute each request via index.html.

    since the url structure is /blog/en — nginx expecting a folder ‘en’ inside ‘blog’.

    but, these are virtual folder, which does not exists on the server.

    hence we need to guide nginx that –

    if users enter the url /blog — go to root folder ‘blog’ and run index.html.

    if user enters the url /blog/some-file.css or some-file.js — go and check
    if file exists in "blog" folder,
    if yes, open it
    else check if any folder exists with the same name in "blog" folder.

    if yes, open it.

    if all fails point that request to /blog/index.html.

    now, there is no folder and files exists for the example request, /blog/en/a-beautiful-world

    — nginx points that request to /blog/index.html as fallback and angular routes that request and execute with a proper modules, controller, etc.


    Thanks

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search