在自架服務的時候,我很疑惑為何不用設定UFW規則就能從外部網路存取,後來發現Docker跟UFW是衝突的,Docker會無視UFW的設定逕行開放通訊埠。這篇文章記錄如何整合二者一起使用。
- Docker版本:24.0.2
- UFW版本:0.36.2
1. 問題來源#
UFW為Ubuntu和Debian系發行版預設使用的防火牆前端。Docker會繞過UFW自行建立iptables規則,因此導致UFW設定的規則失效,變成外部網路能直接存取Docker容器開放的通訊埠。
這會造成安全性問題,比方說用docker-compose跑Nextcloud,會導致除網頁界面外,連資料庫容器的通訊埠跟著暴露到公開網路,之後再用UFW封鎖是無效的。
若是編輯/etc/docker/daemon.json
,把Docker自動調整iptables的功能關閉會使問題更複雜,Docker容器無法對外連線,要手動設定規則。
另一個選項是放棄UFW,改用與Docker相性較好的Firewalld。但…那個是Redhat和SUSE系在用的。
因此我們還是想辦法整合UFW和Docker吧,讓UFW負責管理整個網路和Docker的連線規則。
2. Docker配合UFW運作的解決方法#
現代問題需要現代手段,使用chaifeng撰寫的ufw-docker指令稿能解決這問題。他的 Github有詳細原理解釋,這邊直接講解法。
如果已經修改過/etc/docker/daemon.json
停用iptables,請將相關段落刪除。
編輯
/etc/default/ufw
,將DEFAULT_FORWARD_POLICY="ACCEPT"
修改為DEFAULT_FORWARD_POLICY="DROP"
。安裝此指令稿修改UFW設定檔,再重啟UFW與Docker服務。
sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
sudo chmod +x /usr/local/bin/ufw-docker
sudo ufw-docker install
sudo systemctl restart ufw
sudo systemctl restart docker
在採用chaifeng的指令稿後,來看實際例子學習新的UFW管理方式。
現在這裡有個容器,它將容器內部的8080 TCP通訊埠映射到實體機的8081 TCP通訊埠:
8f4q1aqia searxng/searxng:latest "/sbin/tini -- /usr/…" 2 hours ago Up 2 hours 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp searxng
- 因為上面的指令稿使用了
ufw-user-forward
規則,UFW擋住了所有外部連線,我們就得分別開啟「容器的8080 TCP通訊埠」和「實體機的8081 TCP通訊埠」:
# 查看幫助
sudo ufw-docker help
# 開放容器通訊埠
sudo ufw-docker allow "容器名稱或UUID" 8080/tcp
# 開放實體機通訊埠
sudo ufw allow 8081/tcp
# 重新載入UFW
sudo ufw reload
# 重啟Docker服務
sudo systemctl restart docker
- 這樣子外部網路能存取此容器,該容器也能對外連線了,由UFW接管Docker的連線規則。
如果仍有容器的通訊埠能繞過UFW存取,那麼請重開機試試。
3. 如何移除ufw-docker指令稿#
編輯
/etc/ufw/after.rules
,將# BEGIN UFW AND DOCKER
至# END UFW AND DOCKER
之間的規則移除。移除指令稿
sudo rm /usr/local/bin/ufw-docker
- 重開機。