Error pages not used

How can I load different error pages depending on conditions? If I’m loading /html/goodpages/test it should try /html/goodpages/test.html unless one of the conditions is true, then it should load the right error page from /html/errorpages. I’ve read about if is evil but it doesn’t explain how to fix it. It’s a very simple case it shouldn’t be so hard.

server {
    root /html/goodpages;
    if ($condition != 1) {
        return 400;
    }
    if ($condition != 2) {
        return 401;
    }
    if ($condition != 3) {
        return 403;
    }
    try_files $uri.html;
    error_page 400 /html/errorpages/error400.html;
    error_page 401 /html/errorpages/error401.html;
    error_page 402 /html/errorpages/error402.html;
}

Hello,

I think you are almost there, you would just be missing what is required to make sure you are serving the error pages.

With the return directive, you are indeed defining the error code you want to return (Module ngx_http_rewrite_module), with the error_page, you are defining the URI that should be shown where the error codes happen (Module ngx_http_core_module), but have you made sure that your files in /html/errorpages can be served by NGINX?

From my understanding of the error_page directive’s parameters, it’s not:

error_page [code] [file_path_to_serve_content_from]

Because as explained in the doc, the [uri] parameter is used to perform an “internal redirect”. It’s as if NGINX would make a request to itself to find the content to be returned to the user.

Therefore, for this to work, you’d have to be able to serve the content of your error pages files.

I’d try this conf to edit the one you provided as an example:

server {
    root /html/goodpages;
    if ($condition != 1) {
        return 400;
    }
    if ($condition != 2) {
        return 401;
    }
    if ($condition != 3) {
        return 403;
    }
    try_files $uri.html;
    error_page 400 /errorpages/error400.html;
    error_page 401 /errorpages/error401.html;
    error_page 402 /errorpages/error402.html;

    location /errorpages {
        root /html/errorpages;
    }
}

Do you see better what would be missing? Could you try these modifications in your environment see if it’s any better?

I tried but it didn’t work. Can you try this example?

server {
  listen 80;
  root /html/goodpages;

  if ($condition = 1) {
    return 400;
  }

  try_files $uri =404;

  error_page 400 /ERRORPAGES/error400.html;
  error_page 404 /ERRORPAGES/error404.html;

  location /ERRORPAGES {
    alias /html/errorpages;
    try_files $uri =404;
  }
}

I used a different location path and changed root to alias.

Loading /ERRORPAGES/error400.html and /ERRORPAGES/error404.html in the browser return 200 because the /html/errorpages/error400.html and /html/errorpages/error404.html exist.

Loading /DoesntExist returns 404 and shows /html/errorpages/error404.html.

But if the condition is true it shows the default Nginx 400 page not /html/errorpages/error400.html. You can try it with if ($scheme = "http").

Why is 404 working but not 400?

Hello,
Indeed I tested and you are right, it did not work as expected. I tried some modifications, and for some reason, the following worked:

map $scheme $condition {
    "http" 1;
    default 2;
}

server {
  listen 80;
  root /etc/nginx/html/goodpages;

  error_page 400 /errorpages/error400.html;
  error_page 404 /errorpages/error404.html;

  location / {
    if ($condition = 1) {
      return 400;
    }
  }

  location /errorpages/ {
    root /etc/nginx/html;
  }
}

So it seems putting your rule in a “location” worked better. Maybe due to the internal redirect nature of the error_page, having the whole server block keeping to trigger a 400 error would not properly allow the error page to work. Could you try and let me know if this works as you’d expect?

Cheers.

Thanks I wouldn’t have guessed this. Can someone from nginx explain what is happening or document it?