WordPress + Cloudflared + V2ray 異地組網並隱藏流量

目標

  • 異地組網, 遠程訪問家中環境
  • 結合海外 VPS 翻牆 ( 不在此篇討論 )
  • 使用 V2Ray TLS 加密流量
  • 將 TLS 流量隱藏在正常的 HTTPS 流量中達到混淆目的
  • 使用 Cloudflare 的內網穿透服務, 達到防探測目的 ( 服務器直接和 CF 溝通, 沒有端口暴露 )
  • 使用 Cloudflare 的 CDN 服務, 達到防牆、加速作用

如果你並不是想要做異地組網, 而是想要在 VPS 上跑 (Nginx/Caddy/Apache) + WP + V2Ray, 那麼你其實用不著這麼複雜. 你只需要看這篇文章就可以了.

(這篇博文主要是討論一個沒多少人做過的方案的可行性, 所以你會看到後面還有一大通廢話; 作為教程本文是不合格的, 如果想要尋找教程請出門右轉谷歌搜索. )

網絡拓墣示意圖

準備環境

  • 一台聯網、24×7 運行的機器, 內存 4G+, 空間 8G+
  • 安裝有 Linux 系統 ( 推薦 Openwrt, 或者 樹莓派安裝 PiOS )
  • Cloudflare 帳戶, 託管在 CF 上的域名

執行以下操作準備所需鏡像.

docker pull wordpress
docker pull mariadb
docker pull teddysun/v2ray

使用以下 Dockerfile 構建 Cloudflared 鏡像

FROM debian:latest
VOLUME ["/etc/cloudflared"]
WORKDIR /etc/cloudflared
RUN ln -s /etc/cloudflared /root/.cloudflared
RUN apt update && apt install wget -y
RUN wget https://github.com/cloudflare/cloudflared/releases/download/2021.5.10/cloudflared-linux-amd64 \
    && mv cloudflared-linux-amd64 /usr/local/bin/cloudflared \
    && chmod +x /usr/local/bin/cloudflared

配置 Nginx + WordPress

如果你已經配置好了, 可以直接跳過. 我在這裡貼出我的啟動參數:

docker run --name wordpress \
-v /www/wordpress:/var/www/html \
-p 443:443/tcp \
-p 80:80/tcp \
--net wpblog \
--restart always \
-h wordpress \
--expose 443/tcp \
--expose 80/tcp \
-e 'WORDPRESS_TABLE_PREFIX=wp_' \
-e 'WORDPRESS_DB_HOST=db' \
-e 'WORDPRESS_DB_USER=root'\
-e 'WORDPRESS_DB_PASSWORD=password' \
-e 'WORDPRESS_DB_NAME=wordpress' \
-d wordpress:latest
docker run --name wordpressdb \
-v wordpressdb_data:/var/lib/mysql \
-p 3306:3306/tcp \
--net wpblog \
--restart always \
-h db \
--expose 3306/tcp \
-e 'MARIADB_ROOT_PASSWORD=password' \
-e 'MARIADB_DATABASE=wordpress' \
-d mariadb:latest

V2Ray

V2Ray 啟動參數:

docker run --name v2ray \
-v /etc/v2ray:/etc/v2ray \
--net host \
--restart always \
-d teddysun/v2ray

V2Ray 配置文件:

{
  "inbounds": [
    {
      "port": 9999,
      "listen":"127.0.0.1",
      "protocol": "vmess",
      "settings": {
        "clients": [
          {
            "id": "myawesomepassword",
            "alterId": 0
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "wsSettings": {
        "path": "/myawesomepath"
        }
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "freedom",
      "settings": {}
    }
  ]
}

Cloudflared

Cloudflared 的配置有一點點煩. 我先開了一個 Debian 容器生成了 Cloudflared 的配置文件:

docker run --rm \
-v /etc/cloudflared:/root/.cloudflared \
-it debian:latest

然後在 Debian 中執行:

apt update && apt install wget -y
wget https://github.com/cloudflare/cloudflared/releases/download/2021.5.10/cloudflared-linux-amd64 \
    && mv cloudflared-linux-amd64 /usr/local/bin/cloudflared \
    && chmod +x /usr/local/bin/cloudflared
cloudflared login
cloudflared tunnel create mytunnel
exit

/etc/cloudflared 中新建 config.yml, 寫入:

tunnel: tunnel-id-here
credentials-file: /etc/cloudflared/tunnel-id-here.json

ingress:
  - hostname: myawesomesite.com
    path: /myawesomepath
    service: http://localhost:9999
  - hostname: myawesomesite.com
    service: http://localhost:80
  - service: http_status:404

使用如下啟動參數啟動容器:

docker run --name cloudflared \
-v /etc/cloudflared:/etc/cloudflared \
--net host \
--restart always \
-d cloudflared:latest '/usr/local/bin/cloudflared' '--no-autoupdate' '--config' '/etc/cloudflared/config.yml' 'tunnel' 'run' 'tunnel-id-here'

DNS 配置

打開 Cloudflare, 新建一條 CNAME 紀錄, 如下配置:

| TYPE  | NAME |            CONTENT              | TTL |  Proxy State|
| CNAME |  @   | tunnel-id-here.cfargotunnel.com | auto|   Proxied   |

驗證

$ curl https://myawesomesite.com/myawesomepath                             
Bad Request

後記

使用場景

之所以會有這樣的主意, 是因為我早就將所有文件都掛在 NAS 中了, 我隨身攜帶的筆記本、手機裡面基本沒有任何文件. 那麼當我出遠門的時候, 如果沒有一個可靠的組網方案, 難不成我還得把硬盤拆下來帶著走? ( 主要是留學場景 )

那麼只有 VPN 方案了. 眾所週知天朝的網絡環境超級奇葩, 要滿足搭建 VPN 的條件得開放公網 IP、配置 DDNS、配置端口轉發等一系列操作, 搞不好哪天運營商給妳封了還得重搞. 而且明擺著 VPN 流量流進流出也很不放心.

所以要配置這樣一個 VPN 還是得靠內網穿透. 問題是自己配 VPS + FRP 會被牆, 購買現成的方案性價比低, 好像真的走到僵局了. 當 4月份 CF 宣布 Argo Tunnel 開放之後我就一直在尋找利用它的方法: Cloudflare 現在遍地開花, 和 Cloudflare 長期的 TLS 流量是唯一不會被懷疑 + 不會被牆掉的. 而且有 CF 的 Edge Network 加持, 網絡延遲可能還比自己搭建 VPS 搞內網穿透要小.

剩下的問題就是偽裝問題了. 自然而然的, 我想到了流量 TLS 加密後混在正常的 HTTPS 流量中, 那麼 V2 + WP + CF 的方案就確定下來了.

注意事項

我在網絡拓墣圖裡並沒有畫出來, 那個 Home Lan 其實是走過一個 Openwrt 網關的, Openwrt 上有配置 Passwall 鏈接到我的翻牆 VPS 來保證速度. (大部分配置有軟路由的人也基本就是這麼玩的, 保證全家翻牆)

既然有翻牆這一個環節, 那麼就肯定要注意被牆的問題. 首先我們複習一下牆的手段: 針對網站有 DNS 污染和匹配SNI, 針對 IP 就比較簡單, 直接截下流量就可以了.

因為我們使用 Cloudflared 做內網穿透, 針對 IP 的威脅可以忽視. DNS 污染可以使用 DoH、DoT、dnsProxy, 匹配 SNI 我們可以用 ESNI 嘛. 而且如果是海外訪問(留學), 連牆都不用過.

要在家啟用 dnsProxy, 可以在 Openwrt 中配置 dns2socks ( dns 流量走代理 ); 要使用 DoH、DoT, 參考 Cloudflare 的這篇教程; 配置 ESNI 得先配置加密 DNS, 然後在瀏覽器裡找到對應選項開啟.

推薦的作法

剩下就是路由器用來翻牆的 VPS 會不會被牆. 因為很多沒有被牆的網站 (如 Github ) 訪問速度也和被牆了差不多, 所以我默認是開啟 IP 白名單的. 就是說, 如果 VPS 失效, Cloudflare 也會訪問不了. 如果人在家當然很好辦, 如果人在遠門或者在國外 (留學場景), 要注意把路由器設為 GFWlist 模式.

另外, 在牆內老是訪問同一個域名可能會導致身份關聯 ( 盡量不要在牆內這麼用 ). 如果非要這麼做, 建議配合 Tor 使用或者確保 DoH、ESNI 工作正常. (就是絕對不要在手機上亂用的意思)

為 jsProxy 應用 Material 界面

如果你還不知道的話, jsProxy 是一個基於瀏覽器端實現的網頁代理. 用人話說, 就是你可以把 jsProxy 當作 “翻牆瀏覽器” 使用. 而和雜七雜八的 “翻牆瀏覽器” 不同, jsProxy 不紀錄用戶數據, 而且無需安裝, 隨時可以使用.

因為可以部署在 Cloudflare Workers ( 從雲端運行腳本 ) 的緣故, jsProxy 一直被視為一個很好的白嫖途徑. 不過其他都好, 就是介面有點… 怎麼說呢, 太過復古. 而且 jsProxy 已經長期無人維護, pr 攢了一大堆無人理會, 導致一大堆鏈接無法打開, 默認搜索引擎是谷歌也導致了每次使用它總會被谷歌以機器人的理由擋下來, 體驗非常不友好.

不是我太挑剔, 但是原本的介面真的是有夠醜的

本著 DIY 的精神, 我稍微改動了一下 jsProxy 的代碼, 然後用 MDUI 庫給他前端做了一個美化. 因為我並沒有怎麼學過前端知識, 所以整個網頁現在基本就是一堆 tag soup. 不過總算跑起來了, 而且看著還不賴.

現在 jsProxy 的樣式看起來好多了.

自我感覺良好 ing

得益於 MDUI, 這個網站現在還跟上了 “響應性設計” 的概念, 儘管我完全不知道響應性設計到底是什麼鬼東西. 我修改了默認搜索引擎, 把它改成了 Duckduckgo, 我還刪掉了網站圖標改成了 fontawesome 的字體優化加載速度, 添加了暗黑模式… ( 為什麼要加省略號, 已經沒有可列的了啊 ) 總之, 現在的 jsProxy 絕對比原來的 jsProxy 要好用不只一點.

如果想要體驗的話, 你可以在點擊下方鏈接前往我自己用 CF Worker 搭建的服務, 或者 Clone Git 源碼.

鏈接: jsproxy.justin.education
源碼: git.io/jsproxy-material

WordPress Enligher 插件適配主題

感覺博客缺少一個代碼高亮插件, 所以我就挑了一個免費的, 功能比較多的插件 Enligher 安裝到博客.

好用但是挺好用, 但是好像和當前的主題不太兼容, 具體症狀請見下圖:

可以看見, 不管是編輯器還是實際文章, 這個插件都有兼容性問題.

所以我馬上要做的事情, 就是找出問題並自己解決掉.

我沒有學過任何關於 CSS 或者 JS 的知識, 以下所有紀錄都來源於常識… 如果我有哪邊做錯, 歡迎在評論區指正😄

(下文所有的修改都會寫在文末的 patch 文件中)

編輯器部分

錯位修正

margin 的左右都是 0

這個比較簡單, 修改 enlighter/resources/gutenberg/enlighterjs.gutenberg.min.css , 如下所示:

div[data-type="enlighter/codeblock"] {
	border: 1px solid #cccbcb;
	border-radius: 5px;
	/* max-width: 100%; */
	padding: 15px
}

刪除/移動 干擾信息

右下角的提示 “EnligherJS Syntax Highlighter” 一直都在那裡, 非常佔空間而且還會產生打擾的效果, 所以我們不能讓它達到目的, 可以直接把它刪掉. 另外, 左上角的粗體字提示 Highlighting 種類未免有些太過喧賓奪主, 要是可以把它移到右下角的話豈不完美.

所以我就將 enlighter-footer 的部分刪掉, 然後將 enlighter-title 的部分移到 原來的 footer 的部分. 目前一切進行的都比較順利.

wp.element.createElement("div", {
                    className: "enlighter-header"
                },
                    /*wp.element.createElement("div", {
                        className: "enlighter-title"
                    }, (e = t.language, s()[e] || "Unknown language"))), wp.element.createElement(u, {
                        value: t.content,
                        onChange: function (e) {
                            return n({
                                content: e
                            })
                        },
                        placeholder: "Insert Sourcecode..",
                        "aria-label": "Code"
                    }),*/
                    /*wp.element.createElement("div", {
                        className: "enlighter-footer"
                    },
                        wp.element.createElement("div", {
                            className: "enlighter-footer-label"
                        },
                            wp.element.createElement("strong", null, "EnlighterJS"), " Syntax Highlighter"))*/
                    wp.element.createElement(u, {
                        value: t.content,
                        onChange: function (e) {
                            return n({
                                content: e
                            })
                        },
                        placeholder: "Insert Sourcecode..",
                        "aria-label": "Code"
                    }), wp.element.createElement("div", {
                        className: "enlighter-footer"
                    }, wp.element.createElement("div", {
                        className: "enlighter-footer-label",
                    }, (e = t.language, s()[e] || "Unknown language")))),

美化

到這一步, 編輯器 Enlighter 區塊的效果是這個樣子的:

不夠完美啊!

從使用的角度來說, 它已經夠用了.
但是右下角的那一行字總覺得有點不和諧.

所以我就把它往下移動了一點點, 並且加粗.

div[data-type="enlighter/codeblock"] {
	border: 1px solid #cccbcb;
	border-radius: 5px;
	padding: 15px;
	padding-block-end: 1px /* New */
}
div[data-type="enlighter/codeblock"] .enlighter-footer-label {
	text-align: right;
	font-size: 10px;
	font-family: Menlo,Consolas,monaco,monospace;
	color: #23282d;
	cursor: pointer;
	padding-top: 3px; /* New */
	font-weight: 800 /* New */
}

( 以上所有代碼全部由我目測得到, 且並不理解其含義, 均未考慮兼容性. 使用前請再三考慮 )

最終效果

現在感覺好多了 👌

網頁展示部分

EnlighterJS 官網按鈕倒不難去掉, 插件提供了開關可以直接把它關掉.

將 EnlighterJS website button 設為 Disable 就可以了

那麼接下來要做到就是適配暗黑模式.

適配暗黑模式的話… (撓頭) 要改的變量好像有點太多了, 暫時就不寫了吧.
本身 MDX 的暗黑模式就不太好看, 我的解決方法就是 徹 . 底 . 不 . 開 ! 這下不會有問題了吧?

Patch via Gist

MacArm 為 Qt 配置 WebAssembly 環境

需求

我正在配置 Qt wasm環境, 但是 emsdk 不支持 apple m1 issue 769
上一篇博文 我配置好 wasm 後發現 還是無法配合 qt 使用.

環境:
MacOS Bigsur M1, Qt 5.15.2

單單配置好wasm, 當前的配置還是不能工作, 比如說, 我現在用 clang 編譯一個 Qt 的 Example:

clang 可以跑起來

可以看到, 項目本身沒問題, 能跑起來;

我接著用剛剛配置的 em++ 編譯一遍:

得到一堆報錯

分析上面的報錯, 有一大堆 permission denied 或者 file not found. 結合 Docker 容器的特性, 我們就知道錯誤的根源了. 上面的配置, emcc 的路徑只和當前的路徑對應, 而在 qt 編譯過程中會引用很多不在當前目錄下的文件, 容器找不到, 就只能報錯.

那麼怎麼解決呢? 我們當然可以手動給他映射上去, 但是每一次都這麼幹, 碰到複雜的項目煩也要煩死. 而且如果像第一種沒有 WebAssembly Kit 的情況, qt 自己也不支持, 那麼要做的東西要海了去了. 所以說, 總是要有其他方法的.

這個方法還是 Docker.

解決方案

Qt 官網文檔: using-docker-test-qt-webassembly
maukalinow/qtwasm_builder : Docker Hub

以上文檔的意思是叫我們自己 Build 一個 Docker 鏡像. 但是顯然已經有人做過了, 本著不要重複發明輪子的定律, 我們可以直接將網友做好的鏡像 Pull 過來: (自行根據 Qt 版本選擇)

docker pull maukalinow/qtwasm_builder:5.15_latest

接著, 我們編譯一下剛才的項目測試一下:

docker run --rm -v ~/Desktop/anaclock/bin:/project/build -v ~/Desktop/anaclock:/project/source maukalinow/qtwasm_builder:5.15_latest
cd /Users/justin/Desktop/anaclock/bin
python3 -m http.server

接下來打開 這個地址: http://localhost:8000/analogclock.html

可以看到, 我們的 qt 應用已經在瀏覽器上面原生運行了.

結果非常成功

為 Qt 安裝 emsdk 到現在為止已經成功.

優化

加快項目生成速度

編譯的 Log

觀察以上編譯記錄我們可以發現, 絕大部分的時間都浪費在 generating system library 上了, 而這些庫無疑都是可以復用的. 所以接下來的事情, 就比較簡單了. 在命令後面加一條, 把緩存文件夾映射到宿主機上, 不就成了嗎?

docker run --rm -v ~/Desktop/anaclock/bin:/project/build -v ~/Desktop/anaclock:/project/source -v ~/.emsdk_cache:/root/dev/emsdk/upstream/emscripten/cache maukalinow/qtwasm_builder:5.15_latest

連著運行這個命令兩遍, 可以看出, 第二遍明顯就比第一遍快了 N 多倍.

第二遍編譯的 Log

簡化輸入命令

正如之前提到, 這麼長的命令並不利於記憶, 我們可以寫一個腳本讓他變短很多.

所以我就寫了一個腳本, 你可以在下面的鏈接下載到.

之後只要在目錄下輸入 qtwasm , 構建就自動完成了

自製 Goose 愚人節小病毒

愚人節前我亂翻小衆軟件,突然發現了這個東西,於是就有了靈感:
點擊前往: Desktop-Goose 小衆軟件

這是什麽

程序全屏運行示意圖

這是一個可以瘋狂啓動上述 呆鵝 的小程序,只有按照指令敲入句子才可以將其關掉。
簡而言之,這是一個 啓動器,用來啓動和關閉 Goose 程序,僅此而已。

技術細節

整個程序是我用蹩脚的 C++ 編寫的,使用了 辣鷄 DevC++ ,因此你可以猜到這個東西跑起來是什麽樣子。
代碼比較凌亂。而且因爲我是趕出來的,直接一個文件解決問題,相信我你絕對不會想要去讀這個代碼的 🙂

Debug 模式下可以看到 Daemon

一些值得 Mark的 小技巧有:

  • 適當使用了 Windows Api, 實現了自由控制 文字顔色 和窗口 全屏
  • 用命令控制開啓和 一次性 關閉所有進程
  • 不同的 啓動參數 可以改變程序的行爲
  • 可以通過改變 預編譯 命令 來決定程序的惡心程度
  • 簡單的多綫程實現
  • 開啓了一個 守護進程 來檢查並阻止關閉程序(守護進程也無法關閉)
  • 檢測到嘗試關閉程序會有 懲罰
  • 長時間沒有輸入也有懲罰(多綫程實現)
  • 隱藏了一個 “上帝指令” 允許優雅的關閉程序

下載程序

在下載前,你需要知道:

  • 壓縮包裏只有 文本文件和圖片資源,你需要自己編譯 main.cpp
  • Goose程序需要分別下載,下載完之後放到程序的同級目錄

Goose: 跳轉至官網
程序源碼: 點擊下載

程序沒有任何的傳播性(不會自我複製),隱藏性(不會僞裝),破壞性(不會讀寫其他文件),且不會自動運行(若想達到這一點你可以讓程序自己複製到啓動),因此嚴格來説這個東西并不能被稱作病毒。請在編譯前仔細閲讀代碼,確定沒有問題后運行,一切後果 雨我無瓜.

病毒一般具有 传播性、隐蔽性、感染性、潜伏性、可激发性、表现性或破坏性, 一般具有兩種即以上就可以被稱作電腦病毒。具體請參考 維基百科 – 計算機病毒的特徵