随记一些在日常需求中遇到有关 web server 的配置
Nginx Upstream Header Buffer 相关
业务研发反馈 nginx (fastcgi php) 返回 502 错误,看了一下日志如下:
WARNING
upstream sent too big header while reading response header from upstream
明显是因为 header 头过大,因为 Nginx 默认通常基本就 4k / 8k 左右(因系统而已),“上游”可能有不同应用(如proxy / fastcgi /uwsgi)可以适当设置一下相应的 *_buffers
和 *_buffer_size
以使适当的缓冲区更大,如这里的 PHP 的 fastcgi
*_buffers 16 32k;
*_buffer_size 64k;
*_busy_buffers_size 64k;
#php fastcgi buffer
fastcgi_buffers 32 32k;
fastcgi_buffer_size 128k;
*_buffers 16 32k;
*_buffer_size 64k;
*_busy_buffers_size 64k;
#php fastcgi buffer
fastcgi_buffers 32 32k;
fastcgi_buffer_size 128k;
关于跨域问题配置相关
前端页面有需求通过 Ajax 下载图片资源,反馈需要增加文件存储服务(如图片资源)支持允许跨域访问(指定某个或某些域名),因为默认是不允许,为了防止被盗链之类,通常会配置限制指定域名;
Nginx 可以新增类似如下配置支持
map $http_origin $allow_origin {
~^https?://(blog\.)?yousri\.org$ $http_origin;
~^https?://(log\.)?yousri\.org$ $http_origin;
default "";
}
server {
...
location / {
try_files $uri $uri/ /index.php;
if ($request_method = 'OPTIONS'){
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
return 200;
}
if ($allow_origin != "") {
add_header 'Access-Control-Allow-Origin' $allow_origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Credentials' 'true';
}
}
}
map $http_origin $allow_origin {
~^https?://(blog\.)?yousri\.org$ $http_origin;
~^https?://(log\.)?yousri\.org$ $http_origin;
default "";
}
server {
...
location / {
try_files $uri $uri/ /index.php;
if ($request_method = 'OPTIONS'){
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
return 200;
}
if ($allow_origin != "") {
add_header 'Access-Control-Allow-Origin' $allow_origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Credentials' 'true';
}
}
}
这里使用了map指令来定义一个变量$allow_origin,它根据请求中的$http_origin来匹配允许的域名,也可以直接使用正则表达式来匹配允许的域名
server {
...
location / {
if ($http_origin ~* "^https?://(blog\.yousri\.org|log\.yousri\.org)$") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
}
...
}
...
}
server {
...
location / {
if ($http_origin ~* "^https?://(blog\.yousri\.org|log\.yousri\.org)$") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
}
...
}
...
}
结合配置下载站 备注下 location / root / alias 关系
location 和 root 组合可以理解为在 root 指定目录下进行 location 匹配,location 所匹配内容必须保证在 root 指定目录的子目录,否则配置无效,而且 location 只能向下匹配,不能匹配 location 指定目录上一级目录中的内容。
location ^~ /android/client {
root /app;
if ($request_filename ~* ^.*?\.(pdf|rar|gz|zip|apk|ipa|plist)$){
add_header Content-Disposition: 'attachment;';
}
}
location ^~ /android/client {
root /app;
if ($request_filename ~* ^.*?\.(pdf|rar|gz|zip|apk|ipa|plist)$){
add_header Content-Disposition: 'attachment;';
}
}
这里需要确保 /app 目录下有 location 所要匹配的目录存在,即 /app/android/client 目录存在,否则将匹配失败文件不存在的问题;
location 与 alias 组合,需要保证 location 匹配目录与 alias 指定目录级别相同,否则配置无效,与 location 和 root 组合相同的是,location所匹配内容也只能向下匹配。
location ^~ /android/client {
alias /app/android/;
if ($request_filename ~* ^.*?\.(pdf|rar|gz|zip|apk|ipa|plist)$){
add_header Content-Disposition: 'attachment;';
}
}
location ^~ /android/client {
alias /app/android/;
if ($request_filename ~* ^.*?\.(pdf|rar|gz|zip|apk|ipa|plist)$){
add_header Content-Disposition: 'attachment;';
}
}
上面两种方式的配置,请求同一个 URL 地址,如请求 http://abc.com/android/client/abc.apk
访问文件时,实际的区别主要是:
使用 root 配置情况下,请求到在服务器上的文件路径实际是 /app/android/client/abc.apk;
而如果使用 alias 配置时,请求到在服务器上文件路径实际情况其实是 /app/android/abc.apk;
TIP
使用 alias ,目录名后面一定要加 “/”; alias 只能在location中使用;
关于反向代理功能配置相关
- Proxy 配置允许最大上传配置
client_max_body_size 256m;
client_max_body_size 256m;
TIP
这个参数需要重启 nginx 才可生效,reload 是无法生效
Apache
业务层面原本希望在入口 Haproxy 增加一个配置, 当一个请求 如果有 x-request-id 这个请求头, 则代理的时候也需要把这个请求头传递下去, 如果没有 则 haproxy 用 uuid() 创建一个,然后传递下去。Haproxy access log 需要显示 这个 x-request-id;
因为实际环境中目前 Haproxy 配置使用的模式 TCP,只做 4 层转发功能,并非 7 层转发代理;
遂要在请求入口生成 uuid 作为 trace id 只能在 Apache 层面生成;
所以只能使用 Apache 的 unique_id 模块来实现唯一的 uuid,后端可通过 HTTP_X_REQUEST_ID 获取(或通过默认的 UNIQUE_ID 值获取);
a2enmod unique_id
service restart apache2
## mod_unique_id 生成的token放入环境变量 UNIQUE_ID, 可通过 %{UNIQUE_ID}e 打印 Log Format
#set conf add
<IfModule unique_id_module>
SetEnvIf X-Request-Id "^$" no_request_id
RequestHeader set X-Request-Id %{UNIQUE_ID}e env=no_request_id
</IfModule>
#set conf add header
<IfModule mod_headers.c>
Header add x-request-id %{UNIQUE_ID}e
</IfModule>
a2enmod unique_id
service restart apache2
## mod_unique_id 生成的token放入环境变量 UNIQUE_ID, 可通过 %{UNIQUE_ID}e 打印 Log Format
#set conf add
<IfModule unique_id_module>
SetEnvIf X-Request-Id "^$" no_request_id
RequestHeader set X-Request-Id %{UNIQUE_ID}e env=no_request_id
</IfModule>
#set conf add header
<IfModule mod_headers.c>
Header add x-request-id %{UNIQUE_ID}e
</IfModule>