I'm trying to let Nginx serve my authenticated admin users some static files with PHP. This works great, I get back the file. But it's served with a 404 status code..
I'm using the following (Symfony / Silex) php code:
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
$filePath = '/usr/share/nginx/project/src/path/to/my/protected/static/dir/' . $file;
if (empty($file) || !is_readable($filePath)) {
$app->abort(404);
}
$response = new BinaryFileResponse($filePath);
$response->trustXSendfileTypeHeader();
$response->setPrivate();
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_INLINE,
$file,
iconv('UTF-8', 'ASCII//TRANSLIT', $file)
);
$response->headers->addCacheControlDirective('must-revalidate', true);
return $response;
And here's my nginx config:
server {
listen 443;
listen [::]:443;
root /usr/share/nginx/project/web;
index index.php;
error_page 401 403 404 /404.html;
server_name example.com;
rewrite ^/(.*)/$ /$1 permanent;
location / {
# First attempt to serve request as file, then
# as directory, then let php handle the file
try_files $uri $uri/ /index.php$is_args$args;
index index.php;
autoindex off;
location ~* \.(svg|jpg|jpeg|png|gif|ico|css|js)$ {
expires 150d;
}
}
location ~ \.php$ {
set $path_info $fastcgi_path_info;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
try_files $uri $uri/ /index.php$is_args$args;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
include fastcgi_params;
fastcgi_param APP_ENV production;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
The protected dir lies outside of the root in the nginx config (/usr/share/nginx/project/web
).
I've found these kind of error messages in the logs:
open() "/usr/share/nginx/project/web/admin/static/admin.js" failed
(2: No such file or directory),
request: "GET /admin/static/admin.js HTTP/1.1"
Where /admin/static/admin.js
was indeed the requested url.
Update 1
It looks like nginx always tries to open the url and adds an entry to the error log even php handles the response just fine.
Even if I replace all the php code for just: return new Response('test', 200);
the response code for the body 'test' is still 404...
I also tried adding an extra location block in my nginx config:
location /protected_admin_files {
internal;
alias /usr/share/nginx/project/src/path/to/my/protected/static/dir;
}
And then try to redirect to the file like this:
return new Response('', 200, [
'X-Accel-Redirect' => '/protected_admin_files/' . $file
]);
But also without luck. Same 404 with the right response body...
I've found the cause myself..
This was what I found in the error log once I set the error level to
debug
(here's the full log)Apparently, the nested
location
in my first firstlocation /
block was causing the 404.It got matched because of the extension, making Nginx go looking for the file. Since it's then not found, the 404 is set and apparently not overwritten later in the process when php returns the X-Accel-Redirect header :(.