默認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使用方法。