1

edit - see update at end, it's php-fpm (php.ini) doc_root, but how to fix?

Working with nginx version 1.27.2 and php-8.3.14 on openSUSE Tumbleweed. The problem is this. I normally have a number of directories under the web-server I work with for development purposes. I am a long, long time Apache user/admin, but have only used nginx on Raspberry Pi, etc.. where I’m only concerned with serving files from the main document root. With apache, you simply define the <Directory> and set autoindex and php can handle the files at any level. I can't make that work in nginx.

I decided to configure nginx on my laptop to mirror the functionality I have from Apache on the various servers I have. Basic setup and php-fpm config works fine. The problem is when I create a location for the testing directories with autoindex, I can navigate the directory structure fine, but php cannot find the file to load even though it identifies the exact file to load as shown in the access and error logs.

I’ve probably been through 20 posts here and on StackOverflow and blogs, e.g. PHP Apps in a Subdirectory in Nginx, the nginx manual on, e.g. $request_filename and location, but all posts have a variation of the PHP won’t open my file or php-fpm can’t find the file, while not addressing how to make this work on a multi-directory level basis.

I’ve tried just about every variation of fastcgi_param SCRIPT_FILENAME $xxxxxx and none make any difference, the log entries don’t change, the correct file is found and passed to php-fpm and php-fpm says “I can’t find the correct filename you sent?”

The tmp folder in the following directory tree is the development folder. I have autoindex set on and I work from the folders underneath to test, figure out, implement, whatever ...

 # tree -d /srv /srv ├── http │   ├── cgi-bin │   ├── css │   ├── htdocs │   │   ├── gif │   │   └── include │   ├── js │   ├── sh │   ├── tmp │   │   ├── db │   │   │   └── mongo │   │   │   ├── css │   │   │   ├── include │   │   │   ├── js │   │   │   └── sav │   │   └── php │   │   └── utclocal │   └── vendor │   ├── composer │   ├── mongodb <snip> 

htdocs is the document root and I can serve .php files from it just fine. This problem appeared while working out a log file date/time handling issue, adding a missing year, creating a date instance and converting between UTC/localtime, etc. from logs sent from a Milkv-Duo RISC board that runs busybox and has no clue about localtime. I set up autoindex and basic authentication on /tmp/ and a nested a location to handle .php files. Authentication and traversal are fine, but I cannot serve files by opening them from any level below /tmp/.

The configuration I’m using is:

