關閉 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_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://gitlab-workhorse;
    }

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

#
upstream gitlab_mattermost {
    server 127.0.0.1:8065;
}

與:

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://gitlab_mattermost;
    }

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

用 pfSense 接 AWS Direct Connect (Public VIF) 的方式

公司在菲律賓的辦公室因為常常會需要連到 AWS 傳輸影音資料 (新加坡,ap-southeast-1),但發現偶而會很不順,傳輸的時候會很卡,所以後來決定租了一條專線用 AWS Direct Connect 接進去。

不過因為跑在 AWS 上面的服務是掛在 public network 上,而不是 private ip 的網段,所以就不能用 IPsec site-to-site 打通收工,而需要搞 BGP routing,然後就卡關卡的亂七八糟 XD

首先是文書作業的部份,因為 AWS 對於 public network peering 需要證明你要交換的 IP address 是你自己的 (或是有被授權),這部份在 web console 上建立完 Public VIF 後會進入審核階段,接下來就要開 support ticket 提供 LOA-CFA 文件後才能繼續設定,我們這邊是從 ISP 申請 AWS Direct Connect 線路時拿到這份 PDF 文件。

這邊比較有趣的是,如果你沒有買 support plan 的話無法開 technical support,但官方有跟你說這邊可以 workaround 開 General Info and Getting Started 這個類別:「My public virtual interface is stuck in the "Verifying" state. How can I get it approved?」。

過了審核後接下來是設定 pfSense 的部份,因為是要接通 public network 的部份,所以你要收 AWS 提供的 BGP routing,這部份在 pfSense 上會透過 OpenBGPD 解決,但主要還是因為對 BGP 不熟悉,所以花了不少時間跟 AWS 原廠與台灣的 Partner 一起找問題,不然現在事後來看,自己 tcpdump 應該就有能力找到問題了...

主要的盲點是在我們的 AWS Direct Connect 裡面 BGP 需要走 TCP MD5 Signature Option。

這是一個 TCP extension,連線雙方有一把 shared secret 可以驗證每個 TCP packet 沒有被竄改:「Protection of BGP Sessions via the TCP MD5 Signature Option」。

要注意的是這個協定不是 application level,而是在 TCP 層本身就保護起來,包括 3-way handshake 的部份,所以從一開始 SYN 封包過去就要有 md5sig 的資訊。

這也表示用 telnet 不會通是正常的,這點讓我找問題找錯方向好久...

另外一點是 pfSense 的預設值不支援 TCP MD5 Signature Option (完全沒想過這個可能性 XDDD),這點在 pfSense 的「md5 bgp sessions fail in 2.4.0」這邊有提到:

Do you have "BSD Crypto Device" selected under System > Advanced, Misc tab, for Cryptographic Hardware? If not, select it there and try again.

That module is required for TCP_SIGNATURE to function.

If that works I can either add some warning text to Quagga and FRR or force it to load when that is enabled.

到了對應的選項那邊要選擇,因為我們的 pfSense 機器比較低階,沒有那堆硬體加速度的東西,所以選「BSD Crypto Device (cryptodev)」讓底層的 FreeBSD 去處理。

設定完後新的連線也還是不會有效果,後來想了一下還是整台重開機,然後就通了就通了就通了就通了就通了...

果然弄很久的問題都會是蠢問題,純粹就是不熟悉這些東西造成的。

AWS Global Accelerator 的 TCP 協定

AWS Global Accelerator 是讓使用者先連到最近的 AWS 節點,再透過 AWS 的骨幹網路連到服務上 (可以參考之前寫的「AWS 推出 Global Accelerator,用 AWS 的網路加速」這篇),當時就有說支援 TCP 與 UDP,但剛剛看到「AWS Global Accelerator launches TCP Termination at the Edge」這篇的時候才注意到,本來的產品是把 TCP 封包當作 UDP 在處理,也就是 TCP 3-way handshake 還是要到服務節點本身處理。

現在這個 TCP Termination 的功能則是先在最近的節點上建立 TCP 連線,然後同時往後端的建立連線接起來:

Typically, a TCP connection is established by using a three-way handshake (that is, three messages) between the client on the internet and the application endpoint in the AWS Region. So the farther away the client is from the endpoint, the longer the initial connection setup takes. With TCP termination at the edge, Global Accelerator reduces initial setup time by establishing a TCP connection between the client and the AWS edge location closest to the client. At nearly the same time, Global Accelerator creates a second TCP connection between the edge location and the application endpoint in the AWS Region. With this process, the client gets a faster response from the Global Accelerator edge location, and the connection from the edge location to the application endpoint in the Region is optimized to run over the AWS global network.

這樣連線的速度就會更快,但有可能會有前面建起來但後面建不起來的情況需要處理,一般的應用程式應該還好,畢竟地球上有個 GFW 也常幹這種事情...

TCP Congestion Control Algorithm 的選擇

先前 Ubuntu 桌機用 BBR 跑了一陣子,但有遇到一些問題 (可以參考「Dropbox 測試 BBRv2 的結果」這篇),所以暫時換成 Westwood,但還是陸陸續續會看一下各種研究。

剛剛在「[tor-relays] TCP CCA for Tor Relays (and especially Bridges)」這邊看到一個經驗談:

Here are my completely unscientific scribbles of how all the various algorithms behaved. The scenario is uploading for a minute or so, observing the speed in MB/sec visually, then recording how it appeared to change during that minute (and then repeating this a couple of times to be certain).

tcp_bic.ko       -- 6...5...4
tcp_highspeed.ko -- 2
tcp_htcp.ko      -- 1.5...3...2
tcp_hybla.ko     -- 3...2...1
tcp_illinois.ko  -- 6...7...10
tcp_lp.ko        -- 2...1
tcp_scalable.ko  -- 5...4...3
tcp_vegas.ko     -- 2.5
tcp_veno.ko      -- 2.5
tcp_westwood.ko  -- <1
tcp_yeah.ko      -- 2...5...6

上面是「目視法」觀察到的速度 (MB/sec),看了一下維基百科上 TCP-Illinois 的說明,看起來設計的目的是提供給頻寬大、latency 高的情境下:

It is especially targeted at high-speed, long-distance networks.

來跑跑看好了...

Dropbox 測試 BBRv2 的結果

BBRv1 有不少問題,在 BBRv2 有一些改善 (目前還在測試階段,在「TCP BBR v2 Alpha/Preview Release」這邊可以看到一些說明),而 Dropbox 則是跳下去測試,並且公佈結果:「Evaluating BBRv2 on the Dropbox Edge Network」。

Spoiler alert: BBRv2 is slower than BBRv1 but that’s a good thing.

在文章開頭的這張圖就說明了 BBRv2 的速度比較慢,但是說明這是朝好的方向改善。

BBRv1 的問題其實我自己都有遇到:我自己的 Ubuntu 桌機跑 BBRv1,在我上傳大量資料的時候 (只開一條連線),會導致 PPPoE 的 health check 失敗,於是就斷線了,另外 VM 裡面的 Windows 7 因為也是 bridge mode 跑 PPPoE,也可以看到斷線嘗試重連的訊息,於是只好改掉...

上面提到的問題就是 BBRv1 造成 packet loss 過高,除了我遇到的問題外,這對於其他 loss-based 的 TCP congestion algorithm 來說會有很大的傷害 (i.e. 不公平):

Other tradeoffs were quite conceptual: BBRv1’s unfairness towards loss-based congestion controls (e.g. CUBIC, Compound), RTT-unfairness between BBRv1 flows, and (almost) total disregard for the packet loss:

另外一個改善是 BBRv2 加入了 ECN 機制,可以更清楚知道塞住的情況。

整體上來說應該會好不少,不知道之後正式釋出後會不會直接換掉 Linux Kernel 裡的 BBRv1,或是不換,讓 BBRv1 與 BBRv2 共存?

CloudFront 的 BBR 效能提昇

這是在找一些 TCP congestion algorithm 相關的資訊時發現的,看起來 Amazon CloudFront 導入 BBR 一陣子了:「TCP BBR Congestion Control with Amazon CloudFront」。

