「Nginx」- 反向代理常用配置(proxy_pass)

问题描述
该笔记将记录:与 proxy_pass 有关的常见问题,以及使用配置
解决方案
使用方法可以参考 Module ngx_http_proxy_module / proxy_pass 文档

location /some/path/ {
proxy_pass http://localhost:8000;

proxy_set_header Host $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;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
}

场景:通过不同的 URI 进行反向代理
Module ngx_http_proxy_module / proxy_pass How to remove the path with an nginx proxy_pass – Server Fault How can query string parameters be forwarded through a proxy_pass with nginx? – Stack Overflow
问题描述
1)访问 http://example.com/a/foo/auth 地址,则反向代理到 http://127.0.0.1:8443/foo/auth 地址 1)访问 http://example.com/b/foo/auth 地址,则反向代理到 http://127.0.0.1:8993/foo/auth 地址
解决方法

server {
listen 80;
server_name example.com;

location /a/ {
# 注意,一定要使用 http://127.0.0.1:8443/ 而不是 http://127.0.0.1:8443,否则 传递的 URL 将携带 /a/ 前缀
# 参考文档对 proxy_pass 的描述(是否携带 URI 的区别)
proxy_pass http://127.0.0.1:8443/;

# 传递请求头(默认)
proxy_pass_r[……]

READ MORE

「Nginx」- 配置 GZIP 压缩

通过压缩,可以减少网络传输。压缩的大致流程如下:

用户请求资源文件 => Nginx 压缩被请求的文件 => Nginx 响应被压缩的文件 => 浏览器解压被压缩的文件 => 用户得到资源文件

压缩带来的优点: 1)减小传输文件的大小 2)节约带宽资源 3)提高资源响应速度
压缩带来的缺点: 1)服务端压缩需要消耗 CPU 资源; 2)客户端解压需要消耗 CPU 资源;
配置压缩
配置压缩需要使用 ngx_http_gzip_module 模块,下面是实例配置:

gzip on;
gzip_http_version 1.1;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_types text/plain text/html text/css application/json application/javascript application/x-javascript text/javascript text/xml application/xml application/rss+xml application/atom+xml application/rdf+xml;

# make sure gzip does not lose large gzipped js or css files
# https://web.archive.org/web/20080301065334/http://blog.leetsoft.com/2007/7/25/nginx-gzip-ssl
gzip_buffers 16 8k;

# Disable gzip for certain browsers.
gzip_disable “MSIE [1-6].(?!.*SV1)”;

#
gzip_min_length 20;

测试压缩
使用 CURL 测试 GZIP 压缩是否生效,如果相应中包含 Content-Encoding: gzip 则表示开启成功。如下示例:

# curl –head –header “Accept-Encoding: gzip” “https://example.com/path/to.js”
HTTP/1.1 200 OK
Date: Wed, 20 May 2020 08:10:33 GMT
Content-Type: application/javascript
Last-Modified: Wed, 20 May 2020 02:04:22 GMT
Connection: keep-alive
Vary: Accept-Encoding[……]

READ MORE

「Nginx」- 重定向 HTTP 到 HTTPS 链接

问题描述
自从大规模使用 HTTPS 之后,所有的 HTTP 访问都要重定向到 HTTPS 站点。不然,客户只会输入域名,而很多浏览器又默认使用 HTTP 协议,如果我们没有提供 HTTP 访问,又不重定向,那客户将看到一个空白页(无法访问),客户会以为我们的站点有问题,毕竟客户哪里知道什么是 HTTP 什么是 HTTPS。
因此,我们需要将 HTTP 请求重定向到 HTTPS 站点。当然,这种重定向一般是针对 GET 请求的,没有必要复杂到将 HTTP Post 请求重定向到 HTTPS Post 请求,所以我们也没有讨论这些问题,以后遇到再说。
该笔记将记录:在 Nginx 中,如何重定向 HTTP 请求到 HTTPS 请求,以及写通用便捷的做法。
解决方案
方案一、常规方案
常规方案就是,为每个站点添加重定向,配置大概就是下面的结构:

server {
listen 80;
server_name http.example.com;
rewrite ^(.*) https://$server_name$1 permanent;
}

server {
server_name https.example.com;
listen 443 ssl;

ssl_certificate /path/to/pem;
ssl_certificate_key /path/to/key;

location / {}
}

但是,这种方法最大的问题就是:要为每个域名添加 HTTP 重定向(如第一个 server {} 的配置),那有没有什么方法可以“一劳永逸”呢?那必须有:
方案二、处理全部 HTTP 重定向
时至今日(04/22/2021),如果开启 HTTPS 访问,那么绝大多数情况下,都要将 HTTP 重定向到 HTTPS 站点。
当时为每个域名添加 HTTP rewrite 是件繁琐的事情,而且不利于 Nginx 配置文件的维护,好在有通用的方法。
通过如下配置,能够实现将所有 HTTP 请求重定向到 HTTPS 请求:

