3

I'm trying to set up authorized file access on nginx backed by node.js. For some reason all the examples don't work for me. I'm trying to server files from /data/private/files

My nginx configuration:

...
server {
    listen 4000;
    server_name localhost;

    location / {
        proxy_pass http://127.0.0.1:3000/;
    }

    location /files {
        root /data/private;
        internal;
}  

My node server.js:

var http = require('http');
http.createServer(function (req, res) {
  console.log(req.url);
  res.end('works');
}).listen(3000);

When I request http://localhost:4000/xyz then the request is correctly being passed on to node. When I request http://localhost:4000/files/test.jpg I just get a 404 and nothing gets passed to node. What am I doing wrong? When I commend out internal then test.jpg gets served correctly by nginx directly, so I assume the paths are correct?

I'm pretty sure I had this working at some point before but on a different server somewhere maybe with a different node and nginx version. Tried it with nginx 1.6.0 and 1.2.6, node v0.10.21. I've also added all the proxy_set_header and proxy_pass options that you find in all the examples, nothing works. I'm running this in a Vagrant based Ubuntu VM right now, but doesn't work on Mac either.

I know that I have to set the header through res.setHeader("X-Accel-Redirect", req.url);, but that's not the issue here as I don't even get to that phase where I could set the required header in node.

ti2m
  • 33
  • 3

1 Answers1

5

You misunderstand how internal and X-Accel-Redirect work.

The main idea is that you go to some URL which is proxied to app. Then app decides whether you should get access to file or not. In former case it response with X-Accel-Redirect to protected url (one with internal).

So you should go to some other URL, e.g. http://localhost:4000/get/files/test.jpg and your application could look like this:

var http = require('http');
http.createServer(function (req, res) {
  if (req.url.indexOf('/get/files/') == 0) {
    if (userHasRightToAccess()) {
      res.setHeader('X-Accel-Redirect', res.url.slice(4));
      res.end('');
    } else {
      // return some error
    }
  } else {
    console.log(req.url);
    res.end('works');
  }
}).listen(3000);
Alexey Ten
  • 11,983
  • 5
  • 35
  • 49
  • Thanks a lot! Makes total sense, I got somehow lost on the way the more I read about it. Got stuck on the idea that request and path have to match. Spend hours on it, thanks again! – ti2m May 28 '14 at 07:44
  • Hey Alexey, I'm using this on client ajax side to access the file returned by the nginx server on internal redirect: `http.onreadystatechange = function() { if(http.readyState == 4 && http.status == 200) { localStorage.setItem("Authorization",http.getResponseHeader("Authorization")); window.document.write(http.responseText); } ` But it's not working for me. I'm getting the page html content as part of body of the response but it's opening the page in the current tab. Can you please help on this? – gonephishing Feb 15 '17 at 17:12
  • @gonephishing nginx's internal redirect has nothing to do with ajax. Create new question – Alexey Ten Feb 15 '17 at 17:24