0

I currently have a web app set up behind nginx and need to move it over to Apache httpd.

One feature that is currently missing that I really want to re-implement is a X-Accel-Redirect based feature.

Unlike X-Sendfile, the value for X-Accel-Redirect is treated as an URL, so I can perform all of the same functions on it that I can any other location. In this case, I'm using it to get the actual file from an external server rather than directly from the local server.

Here's the relevant configuration:

location ~* ^/secure-download(.*) {
    internal;

    set $file_info  'attachment; filename=${upstream_http_filename}';
    add_header      Content-Disposition $file_info;

    # proxy configuration code here

    proxy_cache             cachename;
    proxy_cache_valid       200 302 60m; # cache successful responses for 60min
    proxy_cache_valid       404     1m; # cache missing responses for 1min

    resolver                172.31.0.2 8.8.4.4 8.8.8.8 valid=300s;
    resolver_timeout        10s;

    proxy_pass              'https://proxy-server.example.org/$1';

}

There are a lot of advantages to this:

  • I don't have to store the content locally
  • I can manually set the filename downloaded
  • The browser doesn't have to redirect to a different URL
  • I don't have to make the web application download and then serve the content, which is slower.

The problem, as far as I can tell, is there isn't a similar functionality in apache httpd — one that basically says, "Stop serving all of the content I just created and instead serve the URL located in this header".

If this isn't possible I'll probably just rewrite the web app so it downloads the content of the file from the external URL and then serves it, even though that's really a non-ideal situation.

  • Why does the webapp need to service the /secure-download.* path? What value is it adding over just having the webserver handle it? – Jonah Benton Sep 2 '16 at 2:31
  • This is just how you implement X-Accel-Redirect. Because nginx treats it as an URL, you have to specify a location (in this case I'm using secure-download). If I just had the web server handle it as a normal file, then it would need to be in a web accessible root. These files aren't public access and need to be restricted. X-SendFile and X-Accel-Redirect are the standard choice for implementing this unless you opt to download the data in the webapp and serve it directly. – Jordan Reiter Sep 2 '16 at 19:14
  • 1
    There is an x-sendfile module for apache, but it does not support non-filesystem urls. What one could do is use httpfs, a fuse filesystem module, to "mount" remote http servers into the local filesystem, and then x-sendfile from those mount points. Thats a use at ones own risk solution. The question above was more in the vein of- a more ergonomic alternative to x-accel-redirect is to use some webserver supported authorization in front of an ordinary proxy configuration. Is there a reason that the application has to do authorization, rather than the web server? – Jonah Benton Sep 2 '16 at 22:36
  • Yes, web server-based authorization is pretty basic and coarse. A common use case is digital subscriptions/purchases. A user might have access to some but not all of the digital resources, and this information will be stored in a database somewhere. At that point, trying to use the web server's built in authentication methods just isn't going to cut it, especially if access information is stored in a database rather than the filepath. – Jordan Reiter Sep 16 '16 at 16:37
1

Submitting comment as answer for future reference.

There is no directly comparable functionality for apache.

There is an x-sendfile module for apache, but it does not support non-filesystem urls.

What one could do is use httpfs, a fuse filesystem module, to "mount" remote http servers into the local filesystem, and then x-sendfile from those mount points.

That's a "use at one's own risk" solution.

One alternative is as mentioned- change the app to redirect to an external URL.

Another that was not discussed is to use some webserver supported authorization- check for the presence of a cookie or similar- in front of an ordinary remote proxy configuration. This is more sympathetic to the usage of webservers, though may not work for reasons as yet not discussed.

  • Your response answers my question of whether it's possible in Apache httpd — it isn't. Unless I'm missing something, you'd have to reference the file you want directly (e.g. long_unfriendly_path_I_dont_want_users_to_see.pdf) rather than a clean URL like /download/1234.pdf. Or I suppose you might be able to store both the authorization and desired path in cookies, but it's not even clear how that would work. For instance you'd need to provide an intermediate page that set the cookie and then redirected to the download url. – Jordan Reiter Sep 16 '16 at 16:41
0

I just ended up adding code on the application end that downloads the desired file from the proxy and serves it.

Although there's more overhead than the web server serving it directly the response time is still pretty good — I don't notice any slowdown or any apparent additional load. It's possible that this might happen for very large files, in which case I might come up with an alternate solution just for those cases.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.