0

I'm using Nginx as Reverse Proxy for my App Server.

The App Server receives file download requests via this route:

/files/:id

Then the app finds the file path on the File System i.e. /path/to/file/with/id and responds with the file contents.

I don't want to expose the file path to the user.

Is there a way to inform Nginx of the file's path so Nginx can handle the file download for the user, instead of my app server, I don't want to use Nginx as only a reverse proxy or a cache server, I need more of a app server from Nginx.


Overview:

Want to switch from this architecture:

[nodejs/express]> file contents [nginx]> file contents [browser]

to this architecture:

[nodejs/express]> file info [nginx]> file contents [browser]

file info:

path
mimetype
originalname

Nginx has to tell the browser about the originalname and mimetype of the file. the file name is hashed in the path and there's no sign of its mimetype in the file name, so I have to use the file info returned from the app server.

aliep
  • 101
  • 5

3 Answers3

0

You need to setup the app server to redirect (not rewrite!) URLs, i.e. if I request /files/:id I should get a 301 redirect to /path/to/file.

Then you need to setup nginx to serve files from the local filesystem if found and fallback to the reverse proxy if not found.

What will happen is:

  1. The request for /files/:id is proxied by nginx to the backend
  2. The backend sends a 301 redirect to /path/to/file to the client
  3. The client requests /path/to/file
  4. nginx finds the file on the local filesystem and serves it directly

Something like this:

location / {
    try_files $uri $uri/ @backend;
}

location @backend {
    proxy_pass http://ip:80;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;
}

EDIT: if you don't want to let the user know the true url of the file, your only option is to ask the remote server to translate the url or to build the logic to do the mapping inside nginx itself. This could be done by switching from nginx to openresty and using lua-resty-http: https://github.com/pintsized/lua-resty-http

Luca Gibelli
  • 2,731
  • 1
  • 22
  • 30
0

nginx has very limited support form logic for performing operations like this to find out the file name to serve.

You need to modify your application so that instead of giving out an URL /files/:id to users, it will give an URL for the actual static file.

Another option is to simply to add caching to nginx.

Tero Kilkanen
  • 36,796
  • 3
  • 41
  • 63
0

Thanks to @MichaelHampton I used x-accel

https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/

this is a sample config:

express:

    if (file_info.mimetype.split('/')[0] === 'image') {
      res.header(
        'Content-Disposition',
        'inline');
    } else {
      res.header(
        'Content-Disposition',
        'attachment; filename=' + file_info.originalname);
    }

    res.header('Content-Type', file_info.mimetype);
    res.header('X-Accel-Redirect', file_info.path.split('/home')[1]);

nginx:

    location ~ ^/ypj* {
        internal;
        root /home;
    }

    location ~ .* {
        if ($host ~ ^cdn\.(.+)$) {
            proxy_pass http://127.0.0.1:4000;
        }
    }

the file path is something like:

/home/ypj/x/y/z

aliep
  • 101
  • 5