server {
listen 80 default_server;

server_name _;

return 301 https://$host$request_uri;
}

该做法生效的前提是:不要为域名配置 80 监听,这样针对域名的 80 请求才能匹配包含 default_server 的 server {} 块,然后 return 301 将重定向到对应的 HTTPS 站点。
参考文献
Modul[……]

READ MORE

「Nginx」- 获取客户端的真实 IP 地址(Real IP Address)

问题描述
获取客户端真实网络地址,有时候让人头疼。尤其是多种中间件联合使用时,层层相套,而且大家又使用不同的规范,将客户端的真实 IP 地址保存在不同的请求头中;
在这篇笔记中,我们将尝试寻找一种通用的方案,该方案可以让我们方便地定位到客户端的真实 IP 地址;
该笔记将记录:在 Nginx 中,调试并获取客户端真实网络地址(IP Address)的相关方法;
解决方案
第一步、查看客户端的网络地址
客户端的真实网络地址是通过 HTTP 请求头传递的(除了 Proxy 协议,因为我们用的不多,所以这里未讨论该协议)
所以,我们打印所有的与网络地址有关的变量及请求头(至少是我们知道的),这样我们就能知道各种地址信息:

log_format client_ip_address ‘[$time_local] Host=”$http_host”, ‘
‘Forwarded=”$http_forwarded”, ‘
‘X-Forwarded-For=”$http_x_forwarded_for”, ‘
‘X-Forwarded-Host=”$http_x_forwarded_host”, ‘
‘X-Forwarded-Proto=”$http_x_forwarded_proto”, ‘
‘X-REAL-IP=”$http_x_real_ip”, ‘
‘realip_remote_addr=”$realip_remote_addr”, ‘
‘remote_addr=”$remote_addr”, ‘
‘server_addr=”$server_addr”, ‘
‘upstream_addr=”$upstream_addr”, ‘ ;

server {

access_log /var/log/nginx/client-ip-address.log client_ip_address;

}

在这些地址中,如果没有出现客户端的真实网络地址,那多半表示上游下来的请求存在问题。需要修改上游服务,以传递客户端真实网络地址;
第二步、设置请求头,以传递真实地[……]

READ MORE

「HAProxy」- 在 TCP Mode 下,从 Haproxy 向 Nginx 传递客户端真实网络地址

问题描述
客户端 Client 访问对外开放的 HAProxy 服务,然后由 HAProxy 负责负载均衡,来向后端的 Nginx 服务转发流量。如图:
但是,从 Nginx 获取到的 IP 地址为 HAProxy 的IP地址,而不是客户端 Client 的真实 IP 地址。
该笔记将记录:在 HAProxy + Nginx 中,如何获取客户端的真实网络地址(Real IP Address)
系统环境
CentOS 7.0,三台机器:172.31.255.112(Clint);172.31.255.13(HAProxy);172.31.255.125(Nginx-00);
Nginx 1.14.0
HAProxy 1.5.18,在TCP模式下的负载均衡。当然也可以使用HTTP模式,但是效率低啊,我们要用TCP模式。(“使用HTTP效率低”完全是基于“TCP是四层的,而HTTP是七层的”进行的推断)
解决方案
官方已经给出解决方案,参考 Accepting the PROXY Protocol 页面。下面会简单的解释该过程,并标记出需要注意的地方。
在HAProxy的TCP模式下,如果要向Nginx发送客户端的IP地址,它们之间要使用「PROXY协议」。使用PROXY协议后,NGINX才可以从HTTP,SSL,HTTP/2,SPDY,WebSocket,TCP中得知原始IP地址。可以这么理解PROXY协议:HAProxy修改了TCP报文的信息,追加了客户端的IP地址等信息,然后在转发到Nginx。使用PROXY协议没有创建新的连接。
注意,这里讨论的是HTTP协议。对于HTTPS协议,在配置上会有少许的不同,后面会有所提及,而官方文章「Accepting the PROXY Protocol」中也有说明。
下面先介绍HAProxy的注意事项,然后再介绍Nginx的注意事项。
修改HAProxy配置
为了演示问题,这里的HAProxy简单配置。
因为要使用PROXY协议,需要在server中追加send-proxy配置:

listen nginx
mode tcp
bind *:80
balance roundrobin
server nginx-01 172.31.255.125:80 send-proxy weight 1 maxconn 10000 check inter 10s

注意,「PROXY协议」由两个版本,对应的HAProxy中的配置为send-proxy与send-proxy-v2指令,这是用于HTTP协议的。如果是HTTPS协议要使用send-proxy-v2-ssl或者s[……]

READ MORE

「Nginx」- 响应设置

