Я пытаюсь позволить Nginx обслуживать моих аутентифицированных пользователей-администраторов некоторыми статическими файлами с помощью PHP. Это прекрасно работает, я возвращаю файл. Но он подается с кодом статуса 404 ..
Я использую следующий (Symfony / Silex) PHP-код:
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;
А вот мой конфиг nginx:
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;
}
}
Защищенный каталог находится вне корня в конфиге nginx (/usr/share/nginx/project/web
).
Я нашел такие сообщения об ошибках в журналах:
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"
куда /admin/static/admin.js
действительно был запрошенный URL.
Обновление 1
Похоже, что nginx всегда пытается открыть URL-адрес и добавляет запись в журнал ошибок, даже php прекрасно обрабатывает ответ.
Даже если я заменю весь код php просто: return new Response('test', 200);
код ответа для тела ‘test’ по-прежнему 404 …
Я также попытался добавить дополнительный блок местоположения в моей конфигурации nginx:
location /protected_admin_files {
internal;
alias /usr/share/nginx/project/src/path/to/my/protected/static/dir;
}
А затем попробуйте перенаправить файл таким образом:
return new Response('', 200, [
'X-Accel-Redirect' => '/protected_admin_files/' . $file
]);
Но тоже без везения. Тот же 404 с правильным телом ответа …
Я сам нашел причину ..
Это было то, что я нашел в журнале ошибок, как только я установил уровень ошибки debug
(вот полный журнал)
...
[debug] rewrite phase: 1
[debug] http script regex: "^/(.*)/$"[notice] "^/(.*)/$" does not match "/admin/static/admin.js", request: "GET /admin/static/admin.js HTTP/1.1", host: "example.com"[debug] test location: "/"[debug] test location: "protected_admin_files"[debug] test location: ~ "\.(svg|jpg|jpeg|png|gif|ico|css|js)$"[debug] using configuration "\.(svg|jpg|jpeg|png|gif|ico|css|js)$"...
[debug] http filename: "/usr/share/nginx/project/web/admin/static/admin.js"[debug] add cleanup: 00000000025AE108
[error] open() "/usr/share/nginx/project/web/admin/static/admin.js" failed (2: No such file or directory), client: 24.132.134.203, server: example.com, request: "GET /admin/static/admin.js HTTP/1.1", host: "example.com"[debug] http finalize request: 404, "/admin/static/admin.js?" a:1, c:1
[debug] http special response: 404, "/admin/static/admin.js?"[debug] internal redirect: "/index.php?"...
Видимо, вложенный location
в моем первом location /
Блок был причиной 404.
location / {
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;
}
}
Он получил совпадение из-за расширения, заставляя Nginx искать файл. Так как он тогда не найден, 404 устанавливается и, очевидно, не перезаписывается позже в процессе, когда php возвращает заголовок X-Accel-Redirect :(.
Других решений пока нет …