Score:0

NGINX: Return CORS headers when request method is OPTIONS and file exists, otherwise pass to PHP-FPM

cn flag

I have an NGINX with a PHP-FPM instance behind it. OPTIONS requests for paths for which a file exists in the file system should be handled by NGINX. For those requests, NGINX should return Access-Control-* CORS headers. OPTIONS requests for which no file exists should be passed to PHP-FPM.

The logic should be something along those lines:

    location / {
        # In this case: Check if file exists
        # - yes: return CORS headers
        # - no: pass request to PHP-FPM
        if ($request_method = 'OPTIONS') {
            # This causes an error
            try_files @cors;
        }

        # Normal request handling for all non-OPTIONS requests:

        # Try to serve file directly, fallback to index.php if file does not exist
        try_files $uri /index.php$is_args$args;
    }

    location @cors {
        if (-f $request_filename) {
            more_set_headers "Access-Control-Allow-Credentials: true";
            more_set_headers "Access-Control-Allow-Origin: example.com";
            more_set_headers 'Access-Control-Allow-Methods: POST, GET, DELETE, PUT, OPTIONS';
            more_set_headers 'Access-Control-Allow-Headers: content-type,ngsw-bypass';
            more_set_headers 'Access-Control-Max-Age: 3600';

            more_set_headers 'Content-Type: text/plain; charset=UTF-8';
            more_set_headers 'Content-Length: 0';

            return 204;
        }

        try_files /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        fastcgi_pass localhost:9000;
        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        include fastcgi_params;

        fastcgi_param REQUEST_METHOD $request_method;
        fastcgi_param SCRIPT_FILENAME /var/www/public/index.php;
        fastcgi_param DOCUMENT_ROOT /var/www/public;
        fastcgi_param HTTPS $fastcgi_param_https;

        # Prevents URIs that include the front controller. This will 404:
        # http://domain.tld/index.php/some-path
        # Remove the internal directive to allow URIs like this
        internal;
    }

This doesn't work though. Since try_files is not allowed inside an if statement ([emerg] 1#1: "try_files" directive is not allowed here).

Score:0
br flag

you can use the error_page directive to handle the OPTIONS requests for paths for which a file exists in the file system.

location / {
    # Try to serve file directly, fallback to index.php if file does not exist
    try_files $uri /index.php$is_args$args;

    # Handle OPTIONS requests for paths for which a file exists in the file system
    if ($request_method = 'OPTIONS') {
        if (-f $request_filename) {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }
    }
}

# Pass all other requests to PHP-FPM
location ~ \.php$ {
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

the try_files directive is used to serve files directly, with fallback to index.php if the file does not exist. The if block checks if the request method is OPTIONS and if a file exists at the requested path. If both conditions are true, NGINX will add the necessary CORS headers to the response and return a 204 No Content status code.

Orlando avatar
cn flag
I tried something along those lines as well. But NGINX doesn't allow nesting `if` statements
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.