问题描述
该笔记将记录:在 Nginx 中,与响应有关的常见设置,以及相关问题的解决方案。
解决方案
设置响应类型
http headers – Force nginx to send specific Content-Type – Stack Overflow
default_type(Module ngx_http_core_module/default_type),设置默认 MIME 类型:

default_type application/xml;

# http, server, location

type(Module ngx_http_core_module),根据文件扩展名设置返回类型:

types {
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
}

# http, server, location

注意事项,受支持的 MIME 类型参考 /etc/nginx/mime.types 文件(具体文件路径取决于发行版)。
参考文献
Module ngx_http_core_module[……]

READ MORE

「Nginx」- 变量 $request uri 与 $uri 对比

问题描述
对于http://info.example.com/special/hotelbrand/honghe/地址,如果使用如下配置:

if ( $uri !~ ^/special/.* )
{
rewrite ^(.*)$ https://www.example.com/zx/ permanent;
}

在配置中的正则表达式与地址匹配,根据if语句(不匹配则跳转),则页面不应该进行跳转。但是在实际运行过程中,页面被重定向,与预期不符。
原因分析
原因在于我们没有正确理解$request_uri变量与$uri变量。问题在于我们对很多地方的理解有误。
问题分析
随着问题深入调查,我们发现如下配置才会导致问题:

server
{
listen 80;
server_name info.example.com;

if ( $uri !~ ^/special/.* )
{
rewrite ^(.*)$ https://www.example.com/zx/ permanent;
}

error_page 404 = /404.html;
}

也许老手已经看到问题所在了…………事情是这个样子的…………
首先,我们访问的连接不存在。根据error_page 404 = /404.html;配置,我们被“内部重定向”到404.html页面。所谓“内部重定向”是返回404.html页面内容,就好像客户端端在访问404.html页面,而不是让客户端浏览器重定向404.html页面。
但是…………当他内部重定向到404.html时,遇到if语句,而if语句中的$uri变量此时为/404.html值(因为$uri就是这个样子),然后客户端被重定向到在rewrite中定义的连接。
更进一步
如果理解上面的内容,你就能够理解为什么下面的配置会跳转到https://404.example.com地址:

server
{
listen 80;
server_name info.example.com;

if ( $uri ~ /404.html )
{
rewrite ^(.*)$ https://404.example.com permanent;
}

if ( $uri !~ ^/special/.* )
{
rewrite ^(.*)$ https://www.example.com/zx/ permanent;
}

error_page 404 = /404.ht[……]

READ MORE

「Nginx」- 模块及指令(学习笔记)

该部分整理常用的 Nginx 指令,以及需要重点关注的部分(注意事项)。
相关链接
Alphabetical index of directives
模块功能
在 Nginx 中,由很多的模块,用于扩展 Nginx 的功能。
模块(Modules)安装
以前安装模块的时候,只能重新编译在 Nginx 中,在编译时使用相应的选项。
动态模块(Dynamic Modules)
从 NGINX 1.9.11 开始,支持加载动态模块。但是,这样需要模块支持动态加载,参考 Dynamic Modules 文档。
需要使用 load_module 指令加载,例如 load_module modules/ngx_http_echo_module.so; 指令,但是很多发行版的 Nginx 模块是开箱即用的(已经预先设置),所以安装即可。不用我们再单独设置
参考文献
NGINX 加载动态模块(NGINX 1.9.11开始增加加载动态模块支持) How to configure additional modules to nginx after installation? Compiling Third-Party Dynamic Modules for NGINX and NGINX Plus NGINX Docs | Dynamic Modules[……]

READ MORE

「Nginx」- daemon off;

在表面上,就是决定 Nginx 是前台运行(daemon off;)还是后台运行(daemon on;);
我们在命令行执行而产生的是初始化进程,它会产生主进程和工作进程,但是在这之后,他就退出了。
因此,虽然在系统中存在 Nginx 进程,但是它们都也不是原来的启动进程,全是派生出来的。
因此我们在 systemd Supervisor Dockerfile 中,都要启用 -g “daemon on;” 配置。
参考文献
What is the difference between nginx daemon on/off option? How to run Nginx within a Docker container without halting? Controlling Nginx with Supervisor[……]

READ MORE

「Nginx」- http rewrite module

# if
「Module ngx_http_rewrite_module/if」 「If Is Evil」

# 判断用户使用IE浏览器
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}

# 判断referer是否合法
# 参考valid_referers指令
if ($invalid_referer) {
return 403;
}

参考文献
Module ngx_http_rewrite_module Modify $request_uri in Nginx Nginx reverse proxy + URL rewrite Nginx proxy_pass root and specific url only how to reverse proxy via nginx a specific url? How to preserve request url with nginx proxy_pass NGINX proxy_pass with URI modification[……]

