解決WSL2 Docker執行Miniflux出現「socket: address family not supported」錯誤
該問題點很好重現(跟架設環境有關):登入到Miniflux網頁 → Feed → 點一下「在背景更新所有Feed」或是等Miniflux自動更新Feed,在Feed頁面會出現很多網站的RSS都顯示socket: address family not supported by protocol,但是手動更新單一網站的RSS卻又是好的。在Docker Desktop和Rancher Desktop沒遇過,第一次在WSL2安裝Miniflux後遇到這個問題。一直不停詢問Gemini和反覆測試,最後才得以解決。
注意
本文由 Gemini 3 Pro 語言模型產生。
這是一份整理好的技術筆記,特別針對 WSL 2 + Docker 環境下遇到的這個棘手網路問題,詳細記錄了錯誤現象、深層原因以及最終的解決方案。
📍 環境與症狀
環境:
- OS:Windows 10/11 with WSL 2(Ubuntu 24.04)
- Platform:Docker running on WSL 2
- App:Miniflux(Go 語言編寫的 RSS 閱讀器,基於 Alpine Linux Image)
症狀:
Miniflux 無法抓取 RSS Feed,日誌中大量出現以下錯誤:
dial tcp [2606:4700:3036::ac43:83b7]:443: socket: address family not supported by protocol在 WSL 主機上使用
curl測試該網址完全正常(因為 curl 自動走 IPv4)。使用
docker exec進入容器ping外部網站,也能解析出 IPv4。特殊背景:因 ISP 或路由器 IPv6 連線不穩,已在 Windows 的
%UserProfile%/.wslconfig中設定kernelCommandLine=ipv6.disable=1強制在核心層級關閉 IPv6。
🔍 問題根源分析(Root Cause)
這是一個由 WSL 2 特殊網路架構 + Go 語言解析機制 + Linux 核心設定 三者衝突導致的「殭屍 IPv6」現象。
由於 Miniflux 官方 Docker Image 強制使用 Alpine Linux 作為基底,且未提供 Debian/Ubuntu 版本,因此我們無法透過簡單的「更換 Image Tag」(例如換成 miniflux:debian)來避開 Alpine 與 Go 語言在 IPv6 解析上的相容性問題。
這迫使我們必須採用更底層的手段:掛載 gai.conf 設定檔,直接從 OS 層級修正 Alpine 內部的 DNS 解析優先權。
具體衝突層級如下:
- 核心層(Kernel):
我們透過.wslconfig物理關閉了 IPv6 支援。Linux 核心完全不懂 IPv6,任何 IPv6 連線請求都會被直接拒絕(address family not supported)。 - DNS 層(The Conflict):
雖然核心關了 IPv6,但 Docker 容器內的 DNS 解析器(無論是 Docker 內建的127.0.0.11還是 WSL 的 DNS Proxy)在查詢網域時,依然會回傳 AAAA(IPv6)紀錄。 - 應用層(Miniflux/Go):
Miniflux 使用 Go 語言撰寫。Go 的 DNS Resolver 在拿到 IPv4 和 IPv6 兩種地址時,預設行為(Happy Eyeballs 演算法)可能會優先或並行嘗試 IPv6。 - 崩潰點:
Go 程式拿到 IPv6 地址 → 嘗試連線 → 核心瞬間報錯「不支援此協定」。
在高併發(一次更新數百個 Feed)的情況下,這種瞬間錯誤會導致 Go 的連線邏輯崩潰,來不及 Fallback 回 IPv4 就直接判定失敗。
結論:必須從系統層級「強迫」應用程式忽略 IPv6,只使用 IPv4。
🛠️ 解決方案
傳統的 Docker Bridge 網路難以完全過濾 IPv6 DNS 回應。最終極的解法是:使用 Host Network 模式,並掛載自訂的網路設定檔。
步驟 1:準備設定檔
在 docker-compose.yml 同級目錄下,建立兩個檔案。
resolv.conf(強制指定穩定 DNS)
WSL 2 預設的 DNS Proxy 在高負載下容易 Timeout(no such host),我們直接指定 Google DNS。nameserver 8.8.8.8 nameserver 1.1.1.1gai.conf(強制 IPv4 優先)
這是 Linux 的getaddrinfo設定檔。我們要將 IPv4 的優先權調到最高(100),讓系統在解析 DNS 後,永遠把 IPv4 排在第一位。# ::ffff:0:0/96 is the IPv4 mapped prefix. # We set its precedence to 100 (highest), making it preferred over IPv6 (default 40). precedence ::ffff:0:0/96 100
步驟 2:修改 docker-compose.yml
請參照以下範例修改。重點在於切換成 network_mode: host 並掛載上述兩個設定檔。
services:
miniflux:
image: miniflux/miniflux:latest
container_name: miniflux
restart: unless-stopped
# [關鍵 1] 改用 Host 模式,直接繼承 WSL 主機的純淨網路環境
network_mode: host
# Host 模式下不需要 ports 映射,預設會監聽 8080
depends_on:
- db
environment:
# [關鍵 2] 因為改用 Host 模式,資料庫在 "本機",所以要連線到 127.0.0.1
- DATABASE_URL=postgres://miniflux:secret@127.0.0.1/miniflux?sslmode=disable
- RUN_MIGRATIONS=1
# 其他環境變數...
# [關鍵 3] 掛載設定檔,從系統層級覆寫 DNS 行為
volumes:
- ./resolv.conf:/etc/resolv.conf:ro # 解決 DNS Timeout
- ./gai.conf:/etc/gai.conf:ro # 解決 IPv6 優先問題 (address family error)
db:
image: postgres:16
container_name: postgresql
restart: unless-stopped
environment:
- POSTGRES_USER=miniflux
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=miniflux
volumes:
- miniflux-db:/var/lib/postgresql/data
# [關鍵 4] 必須開放 Port,因為 Miniflux 是透過 127.0.0.1 (TCP) 連進來的
ports:
- "5432:5432"
volumes:
miniflux-db:
步驟 3:特別注意 Cloudflare Tunnel(如果有使用)
如果你有搭配 Cloudflare Tunnel,因為改成了 Host Network,Tunnel 容器無法再透過 container_name(如 miniflux)找到對方。
請至 Cloudflare Zero Trust Dashboard → Tunnels → Configure → Public Hostname。
將 Service URL 修改為:
localhost:8080(或127.0.0.1:8080)
步驟 4:重建容器
執行以下指令套用變更:
docker compose down
docker compose up -d
✅ 驗證結果
修改後,觀察 Miniflux 的 Log:
docker compose logs -f --tail=10 miniflux
- 錯誤消失:
socket: address family not supported不再出現。 - 連線行為:如果遇到網路問題,錯誤訊息會變成標準的
dial tcp 1.2.3.4:80: i/o timeout(顯示的是 IPv4 地址),證明系統已經成功強制走 IPv4 通道。
這組設定能確保在 WSL 2 這種特殊的網路環境下,Go 語言程式也能乖乖聽話,不再被 IPv6 的幽靈干擾。