Score:0

NGINX location block pipes everything to index.php except images

cn flag

I have an API server that pipes all traffic to an index.php script that uses the PHP $_SERVER['REQUEST_URI'] variable to interpret the URL and serve up the correct response.

This works perfectly for everything, EXCEPT I have a script that temporarily serves files from a non-authenticated endpoint for public consumption. So the browser interprets the file data correctly, the file extension is included at the end of the URL.

Two examples:

Example 1

https://myapi.com/file/read/0e3970ea32b2cce0285564aeadb36c9d/m7hwCjCKDju88mKbW29EBhxoiuWTz9SF/Q2290814_BDKC3_031122_165240.xlsx

This request is piped to $server_root/index.php, the PHP script pulls the file data from S3 and streams the binary data with the correct mime-type headers. The browser initiates a download and everything works great. (This works fine with .doc and .pdf files too)

Example 2

https://myapi.com/file/read/0e3970ea32b2cce0285564aeadb36c9d/m7hwCjCKDju88mKbW29EBhxoiuWTz9SF/Q2290814_BDKC3_031122_165240.jpg

This JPEG file will not serve correctly, but rather an NGINX-generated 404 page is displayed. After some testing, I've determined that NGINX is not piping the request to $server_root/index.php

NGINX config

Main Config

server {
        listen 80;

        server_name myapi.com;
        
        set_real_ip_from 0.0.0.0/0;
        real_ip_header CF-Connecting-IP;

        index index.php index.html index.htm;

        access_log /var/log/nginx/myapi.com_access.log;
        error_log /var/log/nginx/myapi.com_error.log;

        root /var/www/vhosts/myapi.com/public;

        client_max_body_size 25m;

        include /etc/nginx/conf/include_template.conf;

        add_header                Strict-Transport-Security "max-age=15768000; includeSubDomains; preload";
        add_header                X-Content-Type-Options "nosniff" always;
        add_header                X-Frame-Options "SAMEORIGIN" always;
        add_header                X-XSS-Protection "1; mode=block";
        add_header                Referrer-Policy "no-referrer";

        location / {
            try_files $uri $uri/ /index.php?$query_string;
        }

        location ~ .php$ {
                try_files $uri =404;
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_index index.php;

                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_param  PATH_INFO          $fastcgi_path_info;
                fastcgi_param  PATH_TRANSLATED    $document_root$fastcgi_path_info;

                fastcgi_param  HTTPS 'on';

                fastcgi_buffer_size 128k;
                fastcgi_buffers 256 16k;
                fastcgi_busy_buffers_size 256k;
                fastcgi_temp_file_write_size 256k;

                fastcgi_read_timeout 1800;
                fastcgi_connect_timeout 1800;
                fastcgi_send_timeout 1800;
                proxy_read_timeout 1800;
                proxy_connect_timeout 1800;
                proxy_send_timeout 1800;
                send_timeout 1800;

                include fastcgi_params;
        }

}

/etc/nginx/conf/include_template.conf

    include /etc/nginx/conf/gzip.conf;
    include /etc/nginx/conf/restrictions.conf;
    include /etc/nginx/conf/cors.conf;
    include /etc/nginx/conf/browsercache.conf;

/etc/nginx/conf/gzip.conf

# Enable Gzip compression.
gzip on;

# Disable Gzip on IE6.
gzip_disable "msie6";

# Allow proxies to cache both compressed and regular version of file.
# Avoids clients that don't support Gzip outputting gibberish.
gzip_vary on;

# Compress data, even when the client connects through a proxy.
gzip_proxied any;

# The level of compression to apply to files. A higher compression level increases
# CPU usage. Level 5 is a happy medium resulting in roughly 75% compression.
gzip_comp_level 5;

# The minimum HTTP version of a request to perform compression.
gzip_http_version 1.1;

# Don't compress files smaller than 256 bytes, as size reduction will be negligible.
gzip_min_length 256;

# Compress the following MIME types.
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;
# text/html is always compressed when enabled.

/etc/nginx/conf/restrictions.conf

location /.git { deny all; }
location /.htaccess { deny all; }
location /.htpasswd { deny all; }
location /.user.ini { deny all; }

location ~ ^/\. { deny all; }

location ~ ~$ { deny all; }

location ~* \.sql { deny all; }
location ~* config\.json { deny all; }

#if ($request_method !~ ^(GET|HEAD|POST)$ )
#if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE|OPTIONS)$ )
#{
#       return 405;
#}

/etc/nginx/conf/cors.conf

        location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff|woff2)$ {
            add_header Access-Control-Allow-Origin "*";
            expires 8d;
        }

/etc/nginx/conf/browsercache.conf

location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
            expires 7d;
        }

Question

How can I modify my config to have every request piped to index.php, including image file extensions?

Richard Smith avatar
jp flag
Is the the complete configuration? What is in `/etc/nginx/conf/include_template.conf`? It behaves like you have a `location` that matches URIs ending with `.jpg`
andrewniesen avatar
cn flag
@RichardSmith - good question. I added additional config above. I have read thru it and don't see anything that would cause it to behave like this - although I always wrestle with NGINX
Richard Smith avatar
jp flag
It looks like `/etc/nginx/conf/browsercache.conf` matches that URL, the `jpe?g` pattern matches `jpg`.
andrewniesen avatar
cn flag
Well that does fix it, when I comment out the location in `/etc/nginx/conf/browsercache.conf`, but why would caching affect this?
Richard Smith avatar
jp flag
It has nothing to do with caching, but [how Nginx selects a `location` block to process a request](http://nginx.org/en/docs/http/request_processing.html).
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.