linux 学习笔记-050-Nginx 负载均衡,配置 SSL,SSL 原理

发布于 2018-03-16  685 次阅读


Nginx 负载均衡

可以和代理服务器相结合使用,一台代理服务器代理多台 web 服务器,而多台服务器实现负载均衡的功能,Nginx 不支持代理 Https

例如:user1 通过代理服务器访问站点的时候会被解析到 web1 服务器,user2 通过代理服务器访问站点的时候会被解析到 web2 服务器,并且 Nginx 负载均衡有个功能就是,当 web1 服务器挂掉了,代理服务器就不会把 user1 的请求解析到 web1 服务器,而是会解析到其中一台正常的 web 服务器

[root@am-01:~#] yum -y install bind-util

已加载插件:fastestmirror

base                                                                          | 3.6 kB  00:00:00    

epel/x86_64/metalink                                                          | 7.0 kB  00:00:00    

epel                                                                          | 4.7 kB  00:00:00    

extras                                                                        | 3.4 kB  00:00:00    

updates                                                                       | 3.4 kB  00:00:00    

………………省略部分输出信息………………

已安装:

  bind-utils.x86_64 32:9.9.4-51.el7_4.2                                                             



作为依赖被安装:

  GeoIP.x86_64 0:1.5.0-11.el7                  bind-libs.x86_64 32:9.9.4-51.el7_4.2                 



作为依赖被升级:

  bind-libs-lite.x86_64 32:9.9.4-51.el7_4.2          bind-license.noarch 32:9.9.4-51.el7_4.2        



完毕!

#先安装 dig 包,用来确定拿来实验的域名的 IP 地址
[root@am-01:~#] dig www.qq.com



; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7_4.2 <<>> www.qq.com

;; global options: +cmd

;; Got answer:

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60043

;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1



;; OPT PSEUDOSECTION:

; EDNS: version: 0, flags:; udp: 4096

;; QUESTION SECTION:

;www.qq.com.   IN A



;; ANSWER SECTION:

www.qq.com.  169 IN A 14.17.32.211

www.qq.com.  169 IN A 14.17.42.40

www.qq.com.  169 IN A 59.37.96.63



;; Query time: 25 msec

;; SERVER: 114.114.114.114#53(114.114.114.114)

;; WHEN: 五 3 月 16 23:12:35 CST 2018

;; MSG SIZE  rcvd: 87

#这里可以见到 www.qq.com 有 3 个 IP 地址,这里拿 www.qq.com 做 Nginx 负载均衡实验
[root@am-01:~#] vim /usr/local/nginx/conf/vhost/load.conf

  upstream qq_com

  {

      ip_hash;

      server 14.17.32.211:80;

      server 14.17.42.40:80;

      server 59.37.96.63:80;

  }

  #upstream 用来指定 web server 的 IP 地址,后面的名字可以自定义;ip_hash 是为了使同一个用户始终保持在同一台机器上,预防登录了 A 服务器,一刷新就变成访问 B 服务器,导致要重新登录的情况

  server

  {

      listen 80;

      server_name www.qq.com;

      location /

      {

          proxy_pass      http://qq_com;

  #这个 proxy_pass 要和 upstream 定义的一样

          proxy_set_header Host   $host;

          proxy_set_header X-Real-IP      $remote_addr;

          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      }

  }

#新添加一个 Nginx 负载均衡使用的配置文件
[root@am-01:~#] curl -x127.0.0.1:80 www.qq.com

This is the default site.

[root@am-01:~#] /usr/local/nginx/sbin/nginx -t

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok

nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

[root@am-01:~#] /usr/local/nginx/sbin/nginx -s reload

[root@am-01:~#] curl -x127.0.0.1:80 www.qq.com

………………省略部分输出信息………………

<!-- ̑¹·̷̑ ½⋸-->

<script>

// ͚Ѷ·׎??

var _mtac = {};

(function() {

var mta = document.createElement("script");

mta.src = "http://pingjs.qq.com/h5/stats.js?v2.0.2";

mta.setAttribute("name", "MTAH5");

mta.setAttribute("sid", "500460529");

var s = document.getElementsByTagName("script")[0];

s.parentNode.insertBefore(mta, s);

})();

</script>

</body>

</html><!--[if !IE]>|xGv00|ded9605fd1c9373c01de3b08f32586d6<![endif]-->

#在配置文件未生效时,访问 www.qq.com 的时候会返回默认页面,当重载配置文件后,访问 www.qq.com 的时候会返回 www.qq.com 主页的源代码,这说明 Nginx 负载均衡已经成功了

ssl 原理

https 的通讯是加密的,假如你访问一个重要网站,而这个网站会返回一些重要数据给你,假如不是 https 加密通讯的话,某些厉害的黑客能做到从中监听窃取这些重要数据,而使用 https 加密通讯,就算黑客截取到重要数据,这些数据也是加密的乱码文件,是无法解密的

SSL 工作流程:

01:浏览器发送一个 https 的请求给服务器;

02:服务器要有一套数字证书,可以自己制作,也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面,这套证书其实就是一对公钥和私钥;

03:服务器会把公钥传输给客户端;

04:客户端(浏览器)收到公钥后,会验证其是否合法有效,无效会有警告提醒,有效则会生成一串随机数(只使用一次,下一次访问服务器的时候会重新生成),并用收到的公钥加密;

05:客户端把加密后的随机字符串传输给服务器;

06:服务器收到加密随机字符串后,先用私钥解密(公钥加密,私钥解密),获取到这一串随机数后,再用这串随机字符串加密传输的数据(该加密为对称加密,所谓对称加密,就是将数据和私钥也就是这个随机字符串通过某种算法混合在一起,这样除非知道私钥,否则无法获取数据内容);

07:服务器把加密后的数据传输给客户端;

08:客户端收到数据后,再用自己的私钥也就是那个随机字符串解密

流程图如下:

linux 学习笔记-050-Nginx 负载均衡,配置 SSL,SSL 原理

生产 ssl 密钥对

[root@am-01:~#] rpm -qf `which openssl`

openssl-1.0.2k-8.el7.x86_64

#查看一个命令是由哪个包安装的,假如系统没安装的话,可以用 yum 安装
[root@am-01:~#] cd /usr/local/nginx/conf/

[root@am-01:/usr/local/nginx/conf#] openssl genrsa -des3 -out tmp.key 2048

Generating RSA private key, 2048 bit long modulus

..........+++

..................................+++

e is 65537 (0x10001)

Enter pass phrase for tmp.key:

Verifying - Enter pass phrase for tmp.key:

#这里为利用 openssl 生成私钥,genrsa 表示生成 rsa 格式的私钥,长度为 2048,名字为 tmp.key,生成密钥必须要有密码
[root@am-01:/usr/local/nginx/conf#] openssl rsa -in tmp.key -out am.key

Enter pass phrase for tmp.key:

writing RSA key

#因为用户在客户端浏览器访问网站的时候还要输入私钥所生成的密码,这明显是不科学的,这一句是把 tmp.key 转换为一个没密码的 am.key,这时,tmp.key 和 am.key 是同时存在的,只是一个有密码,一个没密码
[root@am-01:/usr/local/nginx/conf#] rm -rf tmp.key

[root@am-01:/usr/local/nginx/conf#] openssl req -new -key am.key -out am.csr

You are about to be asked to enter information that will be incorporated

into your certificate request.

What you are about to enter is what is called a Distinguished Name or a DN.

There are quite a few fields but you can leave some blank

For some fields there will be a default value,

If you enter '.', the field will be left blank.

-----

Country Name (2 letter code) [XX]:CN

State or Province Name (full name) []:GD     

Locality Name (eg, city) [Default City]:SZ

Organization Name (eg, company) [Default Company Ltd]:am

Organizational Unit Name (eg, section) []:am

Common Name (eg, your name or your server's hostname) []:am-01

Email Address []:runfali@outlook.com



Please enter the following 'extra' attributes

to be sent with your certificate request

A challenge password []:itsupport.0

An optional company name []:am

#把有密码的私钥文件 tmp.key 删除,然后生成证书请求文件,需要拿这个文件和私钥一起生产公钥文件,填写的信息可以随意定义,填写的信息可以在访问站点的时候看到这个证书的信息
[root@am-01:/usr/local/nginx/conf#] openssl x509 -req -days 365 -in am.csr -signkey am.key -out am.crt

Signature ok

subject=/C=CN/ST=GD/L=SZ/O=am/OU=am/CN=am-01/emailAddress=runfali@outlook.com

Getting Private key

#生成公钥,这个公钥的时间是 365 天
[root@am-01:/usr/local/nginx/conf#] ls am.*

am.crt  am.csr  am.key

#可见,证书请求文件,私钥文件,公钥文件均已生成

Nginx 配置 ssl

[root@am-01:/usr/local/nginx/conf#] vim /usr/local/nginx/conf/vhost/ssl.conf

  server

  {

      listen 443;

      server_name am.com;

      index index.html index.php;

      root /data/wwwroot/am.com;

      ssl on;

      ssl_certificate am.crt;

      ssl_certificate_key am.key;

      ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

  }

[root@am-01:/usr/local/nginx/conf#] mkdir /data/wwwroot/am.com

[root@am-01:/usr/local/nginx/conf#] /usr/local/nginx/sbin/nginx -t

nginx: [emerg] unknown directive "ssl" in /usr/local/nginx/conf/vhost/ssl.conf:7

nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed

#新建一个 ssl 的配置文件,同时按照配置信息新建 am.com 目录,并重新加载配置文件,发现提示错误,这是因为当时编译安装 Nginx 的时候没有加上 SSL 相关的参数
[root@am-01:/usr/local/nginx/conf#] cd /usr/local/src/nginx-1.12.1/

[root@am-01:/usr/local/src/nginx-1.12.1#] ./configure --prefix=/usr/local/nginx --with-http_ssl_module

[root@am-01:/usr/local/src/nginx-1.12.1#] make && make install

#重新编译 Nginx,并加上--with-http_ssl_module 参数
[root@am-01:/usr/local/src/nginx-1.12.1#] /usr/local/nginx/sbin/nginx -t

nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok

nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

[root@am-01:/usr/local/src/nginx-1.12.1#] /etc/init.d/nginx restart

Restarting nginx (via systemctl):                          [  确定  ]

[root@am-01:/usr/local/src/nginx-1.12.1#] netstat -lntp

Active Internet connections (only servers)

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name   

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      96982/nginx: master

tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1111/sshd          

tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1837/master        

tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      96982/nginx: master

tcp6       0      0 :::3306                 :::*                    LISTEN      97359/mysqld       

tcp6       0      0 :::22                   :::*                    LISTEN      1111/sshd          

tcp6       0      0 ::1:25                  :::*                    LISTEN      1837/master        

#测试一下配置文件正确性,重启一下 Nginx,查看监听端口,可见已经监听了 443 端口
[root@am-01:/usr/local/src/nginx-1.12.1#] cd /data/wwwroot/am.com/

[root@am-01:/data/wwwroot/am.com#] vim index.html

  SSL

[root@am-01:/data/wwwroot/am.com#] vim /etc/hosts

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4

::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

127.0.0.1 am.com

[root@am-01:/data/wwwroot/am.com#] curl https://am.com

curl: (60) Peer's certificate issuer has been marked as not trusted by the user.

More details here: http://curl.haxx.se/docs/sslcerts.html



curl performs SSL certificate verification by default, using a "bundle"

 of Certificate Authority (CA) public keys (CA certs). If the default

 bundle file isn't adequate, you can specify an alternate file

 using the --cacert option.

If this HTTPS server uses a certificate signed by a CA represented in

 the bundle, the certificate verification probably failed due to a

 problem with the certificate (it might be expired, or the name might

 not match the domain name in the URL).

If you'd like to turn off curl's verification of the certificate, use

 the -k (or --insecure) option.

#这时使用 curl -x127.0.0.1 https://am.com 是无法访问的,需要写 hosts,并且使用 curl https://am.com 去访问,但会提示一堆信息,这是因为证书被标记为不可信任,这是因为证书是自己颁发的私人证书,所以不信任

使用电脑客户端浏览器测试,先写 hosts

linux 学习笔记-050-Nginx 负载均衡,配置 SSL,SSL 原理

到浏览器测试一下,可以见到是可以访问的

linux 学习笔记-050-Nginx 负载均衡,配置 SSL,SSL 原理

linux 学习笔记-050-Nginx 负载均衡,配置 SSL,SSL 原理

注:

假如客户端浏览器访问不到,检查 linux 服务端有没有防火墙限制

扩展

针对请求的 uri 来代理:

http://ask.apelearn.com/question/1049

根据访问的目录来区分后端的 web:

http://ask.apelearn.com/question/920

nginx 长连接:

http://www.apelearn.com/bbs/thread-6545-1-1.html

nginx 算法分析:

http://blog.sina.com.cn/s/blog_72995dcc01016msi.html