Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nginx Location Block for Dynamic Url Segment

Tags:

php

nginx

My PHP app automatically detects that a request routes to the admin area via the keyword manage in the url ie:

http://example.com/manage

This directory doesn't actually exist.

The request should route to the index.php file which is does on the initial request to manage/ but any links produce a "No input file specified." error in nginx.

I need a location block that will work on a non-existent url segment.

I tried re-writing it to the main index file like so:

location /manage {
    try_files $uri $uri/ @back;
}

location @back {
    rewrite ^/manage/(.*)$ /index.php?_route_=$1 last;
}

which works fine for Apache but in Nginx this produces a 500 error.

Any suggestions would be appreciated.

UPDATE:

Full config requested in comments:

upstream myapp {
    server unix:/srv/users/serverpilot/run/myapp.php-fpm.sock;
}

server {
    listen 80;
    server_name my.domain.com;

    root /srv/users/serverpilot/apps/myapp/public;
    index index.php index.html index.htm;

    access_log /srv/users/serverpilot/log/myapp/myapp_nginx.access.log;
    error_log  /srv/users/serverpilot/log/myapp/myapp_nginx.error.log;

    location /asset {
        rewrite ^/asset/(.*)$ /public/asset/$1 break;
    }

    location /image {
        rewrite ^/image/(.*)$ /public/image/$1 break;
    }

    location / {
        try_files $uri $uri/ @front;
    }

    location @front {
        rewrite ^/(.+)$ /index.php?_route_=$1 last;
    }

    location ~ \.php$ {
        include fastcgi.conf;
        fastcgi_pass myapp;
    }
}

UPDATE:

Error log requested.

15/05/14 10:42:04 [error] 32704#0: 
*5 FastCGI sent in stderr: 
"Unable to open primary script: /srv/users/username/apps/myapp/public/manage/index.php (No such file or directory)" 
while reading response header from upstream, client: 129.349.569.789, 
server: myapp.example.com, 
request: "GET /manage/index.php?route=common/forgotten HTTP/1.1", 
upstream: "fastcgi://127.0.0.1:9002", 
host: "myapp.example.com", 
referrer: "http://myapp.example.com/manage"

UPDATE:

Requested .htaccess file:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^(.*)/$ /$1 [L,R=301]
    RewriteRule ^asset/(.*)$ public/asset/$1 [L,QSA]
    RewriteRule ^image/(.*)$ public/image/$1 [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|txt|html|woff|ttf|eot|svg|css|js)
    RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]
</IfModule>
like image 934
Vince Kronlein Avatar asked Nov 10 '22 14:11

Vince Kronlein


1 Answers

From the error log and configuration you posted, the request for /manage/index.php?route=common/forgotten will match both the / and php location blocks.

Given how the Nginx Location Matching Order is set out, the PHP location block will always take precedence and so the request is passed to FastCGI to process and as site.com/manage/index.php does not exist, you get an error. That is, the try_files in / and the rewrite in @frontnever get into the picture at all.

What you need to do is to add a location block that has a higher position in the location matching order than the PHP location block to handle such requests.

upstream myapp {
    server unix:/srv/users/serverpilot/run/myapp.php-fpm.sock;
}

server {
    listen 80;
    server_name example.com;

    root /srv/users/serverpilot/apps/myapp/public;
    index index.php index.html index.htm;

    access_log /srv/users/serverpilot/log/myapp/myapp_nginx.access.log;
    error_log  /srv/users/serverpilot/log/myapp/myapp_nginx.error.log;

    location /asset {
        rewrite ^/asset/(.*)$ /public/asset/$1 break;
    }

    location /image {
        rewrite ^/image/(.*)$ /public/image/$1 break;
    }

    location / {
        try_files $uri $uri/ @front;
    }

    location ~ ^/manage {
        rewrite ^([^?]*)$ /index.php?_route_=$1;
    }

    location ~ \.php$ {
        include fastcgi.conf;
        fastcgi_pass myapp;
    }

    location @front {
        rewrite ^([^?]*)$ /index.php?_route_=$1;
    }
}

With this arrangement, the request will match the /, /Manage and php location blocks. /Manage and php being regex type blocks, will take precedence and among the two, /Manage, because it appears first, will take precedence and redirect accordingly.

For the redirection, the request will match the /, and php location blocks. php will take precedence and as site.com/index.php does exist, process accordingly.

PS. I notice you have _route_ in your config and route in the log. Take it that is just for testing.

**** ALTERNATIVE CONFIG ****

upstream myapp {
    server unix:/srv/users/serverpilot/run/myapp.php-fpm.sock;
}

server {
    listen 80;
    server_name example.com;

    root /srv/users/serverpilot/apps/myapp/public;
    index index.php index.html index.htm;

    access_log /srv/users/serverpilot/log/myapp/myapp_nginx.access.log;
    error_log  /srv/users/serverpilot/log/myapp/myapp_nginx.error.log;

    location ~ \.php$ {
        include fastcgi.conf;
        fastcgi_pass myapp;
    }

    location ~ ^/asset/(.*)$ {
        rewrite ^ public/asset/$1;
    }

    location ~ ^/image/(.*)$ {
        rewrite ^ public/image/$1;
    }

    location / {
        rewrite ^/(.+)/$ /$1 permanent;
        try_files $uri $uri/ @front;
    }

    location @front {
        rewrite ^/([^?]*)$ /index.php?_route_=$1;
    }   
}
like image 53
Dayo Avatar answered Nov 15 '22 13:11

Dayo