9

I'm trying to return a custom 400 error page for non-HTTPS requests in nginx. I'm new to nginx, but I've read many pages of examples on custom error pages and nothing seems to work for me. My config:

server {
    listen 80;

    error_page 400 /400.html;
    location = /400.html {
        root /var/www/html;
    }

    return 400;
}

The return is working, because if I change the code (e.g. to 401 or 500) I get the appropriate default nginx error page. I know that the file exists, because if I take out the return it will serve my 400.html page directly with no problems. But nothing I've tried has resulted in my custom page showing up when I return the error code.

What am I missing?

Update: Other variants I've tried to no avail:

server {
    listen 80;

    error_page 400 /400.html;
    location = /400.html {
        root /var/www/html;
    }

    return 400;
}

server {
    listen 80;

    root /var/www/html;

    error_page 400 /400.html;
    location = /400.html {
        allow all;
    }

    return 400;
}

server {
    listen 80;

    root /var/www/html;
    error_page 400 /400.html;

    return 400;
}
Derek Shockey
  • 344
  • 2
  • 7
  • Specify your root directive outside the location block (i.e. server{root /var/www/html; error_page 400 /400.html; location = /400.html{allow all;}} - I don't think you should even need the location block. (Are you trying to receive SSL connections on port 80, or is the if block just for testing?) – cyberx86 Nov 02 '11 at 01:16
  • @cyberx86 Thanks for the comment. I should have mentioned I've tried variations of moving root around, and originally I had no location block at all. No matter what I still never get my custom error page. I'm not trying to receive SSL connections on port 80, I'm actually trying to show the custom error to all :80 connections assuming they are not SSL. I guess in light of that the _if_ block is not necessary, but removing that didn't help either. – Derek Shockey Nov 02 '11 at 02:25
  • That server block won't ever intercept an SSL connection - unless you are forcing the connection to port 80 - SSL connections happen by default on port 443 - you have told nginx to listen on port 80. So, you never hit the SSL 400 error. Two suggestions - a) try to confirm the above - visit a non-existent 'regular' (non-ssl) page - see if you get your custom error page; maybe add `default` to your listen line. b) create a second server block for ssl - baring that, you can add a line `listen *:443 ssl;` to the server block above - either way, you will need to specify the ssl certificate and key. – cyberx86 Nov 02 '11 at 03:11
  • @cyberx86 I think you're misunderstanding me. I am not trying to do anything here with SSL connections; I am trying to do exactly the opposite, i.e. do something with non-SSL connections (specifically, reject them with a custom error page). The configuration handling SSL connections is in another server block listening to port 443, and that part works fine. – Derek Shockey Nov 02 '11 at 03:21
  • Where did you put `400.html` file? Insert a `error_log` directive and take a look at that. – quanta Nov 02 '11 at 03:48

1 Answers1

9

I found this question on Stackoverflow that accomplishes what I was looking for.

I guess for whatever reason even though a return works inside of a server block, it does not respect any error_page directives. This may be a bug, or an intentional behavior I don't understand. The solution is to put the return inside of a location block:

server {
    listen 80;

    root /var/www/html;

    error_page 400 /400.html;
    location = /400.html {
        internal;
    }

    location / {
        return 400;
    }
}
Derek Shockey
  • 344
  • 2
  • 7