概要:本文描述如何使用 Charles 进行SSL Proxying,以便分析 HTTPS 流量。

Charles 版本:4.2.1

一、安装 SSL 证书

1、Mac电脑端

启动Charles软件,在菜单中找到 Help -> SSL Proxying -> Install Charles Root Certificate,点击即可进行Mac电脑端的SSL根证书安装,如图:

然后会调用系统【钥匙串访问】设置,可以看到 Charles Proxy CA 字样的证书已安装,但由于该证书是Charles自签名的,不被系统信任,所以还需要对其手动设置信任证书。

双击该证书,展开【信任】,设置【使用此证书时】-选择【始终信任】,然后关闭设置即可,如图:

- 阅读剩余部分 -


运行环境:CentOS release 6.9 (Final) ,Amazon Linux AMI 2017.09

1、问题

使用 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。到底怎么回事呢?

2、解惑

问题出在Linux系统启动过程中,也就是说Nginx主进程启动时,上面的限制配置没有生效;实际上系统启动后执行用户登录login时才会使 limits.conf 配置生效。

简单描述一下,Linux内核启动后的系统启动过程如下:

  1. 运行/sbin/init 程序,执行系统的1号进程(此后系统的控制权就交给 /sbin/init 进程了)

  2. 读取 /etc/inittab 来确定系统启动级别(例如 读取到的默认级别是3)

  3. 执行初始化系统脚本 /etc/rc.d/rc.sysinit 来进行系统配置初始化

  4. 执行 /etc/rc.d/rc 脚本,根据启动级别,执行/etc/rc.d/rc*.d/ 下的各种服务启动脚本(比如 rc3.d下的文件)

  5. 执行 /etc/rc.d/rc.local 脚本(其实是/etc/rc.d/rc*.d/ 下的最后一个脚本,即S99local)

  6. 完成了所有的启动任务后,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
#结果见下图

3、解决

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 不生效的问题。



1、tmpwatch 不会删除其作用的目录(即便目录变成空的了)

$ 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


2、注意 find 命令查找时,输出结果中很可能会包含所查找的目录本身

$ 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 proxy timed out with dynamic upstreams

当使用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是经常变化的,所以很容易出现转发错误的情况。

解决方案:

1、使用 Nginx Plus(付费方案)

其中一个解决方案是付费购买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地址。

2、将upstream server配置为变量(取巧免费方案)

另一个免费的方案是按照如下方法进行配置:

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.


关于 proxy_pass 的 forwarded URI:

如果 location 不是 / ,proxy_pass 后的URI不同的写法会有不同的结果。

1、通常情况(upstream 未使用变量)

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 。

2、upstream 使用变量的情况

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 的请求。


参考:Nginx with dynamic upstreams


Caffe,来自伯克利的深度学习框架。本文记录和整理了一下其在CentOS 6.7下的编译安装过程,因其依赖比较多,且大多需要手工编译安装,期间遇到较多编译失败,特整理下来供有需要的人参考,少走一些弯路。

环境:CentOS release 6.7 (Final),Python 2.7

1. Prerequisites

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.

1.1 General dependencies

1.1.1 下面这些包可以使用 yum 安装:
$ sudo  yum install  cmake leveldb-devel snappy-devel hdf5-devel lmdb-devel

1.1.2 yum安装Python 2.7 

我们主要使用Python Caffe,所以需要先安装Python 2.7

$ sudo  yum install python27 python27-devel

注意安装完并没有替换系统默认的python 2.6,最好也不要替换,因为 yum 本身需要python 2.6:

- 阅读剩余部分 -