READ MORE

「Nginx」- location(学习笔记)

遇到 301 重定向
如果 location 以斜线(/)结尾,并且当请求被 proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, grpc_pass 模块处理时,将进行特殊处理: 1)仅响应精确匹配的地址。例如,example.com/user/ 匹配 locaiotn /user/,但 example.com/user 不匹配 location /user/; 2)当不匹配时,将发生 301 重定向,到带斜线的地址。例如,对于 location /user/,请求 example.com/user 将被重定向到 example.com/user/;
参考文献
Module ngx_http_core_module/location[……]

READ MORE

「Nginx」- ngx http core module

# try_files
-「ngx_http_core_module.html#try_files」

Syntax:
try_files file … uri;

 
try_files file … =code;

Default:

Context:
server, location

检查按顺序指定的文件(file)是否存在,并使用第一个找到的文件进行请求处理;处理在当前上下文中执行。 文件的路径是根据root和alias指令从file参数构造。 可以通过在file的末尾指定斜杠来检查目录的存在,例如,“$uri/”。 如果未找到任何文件,则会进行内部重定向到由最后一个参数中指定的uri中。 例如:

location /images/ {
try_files $uri /images/default.gif;
}

location = /images/default.gif {
expires 30s;
}

最后一个参数也可以指向命名位置,如下面的示例所示:

location / {
try_files /system/maintenance.html
$uri $uri/index.html $uri.html
@mongrel;
}
location @mongrel {
proxy_pass http://mongrel;
}

从版本0.7.51开始,最后一个参数也可以是HTTP响应码:

location / {
try_files $uri $uri/index.html $uri.html =404;
}

访问某个地址,返回固定内容:

location /client/index.php {
try_files /index.html /index.html;
}

# error_page
指令「error_page」处理由nginx生成的错误。
默认情况下,无论http状态代码如何,nginx都将返回代理服务器返回的任何内容。所有error_page不会处理proxy_pass的返回。应该使用proxy_intercept_errors on指令,然后再配置error_page指令。
参考文献
Module ngx_http_core_module nginx not serving my error_pag[……]

READ MORE

「Nginx」- ngx_http_xslt_module

背景说明
使用Nginx的autoindex时,输出的页面结构不尽人意,不直观,还有些混乱(列未对齐)。
如果要重定义autoindex输出页面结构,那就需要使用Nginx的xslt模块。(另外一个诡异的做法是使用Nignx的sub_filter指令,向返回的页面中插入代码。)
本文主要内容
本文主要是介绍Nginx的xslt模块中的指令及含义。但是也只是涵盖了一部分指令。
需要进行的准备工作
指令相对容易写,但是前提是你要理解:什么是DTD?、DTD实体是什么?、XSLT是什么?关于这部分的内容,你可以到w3schools.com上学习:

DTD Tutorial

不然,你无法理解Nginx的xslt模块指令中的一些概念及含义。
指令说明
xslt_stylesheet
Syntax: xslt_stylesheet stylesheet [parameter=value …]; Default: — Context: location
定义XSLT样式表及其可选参数。 样式表在配置阶段编译。
可以指定多个样式表。 它们将按指定的顺序依次应用。
参考文献
Nginx/ngx_http_autoindex_module wilhelmy/dirlist.xslt[……]

READ MORE

「Nginx」- try_files(学习笔记)

问题描述
该笔记将记录:try_files 的使用方法、常见场景的配置、常见问题的处理。
当请求某个文件时,返回特定的其他文件

location /client/index.php {
try_files /index.html /index.html;
}

文件存在,但返回 404 状态码
问题描述
对于如下配置,当请求 /foo 地址时,将尝试查找 foo.html 文件,如果不存在则返回 index.html 文件:

location / {
root /srv/html/;
try_files $uri.html index.html;
}

虽然 foo.html 不存在,但是 index.html 是存在的,然而却返回 404 状态码。
问题原因
根据 try_files file … uri; 文档:当文件不存在时,将触发内部重定向到 uri 指定的地址(这里是 index.html 地址)。这是匹配不到的,因为我们没有定义 location index.html,我们应该使用 /index.html,这样能够匹配到 location / 配置。
解决方法
应该使用如下配置:

location / {
root /srv/html/;
try_files $uri.html /index.html;
}

或者定义 location index.html 配置:

location index.html {
# do some stuff
}

参考文献
Module ngx_http_core_module/try_files[……]

READ MORE

「Nginx」- 使用 upstream 指令

使用方法参考 Module ngx_http_upstream_module / upstream 手册。
该笔记将记录:与 upstream 有关的常见问题
当使用域名时,何时发生域名解析
根据 Using a Domain Name in an Upstream Server Group 描述,可以得到以下结论: 1)域名解析发生在启动时 2)使用系统 /etc/resolv.conf 配置文件
参考文献
Module ngx_http_upstream_module / upstream DNS for Service Discovery with NGINX and NGINX Plus[……]

