title: FastCGI sent in stderr: "Primary script unknown" - URL working fine without mentioning index.php using nginx reverse proxy
body: <p>I have prepared a docker environment to run certain PHP based websites using nginx reverse proxy. Things mostly work except for one glitch. The URLs return the output of <code>index.php</code> just fine without mentioning <code>index.php</code> <code>http://web.local/web</code>, however, when I do it like <code>http://web.local/web/index.php</code> or any <code>.php</code> file for that matter.</p>
  <p><code>web</code> container gives the following error.</p>
  <blockquote>
  <p>2021/10/24 11:18:19 [error] 28#28: *3 FastCGI sent in stderr: &quot;Primary script unknown&quot; while reading response header from upstream, client: 192.168.224.6, server: proxy, request: &quot;GET /web/index.php HTTP/1.0&quot;, upstream: &quot;fastcgi://192.168.224.4:9000&quot;, host: &quot;web.local&quot;</p>
  </blockquote>
  <p>and <code>nginx</code> container gives following error.</p>
  <blockquote>
  <p>192.168.224.1 - - [24/Oct/2021:11:18:19 +0000] &quot;GET /web/index.php HTTP/1.1&quot; 404 27 &quot;-&quot; &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36&quot;</p>
  </blockquote>
  <p>I've tried to search previous posts of this <code>FastCGI sent in stderr</code> error but nothing matches my problem.</p>
  <p>Possible issues seem to be difference in users. NGINX proxy container uses <code>root</code> whereas PHP-FPM container uses <code>www-data</code>. Below are my configuration files.</p>
  <p><strong>NGINX (proxy) nginx.conf</strong></p>
  <pre><code>user root;
  worker_processes auto;
  pid /run/nginx.pid;
  include /etc/nginx/modules-enabled/*.conf;
  
  events {
      worker_connections 1024;
  }
  
  http {
  
      upstream nginx-web {
          server web:8110;
      }
  
      upstream nginx-portal {
          server portal:8115;
      }
  
      upstream nginx-api {
          server api:8120;
      }
  
      proxy_set_header   Host $host;
      proxy_set_header   X-Real-IP $remote_addr;
      proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header   X-Forwarded-Host $server_name;
  
      server {
          listen 80;
          server_name proxy;
  
          location /web {
              proxy_pass          http://nginx-web;
          }
  
          location /portal {
              proxy_pass          http://nginx-portal;
          }
  
          location /api {
              proxy_pass          http://nginx-api;
          }
      }
  }
  </code></pre>
  <p><strong>Server block (web) default.conf</strong></p>
  <pre><code>server {
      listen 8110;
      root /var/www/web;
      server_name proxy;
  
      location / {
          try_files $uri $uri/ /index.php$is_args$args;
          index index.php;
      }
  
      location ~ ^/.+\.php(/|$) {
          fastcgi_pass  php:9000;
          fastcgi_index index.php;
          include       fastcgi_params;
          fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      }
  }
  </code></pre>
  <p><strong>docker-compose.yml</strong></p>
  <pre><code>version: &quot;3.9&quot;
  
  services:
    db:
      container_name: db
      image: mysql:5.7
      ports:
        - &quot;3306:3306&quot;
      volumes:
        - &quot;${PROJECT_ROOT}/db:/var/lib/mysql&quot;
        - ./conf/db/my.cnf:/etc/mysql/conf.d/my.cnf:ro
      env_file:
        - .env
      networks:
        - backend
  
    proxy:
      container_name: proxy
      image: nginx:mainline-alpine
      volumes:
        - ./conf/proxy/nginx.conf:/etc/nginx/nginx.conf:ro
      ports:
        - &quot;80:80&quot;
        - &quot;8110:8110&quot;
        - &quot;8115:8115&quot;
        - &quot;8120:8120&quot;
      depends_on:
        - web
        - portal
        - api
      networks:
        - backend
  
    web:
      container_name: web
      image: nginx:mainline-alpine
      volumes:
        - &quot;${PROJECT_ROOT}/web:/var/www/web&quot;
        - ./conf/web/default.conf:/etc/nginx/conf.d/default.conf:ro
      depends_on:
        - php
      networks:
        - backend
  
    portal:
      container_name: portal
      image: nginx:mainline-alpine
      volumes:
        - &quot;${PROJECT_ROOT}/portal:/var/www/portal&quot;
        - ./conf/portal/default.conf:/etc/nginx/conf.d/default.conf:ro
      depends_on:
        - db
        - php
      networks:
        - backend
  
    api:
      container_name: api
      image: nginx:mainline-alpine
      volumes:
        - &quot;${PROJECT_ROOT}/api:/var/www/api&quot;
        - ./conf/api/default.conf:/etc/nginx/conf.d/default.conf:ro
      depends_on:
        - php
      networks:
        - backend
  
    php:
      container_name: php
      image: maciejslawik/php-fpm-xdebug:latest
      ports:
        - &quot;9000:9000&quot;
      volumes:
        - &quot;${PROJECT_ROOT}/web:/var/www/web&quot;
        - &quot;${PROJECT_ROOT}/portal:/var/www/portal&quot;
        - &quot;${PROJECT_ROOT}/api:/var/www/api&quot;
        - ./conf/php/docker-php-ext-xdebug.ini:/usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini:ro
      networks:
        - backend
  
    composer:
      container_name: composer
      image: composer:2
      restart: &quot;no&quot;
      command: install
      volumes:
        - &quot;${PROJECT_ROOT}/composer:/app&quot;
        - ./composer/composer.json:/app/composer.json
      networks:
        - backend
  
    phinx:
      container_name: phinx
      image: vegbrasil/phinx:latest
      volumes:
        - &quot;${PROJECT_ROOT}/migrations/database/migrations:/app/database/migrations&quot;
        - &quot;${PROJECT_ROOT}/migrations/database/seeds:/app/database/seeds&quot;
        - ./conf/phinx/phinx.php:/app/phinx.php:ro
      env_file:
        - .env
      depends_on:
        - db
      restart: &quot;no&quot;
      command: &quot;status&quot;
      environment:
        - TESTS_PHINX_DB_ADAPTER_MYSQL_HOST=db
      networks:
        - backend
  
    schemaspy:
      container_name: schemaspy
      image: schemaspy/schemaspy:latest
      volumes:
        - &quot;${PROJECT_ROOT}/schemaspy/output:/output&quot;
        - ./conf/schemaspy/schemaspy.properties:/schemaspy.properties:ro
      restart: &quot;no&quot;
      depends_on:
        - db
      networks:
        - backend
  
  networks:
    backend:
  </code></pre>
  <p>I've tried to check the output of <code>return 200 $document_root$fastcgi_script_name;</code> and it returns correct values.</p>
  <p>The default <code>PHP-FPM</code> user <code>www-data</code> doesn't have permission to <code>chmod</code> or <code>chcon</code> any file or directory.</p>
  <p><strong>$_SERVER vardump</strong></p>
  <pre><code>array (size=53)
    'PHP_EXTRA_CONFIGURE_ARGS' =&gt; string '--enable-fpm --with-fpm-user=www-data --with-fpm-group=www-data --disable-cgi' (length=77)
    'HOSTNAME' =&gt; string '4b4c2f5dcdb7' (length=12)
    'PHP_INI_DIR' =&gt; string '/usr/local/etc/php' (length=18)
    'HOME' =&gt; string '/var/www' (length=8)
    'PHP_LDFLAGS' =&gt; string '-Wl,-O1 -Wl,--hash-style=both -pie' (length=34)
    'PHP_CFLAGS' =&gt; string '-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64' (length=83)
    'PHP_MD5' =&gt; string '' (length=0)
    'PHP_VERSION' =&gt; string '7.4.0' (length=5)
    'GPG_KEYS' =&gt; string '42670A7FE4D0441C8E4632349E4FDC074A4EF02D 5A52880781F755608BF815FC910DEB46F53EA312' (length=81)
    'PHP_CPPFLAGS' =&gt; string '-fstack-protector-strong -fpic -fpie -O2 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64' (length=83)
    'PHP_ASC_URL' =&gt; string 'https://www.php.net/get/php-7.4.0.tar.xz.asc/from/this/mirror' (length=61)
    'PHP_URL' =&gt; string 'https://www.php.net/get/php-7.4.0.tar.xz/from/this/mirror' (length=57)
    'PATH' =&gt; string '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' (length=60)
    'PHPIZE_DEPS' =&gt; string 'autoconf         dpkg-dev        file        g++         gcc         libc-dev        make        pkg-config      re2c' (length=76)
    'PWD' =&gt; string '/var/www/html' (length=13)
    'PHP_SHA256' =&gt; string '9bb751b20e5d6cc1ea9b1ebf23ef2d5f07f99b2d9cc417bf1d70c04f8b20ec42' (length=64)
    'USER' =&gt; string 'www-data' (length=8)
    'HTTP_ACCEPT_LANGUAGE' =&gt; string 'en-US,en;q=0.9,ur;q=0.8' (length=23)
    'HTTP_ACCEPT_ENCODING' =&gt; string 'gzip, deflate' (length=13)
    'HTTP_ACCEPT' =&gt; string 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' (length=135)
    'HTTP_USER_AGENT' =&gt; string 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' (length=114)
    'HTTP_UPGRADE_INSECURE_REQUESTS' =&gt; string '1' (length=1)
    'HTTP_CACHE_CONTROL' =&gt; string 'max-age=0' (length=9)
    'HTTP_CONNECTION' =&gt; string 'close' (length=5)
    'HTTP_X_FORWARDED_HOST' =&gt; string 'proxy' (length=5)
    'HTTP_X_FORWARDED_FOR' =&gt; string '192.168.224.1' (length=13)
    'HTTP_X_REAL_IP' =&gt; string '192.168.224.1' (length=13)
    'HTTP_HOST' =&gt; string 'web.local' (length=9)
    'SCRIPT_FILENAME' =&gt; string '/var/www/web/index.php' (length=22)
    'REDIRECT_STATUS' =&gt; string '200' (length=3)
    'SERVER_NAME' =&gt; string 'proxy' (length=5)
    'SERVER_PORT' =&gt; string '8110' (length=4)
    'SERVER_ADDR' =&gt; string '192.168.224.7' (length=13)
    'REMOTE_PORT' =&gt; string '54314' (length=5)
    'REMOTE_ADDR' =&gt; string '192.168.224.6' (length=13)
    'SERVER_SOFTWARE' =&gt; string 'nginx/1.21.3' (length=12)
    'GATEWAY_INTERFACE' =&gt; string 'CGI/1.1' (length=7)
    'REQUEST_SCHEME' =&gt; string 'http' (length=4)
    'SERVER_PROTOCOL' =&gt; string 'HTTP/1.0' (length=8)
    'DOCUMENT_ROOT' =&gt; string '/var/www/web' (length=12)
    'DOCUMENT_URI' =&gt; string '/index.php' (length=10)
    'REQUEST_URI' =&gt; string '/web/' (length=5)
    'SCRIPT_NAME' =&gt; string '/index.php' (length=10)
    'CONTENT_LENGTH' =&gt; string '' (length=0)
    'CONTENT_TYPE' =&gt; string '' (length=0)
    'REQUEST_METHOD' =&gt; string 'GET' (length=3)
    'QUERY_STRING' =&gt; string '' (length=0)
    'FCGI_ROLE' =&gt; string 'RESPONDER' (length=9)
    'PHP_SELF' =&gt; string '/index.php' (length=10)
    'REQUEST_TIME_FLOAT' =&gt; float 1635101620.5358
    'REQUEST_TIME' =&gt; int 1635101620
    'argv' =&gt; 
      array (size=0)
        empty
    'argc' =&gt; int 0
  </code></pre>
  <p><strong>Update:</strong> I've changed the server &gt; location block for php as below.</p>
  <pre><code>    location ~ ^/.+\.php(/|$) {
          return 200 $document_root$fastcgi_script_name;
          fastcgi_pass  php:9000;
  #       fastcgi_index index.php;
          include       fastcgi_params;
  #        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
          fastcgi_param SCRIPT_FILENAME /var/www/web/help.php;
      }
  </code></pre>
  <p><strong>Result:</strong> Even though I open the URL <code>http://web.local/web/help.php</code>, it downloads a file with content <code>/var/www/web/index.php</code>. With hardcoded <code>SCRIPT_FILENAME</code> it shows me the output of correct file i.e. <code>help.php</code> so doesn't look like a permission issue as I had felt earlier. I notice that <code>fastcgi_index</code> is also irrelevant.</p>
  <p><strong>Question:</strong> Where is the value of <code>$document_root$fastcgi_script_name</code> coming from?</p>