切換選單
切換偏好設定選單
切換個人選單
尚未登入
若您做出任何編輯,會公開您的 IP 位址。
於 2026年4月12日 (日) 08:42 由 ZhiChao留言 | 貢獻 所做的修訂

前言

剛接觸 Docker 或者平常只使用 1Panel 這類面板的小白用戶,最常遇到的問題應該就是明明 UFW 里沒開放端口,但公網卻可以直接通過端口訪問容器。

以 1Panel 為例,如果你在應用商店安裝應用時,勾選了「端口外部訪問」,此時的容器就會監聽 0.0.0.0

無論你有沒有在 UFW 中開放這個端口,它都已經暴露到了公網。

這個「陳年老坑」的原理很簡單,因為 Docker 會直接修改 Linux 的 iptables 規則,而這些規則的優先級高於 UFW,並且在 UFW 中也不會顯示 Docker 添加的規則。

要想解決這個問題並不難,下面介紹一下最常見的幾種解決方法。

解決方法

禁用 iptables(不推薦)

既然 Docker 會直接修改 iptables 繞過 UFW ,那直接禁用掉 iptables 自動配置,不就輕鬆秒殺了嗎?

/etc/docker/daemon.json 中添加:{"iptables": false}

相信你看到過網上許多的「庸醫」教程就是這麼教的,雖然說能夠解決端口意外暴露的問題,但禁用 iptables 自動配置的同時還可能導致容器無法訪問外部網絡或容器間通信失敗。

因此非常不推薦直接禁用 iptables。

安全組(暫不支持)

如果你買的服務器有安全組功能,這個問題解決起來就非常的簡單了,只要在後台的安全組中禁用端口,Docker 無論如何也不可能繞過安全組。

但是可惜搬瓦工暫時還不支持類似安全組的外置防火牆,可以接着看下面的解決方案,通過合理配置 Docker 和 iptables 來解決這個問題。

監聽 127.0.0.1(推薦)

對於大多數用戶,端口映射時監聽本地 127.0.0.1:8080:80 是最好的解決方法,對應 1Panel 中就是不勾選「端口外部訪問」。

Docker

-p 127.0.0.1:8080:80

Docker Compose

ports:
  - "127.0.0.1:8080:80"

本機的其他應用可以正常通過端口訪問到容器,而外部訪問不了,如果是 Web 應用可以直接用 Nginx 反向代理。

但這個方法也不是完美的,當你想用另一台服務器反向代理時,監聽 127.0.0.1 會導致裝有 Nginx 的服務器也訪問不到容器。

host 模式

直接使用 host 模式也是一個比較常用的解決方案,在 host 模式下,容器不會獲得獨立的網絡命名空間,而是直接共享宿主機的 IP 和端口,自然就可以用 UFW 來控制端口是否開放。

Docker

--network

Docker Compose

network_mode: "host"

缺點也非常的明顯,共享宿主機的網絡會導致網絡沒有隔離、端口衝突等一系列副作用。例如,幾個容器的端口都為 80,就沒法同時運行了。

虛擬局域網

如果你有用另一台服務器反代的需求,又不希望使用 host 模式,可以用 ZeroTier、Tailscale 之類的組網工具,給兩台服務器組一個虛擬局域網,也是個不錯的解決方案。

當然如果你兩台服務器都是搬瓦工的並且位於同一個機房,可以直接利用 Private Network 開啟內網,可以省去組建虛擬局域網的步驟

可以參考這篇文章 搬瓦工進階教程:利用 Private Network 構建高速內網集群

在容器映射端口時,除了映射本機的 127.0.0.0.1:8080:80,再加上一條虛擬局域網的 IP,如 192.168.100.1:8080:80,另一台服務器反代時,填寫 192.168.100.1:8080 即可。

Docker

-p 127.0.0.1:8080:80 \
-p 192.168.100.1:8080:80

Docker Compose

ports:
  - "127.0.0.1:8080:80" # 仅本机访问
  - "192.168.100.1:8080:80" # 仅通过特定局域网 IP 访问

ufw-docker(推薦)

要是你既不想用組網工具,又不想(或不能)用 host 模式,還想用另一台服務器的 Nginx 來反代容器,有沒有更完美的解決方法呢?

有的,兄弟有的。

ufw-docker 是 GitHub 上開源的一個解決方案,具體原理可以查看倉庫的 README,我們這裡簡單介紹一下如何使用。

手動配置

修改 UFW 的配置文件 /etc/ufw/after.rules,在最後添加上如下規則:

# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward

-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
-A DOCKER-USER -m conntrack --ctstate INVALID -j DROP
-A DOCKER-USER -i docker0 -o docker0 -j ACCEPT

-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16

-A DOCKER-USER -j ufw-docker-logging-deny -m conntrack --ctstate NEW -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -m conntrack --ctstate NEW -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -m conntrack --ctstate NEW -d 192.168.0.0/16

-A DOCKER-USER -j RETURN

-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP

COMMIT
# END UFW AND DOCKER

接着重啟 UFW systemctl restart ufw。 此時即便你的容器監聽的是 0.0.0.0,外部也是無法訪問的,同時也不會影響 Docker 容器內部網絡以及容器之間的通信。

⚠️ 注意:如果重啟 UFW 仍不生效,可能需要重啟服務器。

假設現在有一個監聽了 0.0.0.0:8080:80 的容器,私有地址為 172.17.0.2,如果要開放端口可以執行以下命令:

⚠️ 注意:port 為內部的 80 端口,並非映射的 8080 端口

 ufw route allow proto tcp from any to 172.17.0.2 port 80

如果沒有填寫私有地址 172.17.0.2,則會開放所有內部端口為 80 的容器

 ufw route allow proto tcp from any to any port 80

如果你有大量容器需要讓另一台服務器反代,可以直接對那台服務器的 IP 開放

 ufw route allow proto tcp from x.x.x.x to any

想要查看或刪除規則,可以執行

 ufw status numbered

刪除只需要執行 ufw delete + 編號

 ufw delete 2

工具

如果覺得以上操作過於繁瑣,也沒關係,ufw-docker 還提供了工具簡化所有操作

 wget -O /usr/local/bin/ufw-docker \
   <nowiki>https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker</nowiki>
 chmod +x /usr/local/bin/ufw-docker

使用以下命令可以一鍵修改 UFW 的 after.rules 文件

 ufw-docker install

具體的操作可以通過 ufw-docker help 查看,這裡就不過多介紹了。

 ufw-docker allow mysql 3306/tcp
 ​ufw-docker delete allow mysql 3306/tcp

index.php?title=Category:500 常見應用指南 — Application Guides