nginx返回base64编码字符串中的自定义503页面,而不仅仅是html

fhg3lkii  于 7个月前  发布在  Nginx
关注(0)|答案(1)|浏览(78)

我在nginx上有一个奇怪的错误,当我试图在nginx上实现一个自定义的503错误页面时,我的维护期。
我的自定义页面位于/opt/app_name/maintenance_on. html
我的nginx配置看起来像这样:

server {
listen 80;

server_name app-name;
root /opt/app_name;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
proxy_set_header X-Client-IP $remote_addr;
proxy_set_header HTTP_X_FORWARDED_HOST $remote_addr;

access_log  /var/log/nginx/app-name-access.log;
error_log       /var/log/nginx/app-name-error.log;

proxy_buffers   16  64k;
proxy_buffer_size   128k;

proxy_read_timeout 900s;
proxy_connect_timeout 900s;
proxy_send_timeout 900s;

proxy_next_upstream error   timeout invalid_header  http_500    http_502
http_503;

types {
 text/less less;
 text/scss scss;
}

gzip    on;
gzip_min_length 1100;
gzip_buffers    4   32k;
gzip_types  text/css text/less text/plain text/xml application/xml applicatio>
gzip_vary   on;
client_header_buffer_size 4k;
large_client_header_buffers 4 64k;
client_max_body_size 0;

location / {
 if (-f /opt/app_name/maintenance_on.html) {
 return 503;
 }
 proxy_pass    http://127.0.0.1:XXXX;

 proxy_redirect off;
}

location /longpolling {
 proxy_pass http://127.0.0.1:XXXX;
}
location ~* .(js|css|png|jpg|jpeg|gif|ico)$ {
 expires 2d;
 proxy_pass http://127.0.0.1:XXXX;
 add_header Cache-Control "public, no-transform";
}

location ~ /[a-zA-Z0-9_-]*/static/ {
 proxy_cache_valid 200 302 60m;
 proxy_cache_valid 404      1m;
 proxy_buffering    on;
 expires 864000;
 proxy_pass    http://127.0.0.1:XXX;
}

error_page 503 @maintenance;
location @maintenance {
 rewrite ^(.*)$ /maintenance_on.html break;
}
}

字符串
页面看起来像这样:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
    <title>Performing Maintenance</title>
    <style type="text/css">
        body { text-align: center; padding: 150px; }
        h1 { font-size: 40px; }
        body { font: 20px Helvetica, sans-serif; color: #333; }
        #article { display: block; text-align: left; width: 650px; margin: 0 au>
        a { color: #dc8100; text-decoration: none; }
        a:hover { color: #333; text-decoration: none; }
    </style>
</head>
<body>
<div id="article">
    <h1>The system is currently getting some Updates.</h1>
    <div>
        <p>We apologize for the inconvenience, but we're performing some mainte>
        <p>&mdash; Maintainer</p>
    </div>
</div>
</body>
</html>


这个配置的问题是,nginx像预期的那样重定向到503,但是响应包含的html页面是base64编码的字符串,而不是html页面。所以浏览器不会显示任何东西。

xmjla07d

xmjla07d1#

虽然根本原因尚不清楚,但我能够找到解决方案。

TL;DR

default_type text/html;

字符串

分析

在这些配置用例中,唯一会发生变化的是add_headerdefault_type语句。

案例1:HTTP 200可以正常工作,但具有重复的标头

HTTP状态代码200似乎使nginx使用给定的头,尽管它得到了重复。

配置

server {
  listen 443 ssl http2;
  server_name ${SITES};
  ssl_certificate ${CERTLOC}/${SITE}/fullchain.pem;
  ssl_certificate_key ${CERTLOC}/${SITE}/privkey.pem;
  location / {
    add_header Content-Type text/html;
    return 200 '<!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>';
  }
}

响应

$ curl -I https://maintenance.molnix.com; echo ""; curl https://maintenance.molnix.com; echo ""
HTTP/2 200 
server: nginx
date: Tue, 07 Nov 2023 06:35:46 GMT
content-type: application/octet-stream
content-length: 383
content-type: text/html
    
<!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>

案例2:HTTP 503不起作用

将HTTP状态代码更改为503(与502相同,可能是其他代码)似乎会使nginx忽略内容类型头,并导致浏览器依赖于默认的八位字节流。

配置

server {
  listen 443 ssl http2;
  server_name ${SITES};
  ssl_certificate ${CERTLOC}/${SITE}/fullchain.pem;
  ssl_certificate_key ${CERTLOC}/${SITE}/privkey.pem;
  location / {
    add_header Content-Type text/html;
    return 503 '<!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>';
  }
}

响应

$ curl -I https://maintenance.molnix.com; echo ""; curl https://maintenance.molnix.com; echo ""
HTTP/2 503 
server: nginx
date: Tue, 07 Nov 2023 06:39:06 GMT
content-type: application/octet-stream
content-length: 383
    
<!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>

用例3:HTTP 503按预期工作

在这里,只设置默认类型会导致表面上nginx强制的头本身被更改,而不需要进一步的设置。因为它不是add_header语句,所以它还具有允许继承其他头的好处,这降低了配置的复杂性。

配置

server {
  listen 443 ssl http2;
  server_name ${SITES};
  ssl_certificate ${CERTLOC}/${SITE}/fullchain.pem;
  ssl_certificate_key ${CERTLOC}/${SITE}/privkey.pem;
  default_type text/html;
  location / {
    return 503 '<!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>';
  }
}

响应

$ curl -I https://maintenance.molnix.com; echo ""; curl https://maintenance.molnix.com; echo ""
HTTP/2 503 
server: nginx
date: Tue, 07 Nov 2023 06:39:44 GMT
content-type: text/html
content-length: 383
strict-transport-security: max-age=15768000
    
<!DOCTYPE html><html><meta http-equiv="refresh" content="60"><title>Maintenance</title><body><style>body { text-align: center; padding: 150px; font: 20px Helvetica, sans-serif; color: #333; }</style><div><h1>Maintenance ongoing &#x1F477;</h1><p>The page will reload automatically once maintenance has completed, or you can <a href="">click here to reload</a>.</p></div></body></html>

注解

  • 最后一个响应中的HSTS头来自conf.d,在此站点配置中不使用头语句时会保留该头。对于OP情况,可以忽略响应的该部分。
  • curl似乎可以自动解码base64,这与浏览器完全不同,在浏览器中,响应和页面根本不呈现,或者浏览器对八位字节流进行编码(如果还没有)。我没有检查原始数据流来确认,因为它不会影响实际意义。
  • 如果您正在试用这些配置,请将${SITES}替换为您的站点,例如我们使用maintenance.molnix.com,将${CERTLOC}/${SITE}替换为您的证书路径-在本示例中,此路径遵循Let's Encrypt约定,分别为/etc/letsencrypt/livemaintenance.molnix.com
  • 在Ubuntu 22.04 LTS库存软件包上测试

相关问题