worker_processes auto; worker_cpu_affinity auto; events { multi_accept on; worker_connections 1024; use epoll; } http { charset utf-8; include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log warn; sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; log_not_found off; types_hash_max_size 4096; client_max_body_size 16M; keepalive_timeout 65; include conf.d/*.conf; server { listen 443 ssl; server_name wizard.mydomain.com localhost; ssl_certificate 'ssl/server.crt'; ssl_certificate_key 'ssl/server.key'; ssl_protocols TLSv1.2; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root /srv/http/htdocs/; index index.php index.html index.htm; } include /etc/nginx/php_fastcgi.conf; location ~ /css/[^/]+\.css$ { root /srv/http; access_log off; log_not_found off; } location /tmp/ { root /srv/http; autoindex on; autoindex_exact_size off; satisfy all; allow 192.168.6.0/24; allow 127.0.0.1; deny all; auth_basic "wizard restricted"; auth_basic_user_file /etc/nginx/basic_auth; location ~ [^/]\.(php|html|txt)(/|$) { include fastcgi_params; fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_param SCRIPT_FILENAME $request_filename; } } location ~ /js/[^/]+\.js$ { root /srv/http; access_log off; log_not_found off; } location ~ /sh/[^/]+\.sh$ { root /srv/http; access_log off; log_not_found off; } location = favicon.ico { access_log off; log_not_found off; } } include vhosts.d/*.conf; } 

The included php_fastcgi.conf is:

 location ~ [^/]\.(php|html|htm)(/|$) { # 404 try_files $fastcgi_script_name =404; # default fastcgi_params include fastcgi_params; ## fastcgi settings root /srv/http/htdocs/; fastcgi_pass unix:/run/php-fpm/php-fpm.sock; fastcgi_index index.php; fastcgi_buffers 8 16k; fastcgi_buffer_size 32k; fastcgi_param DOCUMENT_ROOT $realpath_root; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; } 

The location /tmp/ and nested location ~ [^/]\.(php|html|txt)(/|$) are the blocks that I’m trying to figure out. Every time I click on a .php file while traversing the directories under /tmp/, the file (e.g. /srv/http/tmp/php/utclocal/utclocal.php) is found, the logs show the correct filename being provided by the correct referring directory, but then php reports the error No input file specified. on stderr, complaining the correct filename can’t be found. The access and error logs show the following:

access.log

127.0.0.1 - david [26/Nov/2024:18:11:04 -0600] "GET /tmp/php/utclocal/ HTTP/1.1" 200 286 "https://wizard.mydomain.com/tmp/php/" "Mozilla/5.0 (X11; Linux x86_64; rv:132.0) Gecko/20100101 Firefox/132.0" "-" 

error.log

2024/11/26 18:11:06 [error] 132925#132925: *3660 FastCGI sent in stderr: "Unable to open primary script: /srv/http/tmp/php/utclocal/utclocal.php (No such file or directory)" while reading response header from upstream, client: 127.0.0.1, server: wizard.mydomain.com, request: "GET /tmp/php/utclocal/utclocal.php HTTP/1.1", upstream: "fastcgi://unix:/run/php-fpm/php-fpm.sock:", host: "wizard.mydomain.com", referrer: "https://wizard.mydomain.com/tmp/php/utclocal/" 

The file shown in the error.log, /srv/http/tmp/php/utclocal/utclocal.php is very much the correct file, is world-readable, and does exist:

$ ls -al /srv/http/tmp/php/utclocal/utclocal.php -rw-r--r-- 1 david david 1526 Nov 26 16:32 /srv/http/tmp/php/utclocal/utclocal.php 

From reading, it seems there is a problem between the nested location ~ [^/]\.(php|html|txt)(/|$) under /tmp/ and the location ~ [^/]\.(php|html|txt)(/|$) that is at the higher level handling /. I think I understand the precedence for the last prefix string in the config file being saved and controlling before location REGEX matching is done in the order specified in the config file, and then if an exact match is found, that block is used, but if not, the matching prefix string block is used.

This is where I’m confused on how to alter the nginx.conf file to properly handle the nested /tmp/ location so that I can open any php, html or txt file under /tmp/. The nested REGEX for location ~ [^/]\.(php|html|txt)(/|$) should match, so that block should be used. For some reason, and it may be a problem with that config I don't see, any .php or .html or .txt file I click on all are not found by php-fpm. I would at least expect files directly under /tmp/ to be served, but they are not, and this makes me think the earlier location for .php files is being triggered?

Since the number of directory components can vary under /tmp/, how do I need to handle the config, or a rewrite, so the filenames are properly handled by php-fpm. Do I need an alias instead of a root or a location @rewrite { .. }? Or am I going about this wrong with the nested setup under /tmp/? Any help will be greatly appreciated.

Sorry for the length of the question, but I wanted to try and include all relevant information necessary to the problem. If anything else is needed, drop a comment and I'll edit and provide whatever is needed.

Update - Issue Identified - php-fpm (php.ini) doc_root

This was a bit of a revelation. Chasing the nginx.conf problem of php works fine under the loction / but can't find the file under location /tmp/ I decided the switch gears and go back through php-fpm config. To test I changed the doc_root from /srv/http/htdocs to simply /srv/http and presto the php files anywhere under /tmp/ magically started working!

However, there is always a downside -- and php files under / now show the "No input file specified." error on stderr from php-fpm.

This a difficult issue. In apache you have the concept of server_root (the absolute base for files served when specifically allowed by a <Directory> or <location>, and you have the document_root the default path for files handed by the server. php on apache does not mind where the php files come from. However, with nginx the php-fpm php.ini doc_root seems to limit where it will handle php files from.

This makes this question one of "is this something I can handle with the nginx config?" or "is this a limitation of nginx and php-fpm?". After pulling my hair out over "why one directory would serve php files and not the other" looking at the nginx config, at least now I know both configs were fine, it was the doc_root in the php-fpm php.ini that made the difference.

Can I set up nginx to serve php files out of both /srv/http/htdocs (as the normal doc_root) and serve php files out of /srv/http/tmp? I'm thoroughly confused at this point.

3
  • You need to use location ^~ /tmp/ Commented Nov 27, 2024 at 8:28
  • @RichardSmith Progress! the 404 has changed to a 200, but now it is trying to download the .php file instead of processing it through php-fpm. Log says "GET /tmp/utclocal.php HTTP/1.1" 200 1526 ... Nothing in the error.log, so it is finding the file okay. Buy why is it downloading instead of displaying. I seem to remember seeing a post or two on this. I'll look. Commented Nov 27, 2024 at 9:02
  • I currently have location ^~ /tmp/.*[^/]\.(php|html|txt)(/|$) { that is still nested inside location /tmp/ {. No entries in the error.log and access shows the correct file and the 200 response code, but it opens the file-save dialog with the php file in it to be saved. Should I unnest the fastcgi block out of the /tmp/ block? Commented Nov 27, 2024 at 9:32

1 Answer 1

0

The Solution and details of php-fpm config and php.ini comments

On openSUSE Tumbleweed, php-fpm is built and configured with cgi.force_redirect enabled. phpinfo() shows both "master value" and "local value" set to on. In this case, the php.ini file, doesn't recommend setting doc_root. However, during the configuration, it was set, e.g.

; The root of the PHP pages, used only if nonempty. ; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root ; if you are running php as a CGI under any web server (other than IIS) ; see documentation for security issues. The alternate is to use the ; cgi.force_redirect configuration below ; https://php.net/doc-root doc_root = /srv/http/htdocs 

The entire problem has been trying to serve php files out of /srv/http/tmp which simply fails to be able to find the file based on this doc_root setting.

Going though the config on Archlinux pointed me in the right direct. Arch does does not set cgi.force_redirect and doesn't set doc_root. I run apache on Arch with php-fpm and there is no artificial limit to where php files will be recognized (so long as your apache config provides access to the location and the php.ini include path and open_basedir are unset or properly set).

Returning to openSUSE Tumbleweed, based on the Arch config, I decided to test unsetting doc_root in the php-fpm php.ini. BINGO! Problem solved. php files are now served from all locations. The nginx.config was fine. (the $uri parser is very good at getting the filesystem location right, given a broad range of the fastcgi settings -- I tried pretty much all variations and it made no difference). So it was the doc_root setting in php.ini all along. Commenting doc_root is all it took:

; doc_root = /srv/http/htdocs 

It's always the last-stone left unturned that has the answer hiding underneath. When you have checked your nginx.config until your eyes are crossing and can't find any issues -- look elsewhere. Hopefully this will provide help to anyone else with mysterious "php-fpm won't serve files from /some/path and will from /some/other/path. Double-check the doc_root setting in php-fpm php.ini.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.