不過 BBR 被研究的愈來愈多,大家開始發現這個演算法的霸道,跟其他的 TCP congestion algorithm 並不太能和平共存,但這就跟軍事武器一樣,隔壁升級了你就得跟著升級,抱怨沒有用,只會被消滅...

AWS System Manager 支援 SSH 的 -L 功能 (Port Forwarding)

AWS System Manager 宣佈支援了 SSH Port Forwarding 的功能 (也就是 OpenSSH 指令裡的 -L):「New – Port Forwarding Using AWS System Manager Sessions Manager」。

以往是連到那台主機上後,再透過 -R 反過來再穿一層,但這必須在那台機器有 Internet 存取權限的情況下才有辦法做... 這次的方法是 AWS System Manager 直接提供了,所以只需要可以連到主機就可以做。

用 Machine Learning 改善 Streaming 品質的服務與論文

Hacker News 上看到「Puffer」這個服務,裡面利用了 machine learning algorithm 動態調整 bitrate,以提昇傳輸品質。

測試得到的數據後來被整理起來一起放進論文:「Continual learning improves Internet video streaming」。

在開頭介紹了 Fugu 這個演算法:

We describe Fugu, a continual learning algorithm for bitrate selection in streaming video.

而 Puffer 就是實驗網站:

We evaluate Fugu with Puffer, a public website we built that streams live TV using Fugu and existing algorithms. Over a nine-day period in January 2019, Puffer streamed 8,131 hours of video to 3,719 unique users.

這個站台提供了許多真實的頻道進行測試:

Stream live TV in your browser. There's no charge. You can watch U.S. TV stations affiliated with the NBC, CBS, ABC, PBS, FOX, and Univision networks.

可以看到 Fugu 的結果很好,比起其他提出的方案是全面性的改善:

這邊是用 WebSocket 測試,並且配合了不同的 TCP congestion algorithm,沒有太考慮額外的計算成本...

Netflix 找到的 TCP 實做安全性問題...

這幾天的 Linux 主機都有收到 kernel 的更新,起因於 Netflix 發現並與社群一起修正了一系列 LinuxFreeBSD 上 TCP 實做 MSSSACK 的安全性問題:「https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-001.md」。

其中最嚴重的應該是 CVE-2019-11477 這組,可以導致 Linux kernel panic,影響範圍從 2.6.29 開始的所有 kernel 版本。能夠升級的主機可以直接修正,無法升級的主機可以參考提出來的兩個 workaround:

Workaround #1: Block connections with a low MSS using one of the supplied filters. (The values in the filters are examples. You can apply a higher or lower limit, as appropriate for your environment.) Note that these filters may break legitimate connections which rely on a low MSS. Also, note that this mitigation is only effective if TCP probing is disabled (that is, the net.ipv4.tcp_mtu_probing sysctl is set to 0, which appears to be the default value for that sysctl).

Workaround #2: Disable SACK processing (/proc/sys/net/ipv4/tcp_sack set to 0).

第一個 workaround 是擋掉 MSS 過小的封包,但不保證就不會 kernel panic (文章裡面用語是 mitigation)。

第二個 workaround 是直接關掉 SACK,這組 workaround 在有 packet loss 的情況下效能會掉的比較明顯,但看起來可以避免直接 kernel panic...

HTTP/3 (QUIC) 的反面看法

這篇整理了 HTTP/3 (QUIC) 的反面看法,算是常見的疑慮都列出來了:「QUIC and HTTP/3 : Too big to fail?!」。

其實大多都是使用 UDP 而導致的問題:

  • 因為 UDP 導致 firewall 可能沒開,以及可能會需要等 timeout 走回 TCP 的問題。
  • 因為 UDP 變成很多事情在 userland 處理,而導致的 CPU 使用率比使用 TCP 的 TLS 1.2/1.3 高很多。
  • 因為 UDP 導致 amplification attack 的安全性問題,以及對應的 workaround 產生的頻寬議題。
  • 由於 UDP 會需要自己控制擁塞,等於是在 UDP 上面又重做了一次 TCP congestion algorithm,而且因為重作所以得考慮與 TCP 搶資源的公平性。

整篇文章算是整理了一般對 HTTP/3 的疑慮,之後如果有進展的話,可以再拿出來當 checklist 再確認有哪些有改善...