Using X-Accel-Redirect with PHP?

I’m trying to serve files via PHP using the X-Accel-Redirect header. Here’s the PHP file I have:

<?php
header('Cache-Control: public, must-revalidate');
header('Pragma: no-cache');
header('Content-Type: image/jpg');
header('Content-Disposition: attachment; filename=background.jpg');
header('Content-Transfer-Encoding: binary');
header("X-Accel-Redirect: /home/pi/caddywww/images/background.jpg");
?>

This just produces an empty file and the jpeg file isn’t served. Where am I going wrong? Is there a setting I need to make in my Caddyfile to get this to work?

It would appear that I need to use the http.internal directive in my Caddyfile to do this, but I’m not getting anywhere. Here is what my Caddyfile looks like now:

192.168.1.77:443 {
    root /home/pi/caddywww

	
    gzip
    fastcgi / /var/run/php/php7.0-fpm.sock {
        ext   .php
        split .php
        index index.php
    }
	
	internal /internal
	proxy /private http://localhost:9000
	

}

And here is what my PHP file currently looks like:

<?php
header('Content-Type: text/plain');
header("X-Accel-Redirect: /private/file.txt");
?>

I have file.txt in the /internal folder. When I try to access http://192.168.1.77:443/internal/file.txt, I get a 404 error. Which is what is expected.

However, when I try to to go to the PHP file to load that text file, I just get a 502 bad gateway error. I’m guessing it’s to do with the proxy line in the Caddyfile, but I don’t know what I am suppose to put there.

Hi @peter, unfortunately I have zero experience with sendfile/accel-redirect, but this part:

A 502 should only come if there’s a problem with the upstream server. For example - if the PHP script was generating a 404 somehow, or redirecting Caddy to another Location with the file that returned 404, then that response should be returned to the client, not a 502. That one should just be sending a few headers, there shouldn’t be any 502 involved. Does a simple PHP file with no X-Accel-Redirect (e.g. just an echo "test" or something) work?

PHP is definitely working fine. I have several PHP files running on Caddy. Interestingly, if I add this header to the PHP file:

header('Content-Disposition: attachment; filename=file.txt');

I then get a file not found error when I try to access the PHP file. So it seems like it’s attempting to redirect, but just failing (or maybe redirecting to the wrong location).

I’ve been trying to use the documentation here: https://caddyserver.com/docs/internal But it’s really sparse. I understand that using internal /internal will restrict access to the folder named eternal, and this works fine. I just don’t know what I put for the proxy portion that’s required to get this all working.

I found this example of what I am trying to accomplish using Caddy and the Go language: https://github.com/kschaper/caddy-internal-example

It appears they are using Go on port 9000, where as I have PHP setup as a Unix socket (I wouldn’t even know how to change this if I wanted to). I tried changing my proxy line in the Caddyfile to this:

proxy /private unix:/var/run/php/php7.0-fpm.sock

But still not working.

What’s the proxy for, exactly?

Edit: proxy is for proxying HTTP content. Your PHP socket is a FastCGI listener, not HTTP.

I think I figured it out! I removed the proxy line from the Caddyfile completely (leaving just the internal directive).

Then, my PHP file looks like this:

header('Content-Type: text/plain');
header("X-Accel-Redirect: /internal/file.txt");

Now when I go to the PHP file, the file.txt is loaded. However, if I try to access internal/file.txt directly, I get a 404 error (which is exactly what I want). My original attempt wasn’t using the internal directive, so it didn’t work.

My second attempt was using the example with a proxy. The whole proxy thing was throwing me off (I’m sure there is a reason for it in the documention and the example I linked to, but I can’t figure that out).

Anyways, thanks for the help. The purpose of this is to have a directory full of files that can only be accessed if the user authenticates themselves via a PHP auth system.

1 Like

Excellent! Not that I was much help here, I think, but glad you’ve got it working.

Now that I have it working, I’m trying it with some larger files (the background.jpg that I referenced in the first post). This file is 700kb and it takes noticeably longer to load. If I load background.jpg directly from Caddy, it pops up almost instantly on my local network. If I try to access it through the PHP file using X-Accel-Redirect, it takes a second to “draw” the image on the screen.

In order to test this further, I loaded a 100MB file onto the Caddy server. Downloading it via the webbrowser from the Caddy server results in a 8.1 MB/s transfer rate. Caddy is running on a Raspberry Pi 2, so not the speediest, but fine for my needs.

Now, downloading the same file through PHP using X-Accel-Redirect, results in a 1.3 MB/s transfer rate. More than 6 times slower!

It was my impression that X-Accel-Redirect was designed to avoid slowdowns like this. Back to the drawing board.

I also had a Raspi 2, and can confirm that is roughly the maximum transfer speed it is capable of. :slight_smile:

Are both your tests running through PHP? If so, that is almost certainly a bug in Caddy. If not, I’d suspect the slowdown is not X-Accel-Redirect, but the proxying to PHP instead (even so, I’d expect that to be faster in Caddy 2, where we’ve already made a number of significant optimizations over Caddy 1!).

Hi Matt,

Both of my tests are not running through PHP, only the slow test. I thought the purpose of X-Accel-Redirect was to essentially “hand off” the files back to the webserver, so that PHP wasn’t involved any longer (thus resulting in a much faster speed). Here’s a blog that talks about this https://idiallo.com/blog/making-php-as-fast-as-nginx-or-apache I could be misunderstanding this though.

I’m not running Caddy 2, I just checked and it looks like it’s version 0.10.11 (I installed it last year, and I’m not great with Linux so I don’t like messing with things once I have them working). I’ve borked my Raspberry Pi install a few times in the past and the only way I could get it going again was to wipe the SD card and start fresh.

Is there a relatively safe way to upgrade to a newer version of Caddy?

Edit: Just upgraded to Caddy 1.0.1 without breaking anything (yay), slow speeds in X-Accel-Redirect remain the same.