Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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;
}
share|improve this question
    
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 2 '11 at 1: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 Nov 2 '11 at 2: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 2 '11 at 3: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 Nov 2 '11 at 3:21
    
Where did you put 400.html file? Insert a error_log directive and take a look at that. –  quanta Nov 2 '11 at 3:48

1 Answer 1

up vote 1 down vote accepted

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;
    }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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