READ MORE

「z.Error List (Nginx and Tengine)」

# ‘struct crypt_data’ has no member named ‘current_salt’
「Tengine Docker问题 #721」 「bugfix: error “‘struct crypt_data’ has no member named ‘current_salt'” occurs while compiling」
问题描述: src/os/unix/ngx_user.c:35:7: error: ‘struct crypt_data’ has no member named ‘current_salt’
问题原因: 是glibc的Bug
解决办法:

#!/bin/sh

wget https://code.aliyun.com/Darkly/tengine/commit/a0e4b2a0534b5b5a9e1a8fbcc928e7a1c66cfcff.diff

patch ./bundle/nginx-1.7.7/src/os/unix/ngx_user.c a0e4b2a0534b5b5a9e1a8fbcc928e7a1c66cfcff.diff

# 然后重新执行configure …命令

# ngx_event_openssl.c error: storage size of ‘md’ isn’t know
未解决
解决办法: 直接把报错的模块关掉,不编译报错的模块。
curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number
curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number – Stack Overflow
在 Nignx 的 ssl 配置中,应该使用 listen 443 ssl; 而不是 listen 443 配置。[……]

READ MORE

「Nginx」- [emerg] host not found in upstream “xxx” in xxx:xxx

问题描述
当遇到 [emerg] host not found in upstream 错误时,通过配置 resolver 可以解决。
但是今天遇到一个奇怪的问题:

[root@nginx02 ~]# /usr/local/tengine/sbin/nginx -t
nginx: [emerg] host not found in upstream “nianhui.dfwsgroup.com” in /usr/local/tengine/conf/virtual_host/nianhui.dfwsgroup.com.conf:15
nginx: configuration file /usr/local/tengine/conf/nginx.conf test failed

[root@nginx02 ~]# /usr/local/tengine/sbin/nginx -t
nginx: the configuration file /usr/local/tengine/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/tengine/conf/nginx.conf test is successful

我们并没有修改 Nginx 配置,它自己就好了(时间戳为证)

[root@nginx02 ~]# ll /usr/local/tengine/conf/virtual_host/nianhui.dfwsgroup.com.conf
-rw-r–r– 1 root root 810 May 2 2019 /usr/local/tengine/conf/virtual_host/nianhui.dfwsgroup.com.conf

[root@nginx02 ~]# ll /usr/local/tengine/conf/nginx.conf
-rw-r–r– 1 root root 2767 May 15 16:33 /usr/local/tengine/conf/nginx.conf

Tengine version: Tengine/2.3.0 (nginx/1.15.9)
问题原因
DNS 服务问题,导致域名无法被解析[……]

READ MORE

「Nginx」- nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)

问题描述
在启动 Nginx 服务时,产生如下错误:

nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)

问题原因
导致该问题的原因有很多,我们这里将列举我们的场景,以及解决方案。
原因一、端口被占用
这是最常见的原因,80 端口被占用,导致 Nginx 服务进行绑定。
解决方案
找到占用 80 端口的进程,并将其结束。
原因二、Dual-Stack Sockets for IPv6
这是 IPv4 到 IPv6 过渡期经常发生的问题。如下配置也将导致上述错误:

server {
listen [::]:80 ipv6only=off;
server_name dual-stack.example.com;
}
server {
listen 0.0.0.0:80;
server_name ipv4.example.com;
}

通过 ipv6only=off 选项,当前创建的 Socket 是双栈的,IPv4 将被映射到 IPv6,此时只能创建一条监听,不能再监听 IPv4。
相关文献: IPv4-Mapped IPv6 Address – Teknologisk videncenter c – Dual stack with one socket – Stack Overflow
解决方案
既然不能监听 IPv4,并且现在是双栈,我们能够放心的监听 IPv6 地址(同时也保证 IPv4 访问):

server {
listen [::]:80 ipv6only=off;
server_name dual-stack.example.com;
}
server {
listen [::]:80;
server_name ipv4.example.com;
}
# 因为场景特殊,我们无法修改第一个 Server 的配置
# 当然,还可以关闭双栈。

参考文献
IPv4-Mapped IPv6 Addre[……]

READ MORE

「Nginx」- no resolver defined to resolve

问题症状
Nginx的错误日志里,有如下信息:

no resolver defined to resolve example.com

