title: How to convert a simple index.php redirection from apache to nginx format?
body: <p>From an old project, I got this .htaccess file, which currently handle the apache rewrite rules:</p>
  <pre><code>&lt;IfModule mod_rewrite.c&gt;
      RewriteEngine On
      # Folders / files to exclude from rewrite divided by Pipe goes here:
      RewriteRule (^|/)install(/|$) - [L,NC]
      RewriteRule (^|/)web(/|$) - [L,NC]
  
      # turn empty requests into requests for &quot;index.php&quot;,
      # keeping the query string intact
      RewriteRule ^$ index.php [QSA]
  
      RewriteCond %{REQUEST_FILENAME} !-d
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteCond %{REQUEST_FILENAME} !favicon.ico$
      RewriteRule ^(.+)$ index.php [QSA,L]
  
      RewriteRule ^(.+)$ index.php [QSA,L]
  &lt;/IfModule&gt;
  </code></pre>
  <p>What the above snippet basically does, is that it rewrites all requests to index.php by keeping the query part string intact and stop after the first match, unless the file or folder exists.</p>
  <p>So, in conclusion, by consulting the Nginx docs and by adding some additional security (permit access to sensible folders and files) and performance-related stuff (enable gzip or brotli output compression where it's possible [depending on the client, which one it is able to process]), I got this:</p>
  <pre><code>server {
      listen 80;
      listen [::]:80;
      server_name subdomain.example.com;
      return 301 https://$host$request_uri;
  }
  
  server {
      listen 443 ssl http2;
      listen [::]:443 ssl http2;
      server_name tdc.wunner-software.de;
  
      ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
      ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  
      # Add headers to serve security-related headers
      # Before enabling Strict-Transport-Security headers please read into this
      # topic first.
      add_header Strict-Transport-Security &quot;max-age=15768000; includeSubDomains; preload;&quot; always;
      #
      # WARNING: Only add the preload option once you read about
      # the consequences in https://hstspreload.org/. This option
      # will add the domain to a hardcoded list that is shipped
      # in all major browsers and getting removed from this list
      # could take several months.
      add_header Referrer-Policy &quot;no-referrer&quot; always;
      add_header X-Content-Type-Options &quot;nosniff&quot; always;
      add_header X-Download-Options &quot;noopen&quot; always;
      add_header X-Frame-Options &quot;SAMEORIGIN&quot; always;
      add_header X-Permitted-Cross-Domain-Policies &quot;none&quot; always;
      add_header X-Robots-Tag &quot;none&quot; always;
      add_header X-XSS-Protection &quot;1; mode=block&quot; always;
  
      # Remove X-Powered-By, which is an information leak
      fastcgi_hide_header X-Powered-By;
  
      # Path to the root of your installation
      root /srv/www/vhosts/example.com/subdomain.example.com;
  
      index index.php index.html;
  
      charset utf-8;
  
      location = /robots.txt {
          allow all;
          log_not_found off;
          access_log off;
      }
  
      # set max upload size
      client_max_body_size 512M;
      fastcgi_buffers 64 4K;
  
      # Enable gzip but do not remove ETag headers
      gzip on;
      gzip_vary on;
      gzip_comp_level 4;
      gzip_min_length 256;
      gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
      gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
  
      brotli on;
      brotli_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
  
      # Adding the cache control header for js, css and map files
      # Make sure it is BELOW the PHP block
      location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
          try_files $uri /index.php$request_uri;
          add_header Cache-Control &quot;public, max-age=15778463&quot;;
          # Add headers to serve security related headers (It is intended to
          # have those duplicated to the ones above)
          # Before enabling Strict-Transport-Security headers please read into
          # this topic first.
          add_header Strict-Transport-Security &quot;max-age=15768000; includeSubDomains; preload;&quot; always;
  
          # Optional: Don't log access to assets
          access_log off;
      }
  
      location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap|mp4|webm)$ {
          try_files $uri /index.php$request_uri;
          # Optional: Don't log access to other assets
          access_log off;
      }
  
      location ~ ^/vendor/.*$ {
          deny all;
      }
  
      location ~ ^\.htaccess$ {
          deny all;
      }
  
      #rewrite ^(.*)/$ index.php$is_args$args break;
  
      location ~ /(.*)$ {
          index index.php;
          try_files $uri $uri/ /index.php$is_args$args;
      }
  
      location ~ \.php$ {
          fastcgi_split_path_info ^(.+\.php)(/.+)$;
          include fastcgi.conf;
          fastcgi_param HTTP_PROXY &quot;&quot;;
          fastcgi_param HTTPS $https;
          fastcgi_buffers 8 16k;
          fastcgi_buffer_size 32k;
          fastcgi_read_timeout 300s;
          client_body_buffer_size 128k;
          fastcgi_pass php-handler;
          http2_push_preload on;
      }
  
      access_log /var/log/nginx/subdomain_example_com_ccess.log;
      error_log /var/log/nginx/subdomain_example_com_error.log;
  }
  </code></pre>
  <p>The new Nginx configuration above downloads the PHP file instead of bypassing it to the FPM handler. I have found <a href="https://stackoverflow.com/questions/7046301/nginx-rewrite-all-directory-requests-to-index-php">this</a> and <a href="https://stackoverflow.com/questions/12924896/rewrite-all-requests-to-index-php-with-nginx">this</a> SO questions, but it doesn't seem to do the trick for me. Also, as mentioned in Nginx documentation, <code>if</code> is evil and we should avoid using it unless we are 100 percent sure what's going on. So, for my configuration, I avoided using it. Mainly because regex syntax also works with <code>location</code> and is way more securer in that context than <code>if</code>. I mean, as far as I know. Please correct me, if I'm wrong.</p>
  <p>The main <code>nginx.conf</code> file is dead simple right now:</p>
  <pre><code>user  nginx;
  worker_processes  1;
  
  # load_module lib64/nginx/modules/ngx_http_fancyindex_module.so;
  # load_module lib64/nginx/modules/ngx_http_geoip_module.so;
  # load_module lib64/nginx/modules/ngx_http_headers_more_filter_module.so;
  # load_module lib64/nginx/modules/ngx_http_image_filter_module.so;
  # load_module lib64/nginx/modules/ngx_http_perl_module.so;
  # load_module lib64/nginx/modules/ngx_http_xslt_filter_module.so;
  # load_module lib64/nginx/modules/ngx_mail_module.so;
  # load_module lib64/nginx/modules/ngx_rtmp_module.so;
  # load_module lib64/nginx/modules/ngx_stream_geoip_module.so;
  # load_module lib64/nginx/modules/ngx_stream_module.so;
  
  error_log  /var/log/nginx/error.log;
  #error_log  /var/log/nginx/error.log  notice;
  error_log  /var/log/nginx/error.log  info;
  
  #pid        /run/nginx.pid;
  
  events {
      worker_connections  1024;
      use epoll;
  }
  
  
  http {
      include       mime.types;
      default_type  application/octet-stream;
  
      #log_format  main  '$remote_addr - $remote_user [$time_local] &quot;$request&quot; '
      #                  '$status $body_bytes_sent &quot;$http_referer&quot; '
      #                  '&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;';
  
      #access_log  /var/log/nginx/access.log  main;
  
      sendfile        on;
      #tcp_nopush     on;
  
      #keepalive_timeout  0;
      keepalive_timeout  65;
  
      gzip  on;
  
      include conf.d/*.conf;
  
      server {
          listen       80;
          server_name  localhost;
  
          #charset koi8-r;
  
          #access_log  /var/log/nginx/host.access.log  main;
  
          location / {
              root   /srv/www/htdocs/;
              index  index.html index.htm;
          }
  
          #error_page  404              /404.html;
  
          # redirect server error pages to the static page /50x.html
          #
          error_page   500 502 503 504  /50x.html;
          location = /50x.html {
              root   /srv/www/htdocs/;
          }
  
          # proxy the PHP scripts to Apache listening on 127.0.0.1:80
          #
          #location ~ \.php$ {
          #    proxy_pass   http://127.0.0.1;
          #}
  
          # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
          #
          location ~ \.php$ {
              root           /srv/www/htdocs/;
              fastcgi_pass   127.0.0.1:9000;
              fastcgi_index  index.php;
              fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
              include        fastcgi_params;
          }
  
          # deny access to .htaccess files if Apache's document root
          # concurs with Nginx's one
          #
          location ~ /\.ht {
              deny  all;
          }
      }
  
  
      # another virtual host using a mix of IP-, name-, and port-based configuration
      #
      #server {
      #    listen       8000;
      #    listen       somename:8080;
      #    server_name  somename  alias  another.alias;
  
      #    location / {
      #        root   /srv/www/htdocs/;
      #        index  index.html index.htm;
      #    }
      #}
  
  
      # HTTPS server
      #
      #server {
      #    listen       443 ssl;
      #    server_name  localhost;
  
      #    ssl_certificate      cert.pem;
      #    ssl_certificate_key  cert.key;
      
      #    Allow TLS version 1.2 only, which is a recommended default these days
      #    by international information security standards.
      #    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/www/htdocs/;
      #        index  index.html index.htm;
      #    }
      #}
  
      include vhosts.d/*.conf;
  }
  </code></pre>
  <p>The file above is mainly the openSUSE distributor shipped file, with a few changes.</p>
  <p>And this is my <code>base.conf</code> file, which defines the FPM proxy handler for nginx (in order to don't repeat yourself; it's neccessarily needed anyways):</p>
  <pre><code>upstream php-handler {
      server 127.0.0.1:9000;
      #server unix:/var/run/php/php7.2-fpm.sock;
  }
  </code></pre>
  <p>I'd appreciate any help with that issue.</p>