概要:本文描述如何使用 Charles 进行SSL Proxying,以便分析 HTTPS 流量。
Charles 版本:4.2.1
启动Charles软件,在菜单中找到 Help -> SSL Proxying -> Install Charles Root Certificate,点击即可进行Mac电脑端的SSL根证书安装,如图:
然后会调用系统【钥匙串访问】设置,可以看到 Charles Proxy CA 字样的证书已安装,但由于该证书是Charles自签名的,不被系统信任,所以还需要对其手动设置信任证书。
双击该证书,展开【信任】,设置【使用此证书时】-选择【始终信任】,然后关闭设置即可,如图:
运行环境:CentOS release 6.9 (Final) ,Amazon Linux AMI 2017.09
使用 yum 安装的Nginx,会在系统 service 中添加 rc.d 启动脚本,以便在系统重启时,随系统自动启动Nginx。
但随系统自动启动的Nginx,其Max open files limit 是系统默认的1024/4096(并不是我们在 /etc/security/limits.conf 中配置的数字):
所以在访问量不大的情况下,你都会在nginx error log 中,发现"worker_connections exceed open file resource limit: 1024"的报警:
2017/12/28 11:53:20 [warn] 5765#5765: 8192 worker_connections exceed open file resource limit: 1024
你可能会觉得很奇怪,我明明在 /etc/security/limits.conf 中设置了nofile 131072 参数啊,而且这个设置也一直都生效的(ulimit -n 检查OK),之前手动启动Nginx也都是应用这个nofile 设置的。
$ cat /etc/security/limits.conf # /etc/security/limits.conf # #<domain> <type> <item> <value> # * - nofile 131072
其实,这个问题也存在于随系统启动的其他服务,如Apache。到底怎么回事呢?
问题出在Linux系统启动过程中,也就是说Nginx主进程启动时,上面的限制配置没有生效;实际上系统启动后执行用户登录login时才会使 limits.conf 配置生效。
简单描述一下,Linux内核启动后的系统启动过程如下:
运行/sbin/init 程序,执行系统的1号进程(此后系统的控制权就交给 /sbin/init 进程了)
读取 /etc/inittab 来确定系统启动级别(例如 读取到的默认级别是3)
执行初始化系统脚本 /etc/rc.d/rc.sysinit 来进行系统配置初始化
执行 /etc/rc.d/rc 脚本,根据启动级别,执行/etc/rc.d/rc*.d/ 下的各种服务启动脚本(比如 rc3.d下的文件)
执行 /etc/rc.d/rc.local 脚本(其实是/etc/rc.d/rc*.d/ 下的最后一个脚本,即S99local)
完成了所有的启动任务后,Linux会启动终端或X-Window来等待用户登录。
至此系统启动过程完成,当用户登录时,才会执行/etc/profile,~/.bash_profile和~/.bashrc 环境配置文件等;
关键一点是用户登陆时才会使 /etc/security/limits.conf 配置文件生效,这个比Nginx进程启动晚,此时的ulimit -n查到的值不是Nginx进程启动时的值。
这里简单扩展一下Linux是如何加载这个 limits.conf 文件的:
$ cat /etc/pam.d/login #%PAM-1.0 ... account include system-auth password include system-auth session include system-auth ... $ cat /etc/pam.d/system-auth #%PAM-1.0 # This file is auto-generated. # User changes will be destroyed the next time authconfig is run. ... session required pam_limits.so ... $ grep -a "/etc/security/limits.conf" /lib64/security/pam_limits.so #结果见下图
1)登录系统,手动运行 service nginx restart 重启Nginx服务
可以解决上述问题,因为此时 limits.conf 配置已经生效。
但是这个方法每次系统重启都要手动执行,有时忘了就麻烦了,甚至机器多的时候更糟糕。
2)在 /etc/rc.local 设置Nginx重启命令,并在 Nginx 启动前执行 ulimit 命令
$ tail /etc/rc.local # for nginx ulimit -SHn 131072 service nginx restart
可以解决上述问题。
注:仅仅在 /etc/rc.local 中添加 service nginx restart 命令是不行的。
3)有人说 Nginx 有个配置文件参数 worker_rlimit_nofile
经实测,无法解决上述 Nginx 随系统 service 自动启动时ulimit -n 不生效的问题。
$ ls -l ligb/ total 10160 -rw-r--r-- 1 user1 user1 10383462 Apr 21 2017 10m.rar $ /usr/sbin/tmpwatch -m 7d ligb $ ls -l #(ligb目录还在) drwxr-xr-x 2 root root 4096 Apr 21 2017 ligb
$ ls -l ligb/ total 4 -rw-rw-r-- 1 user1 user1 395 Mar 18 2017 output $ find ligb -mtime +30 ligb #(被查找的当前目录也出现在了结果中) ligb/output
这种情况下如果运行命令 find ligb -mtime +30 -exec rm -rf {} \;
就会把 ligb 目录给删除,然后find 命令提示错误 No such file or directory:
$ find ligb -mtime +30 -exec rm -rf {} \; find: `ligb': No such file or directory
可以使用 -path 参数将当前被查找的目录排除在结果之外:
$ find ligb2 ! -path ligb2 -mtime +30 ligb2/output
以避免出现你所意想不到且不希望的结果(如把被查找的目标目录本身给删除了,从而造成其他错误)。
在访问带目录的URL时,如果末尾不加斜杠(“/”),Nginx默认会自动加上,其实是返回了一个301跳转,在新的Location中加了斜杠。
但这个默认行为在Nginx前端有LB负载均衡器、且LB的端口与Nginx Server监听的端口不同时,可能会导致访问出错。
比如域名所指向的LB对外监听端口80,转发到后端Nginx 8080端口,当Nginx进行上述自动重定向时,导致重定向到了域名的8080端口,如:
$ curl -I http://www.mydomain.com/app HTTP/1.1 301 Moved Permanently Date: Tue, 21 Nov 2017 08:27:50 GMT Content-Type: text/html Content-Length: 178 Connection: keep-alive Server: nginx Location: http://www.mydomain.com:8080/app/ (这里由于LB没有监听8080端口,导致访问出错)
此时,解决方法有两种。
1)新版本nginx(≥1.11.8)可以通过设置 absolute_redirect off; 来解决:
server { listen 8080; server_name www.mydomain.com; absolute_redirect off; #取消绝对路径的重定向 root html; ... }
即使用相对路径的重定向,结果如下:
$ curl -I http://www.mydomain.com/app HTTP/1.1 301 Moved Permanently Date: Tue, 21 Nov 2017 07:45:21 GMT Content-Type: text/html Content-Length: 178 Connection: keep-alive Server: nginx Location: /app/ (这里变成了相对路径)
2)LB是80端口的,旧版本nginx(<1.11.8)可以增加 port_in_redirect off; 参数来解决:
server { listen 8080; server_name www.mydomain.com; #absolute_redirect off; # appeared in version 1.11.8 port_in_redirect off; ... }
即去掉重定向后的Location中的端口,效果如下:
$ curl -I http://www.mydomain.com/app HTTP/1.1 301 Moved Permanently Date: Tue, 21 Nov 2017 13:03:34 GMT Content-Type: text/html Content-Length: 178 Connection: keep-alive Server: nginx Location: http://www.mydomain.com/app/
如果LB监听非80端口,那建议升级Nginx到1.11.8版本以上了。
当使用Nginx 转发请求到AWS ELB(即把ELB的域名作为proxy_pass的upstream)时,由于ELB域名的IP经常变化,会出现Nginx转发请求失败(连接upstream超时)的情况。Nginx 配置样例如下:
location / { proxy_pass http://service-1234567890.us-east-1.elb.amazonaws.com; }
原因在于Nginx解析域名的时机:
Nginx仅在启动的时候,对配置文件中的upstream域名进行解析,并将得到A记录IP地址全部作为upstream,直到下一次加载配置文件时,才会更新域名解析结果。而AWS ELB域名的IP是经常变化的,所以很容易出现转发错误的情况。
其中一个解决方案是付费购买Nginx Plus版本,然后在配置文件 upstream 组配置中,在 server 指令后添加 resolve 标记。
Example:
upstream backend { server service-1234567890.us-east-1.elb.amazonaws.com resolve; }
这样Nginx 就会遵循域名的TTL过期机制,当TTL过期时重新进行域名解析,获得server (AWS ELB)域名更新后IP地址。
另一个免费的方案是按照如下方法进行配置:
resolver 172.16.0.23; set $upstream_endpoint http://service-1234567890.us-east-1.elb.amazonaws.com; location / { proxy_pass $upstream_endpoint; }
即为Nginx 配置一个域名解析器 resolver ,并将 upstream server 配置为一个变量。
这样Nginx 也会遵循域名的TTL过期机制,并在收到请求一个过期的upstream server域名时重新进行域名解析。
这个方法奏效的原因可以在Nginx 官方文档中对 proxy_pass 指令的描述末尾中可以找到:
A server name, its port and the passed URI can also be specified using variables:
proxy_pass http://$host$uri;
or even like this:
proxy_pass $request;
In this case, the server name is searched among the described server groups, and, if not found, is determined using a resolver.
如果 location 不是 / ,proxy_pass 后的URI不同的写法会有不同的结果。
1)假设我们有如下配置:
location /foo/ { proxy_pass http://127.0.0.1:8080; }
当我们请求 /foo/bar/baz 时,Nginx 会转发请求到 http://127.0.0.1:8080/foo/bar/baz 。
2)但如果我们这样配置:
location /foo/ { # Note the trailing slash ↓ proxy_pass http://127.0.0.1:8080/; }
Nginx 会去除在 loation 中指定的路径,再将URI余下的部分转发。则请求 /foo/bar/baz 时,会被转发到 http://127.0.0.1:8080/bar/baz 。
1)假设我们按刚才的解决方案如下进行配置
resolver 172.16.0.23; set $upstream_endpoint http://service-1234567890.us-east-1.elb.amazonaws.com/; location /foo/ { proxy_pass $upstream_endpoint; }
当我们请求 /foo/bar/baz 时,Nginx 会转发请求到 / ,而不是 /bar/baz 。
如果想实现通常情况下Nginx 的转发行为,可以在上述配置中去掉upstream末尾的 / ,手工写rewrite 实现:
resolver 172.16.0.23; set $upstream_endpoint http://service-1234567890.us-east-1.elb.amazonaws.com; location /foo/ { rewrite ^/foo/(.*) /$1 break; proxy_pass $upstream_endpoint; }
这样,当我们请求 /foo/bar/baz 时,后端 upstream 会收到 /bar/baz 的请求。
Caffe,来自伯克利的深度学习框架。本文记录和整理了一下其在CentOS 6.7下的编译安装过程,因其依赖比较多,且大多需要手工编译安装,期间遇到较多编译失败,特整理下来供有需要的人参考,少走一些弯路。
环境:CentOS release 6.7 (Final),Python 2.7
Caffe has several dependencies:
● CUDA is required for GPU mode.(CUDA for GPU,暂时没用GPU)
○ library version 7+ and the latest driver version are recommended, but 6.* is fine too
○ 5.5, and 5.0 are compatible but considered legacy
● BLAS via ATLAS, MKL, or OpenBLAS.
● Boost >= 1.55(!!不要使用yum安装,yum安装的 boost-1.41 版本过低!!)
● protobuf, glog, gflags, hdf5(!!前三个同样不要使用yum安装,版本过低!!)
Optional dependencies:
● OpenCV >= 2.4 including 3.0(!! yum安装的版本是2.0,也不够!!)
● IO libraries: lmdb, leveldb (note: leveldb requires snappy)
● cuDNN for GPU acceleration (v5)
Pycaffe and Matcaffe interfaces have their own natural needs.
● For Python Caffe: Python 2.7 or Python 3.3+, numpy (>= 1.7), boost-provided boost.python
● For MATLAB Caffe: MATLAB with the mex compiler.
$ sudo yum install cmake leveldb-devel snappy-devel hdf5-devel lmdb-devel
我们主要使用Python Caffe,所以需要先安装Python 2.7
$ sudo yum install python27 python27-devel
注意安装完并没有替换系统默认的python 2.6,最好也不要替换,因为 yum 本身需要python 2.6: