當新浪防盜鏈時,我在想些什麼?續

起步

在去年五月份的時候,新浪免費圖牀做了防盜鏈機制,羊毛就不能褥了。個人博客不掛圖片忍忍也就過去,但在某些時候還是不便。後來我採用 docker 鏡像 + 開源圖牀系統 lychee-docker 的方式,在自己的阿里服務器上搭建了一個簡易圖牀。時移近一年,使用起來沒有什麼不對勁的地方。但當時我知道的東西還是太少,做了許多不規範的操作,現在想彌補。

我基於前文(當新浪防盜鏈時,我在想些什麼?)在虛擬機裏還原了過往操作,並將在此基礎上彌補之前的不足。其用意是:倘若你不幸參看我寫的教程部署了圖牀系統,那麼我帶你入坑的,我負責把你帶出來。

HTTP -> HTTPS

關於谷歌對 HTTP 協議越來越不友好的新聞屢見不鮮,而作爲增加了加密層的 HTTPS 協議已經出來多年。不論是跟風還是爲保數據安全,將 HTTP 更換至 HTTPS 都顯得必要。

如果你的網站還不是 HTTPS,瀏覽器市場的霸主 chrome 就會負責任的告訴遊客:當前您訪問的網站不安全
在這裏插入圖片描述

所以第一步要做的就是,把 lychee-docker 原有的 HTTP 修改爲 HTTPS。這其實很簡單,因爲圖牀系統使用 nginx 做代理,我們只需要修改 nginx 配置即可。

在動手之前,我們還需要準備 HTTPS 證書。譬如我的服務器與域名都是阿里那兒買的,於是證書索性也從阿里購買(SSL證書)。對於個人站點來說,所謂“購買”就是申請,不用花錢。當然,你也可以去其他機構獲取證書,我既不曾嘗試,便不再妄言,心中有疑惑可以向搜索引擎傾述。

我爲方便本地演示,需要做一個僞證書,否則不能開啓 HTTPS。

$ openssl req -x509 -newkey rsa:2048 -nodes -sha256 -keyout localhost-cert.key -out localhost-cert.pem

在這裏插入圖片描述
執行上述命令之後,在當前目錄下就會生成 localhost-cert.key, localhost-cert.pem 兩個文件。現在將其拷貝進圖牀所在的 docker 容器中。

$ docker cp localhost-cert.pem [container_id]:/etc/nginx
$ docker cp localhost-cert.key [container_id]:/etc/nginx

接着進入容器,修改 nginx 的配置。使其支持 HTTPS。

$ docker exec -it [container_id] bash  # 進入 docker
(docker) $ vi /etc/nginx/sites-enabled/lychee
  • 這裏說明一下,所有在 docker 容器裏面執行的命令,用 (docker) 前綴加以提示。

替換爲以下內容。

server {
        listen 443 ssl;
        server_name localhost;

        ssl_certificate      localhost-cert.pem;  # 注意 1
        ssl_certificate_key  localhost-cert.key;  # 注意 2

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        root /var/www/lychee;
        index index.php;
        client_max_body_size 20G;
        access_log /var/log/nginx/lychee.access.log;
        error_log /var/log/nginx/lychee.error.log;

        location / {
            index  index.php index.html index.htm;
        }

        location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
            expires max;
            add_header Pragma public;
            add_header Cache-Control "public, must-revalidate, proxy-revalidate";
        }

        location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_index index.php;
            include fastcgi_params;
        }
        
        include php.conf;
}

server {
        listen 80;
        server_name 192.168.111.136:5121;  # 注意 3
        rewrite ^(.*) https://$server_name$1 permanent;
}

你可以仔細對比上述內容和原來 /etc/nginx/sites-enabled/lychee 文件中的內容。其實就是把 server 中的 80 修改爲 443 ssl,同時添加一系列 ssl 的設置。如果你有自己的 HTTPS 證書,你需要替換掉 localhost-cert.pem 和
localhost-cert.key,一定要確保文件路徑正確。

最後在末尾添加監聽 80 端口的 server,這樣做是爲了同時支持對 80 端口的訪問,但並不能讓用戶真去訪問 80 端口。rewrite ^(.*) https://$server_name$1 permanent 表示所有訪問 80 端口的請求,都會自動跳轉到 HTTPS 監聽的端口。在 80 sever 中,需要留意 server_name 對應的值,這裏寫入的是容器外的 ip:port。域名也行,比方說我的域名是 youguanxinqing.xyz,所以我圖牀中 80 端口對應的 server_name 是:

server_name youguanxinqing.com:5121

在前文中我們用 5120 映射容器 80 端口,而 5121 映射容器中的 443 端口。

最後重啓 nginx。

(docker) $ supervisorctl

在這裏插入圖片描述

爲運行容器添加端口映射

到了這裏,別以爲就大功告成。用 docker ps 命令可以看到,容器與宿主機之間僅有一個端口映射:5120:80。我們還需要添加 5121:443,肯定不能去重新生成一個容器,所以涉及到修改 docker 配置。需要先把宿主機中的 docker 主進程停下來。

$ systemctl stop docker
$ cd /var/lib/docker/containers/[container_id]*
$ vim hostconfig.json
  • container_id 是你容器的 id 值,事實上這個值只是一串 hash 的前綴而已,爲了進入對應的目錄,需要在末尾添加通配符 *

hostconfig.json 文件中找到 PortBindings:"PortBindings":{"80/tcp":[{"HostIp":"","HostPort":"5120"}]}。我們根據 80 端口的映射格式,添加一個 443 端口(其實就是把內容複製一遍,修改一下端口值就好)。爲方便你觀看,我將關鍵內容縮進之後呈現如下。

"PortBindings":{
	"80/tcp":[{"HostIp":"","HostPort":"5120"}], 
	"443/tcp":[{"HostIp":"","HostPort":"5121"}]
}

保存退出,同級目錄下打開 config.v2.json,找到"ExposedPorts":{"80/tcp":{}}。以同樣的方式添加一個 443。

"ExposedPorts":{
	"80/tcp":{}, 
	"443/tcp":{}
}

啓動 docker,啓動容器:

$ systemctl start docker 
$ docker start [container_id]

如果操作無誤,在執行 docker ps 命令後,你應該可以看到輸出信息中有這樣一段內容。有,則說明成功:

0.0.0.0:5120->80/tcp, 0.0.0.0:5121->443/tcp

現在訪問圖牀就應該能看到協議是 HTTPS 了,即使你訪問是 http://$your_host:5120 也會跳轉到 https://$your_host:5121。
在這裏插入圖片描述
由於我使用的是本地測試環境,證書是未經認證的僞證書。所以訪問的時候前面還是有“不安全”三個字。實際場景應該呈如下這般:
在這裏插入圖片描述

HTTPS -> HTTP2

這是一個可選項,但我建議你選擇。

照理說更換爲 HTTPS 已經很 OK 了,安全性也有了,“小鎖”也是賊好看。但 HTTPS 其實只是 HTTP + SSL,在 HTTP 外面套了一層 SSL 而已,使用的還是 HTTP1.1 協議——這玩意兒很落伍了。如果你不怕麻煩,爲什麼不來試試 HTTP2 呢?相較於 HTTP1.1 來說,HTTP2 允許信道複用,分幀傳輸,頭信息壓縮,從傳輸效率上可以嘲諷 1.1 小弟弟。
在這裏插入圖片描述
要想容器中的 nginx 支持 HTTP2 需要源碼編譯一個版本高一點的 nginx。lychee-docker 中的 nginx 爲 1.4.6,而如今最新穩定版本是 1.16.1。這是下載地址,畢竟是外網,如果你訪問速度太慢可以從我的網盤下載(鏈接放在文末)。如果你太懶,不想編譯也是可以的,我已將編譯好的可執行文件放在網盤中。

