CakePHP 4 $this->request->referer() not working in production

Written by James McDonald

June 24, 2020

Just had a situation where I couldn’t get a redirect to work. My CakePHP app is in an Apache enabled docker container behind an nginx reverse proxy


The above simply refused to work in my development environment it worked fine

http://localhost:8090/blah/ worked fine


and it would return nothing

It turned out that if your hostnames don’t match i.e. your front end is accessed via and your backend is accessed via http://localhost:8090/blah then a call to $request->referer() return bupkis

This works although I imagine some sanitizing needs to be done to stop it just accepting any forged referer URL

$this->redirect($this->request->referer($local = false));


$referer = $this->request->referer(false);
if( preg_match('', $referer ) === 1 ) {
     return $this->redirect($referer);
} else {
     return $this->redirect([ 'action' => 'index' ]);

Taking into account a trusted proxy (i.e. it can tell you what the external http_host name is)

        $this->request->trustProxy = true;
        $referer = $this->request->referer($local = false);
        $host = $this->request->host(); 
        $scheme = $this->request->scheme();

        if (preg_match('/^' . $scheme . ':\/\/' . $host . '/', $referer) === 1) {
            return $this->redirect($referer);
        return $this->redirect(['action' => 'index']);

Nginx Configuration

Note I’m only trusting this because nginx is setting the headers:

upstream my-test {
location /test {
    proxy_pass http://my-test;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $server_name;
    proxy_set_header X-Forwarded-Proto https;

Notes about this nginx config

Front end running https Backend running http

This nginx frontend server block is running ssl enabled

The backend is running only http so specify http:// to upstream

proxy_pass http://my-test;

Proxy Pass Trailing Slash or Lack of it Changes the Behavior

Without a trailing slash

If you specify no trailing forward slash then the location and all subsequent pieces are passed. For example a request made to the front end nginx to:
# is passed to the backend as

With a trailing slash

if you specify proxy_pass http://my-test/; a request to will be passed on without the location /test parameter
# is passed to the backend as

X-Forwarded-Proto Header Required

I found if I didn’t set this header

proxy_set_header X-Forwarded-Proto https;

Then after I posted a delete e.g. POST /test/controller/delete/23 the 302 redirect issued to the client would have the wrong scheme in the location header:


And then nginx would issue an internal redirect and mess-up the redirect

with the X-Forwarded-Proto header set it performed as required



Submit a Comment

Your email address will not be published.

You May Also Like…

PHP Iterators

Just came across a Youtube talk "Iterators in PHP" by Jake Smith published in 2014 that steps through the many...

PHP array_map Multiple Arrays

array_map can take multiple arrays. I like how it starts mapping through them starting at the first element of each...