默认nginx是没有安装ssl模块的,须要编译安装nginx时加入--with-http_ssl_module选项。php
关于SSL/TLS原理请参考 这里,若是你只是想测试或者自签发ssl证书,参考 这里 。css
提示:nignx到后端服务器因为通常是内网,因此不加密。html
全站作ssl是最多见的一个使用场景,默认端口443,并且通常是单向认证。java
server { listen 443; server_name example.com; root /apps/www; index index.html index.htm; ssl on; ssl_certificate ../SSL/ittest.pem; ssl_certificate_key ../SSL/ittest.key; # ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; # ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; # ssl_prefer_server_ciphers on; }
若是想把http的请求强制转到https的话:nginx
server { listen 80; server_name example.me; rewrite ^ https://$server_name$request_uri? permanent; ### 使用return的效率会更高 # return 301 https://$server_name$request_uri; }
ssl_certificate 证书实际上是个公钥,它会被发送到链接服务器的每一个客户端,ssl_certificate_key私钥是用来解密的,因此它的权限要获得保护但nginx的主进程可以读取。固然私钥和证书能够放在一个证书文件中,这种方式也只有公钥证书才发送到client。算法
ssl_protocols 指令用于启动特定的加密协议,nginx在1.1.13和1.0.12版本后默认是 ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2,TLSv1.1与TLSv1.2 要确保 OpenSSL >= 1.0.1 ,SSLv3 如今还有不少地方在用但有很多被攻击的漏洞。shell
ssl_ciphers 选择加密套件,不一样的浏览器所支持的套件(和顺序)可能会不一样。这里指定的是OpenSSL库可以识别的写法,你能够经过 openssl -v cipher 'RC4:HIGH:!aNULL:!MD5'(后面是你所指定的套件加密算法) 来看所支持算法。segmentfault
ssl_prefer_server_ciphers on 设置协商加密算法时,优先使用咱们服务端的加密套件,而不是客户端浏览器的加密套件。后端
ssl_session_cache shared:SSL:10m; : 设置ssl/tls会话缓存的类型和大小。若是设置了这个参数通常是 shared,buildin 可能会参数内存碎片,默认是 none,和 off 差很少,停用缓存。如shared:SSL:10m 表示我全部的nginx工做进程共享ssl会话缓存,官网介绍说1M能够存放约4000个sessions。 详细参考serverfault上的问答 ssl_session_cache。浏览器
ssl_session_timeout : 客户端能够重用会话缓存中ssl参数的过时时间,内网系统默认5分钟过短了,能够设成30m即30分钟甚至4h。
设置较长的 keepalive_timeout 也能够减小请求ssl会话协商的开销,但同时得考虑线程的并发数了。
提示:在生成证书请求csr文件时,若是输入了密码,nginx每次启动时都会提示输入这个密码,可使用私钥来生成解密后的key来代替,效果是同样的,达到免密码重启的效果:
openssl rsa -in ittest.key -out ittest_unsecure.key
若是你是找一个知名的ssl证书颁发机构如VeriSign、Wosign、StartSSL签发的证书,浏览器已经内置并信任了这些根证书,若是你是自建C或得到二级CA受权,都须要将CA证书添加到浏览器,这样在访问站点时才不会显示不安全链接。各个浏览的添加方法不在本文探讨范围内。
一个站点并非全部信息都是很是机密的,如网上商城,通常的商品浏览能够不经过https,而用户登陆以及支付的时候就强制通过https传输,这样用户访问速度和安全性都获得兼顾。
可是请注意不要理解错了,是对页面加密而不能针对某个请求加密,一个页面或地址栏的URL通常会发起许多请求的,包括css/png/js等静态文件和动态的java或php请求,因此要加密的内容包含页面内的其它资源文件,不然就会出现http与https内容混合的问题。在http页面混有https内容时,页面排版不会发生乱排现象;在https页面中包含以http方式引入的图片、js等资源时,浏览器为了安全起见会阻止加载。
下面是只对example.com/account/login登陆页面进行加密的栗子:
root /apps/www; index index.html index.htm; server { listen 80; server_name example.com; location ^~ /account/login { rewrite ^ https://$server_name:443$request_uri? permanent; } location / { proxy_pass http://localhost:8080; ### Set headers #### 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_redirect off; } } server { listen 443 ssl; server_name example.com; ssl on; ssl_certificate ../SSL/ittest.pem; ssl_certificate_key ../SSL/ittest.key; ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; ssl_prefer_server_ciphers on; location ^~ /account/login { proxy_pass http://localhost:8080; 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_redirect off; ### Most PHP, Python, Rails, Java App can use this header -> https ### proxy_set_header X-Forwarded-Proto $scheme; } location / { rewrite ^ http://$server_name$request_uri? permanent; } }
关于rewrite与location的写法参考这里。当浏览器访问http://example.com/account/login.xx时,被301到https://example.com/account/login.xx,在这个ssl加密的虚拟主机里也匹配到/account/login,反向代理到后端服务器,后面的传输过程是没有https的。这个login.xx页面下的其它资源也是通过https请求nginx的,登陆成功后跳转到首页时的连接使用http,这个可能须要开发代码里面控制。
上面配置中使用了proxy_set_header X-Forwarded-Proto $scheme,在jsp页面使用request.getScheme()获得的是https 。若是不把请求的$scheme协议设置在header里,后端jsp页面会一直认为是http,将致使响应异常。
ssl配置块还有个与不加密的80端口相似的location /,它的做用是当用户直接经过https访问首页时,自动跳转到不加密端口,你能够去掉它容许用户这样作。
上面的两种配置都是去认证被访问的站点域名是否真实可信,并对传输过程加密,但服务器端并无认证客户端是否可信。(实际上除非特别重要的场景,也不必去认证访问者,除非像银行U盾这样的状况)
要实现双向认证HTTPS,nginx服务器上必须导入CA证书(根证书/中间级证书),由于如今是由服务器端经过CA去验证客户端的信息。还有必须在申请服务器证书的同时,用一样的方法生成客户证书。取得客户证书后,还要将它转换成浏览器识别的格式(大部分浏览器都认识PKCS12格式):
openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
而后把这个client.p12发给你相信的人,让它导入到浏览器中,访问站点创建链接的时候nginx会要求客户端把这个证书发给本身验证,若是没有这个证书就拒绝访问。
同时别忘了在 nginx.conf 里配置信任的CA:(若是是二级CA,请把根CA放在后面,造成CA证书链)
proxy_ignore_client_abort on; ssl on; ... ssl_verify_client on; ssl_verify_depth 2; ssl_client_certificate ../SSL/ca-chain.pem; # 在双向location下加入: proxy_set_header X-SSL-Client-Cert $ssl_client_cert;
nginx默认安装了一个 ngx_http_geo_module,这个geo模块能够根据客户端IP来建立变量的值,用在如来自172.29.73.0/24段的IP访问login时使用双向认证,其它段使用通常的单向认证。
geo $duplexing_user { default 1; include geo.conf; # 注意在0.6.7版本之后,include是相对于nginx.conf所在目录而言的 }
语法 geo [$address] $variable { … },位于http段,默认地址是$reoute_addr,假设 conf/geo.conf 内容:
127.0.0.1/32 LOCAL; # 本地 172.29.73.23/32 SEAN; # 某个IP 172.29.73.0/24 1; # IP段,能够按国家或地域定义后面的不一样的值
须要配置另一个虚拟主机server{ssl 445},里面使用上面双向认证的写法,而后在80或443里使用变量$duplexing_user去判断,若是为1就rewrite到445,不然rewrite到443。具体用法能够参考nginx geo使用方法。