關閉 GitLab 的 nginx,使用自己裝的 nginx

我自己架設的 GitLab 是透過「Install self-managed GitLab」這邊的方法裝進 Ubuntu 系統內的 (我在自己的 wiki 上也有整理:「GitLab」),他會自己下載所有對應的套件,包括了 nginx

但這樣就直接把 TCP port 80/443 都吃掉了,同一台機器要放其他的 virtual host 就比較麻煩,所以找了些方法讓 GitLab 不要佔用 TCP port 80/443。

首先是找到這篇,資料有點舊,但裡面關掉 nginx 的方法還算是有用:「How to setup gitlab without embedded nginx」。

現在只要把 /etc/gitlab/gitlab.rb 裡面的:

  • nginx['enable'] 改成 false
  • web_server['external_users'] 改成 ['www-data']

然後跑 gitlab-ctl reconfigure 讓他更新設定檔,接下來停掉整個 GitLab 再打開 (或是重開機) 讓 nginx 完全失效就可以了。

接下來弄好自己的 nginx 以及 HTTPS 設定,這個部份我自己偏好用 dehydrated,其他人會有不同的偏好設法。

在弄完 nginx 後再來是 proxy_pass 類的資訊要帶進去,這個部份可以參考本來 GitLab 的 nginx 設定檔 (在 /var/opt/gitlab/nginx/conf/ 這下面),其中最重要的就是 GitLab 本身,我們會在 /etc/nginx/conf.d/upstream.conf 裡面寫入對應的 upstream 資訊 (沒這個檔案就自己生一個):

upstream gitlab-workhorse {
    server unix:/var/opt/gitlab/gitlab-workhorse/sockets/socket;
}

接下來是在對應的 virtual host 下設定 proxy_pass

    location / {
        proxy_pass http://gitlab-workhorse;
    }

另外我有啟用 GitLab 提供的 Mattermost,所以也要翻設定導進去:

#
upstream gitlab_mattermost {
    server 127.0.0.1:8065;
}

與:

    location / {
        proxy_pass http://gitlab_mattermost;
    }

都弄好後叫 nginx 重讀設定,接下來應該就會動了... 然後 TCP port 80/443 也算自由了,要掛其他的網域上去應該都 OK。

這幾天 blog 被掃,用 nginx 的 limit_req_zone 擋...

Update:這個方法問題好像還是不少,目前先拿掉了...

這幾天 blog 被掃中單一頁面負載會比較重的頁面,結果 CPU loading 變超高,從後台可以看到常常滿載:

看了一下是都是從 Azure 上面打過來的,有好幾組都在打,IP address 每隔一段時間就會變,所以單純用 firewall 擋 IP address 的方法看起來沒用...

印象中 nginx 本身可以 rate limit,搜了一下文件可以翻到應該就是「Module ngx_http_limit_req_module」這個,就設起來暫時用這個方式擋著,大概是這樣:

limit_conn_status 429;
limit_req_status 429;
limit_req_zone $binary_remote_addr zone=myzone:10m rate=10r/m;

其中預設是傳回 5xx 系列的 service unavailable,但這邊用 429 應該更正確,從維基百科的「List of HTTP status codes」這邊可以看到不錯的說明:

429 Too Many Requests (RFC 6585)
The user has sent too many requests in a given amount of time. Intended for use with rate-limiting schemes.

然後 virtual host 的設定檔內把某個 path 放進這個 zone 保護起來,目前比較困擾的是需要 copy & paste try_filesFastCGI 相關的設定:

    location /path/subpath {
        limit_req zone=myzone;
        try_files $uri $uri/ /index.php?$args;

        include fastcgi.conf;
        fastcgi_intercept_errors on;
        fastcgi_pass php74;
    }

這樣一來就可以自動擋下這些狂抽猛送的 bot,至少在現階段應該還是有用的...

如果之後有遇到其他手法的話,再見招拆招看看要怎麼再加強 :o

Google Chrome 的 Cache Partition 生效

去年提到的「Google Chrome 要藉由拆開 HTTP Cache 提昇隱私」在最近推出的 Chrome 86 預設生效了:「Chrome changes how its cache system works to improve privacy」。

Google 的文章「Gaining security and privacy by partitioning the cache」這邊有提到不同瀏覽器都有打算要支援類似的架構,對應的差異:

Is this standardized? Do other browsers behave differently?

"HTTP cache partitions" is standardized in the fetch spec though browsers behave differently:

  • Chrome: Uses top-level scheme://eTLD+1 and frame scheme://eTLD+1
  • Safari: Uses top-level eTLD+1
  • Firefox: Planning to implement with top-level scheme://eTLD+1 and considering including a second key like Chrome

文章裡面看到了有趣的東西,是他提到了 Fetch 這個標準,然後是在「2.7. HTTP cache partitions」這邊出現了對應的說明:

To determine the HTTP cache partition, given request, run these steps:

Let key be the result of determining the network partition key given request.

If key is null, then return null.

Return the unique HTTP cache associated with key. [HTTP-CACHING]

所以看起來是訂 Fetch 時寫下一套方法,然後拿來擴大套用到整個瀏覽器...

Google Chrome 要開始管制非 HTTP 的下載了

Google Chrome 前陣子宣佈了要淘汰透過 HTTP 下載檔案的計畫:「Protecting users from insecure downloads in Google Chrome」。

分成不同檔案類型的下載,可以看到不同類型檔案會在不同時間點被阻擋:

所以到時候 IE 的功能又多了一個?

Python 新的 HTTP client library:HTTPX

看到「A next-generation HTTP client for Python.」這個專案冒出來,宣稱是下一代 Python 的 HTTP client library:

HTTPX is a fully featured HTTP client for Python 3, which provides sync and async APIs, and support for both HTTP/1.1 and HTTP/2.

目前專案還在 beta,目標是在今年四月出 1.0 版。從說明裡面可以看到,目前的方向是打算相容 requests,讓現有的程式可以不用做太多修改就轉移過來。

再來從開發者的角度來看,HTTPX 比 requests 多了這些功能:

  • Standard synchronous interface, but with async support if you need it.
  • HTTP/1.1 and HTTP/2 support.
  • Ability to make requests directly to WSGI applications or ASGI applications.
  • Strict timeouts everywhere.

但如果就支援這些功能的角度來看,修改 requests 看起來應該會比較快?開新的專案感覺跟 Kenneth Reitz 有關...

Kenneth Reitz 有兩個很有名的作品,一個是這個,另外一個是 Pipenv,也就是在「pipenv 的凋零與替代方案 poetry」這邊提到的事情。

然後看了一下 CHANGELOG.md 內的資訊,裡面最早的記錄是 0.6.0 (2019/06/21),而從 Contributors to encode/httpx 這頁看起來則是 2019/03/31 開始發展的,就這些時間點看起來,原因大概跟 Kenneth Reitz 有關... 雖然沒有找到文章直接提到這件事情。

不過 HTTPX 需要 Python 3.6+ 才能跑,對於版本的要求比較高,如果是 16.04 預設的 python3 (3.5) 就沒辦法跑了,18.04 預設的 python3 (3.6) 也才剛好符合...

之後應該是 HTTPX 與 requests 兩邊都得關注了,看看會有什麼發展...

HTTP/1.1 與 HTTP/2 的最佳化技巧

這篇在討論,無論是 HTTP/1.1 時代,或是 HTTP/2 時代下 (裡面還包括了 HTTP/2 的 Server Push),各種讓下載速度最佳化的技巧以及造成的複雜度:「Performance testing HTTP/1.1 vs HTTP/2 vs HTTP/2 + Server Push for REST APIs」。

文章裡其中一個提到的是各類「打包」的技巧,也就是 JavaScript 的 bundle,或是 CSS 的 Image sprites,甚至是 API 的合併,像是很多人會考慮的 GraphQL

雖然在 HTTP/2 年代我們常說可以省下來,但這並不代表「打包」在 HTTP/2 情境下沒有效果,只是改善的幅度比較少,所以這個最佳化的技巧比起 HTTP/1.1 年代,可以放到後面一點再做,先把人力放到其他地方。但如果團隊工具已經熟悉打包技巧的話 (可能是以前就已經做好了),其實繼續使用沒有太大問題...

另外是 Server Push 的情境,意外的反而可以提昇不少速度,看起來主要是少了請求的時間,所以快不少。

再來是跨網域時 CORS 的問題,在 Flash 的年代是一個 crossdomain.xml 解決,但現在的解法是多一個 OPTIONS request,反而造成很大的效能問題... 文章裡提到現在看起來有個 Draft 在發展與 Flash 類似的機制:「Origin Policy」。

作者在測試完後得到的結論其實跟蠻多「直覺」相反的:

  • If speed is the overriding requirement, keep using compound documents.
  • If a simpler, elegant API is the most important, having smaller-scoped, many endpoints is definitely viable.
  • Caching only makes a bit of difference.
  • Optimizations benefit the server more than the client.

省頻寬的方法:終極版本...

看到「Three ways to reduce the costs of your HTTP(S) API on AWS」這邊介紹在 AWS 上省頻寬費用的方法,看了只能一直笑 XD

第一個是降低 HTTP response 裡沒有用到的 header,因為每天有五十億個 HTTP request,所以只要省 1byte 就是省下 USD$0.25/day:

Since we would send this five billion times per day, every byte we could shave off would save five gigabytes of outgoing data, for a saving of 25 cents per day per byte removed.

然後調了一些參數後省下 USD$1,500/month:

Sending 109 bytes instead of 333 means saving $56 per day, or a bit over $1,500 per month.

第二個是想辦法在 TLS 這邊下手,一開始其中一個方向是利用 TLS session resumption 降低第二次連線的成本,但他們發現沒有什麼參數可以調整:

One thing that reduces handshake transfer size is TLS session resumption. Basically, when a client connects to the service for the second time, it can ask the server to resume the previous TLS session instead of starting a new one, meaning that it doesn’t have to send the certificate again. By looking at access logs, we found that 11% of requests were using a reused TLS session. However, we have a very diverse set of clients that we don’t have much control over, and we also couldn’t find any settings for the AWS Application Load Balancer for session cache size or similar, so there isn’t really anything we can do to affect this.

所以改成把 idle 時間拉長 (避免重新連線):

That leaves reducing the number of handshakes required by reducing the number of connections that the clients need to establish. The default setting for AWS load balancers is to close idle connections after 60 seconds, but it seems to be beneficial to raise this to 10 minutes. This reduced data transfer costs by an additional 8%.

再來是 AWS 本身發的 SSL certification 太肥,所以他們換成 DigiCert 發的,大幅降低憑證本身的大小,反而省下 USD$200/day:

So given that the clients establish approximately two billion connections per day, we’d expect to save four terabytes of outgoing data every day. The actual savings were closer to three terabytes, but this still reduced data transfer costs for a typical day by almost $200.

這些方法真的是頗有趣的 XDDD

不過這些方法也是在想辦法壓榨降低與 client 之間的傳輸量啦,比起成本來說反而是提昇網路反應速度...

一個超小的 HTTP Server Library

httpserver.h 這個專案是用 C 寫的,就一個 .h 檔,從範例可以看到用法不算太複雜:

#define HTTPSERVER_IMPL
#include "httpserver.h"

#define RESPONSE "Hello, World!"

void handle_request(struct http_request_s* request) {
  struct http_response_s* response = http_response_init();
  http_response_status(response, 200);
  http_response_header(response, "Content-Type", "text/plain");
  http_response_body(response, RESPONSE, sizeof(RESPONSE) - 1);
  http_respond(request, response);
}

int main() {
  struct http_server_s* server = http_server_init(8080, handle_request);
  http_server_listen(server);
}

然後同時支援 epollkqueue。拿來寫小東西還蠻有趣的,不過如果複雜一點的東西還是會考慮其他的框架就是了,畢竟會 blocking 的東西太多了...

Google Chrome 要藉由拆開 HTTP Cache 提昇隱私

在「Prepare For Fewer Cache Hits As Chrome Partitions Their HTTP Cache」這邊看到的,Google Chrome 打算要拆開 HTTP Cache 以提昇安全性與隱私性。

有 cache 跟沒有 cache 可以從讀取時間猜測出來,這樣就可以知道瀏覽器是否有這個特定 url 的 cache。

在原文的作者所給的例子沒有這麼明顯,這邊舉個實際一點的例子來說好了... 我想要知道你有沒有看過 zonble 的「返校」這篇文章,我就拿這篇文章裡面特有的資源來判斷。

以這篇文章來說,我可以選擇第一張圖片的網址 https://i0.wp.com/c1.staticflickr.com/1/603/31746363443_3c4f33ab18_n.jpg?resize=320%2C200&ssl=1 這個 url 來判斷讀取時間,藉此我就可以反推你有沒有看過這篇文章,達到攻擊隱私的效果。

解決的方法就是作者文章裡所提到的方法,把 HTTP cache 依照不同的網站而分開 (在 Safari 已經支援這個功能,而 Firefox 正在研究中)。

當然這樣做應該會對流量有些影響,但考慮到這些日子有很多新技術可以增加下載速度,這個功能應該是還能做...

Caddy Server 要採用 Open Source...

Caddy Server 是一套 HTTP Server,目標是讓使用者可以很容易設定一個安全的 HTTP Server。

程式碼本身是 open source (採用 Apache License 2.0),但官方包出來的 binary 則是限制個人免費使用或是購買訂閱,但如果你自己編譯打包的話又還是 open source license,是一個很奇怪的商業模式...

再加上看到他的設定檔的格式後,發現他包太多東西了 (連 markdown 相關的處理都包進去),實在是不愛這種設計 (感到遲早會有滿滿的 CVE),而 nginx 就是把 HTTP Server 相關的業務處理好,相較起來就懶的理了...

現在看起來 Caddy Server 應該覺得這樣沒賺頭而決定把訂閱拿掉,全部都開放出來:「Proposal: Permanently change all proprietary licensing to open source」。

但比較奇怪的還是,這件事情其實你也不用徵求社群意見,你們自己公司內部確認好就好,這個比較像是 PR 而已...