用 OpenResty 寫了一個 SNI 代理

0   1532 轉為簡體

功能類似於dlundquist/sniproxy

推薦 OpenResty 加上 stream 模塊和 ngx_stream_lua_module 模塊。在 1.9.15.1 上測試通過。

示例配置:

A Lua table sni_rules should be defined in the init_worker_by_lua_block directive.

The key can be either whole host name or regular expression. Use . for a default host name. If no entry is matched, connection will be closed.

The value is a table containing host name and port. If host is set to nil, the server_name in SNI will be used. If the port is not defined or set to nil, 443 will be used.

Rules are applied with the priority as its occurrence sequence in the table. In the example above, twitter.com will match the third rule rather than the fourth.

If the protocol version is less than TLSv1 (eg. SSLv3, SSLv2), connection will be closed, since SNI extension is not supported in these versions.

升級到Ubuntu16.04,開始接受systemd的調教

7   2682 轉為簡體

sudo do-release-upgrade -d

然後進入看戲模式

OpenVZ

openvz(打滿補丁的)內核2.6.32-042stab111.X之前不支持220以上版本的systemd,而16.04用的是229,所以升完之後你會得到一個沒有systemd存在的美好世界。

只是因為systemd啟動不了,所以開機啟動項也都不啟動了,你得去serial console裏手動設ip和route。所以還是發個tk讓客服去升級母雞內核吧www

 

udev

system-udev會自動把網卡名字改成奇怪的em0或者ens0什麼的,詳情見這裡

反正systemd說什麼都是對的,所以兄弟請幹了這碗熱巧克力

可以修改/etc/default/grub 的GRUB_CMDLINE_LINUX,改成:

biosdevname=0

就可以繼續使用eth0命名了

 

mysql-apt-config

mysql的官方apt源里還沒有支持16.04,而update-manager會嘗試將sources.list.d里的源都替換成xenial去更新,所以可能會因為mysql的源沒有candidate而報錯。

解決辦法就是先把/etc/apt/sources.list.d/mysql.list改個擴展名,升完再改回去,然後把裡面的trusty改成xenial。這樣(mysql支持以後)就可以收到16.04的更新了。

 

update-manager的編碼問題

哈哈哈哈哈哈哈哈哈哈哈哈哈哈我先笑一會

add-apt-repository的時候這個問題就存在,如果ppa源的標題帶有奇怪的字符會報錯。因為Python3是根據當前LC_ALL來自動選擇codec的。

然後update-manager也會死在同一個地方,所以記得先export LC_ALL=posix,再sudo do-release-upgrade -d,再喝茶

Let’s Encrypt集中化管理

9   1407 轉為簡體

Let’s Encrypt的證書籤發原理實際上和傳統的PKI一樣,只不過自動化完成了生成CSR和私鑰、提交CSR、取回證書的過程。

此外還要驗證域名所屬,這一部分和傳統的簽發機構是一樣的,不過傳統的簽發機構還允許我們使用域名whois中填寫的郵箱來驗證,而Letsencrypt貌似只能通過http challenge的方式來驗證。即和驗證服務器約定一個uri和隨機字符串,驗證服務器請求這一uri,如果得到的內容和約定的隨機字符串相同,則驗證通過。如圖所示:

letsencrypt_howitworks

官網上抄的)

這意味着我們得在每台部署https的前端的負載均衡服務器上都裝一個letencrypt工具。有沒有什麼集中化管理的辦法的呢?

實際上,由於challenge的uri的有規律,我們可以將前端服務器收到的這類請求代理到同一台專門用來簽發、更新證書的服務器上。如圖所示:

letsencrypt_howitworks_proxypass

  1. 當在服務器B上發起域名a.example.com新的簽發請求後,Let’s Encrypt的簽發服務器返回一個challange uri (8303)和response (ed98)。
  2. 服務器B使用webroot插件將這個uri和response寫入本地磁盤上對應的文件。
  3. Let’s Encrypt的簽發服務器為了驗證example.com的所屬,查詢到example.com指向前端服務器A,於是發送一個HTTP請求/.well-known/acme-challenge/8303到服務器A
  4. 服務器A反代這一請求到服務器B
  5. B讀取剛才第二步時寫入到response,返回到A;A返回到Let’s Encrypt的簽發服務器
  6. 驗證成功,發證!

然後,我們只要從服務器A上取回存儲在B上到證書就可以了。可以在B上做一個RESTful的api。注意要配置allow和deny。

A服務器(前端)的nginx配置如下:

B服務器的nginx配置如下:

然後在B上運行:

讓Coreseek支持索引日語假名

10   1104 轉為簡體

coreseek是一個修改版的sphinx,用mmseg來做中文分詞。但是發現一個問題,日語搜索總是效果很差,全部是假名的關鍵詞會返回一個空結果。

開始猜想是不是詞庫沒有包含日語的關係,後來仔細想了一想,mmseg對於沒有在詞典里的詞應該是直接一元分詞的,按理說也不應該出現無法索引日語的關係。我們可以通過mmseg命令行工具來證明這一點:

證明mmseg進行了一元分詞。

那麼為什麼coreseek搜不到假名呢?我找啊找啊終於發現在coreseek使用mmseg進行分詞的過程中,對輸入字符做了一個過濾,並且有一個注釋:

可見coreseek雖然將CJK (Chinese, Japanese, Korean) 中所有漢字、全角字符和標點加入了範圍,但是卻漏掉了平假名和片假名。因此我們將第三個range改成0x3000, 0x30FF, 0x3000就可以修正這個問題。

其中:

我把修改後的版本放到了github

另外,這裡可以查詢到Unicode編碼範圍對應的字符內容;unicode.org有一個database,但是是一個列出了全部字符的大pdf,我似乎沒有找到類似的分類。

對於Ubuntu/Debian,這裡有編譯好的coreseek的deb包:i386 amd64;依賴於mmseg:i386 amd64;mmseg自帶的詞典