Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying an Nginx regular expression so that it is applied only in some cases

I'm creating a hybrid PHP/Node.js application. For PHP, I'm using the Yii framework. Within Node.js, I use express.

PHP is running through Nginx. I use the proxy_pass directive to funnel any request starting with /node to the Node server running on port 3000 (e.g. server.com/node/api is proxyed to server.com:3000/api.)

This works well, for the most part. However, one of the directives in my Nginx configuration file ensures that requests for non-existent static files are not passed on to Yii. Instead, a simple 404 error is returned. The original version of this directive looks like this:

location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar|txt)$ {
    try_files $uri =404;
    #For production servers you can set expires header with a long period
    expires 3M;
}

The problem with this directive is that some static files (notably the socket.io client) are served by Node.js. When the browser requests server.com/node/socket.io/socket.io.js, the above rule gets fired, and Nginx returns the 404.

What I want to do is modify the rule so that the 404 is returned only when the request for a static file is NOT preceded by /node/. I've tried various combinations of rules, but none of them seem to work. After consulting the perl regular expression documentation, here's one that I thought might work, but doesn't:

location ~* (?<!/node/)\.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar|txt)$ {
    try_files $uri =404;
    expires 3M;
}

I thought the negative/look-behind part of the rule, (?<!/node/), would work to exclude requests starting with /node/, but it doesn't. Instead, the rule gets fired for both genuinely non-existent js files and for socket.io.js (and various other static files served from Node.js.) So in both cases I get a 404.

How should I change the regular expression so that the rule only gets applied when the request does NOT start with /node/?

like image 415
Terrence Avatar asked Dec 06 '25 20:12

Terrence


2 Answers

If I read your question right, you're talking about paths that don't start with /node/. That's a lot simpler than matching something that's not preceded by something. This should do it:

location ~* ^(?!/node/).*\.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar|txt)$ {

I think @Pogo almost had it, but as I understand it location doesn't include the server name. The regex start anchor, ^, matches the position immediately after .com (in this case) and before the first slash. Thus, ^(?!/node/) ensures that your path doesn't start with /node/.

like image 146
Alan Moore Avatar answered Dec 08 '25 11:12

Alan Moore


I think the problem might be because, javascipt doesn't support look behinds fully. You can look ahead at the start to see if it is not /node/ and then continue.

So,

.*com(?!/node/).*\.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar|txt)$

might help you.

like image 21
pogo Avatar answered Dec 08 '25 12:12

pogo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!