问题原因
这已经和明显了,就是提示你没有定义resolver指令。
Nginx就这样,它不理会系统的DNS(/etc/resolv.conf)配置。
如果你在配置文件中使用了域名或主机名,一定要配置resolver指令。
解决方案
配置resolver指令,指定DNS服务器。
详细参考「resolver」手册。
# 在k8s中
「kubernetes dns resolver in nginx」
让它走集群的DNS:resolver kube-dns.kube-system.svc.cluster.local
这里要使用FQDN,否则容器里的/etc/resolv.conf中就要配置search指令。
关于「search」指令可以参考「In /etc/resolv.conf, what exactly does the “search” configuration option do?」一文。
相关链接
Websites show 502 Bad Gateway: no resolver defined to resolve example.com Nginx resolver address from /etc/resolv.conf A Quick Review of Key DNS Features Module ngx_http_upstream_module/upstream Module ngx_http_core_module/resolver[……]

READ MORE

「php-fpm.conf」

;;;;;;;;;;;;;;;;;;;;;
; FPM Configuration ;
;;;;;;;;;;;;;;;;;;;;;

; All relative paths in this configuration file are relative to PHP’s install
; prefix (@prefix@). This prefix can be dynamically changed by using the
; ‘-p’ argument from the command line.

; Include one or more files. If glob(3) exists, it is used to include a bunch of
; files from a glob(3) pattern. This directive can be used everywhere in the
; file.
; Relative path can also be used. They will be prefixed by:
; – the global prefix if it’s been set (-p argument)
; – @prefix@ otherwise
;include=etc/fpm.d/*.conf

;;;;;;;;;;;;;;;;;;
; Global Options ;
;;;;;;;;;;;;;;;;;;

[global]
; Pid file
; Note: the default prefix is @EXPANDED_LOCALSTATEDIR@
; 默认值: none
;pid = run/php-fpm.pid

; Error log file
; If it’s set to “syslog”, log is sent to syslogd instead of being written
; in a local file.
; Note: the default prefix is @EXPANDED_LOCALSTATEDIR@
; 默认值: log/php-fpm.log
;error_log = log/php-fpm.log

; syslog_facility is used to specify what type of program is logging the
; message. This lets syslogd specify that messages from different facilities
; will be handled differently.
; See syslog(3) for possible values (ex da[……]

READ MORE

「PHP」- php.ini

Changeable
文档「List of php.ini directives」列出了PHP.INI中的指令。
而「Changeable」列显示了「模式」,该「模式」决定了「在什么时候」和「在什么位置」可以设置指令。下面是简短的介绍:

模式
含义

PHP_INI_USER
可以在:(1)用户脚本(比如使用ini_set()函数);(2)Windows注册表;(3)从PHP 5.3开始的.user.ini文件;

PHP_INI_PERDIR
可以在:php.ini;htaccess;httpd.conf;.user.ini;

PHP_INI_SYSTEM
可以在:php.ini;htaccess;httpd.conf;

PHP_INI_ALL
可以在:任何地方;

有关「模式」定义,请参阅「Changeable mode values」部分。
配置文件的加载路径
The configuration file (php.ini) is read when PHP starts up. For the server module versions of PHP, this happens only once when the web server is started. For the CGI and CLI versions, it happens on every invocation.
采集自源码目录下的php.ini-production文件

SAPI module specific location.
The PHPRC environment variable. (As of PHP 5.2.0)
A number of predefined registry keys on Windows (As of PHP 5.2.0)
Current working directory (except CLI)
The web server’s directory (for SAPI modules), or directory of PHP (otherwise in Windows)
The directory from the –with-config-file-path compile time option, or the Windows directory (C:\windows or C:\winnt)[……]

READ MORE

「Nginx, PHP-FPM」- NGINX 502 Bad Gateway

问题描述
浏览器访问 URL 地址,页面显示 502 Bad Gateway 信息。
问题原因
导致该问题可能有多种原因:
第一种、服务未启动
没有启动 PHP-FPM 服务导致 Nginx 无法访问,因此返回 502 错误。
第二种、配置错误
虽然启动 PHP-FPM 服务,但是 Nginx 配置错误。
比如 Nigix 连接 9000 端口,但是 PHP-FPM 监听 sock 文件。
第三种、进程提前退出
这些问题都是因为 PHP-FPM 工作进程退出,导致连接关闭。
在 Nginx 中将看见 104: Connection reset by peer 消息:

2020/05/28 16:30:58 [error] 915#0: *17358 recv() failed (104: Connection reset by peer) while reading
response header from upstream, client: 192.168.50.1, server: www.example.com, request: “HEAD /path/to
/somewhere HTTP/1.1”, upstream: “fastcgi://127.0.0.1:9000”, host: “www.example.com”

但是 PHP-FPM 的错误日志可能不同:
#1 child <PID> exited on signal 11 (SIGSEGV)
在 PHP-FPM 中,错误日志(对应时间点):

[28-May-2020 16:30:58] WARNING: [pool www] child 3359 exited on signal 11 (SIGSEGV) after 7066.544041 seconds from start
[28-May-2020 16:30:58] NOTICE: [pool www] child 21771 started

至于问题原因嘛,也是各种各样(php-fpm child process exited on signal 11)
对于我们的场景,也没啥高级的排查思路: 1)从日志看,SIGSEGV,这是段错误的信号,那就是说 PHP-FPM 程序异常退出 2)那就看内核日志信息,dmesg | grep -F “php-fpm[<PID>]”,在输出中显示 memcache.so 程序段错误 3)那我们能猜测的大概原因是:在程序中,使用的 Memcache 插件存在 BUG 导致段错误。
TODO ! 通过 dmesg 排查进程[……]

READ MORE

「PHP」- 程序性能分析及调试工具

PHP程序性能分析性能及性能调试工具
Ifp/cachegrind/Valgrind/Xdebug/XHProf

章节列表
「Xdebug」- PHP 调试工具,分析工具 「PHP」- XHProf,性能分析[……]

READ MORE

「PHP」- XHProf,性能分析

问题描述
XHProf,由 Facebook 开源出的 PHP 程序性能分析工具。
在数据收集阶段,它跟踪调用次数与测量数据,展示程序动态调用的弧线图。 它在报告、后期处理阶段计算了独占的性能度量,例如运行经过的时间、CPU 计算时间和内存开销。 函数性能报告可以由调用者和被调用者终止。 在数据搜集阶段 XHProf 通过调用图的循环来检测递归函数,通过赋予唯一的深度名称来避免递归调用的循环。
XHProf Web界面:XHProf 包含基于 HTML 的简单用户界面(由 PHP 写成)。 基于浏览器的用户界面使得浏览、分享性能数据结果更加简单方便。
调用图:XHProf 的报告对理解代码执行结构常常很有帮助。 比如此分层报告可用于确定在哪个调用链里调用了某个函数,支持查看调用图。
结果数据处理及分析:XHProf 对两次运行进行比较(又名 “diff” 报告),或者多次运行数据的合计。 对比、合并报告,很像针对单次运行的“平式视图”性能报告,就像“分层式视图”的性能报告。
解决方案
第一步、安装扩展
安装依赖 XHProf 插件本身无过多依赖。但是收集到的数据是通过PHP开发的Web界面来显示的,所以需要安装Web环境。
Github上还有一个带GUI的XHProf分支,可以到Github上下载这个分支
安装扩展
可以到PCEL中下载XHProf,然后使用phpize手动安装; 或者使用PCEL安装扩展。这里使用pecl命令直接安装:

pecl search xhprof

# 根据输出,执行:
pecl install xhprof-0.9.4

修改 php.ini 文件,启用扩展,并配置相依的参数:

[xhprof]
;; 启动扩展
extension=xhprof.so

;; 由xhprof收集的数据的保存目录。
xhprof.output_dir=”/path/to/output/dir”

重启 PHP-FPM 服务,检查XHProf是否加载进来。
第二步、采集数据
项目里使用了三个PHP框架,站点比较多,不能挨个添加;而且随处都有exit(),这就导致xhprof_disable()函数无法执行。所以采用如下解决办法: 使用php.ini中的auto_prepend_file变量,并且使用register_shutdown_function函数。
创建prepend.php 内容如下:

<?php

mxhprof_start();

register_shutdown_function(mxhprof_shutdown);

function mxhprof_start([……]

READ MORE

「Xdebug」- PHP 调试工具,分析工具

问题描述
Xdebug 是个开源的PHP程序调试工具,可以使用它来调试、跟踪及分析程序运行状态。当然,Xdebug需要结合PHP的开发工具一起来使用。
解决方案
第一步、安装扩展
扩展下载 到官网下载对应的Xdebug版本。官网地址:https://xdebug.org/download.php
编译安装扩展 phpize configre make make make install
第二步、配置扩展
修改php.ini,加入如下配置:

[Xdebug]
;指定Xdebug扩展文件的绝对路径
zend_extension=D:/phpext/php_xdebug-2.4.1-5.4-vc9.dll
;启用性能检测分析
xdebug.profiler_enable=On
;启用代码自动跟踪
xdebug.auto_trace=on
;允许收集传递给函数的参数变量
xdebug.collect_params=On
;允许收集函数调用的返回值
xdebug.collect_return=On
;指定堆栈跟踪文件的存放目录
xdebug.trace_output_dir=”D:/debug”
;指定性能分析文件的存放目录
xdebug.profiler_output_dir=”D:/debug”
xdebug.profiler_output_name = “cachegrind.out.%p”
xdebug.remote_enable = On
xdebug.remote_port=9000
xdebug.remote_handler = dbgp
xdebug.remote_host = localhost
xdebug.var_display_max_depth = 10

重启 php-fpm 加载扩展。
检查扩展是否正确加载。
第三步、配置 IDE
WIP
参考文献
Homepage:https://xdebug.org 安装文档:https://xdebug.org/docs/install[……]

READ MORE

「Phusion Passenger」- 应用服务器

问题描述
很多时候,当我们解决 A 问题时,会无意发现 B 工具。或许该工具与解决 A 问题完全无关,但是我们还是选择简单了解该工具,增加自己的知识储备,开阔视野。
其实我们也想不到,在解决内存占用过高问题时会发现 Web 应用部署工具,这只能说明我们不专心。
该笔记将记录:什么是 Phusion Passenger 以及简单案例让我们快速了解 Phusion Passenger 的使用方法。
解决方案
示例是讲解工具的最好开始
很显然这是段 Nginx 配置,并存在未知的 passenger_* 配置行,这里也很明显与 NodeJS 有关系:

server {
listen 80;
server_name yourserver.com;

# Tell Nginx and Passenger where your app’s ‘public’ directory is
root /path/to/app/public;

# Turn on Passenger
passenger_enabled on;
# Tell Passenger that your app is a Node.js app
passenger_app_type node;
passenger_startup_file app.js;
}

如果想以传统的方式部署 NodeJS 应用,我们需要: 1)运行 node app.js 启动运行(还要考虑服务的管理、自动启动等等) 2)然后,再配置 Nginx proxy_pass 转发,以及相关参数配置;
而使用 Passenger 则会更容易操作,仅需要: 1)为 Nginx 安装 Passenger 模块; 2)然后,在 nginx.conf 中添加应用相关的配置; 2)最后,启动 Nginx 服务,而应用也随之启动;
这正式 Passenger 吸引我们的地方,它简化我们对 Web 应用的管理方式。
功能及特性
而 Passenger 不单单如此,它还有很多其他特性: 1)支持 Python NodeJS Ruby 语言; 2)安全强化,能够预防常见攻击; 3)应用监控,监控应用程序性能、崩溃、挂起、内存泄漏等等问题; 4)问题分析,通过请求检查、回溯转储 CPU 和内存状态来解决应用程序问题; 5)……
参考文献
Deploying a Node.js application – Nginx – Passenger Library phusion/passenger: A fast and robust web server and application[……]

READ MORE

「Polipo」- a Caching Web Proxy

!!! Polipo is no longer maintained !!!
Polipo — a caching web proxy
https://www.pps.jussieu.fr/~jch/software/polipo/
jech/polipo: The Polipo caching HTTP proxy

章节列表
「Polipo」- 将 SOCKS 转换为 HTTP(S) 代理[……]

READ MORE

「Polipo」- 将 SOCKS 转换为 HTTP(S) 代理

问题描述
现在我们有 SOCKS 代理服务器,但是由于部分软件功能限制,我们需要使用 HTTP(S) 代理服务。
该笔记将记录:将 SOCKS 代理服务 转化为 HTTP(S) 代理服务 的方法。
解决方案
通过 Polipo 软件,能够将 SOCKS Porxy 转化为 HTTP Proxy 服务。
系统版本:Debian GNU/Linux 10
第一步、安装服务

apt-get install polipo

第二步、修改配置

cp /etc/polipo/config /etc/polipo/config.backup

cat > /etc/polipo/config <<EOF
# 日志等级
logSyslog = false
logFile = /var/log/polipo/polipo.log
logLevel=255

# 上游代理服务
socksParentProxy = “127.0.0.1:1080”
socksProxyType = socks5

# 监听服务地址及端口
proxyAddress = “::0” # both IPv4 and IPv6
# proxyAddress = “0.0.0.0” # or IPv4 only
proxyPort = 8123
EOF

有关日志等级设置,可以参考 http proxy – Make polipo to log all urls – Unix & Linux Stack Exchange 问题
第三步、启动服务

systemctl start polipo
systemctl enable polipo

第四步、代理验证

# 此命令将返回代理 IP 地址
curl –proxy http://127.0.0.1:8123 http://bot.whatismyipaddress.com/

# 测试 Google 访问
curl –proxy http://127.0.0.1:8123 https://www.google.com

常见问题汇总
Couldn’t create disk file … Permission denied
问题描述: 在启动 Polipo 服务之后,使用期间产生如下错误:

Couldn’t create disk file /var/cache/polipo/repo.zabbix.com/hI-bv4EBKjxz41aA4cXXMQ==: Permission denied

问题原因: 通常不会遇到这个问题。在我们的场[……]

READ MORE

「Squid」

相关链接
squid-cache wiki/Current Features
http://www.squid-cache.org/ http://wiki.squid-cache.org/SquidFaq http://www.squid-cache.org/Doc/config/[……]

READ MORE

「Tomcat」- 杂记

内容简介
本文是对Tomcat的一些杂记。
修改上传文件大小
-「How to Increase Tomcat Upload File Size Limit」[……]

READ MORE