注意了,nginx 有個蛋疼的地方,如果想無縫替換 nginx 可執行文件,就必須使用相同的參數,所以需要進入容器獲取 nginx 配置時的參數。命令也很簡單。

(docker) $ nginx -V

在這裏插入圖片描述
configure arguments: ” 後面就是我們要用到的配置參數,需要記錄下來。回到宿主機,開始我們的源碼編譯之旅:

$ tar xf nginx-1.16.1.tar.gz
$ cd nginx-1.16.1
$ ./configure ...  # ... 表示之前記錄的那串參數

回車之後大概率你會遇到這樣一個錯誤:./configure: error: invalid option "--with-http_spdy_module",這是因爲新版的 nginx 不支持該選項,需要將此參數替換爲 --with-file-aio --with-http_v2_module

繼續回車你還會遇到錯誤,類似於這樣的一系列錯誤 ./configure: error: the HTTP XSLT module requires the libxml2/libxslt。這是因爲你環境上缺少編譯時用到的依賴。我暫無法告訴你需要安裝哪些依賴,但你可以參考 Linux Nginx安裝以及可能出現錯誤 這篇文章,幾乎涵蓋了所有需要安裝的依賴。

當 configure 成功後你能看到輸出信息如下。
在這裏插入圖片描述
開始編譯 nginx。編譯成功後可執行文件在 objs 目錄下,你可以 ll 進行查看。

$ make
$ ll objs/nginx

我們需要先去備份容器中的 nginx。

(docker) $ mv /usr/sbin/nginx /usr/sbin/nginx.old

回到宿主機將剛剛編譯好的 nginx 拷貝到容器中:

$ docker cp objs/nginx [container_id]:/usr/sbin/

進入容器重啓 nginx。重啓命令在上面貼過圖,這裏就不重複了。很遺憾,nginx 進程會起不來。這是因爲 nginx 鏈接的動態庫在容器中沒找到。我整理了 supervisor 錯誤日誌中的輸出信息,一共需要六個動態庫。

/usr/sbin/nginx: error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory
/usr/sbin/nginx: error while loading shared libraries: libssl.so.10: cannot open shared object file: No such file or directory
/usr/sbin/nginx: error while loading shared libraries: libcrypto.so.10: cannot open shared object file: No such file or directory
/usr/sbin/nginx: error while loading shared libraries: libgd.so.2: cannot open shared object file: No such file or directory
/usr/sbin/nginx: error while loading shared libraries: libjpeg.so.62: cannot open shared object file: No such file or directory
/usr/sbin/nginx: error while loading shared libraries: libpng15.so.15: cannot open shared object file: No such file or directory

這裏我說明一下,我的宿主機環境是 centos7,而 docker 容器中是 ubuntu 14,我直接將這些需要的動態庫拷貝到容器的 /usr/lib 目下,發現是可行的。由於還涉及到動態庫軟鏈接,避免累述,我把這些動態庫整理之後放在網盤裏,請自行下載。將動態庫拷貝到容器的 /usr/lib 目錄下,修改 /etc/nginx/sites-enabled/lychee 文件,進入 supervisorctl 啓動 nginx。

$ docker cp [動態庫] [container_id]:/usr/lib

(docker) $ vi /etc/nginx/sites-enabled/lychee
# listen 443 ssl;
# 修改爲:
# listen 443 ssl http2;

倘若一切成功,訪問頁面能看到請求的協議是 h2,也就是 http2 的縮寫。
在這裏插入圖片描述

如何排查其他問題

在升級 nginx 過程中,我遇到的所有問題已經在前面一一說明了。但不同的人操作會遇到不同的問題,這在部署環境時屢見不鮮。一旦遇到上述之外的問題,請查看容器中 nginx 和 supervisor 的日誌信息,根據錯誤內容到搜索引擎中尋找答案。

  • nginx 日誌路徑:/var/log/nginx。
  • supervisor 日誌路徑:/var/log/supervisor。

感謝

鏈接:https://pan.baidu.com/s/1rjW5ysRD_3EQinvkIFl7ng 提取碼:yvt7

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章