Use Nginx to proxy files from remote location using X-Accel-Redirect

Nginx supports X-Accel-Redirect for local files with no extra hassle, but what happens if you need to serve files located in some remote location like s3 and you don’t want to expose direct urls to the files? Sometimes you may want that to have control over stats or to keep an option to migrate to another file server without changing original urls.

Here is what you do:

location ~* ^/internal_redirect/(.*?)/(.*) {
internal;
# If you use variables in proxy pass you need to
# tell nginx how to resolve your host
# otherwise you will get 502 errors
# you could also use google 8.8.8.8
resolver 172.16.0.23;
proxy_buffering off;
proxy_set_header Content-Length "";
proxy_set_header Cookie "";
proxy_hide_header x-amz-request-id;
proxy_hide_header x-amz-meta-uid;
proxy_hide_header x-amz-id-2;
proxy_hide_header x-amz-meta-mode;
proxy_hide_header x-amz-meta-mtime;
proxy_hide_header x-amz-meta-gid;
proxy_hide_header x-amz-version-id;
proxy_hide_header accept-ranges;
# Do not touch local disks when proxying
# content to clients
proxy_method GET;
proxy_pass_request_body off;
proxy_max_temp_file_size 0;
set $download_host $1;
set $download_uri $2;
set $download_url http://$download_host/$download_uri;
add_header x-by "$instance_id:s3";
proxy_pass $download_url;
}

Then in your application you need to set X-Accel-Redirect header with remote file hostname ( first part ) and URI (second part).

X-Accel-Redirect: /internal_redirect/assets.example.com.s3-website-us-east-1.amazonaws.com/file/uri.jpg

Potentially you could use the same idea for private files stored on S3. For that you would need to generate correct Authorization header

proxy_set_header Authorization "value";

which might be a little tricky, but possbile with perl support ( extract required tokens from instance metadata if you are using IAM roles, or use access keys passed to the instance somehow ).

Join the Newsletter

Over the last 20+ years I wrote a ton of code, ran mission critical systems and co-founded multiple startups. Lately as a Dad and the CTO I've been focusing on the topics of leadership, motivation and life observation.

Consider subscribing if you found my writing useful and relevant.

    I won't send you spam. Unsubscribe at any time.

    1 Comment

    1. Using njs (nginx js scripting) you can strip the whole $1$2 & co

      js_include x_proxypass.js;
      js_set $x_proxypass x_proxypass;

      location /x-proxypass/ {
      internal;

      proxy_buffering off;
      proxy_pass $x_proxypass;
      }

      With x_proxypass.js being

      function x_proxypass(r) {
      return String.bytesFrom(r.uri.replace(‘/x-proxypass/’, ”), ‘base64’);
      }

      Then, your script should use X-Acccel-Redirect: “/x-proxypass/ “+ base64encode(“https://aws stuffs with all the pass”)

      Reply

    Leave a Reply