6

So, when doing curl -i http://example.com on my server, I get this response in body:

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>

It shows that I'm running nginx and I'd like to remove this information.

Here's my nginx.conf redirect to HTTPS (together with my try to change 301 response body):

server {
    listen       80;
    server_name  localhost;
    error_page 301 = /301.html;
    location /301.html {
        return 301 "<h1>use https</h1>";
    }
    return 301   https://$host$request_uri;
}

Any idea how to change 301 response body?

1

5 Answers 5

4

There's a great post about custom error pages at the following URL. The following is an abbreviated version of how it can be used to remove nginx branding from the 301 and 302 HTTP responses.

One NGINX error page to rule them all

nginx.conf

http {

  map $status $status_text {
    301 'Moved Permanently';
    302 'Found';
  }

  server {

    listen 1.1.1.1;
    server_name _;

    error_page 301 302 /error.html;

    location = /error.html {
      ssi on;
      internal;
      auth_basic off;
      root /var/website/custom_error_pages;
    }

    root /var/website/empty_dir;
  
    location / {
      return 301 https://www.website.com$request_uri;
    }
}

/error.html

<html>
  <head><title>www.website.com</title></head>
  <body><h1>
    <!--# echo var="status" default="000" --> - <!--# echo var="status_text" default="Error" -->
  </h1></body>
</html>
1

create file 301.html, this file should contains content which you want to display. If path to file is /usr/share/nginx/html/301.html adjust config to:

server {
    listen       80;
    server_name  localhost;

    location / {
        error_page 301 = /301.html;
        return 301   https://$host$request_uri;
    }

    location /301.html {
        root /usr/share/nginx/html/;
    }

}

And this will return your custom 301.html file

1
  • 2
    This actually changes HTTP code to 200 which stops the actual redirect. A very bad solution. Jan 17, 2018 at 3:19
0

Try placing your return 301 https://$host$request_uri; directive inside a location / { block. Just that one line.

server {
    listen       80;
    server_name  localhost;
    error_page 301 = /301.html;
    location /301.html {
        return 301 "<h1>use https</h1>";
    }
    location / {
        return 301   https://$host$request_uri;
    }
}
1
  • I dont think this will work since second param to 301 modifies location header instead of body.
    – svobol13
    Sep 12, 2019 at 19:21
0

It is a bit hacky and confusing, but it works:

server {
    listen       80;
    server_name  localhost;
    error_page 301 /_use_https_;

    location = /_use_https_ {
        internal;
        # We have to return 200 to modify content. 
        # If we would use 301 we would modify Location header.
        # Dont worry, HTTP status will be 301.
        return 200 "<h1>use https</h1>";
    }

    # redirect has to be enclosed in location
    location / {   
         return 301 https://$host$request_uri;
    }
}
0

The accepted answer by phbits is great, but there are some pitfalls if you want to apply this to a reverse-proxy situation with proxy_intercept_errors on, so that the error page also replaces errors sent by the backend (related mailing list thread).

If your backend replies with a 301 or 302, nginx will drop the Location: header when serving the error page to the client, despite retaining the correct status code. So the client will see a page that says <h1>302 Found</h1> but will not be redirected. The solution is to re-add the Location header from the upstream response using add_header Location "$upstream_http_location".

This took me some time to figure out, so below is my complete setup, based on Adriaan's Blog, in case someone runs into the same situation in the future.

/etc/nginx/sites-enabled/myserver.conf

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example.com;

    include snippets/errorpage.conf;

    location / {
        proxy_pass http://127.0.0.1:7080/;
        proxy_set_header Host $http_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-Proto $scheme;
    }
}

/etc/nginx/snippets/errorpage.conf

error_page 01 302 303 304 307 308 400 401 402 403 404 405 406 407 408 409 410      
    411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 
    431 451 500 501 502 503 504 505 506 507 508 510 511 /error.html;
                                                                    
location /redirect-test {        # Just for testing                                   
    return 302 /foo-bar;         # Use nc example.com 80 <<<$'GET /redirect-test HTTP/1.0\r\nHost: example.com\r\n\r\n'                                   
}                                                                   
                                                                    
proxy_intercept_errors on;                                          
location = /error.html {                                            
  ssi on;                                                           
  internal;                                                         
  auth_basic off;                                                   
  root /var/www/default;                                            
  add_header Location "$upstream_http_location";                    
}                                                                   

/etc/nginx/conf.d/status-codes.conf

map $status $status_text {
  301 'Moved Permanently';
  302 'Found';
  303 'See Other';                                                                                      
  304 'Not Modified';                                                                                   
  307 'Temporary Redirect';                                                                             
  308 'Permanent Redirect';      
  400 'Bad Request';
  401 'Unauthorized';
  402 'Payment Required';
  403 'Forbidden';
  404 'Not Found';
  405 'Method Not Allowed';
  406 'Not Acceptable';
  407 'Proxy Authentication Required';
  408 'Request Timeout';
  409 'Conflict';
  410 'Gone';
  411 'Length Required';
  412 'Precondition Failed';
  413 'Payload Too Large';
  414 'URI Too Long';
  415 'Unsupported Media Type';
  416 'Range Not Satisfiable';
  417 'Expectation Failed';
  418 'I\'m a teapot';
  421 'Misdirected Request';
  422 'Unprocessable Entity';
  423 'Locked';
  424 'Failed Dependency';
  425 'Too Early';
  426 'Upgrade Required';
  428 'Precondition Required';
  429 'Too Many Requests';
  431 'Request Header Fields Too Large';
  451 'Unavailable For Legal Reasons';
  500 'Internal Server Error';
  501 'Not Implemented';
  502 'Bad Gateway';
  503 'Service Unavailable';
  504 'Gateway Timeout';
  505 'HTTP Version Not Supported';
  506 'Variant Also Negotiates';
  507 'Insufficient Storage';
  508 'Loop Detected';
  510 'Not Extended';
  511 'Network Authentication Required';
  default 'Something is wrong';
}

/var/www/default/error.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>example.com Error</title>
  </head>
<body>
    <h1><!--# echo var="status" default="" --> <!--# echo var="status_text" default="Something goes wrong" --></h1>
</body>
</html>

/etc/nginx/conf.d/no-headers.conf

#more_clear_headers Server;   # Remove Server header, or
more_set_headers 'Server: haproxy'; # Or whatever

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .