1. 程式人生 > >在nginx伺服器上配置ssl代理https以及wss的一些筆記

在nginx伺服器上配置ssl代理https以及wss的一些筆記

1、前言

    因為微信小程式在與伺服器通訊時必須使用ssl協議,所以準備著手在nginx伺服器上配置好ssl

2、初步想法

    之前有看過一點關於實現wss連線的文章,大致瞭解到ssl是一個在運作在傳輸層的安全通訊協議,他的通訊流程大致為:

伺服器認證階段:

1)客戶端向伺服器傳送一個開始資訊“Hello”以便開始一個新的會話連線;

2)伺服器根據客戶的資訊確定是否需要生成新的主金鑰,如需要則伺服器在響應客戶的“Hello”資訊時將包含生成主金鑰所需的資訊;

3)客戶根據收到的伺服器響應資訊,產生一個主金鑰,並用伺服器的公開金鑰加密後傳給伺服器;

4)伺服器回覆該主金鑰,並返回給客戶一個用主

金鑰認證的資訊,以此讓客戶認證伺服器。

    以我的理解來看,主金鑰即每次的會話金鑰,公開金鑰即網站的證書,然後在伺服器回覆主金鑰時,實際上是拿自己的私鑰來先解開公鑰加密的會話金鑰,然後再利用證書中的公鑰加密一段回覆資訊給客戶。在這個過程中需要注意的是會話金鑰是由客戶產生的。

    知道了ssl是怎麼運作了,然後我開始的想法是,直接在伺服器的python程式碼中直接實現ssl通訊,但是因為我的小程式端使用的是需要ssl加密的websocket,而PC端則是裸奔的socket通訊,而ssl又是一個傳輸層協議,所以對客戶端的識別是一個小問題,我的第一個想法是開闢兩個埠,一個用於處理小程式端,另一個處理PC端,這樣也就需要繼承兩次socketserver.BaseRequestHandler,重寫兩次handle函式,準備的參考程式碼:

Python3+ssl實現加密通訊,其中大致說的是,在得到一個socket後,利用ssl模組中的SSLContext上下文的wrap_socket()函式來得到一個帶ssl的socket,然後用這個新的socket進行通訊,這其實已經是一個挺簡便的方法了。

    然後在查閱了其他資料後,我又決定在PC客戶端也乾脆實現好ssl好了,緊接著我發現一些文章上所說的根證書我並沒有,雖然可能和普通證書沒有什麼區別,而且網路上關於這個的程式碼很少,由此我找到了一份ssl官方的開發者文件翻譯版,雖然是機翻:Python 聯網 | Networking ssl,不過此時我也不準備用python程式碼直接實現ssl了,還是用nginx直接代理ssl比較實在吼吼吼。

3、獲取證書

    證書我並沒有選擇自己生成,而是準備使用各大雲平臺的免費ssl證書,開始時選擇了阿里雲的Symantec免費單域名版ssl,結果沒通過安全稽核,域名沒什麼敏感詞,嗶了狗了。。。然後死馬當活馬醫,又去了騰訊雲的ssl里弄了的Symantec免費ssl,結果居然成功了,然後拿到了nginx的證書,一份是crt檔案,一份是key檔案

4、配置nginx

    接下來就是配置nginx中的ssl了,就不說中間的探索和試錯過程了,直接說結論

    我的nginx配置目錄為/etc/nginx/conf.d   就我的瞭解,nginx伺服器啟動時會挨個執行這裡面的.conf檔案,這些conf檔案中一般會有server欄位,例如:

    server中開始有listen引數,填的當然是監聽埠443啦,然後是server_name,這就是url,兩個結合一起就是url:listen, 然後配置要配置ssl的話就又ssl,ssl_certificate,ssl_certificate_key引數,比較一目瞭然,ssl一般填寫on。再後面就是一些協議細節配置了。

    接著是location欄位,後面會接一個小欄位,這個就是當客戶訪問指定埠時使用的協議標識,wss就是/wss,http直接是/,根據標識的不同,定位到的程式碼段就不同,比如當識別為http標識時就會到下面的location程式碼段當中,程式碼塊中有相關的處理根目錄,預設文件日誌等等設定,需要注意的是proxy_pass引數,這個填的是http://$upstram$/,其中upstream需要事先定義例如:

    這裡的upstream就是“web”,這裡面只有一段地址串,可以理解為一個出口,之前的proxy_pass引數就是作為一個代理將當前的請求跳轉到另一個出口,我的程式碼中將其跳轉為8080埠,然後nginx又會繼續將url:8080作為一個請求來處理(但是ssl已經轉載好了)。

    然後我又在這個配置資料夾裡建立了一個新的配置檔案http2https.conf,,其監聽的埠就是8080,在這裡我就配置好正經的http請求該配置的東西, 然後為了讓普通的http請求也能夠跳轉到https,我在原先監聽80埠的程式碼段,中加上了

return      301 https://$server_name$request_uri;

  或者

rewrite ^(.*)$  https://$host$1 permanent; 

    也可以,前者是新的寫法,這樣普通的http也就是80埠的請求就被轉成了443埠的請求了,隨後就會呼叫之前第一個檔案中的程式碼進行多次跳轉將客戶的請求變成https請求。