SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-09-04

Rocky Linux 修改 SSH 埠:SELinux 與 firewalld 設定

在 Rocky Linux 或 AlmaLinux 修改 SSH 埠需正確設定 firewalld、SELinux 與 sshd_config。本指南提供標準作業流程,避免因 semanage 套件缺失或 SELinux 標籤錯誤導致無法遠端登入伺服器。

為何在此處變更 SSH 埠需要三個步驟

若要在 Rocky Linux、AlmaLinux、CentOS Stream 或 Fedora 上變更 SSH 埠,僅編輯單一設定檔是不夠的。三個獨立的系統各自決定新埠號的連線是否生效。firewalld 決定封包是否能抵達機器;SELinux 決定 sshd 是否獲准綁定該埠號;sshd_config 則決定 daemon 要監聽哪個埠。若遺漏 SELinux 步驟,daemon 將拒絕啟動;若遺漏 firewalld 步驟,服務雖能啟動並監聽,但外部將無法連線。

在 Ubuntu 上,同樣的工作只需編輯一次並重啟服務,因為 Ubuntu 使用 AppArmor 而非 SELinux,且預設未提供限制 sshd 可綁定埠號的設定檔。若該系統執行了 ufw,只需新增一條規則即可。這就是兩者的主要差異。RHEL 系列發行版在全新安裝時預設啟用 firewalld 與 SELinux enforcing 模式,兩者皆會檢查埠號。

請依照此順序執行,以確保目前的連線階段在每個步驟中皆不會中斷:

  1. 在 firewalld 中開啟新埠號,並暫時保留埠 22 開啟。
  2. 使用 semanage 為新埠號新增 SELinux 標籤。
  3. 在 sshd 設定檔中設定埠號。
  4. 重啟 sshd,接著在關閉第一個終端機前,從第二個終端機以新埠號登入。
在開始之前,請先找到服務供應商提供的網頁控制台(VNC 或 serial),並確認能透過該控制台登入。若變更過程出錯,該控制台是您唯一的復原管道。變更埠號是租戶將自己鎖在剛付費購買的伺服器外,最常見的原因之一。

首先,安裝 semanage

semanage 是用於編輯 SELinux 政策設定的工具,而 Rocky Linux 或 AlmaLinux 的最小化安裝並不包含此工具。它位於 policycoreutils-python-utils 套件中。

sudo dnf install -y policycoreutils-python-utils

若在安裝該套件前執行此指令,會出現 sudo: semanage: command not found 錯誤,許多讀者往往在此時誤以為系統未安裝 SELinux 而跳過此步驟。事實上 SELinux 已安裝,僅缺少管理工具。若您對 dnf 的語法感到陌生,dnf 與 apt 指令對照表 可協助您將其對應至您熟悉的指令。

選擇一個連接埠並確認其未被佔用

1024 到 65535 之間的任何閒置 TCP 連接埠皆可使用。在決定使用前,請先執行以下兩項檢查:

sudo ss -tlnp | grep -w 2222
sudo semanage port -l | grep -w 2222

第一項檢查顯示是否有處理程序已在該連接埠進行監聽。第二項檢查顯示 SELinux 政策是否已將該連接埠指派給其他服務類型。若連接埠閒置,兩項指令皆不會回傳任何內容。若該連接埠已被政策佔用,步驟 2 中的 semanage port -a 將會失敗並顯示 ValueError: Port tcp/2222 already defined,此時請選擇其他連接埠號碼。

本指南全程以 2222 作為範例。由於 2222 是掃描器在 22 埠之後最常嘗試的目標,在正式伺服器上請選擇較不顯眼的連接埠。

步驟 1:在 firewalld 中開啟連接埠

sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports

--permanent 會將規則寫入磁碟上的區域設定檔,但不會更動目前運作中的防火牆。--reload 則會將磁碟上的設定載入至運作中的防火牆。若跳過重新載入步驟,該規則雖已存在,但在 firewalld 下次重啟前不會生效;這是導致此程序看起來「無故失敗」最常見的原因。

暫時保留 ssh 服務項目。該項目負責維持 22 埠開啟,是您進行測試時的備援機制。

請同時檢查供應商的控制台。許多主機商會在 VPS 前端部署作業系統層級以外的網路防火牆,因此即使您已在 firewalld 開啟連接埠,流量仍可能在上游被阻擋。若您對此模型不熟悉,可參考 firewalld 基礎指南:VPS 篇,其中涵蓋了區域(zones)以及執行階段(runtime)與永久(permanent)設定的差異。

步驟 2:為 SELinux 標記連接埠

sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo semanage port -l | grep ssh_port_t

-a 用於新增連接埠指派。-t ssh_port_t 是 SSH 連接埠所使用的類型。執行第二個指令可列出目前 ssh_port_t 所涵蓋的所有項目,以便在異動 daemon 之前,確認該連接埠號碼已成功加入。

為何 SELinux 會封鎖該連接埠

SELinux (security-enhanced Linux) 會為系統上的每個物件加上標籤,而 TCP 連接埠編號也與其他物件無異。SSH daemon 執行時受限於名為 sshd_t 的網域中。安全性原則僅允許 sshd_t 綁定標籤為 ssh_port_t 的 TCP 連接埠,而系統預設僅有 22 號連接埠擁有此標籤。若要求 daemon 綁定 2222 埠,核心會檢查該標籤,發現該編號被指派了通用的類型原則,進而拒絕該 socket 的 name_bind 權限。

這就是為何此類失敗看起來不像防火牆問題的原因。核心在監聽 socket 建立前就已拒絕請求,因此 sshd 會回報錯誤並結束執行。防火牆問題則恰好相反:daemon 執行正常,但封包在進入時被丟棄。

getenforce 可顯示伺服器目前的模式。在 Permissive 模式下,拒絕行為會被記錄但不會強制執行,因此變更連接埠看似成功,但當有人執行 setenforce 1 或伺服器重啟進入 enforcing 模式時就會失效。無論如何,請務必為連接埠加上標籤。伺服器 SELinux 基礎指南 有詳細說明模式、上下文 (context) 與布林值 (boolean)。連接埠並非唯一會受此影響的物件;相同的原則也會阻止容器讀取掛載的主機目錄,直到該路徑被重新標記為止。這也是為何 在 Rocky Linux 或 AlmaLinux 上安裝 Docker 的教學中,會包含 Ubuntu 指南從未提及的 SELinux 設定步驟。

步驟 3:在 sshd 設定中指定連接埠

在 Rocky Linux 9 與 10、AlmaLinux 9 與 10 以及目前的 Fedora 版本中,/etc/ssh/sshd_config 的開頭包含一行 include 指令,因此最妥善的修改方式是建立一個額外的設定檔(drop-in file)。這樣做可確保套件更新時不會覆蓋您的設定。

grep -n '^Include' /etc/ssh/sshd_config
echo 'Port 2222' | sudo tee /etc/ssh/sshd_config.d/10-port.conf
sudo sshd -t

如果 grep 中沒有 Include 行(例如在 Rocky Linux 8 或其他較舊的映像檔中),請直接將 Port 2222 加入 /etc/ssh/sshd_config。sshd -t 會解析完整的設定檔(包含額外載入的檔案),並回報語法錯誤。請務必在重新啟動服務前修正所有錯誤,因為若設定檔解析失敗,sshd 將無法重新啟動。

Port 可以出現多次,sshd 會監聽所有列出的連接埠。在設定初期,同時保留 Port 22 與 Port 2222 是一種低成本的安全防護措施,但請務必記得在確認連線正常後移除舊的連接埠。

您的 sshd 是否由 socket 單元啟動?

部分映像檔透過 systemd socket activation 啟動 SSH,而非作為常駐服務執行。在此設定下,systemd 會接管監聽 socket 並將連線轉交給 sshd,因此 Port 在 sshd_config 中的設定會被完全忽略。在重新啟動任何服務前,請先進行檢查:

systemctl is-enabled sshd.socket

若出現 enabled,表示連接埠是在 socket 單元中設定,而非在 sshd_config 內:

sudo systemctl edit sshd.socket
[Socket]
ListenStream=
ListenStream=2222

必須使用空的 ListenStream=。由於數值會在各個 drop-in 設定檔中累加,若未先以空值清空列表,socket 將會同時監聽 22 與 2222 埠。請使用 sudo systemctl daemon-reload 套用變更,隨後執行 sudo systemctl restart sshd.socket。若您的伺服器上未啟用或不存在該單元,則本節內容不適用。

步驟 4:重新啟動,並從第二個終端機進行測試

sudo systemctl restart sshd
systemctl status sshd
sudo ss -tlnp | grep sshd

請保持此終端機開啟,不要登出。在您的本機開啟第二個終端機,並透過新的連接埠進行連線:

ssh -p 2222 youruser@203.0.113.10

僅在確認第二次登入成功後,再關閉第一個連線。若連線失敗,您仍保有目前的 shell,可隨時復原所有變更。養成此習慣是「五分鐘變更」與「花一下午處理供應商控制台」之間的關鍵差異。

防火牆丟棄封包還是 SELinux 拒絕存取?如何區分

從您的筆記型電腦來看,這兩種失敗狀況幾乎完全相同。但在伺服器端,它們的表現截然不同。

  • 若 systemctl status sshd 顯示該單元失敗,代表 daemon 從未取得其 socket。這是設定錯誤或 SELinux 拒絕存取所致。
  • 若該單元狀態為 active 且 ss -tlnp 顯示 sshd 已綁定至新連接埠,則 daemon 運作正常,問題出在網路路徑上:可能是 firewalld、供應商的外部防火牆,或是您撥接的位址與連接埠錯誤。

針對 SELinux 的情況,請閱讀稽核記錄,不要憑空猜測:

sudo ausearch -m AVC -ts recent
sudo journalctl -u sshd -n 50 --no-pager

name_bind 對類別 tcp_socket 的拒絕記錄會標示 comm="sshd" 中的處理程序、src= 中的連接埠號,以及 tcontext= 中該連接埠實際持有的標籤。最後一個欄位即為答案。若顯示內容非 ssh_port_t,代表步驟 2 未正確套用到您使用的連接埠,通常是連接埠號輸入錯誤或協定不符。若您希望 sealert 將記錄轉譯為易讀語句,請安裝 setroubleshoot-server。

當核心拒絕綁定時,sshd 本身寫入的訊息如下:

error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.

在 1024 以上的連接埠出現 Permission denied(此處無需 root 權限即可綁定)是 SELinux 的典型特徵。若同一行出現 Address already in use,則屬於不同故障:有其他處理程序佔用了該連接埠。從客戶端來看,連線被拒絕與連線逾時的差異 可區分兩種網路狀況,因為「被拒絕」代表封包已抵達主機但無服務監聽,而「逾時」則代表完全沒有回應。

關閉 22 埠並更新用戶端設定

確認在新埠號成功登入多次後,即可關閉 22 埠:

sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

請勿更動 22 埠上的 SELinux 標籤。該標籤源自基礎原則,一旦防火牆阻擋封包進入,該標籤便不再具備任何權限。

接著修正用戶端設定,因為所有預設使用該埠的工具現在都需要重新指定。請在您的本機設定一次 ~/.ssh/config,無須再重複輸入 -p:

Host myvps
  HostName 203.0.113.10
  Port 2222
  User youruser

scp、sftp、rsync 與 Ansible 都會讀取該檔案。備份工作、監控檢查與寫死 22 埠的 cron script 則不會讀取,因此請趁著對變更記憶猶新時,將這些項目一併找出並修正。

變更連接埠的效益與侷限

此舉能減少日誌雜訊。自動化掃描器會不斷攻擊 22 埠,移至其他連接埠可過濾掉大部分日誌條目,讓真實事件更易於識別。這並非安全防護手段。任何掃描整個連接埠範圍的掃描器,仍會發現您的 daemon 並讀取其版本標頭。請將變更連接埠視為日常維護,真正的防護應建立在僅限金鑰驗證並停用密碼登入,詳細步驟請參考 VPS 的 SSH 強固指南。

上述內容在兩大 RHEL 重建版上的運作方式完全相同,因為它們源自相同的原始碼。若您仍在兩者間抉擇,請參閱 Rocky Linux 與 AlmaLinux 比較。之所以有兩個幾乎相同的重建版可供選擇,是因為 CentOS 自 2020 年起不再提供此類版本,詳細經過請見 從 Red Hat 到 CentOS 再到 Rocky 與 AlmaLinux 的演變。在參考舊指南前,請先使用 cat /etc/os-release 確認您實際使用的發行版本。針對 Rocky Linux 8 編寫的指南目前仍有不錯的搜尋排名,其 semanage 與 firewall-cmd 步驟依然正確,但 Rocky 8 沒有 sshd_config.d 引入行,也不需考慮 socket 單元,因此這些指南中關於 sshd 的部分與目前的系統並不相符。

必須告知 fail2ban 新的連接埠

fail2ban 並未包含在基礎儲存庫中。它來自 EPEL (Extra Packages for Enterprise Linux):

sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalld

fail2ban-firewalld 子套件能讓 fail2ban 透過 firewalld 執行封鎖,這正是當 firewalld 管理規則集時所需要的運作方式。

預設的 sshd jail 設定了 port = ssh,該名稱會透過 /etc/services 解析為 22。在您變更連接埠後,該 jail 會監控一個無人攻擊的連接埠,導致在 2222 埠發生登入失敗時無法封鎖任何來源。請在 /etc/fail2ban/jail.local 中直接以數字設定連接埠:

[sshd]
enabled = true
port = 2222
backend = systemd
maxretry = 5
bantime = 3600

backend = systemd 會從 journal 讀取失敗紀錄,而非從 /var/log/secure 讀取;在未安裝 rsyslog 的最小化安裝環境中,這是較安全的選擇。使用 sudo systemctl enable --now fail2ban 啟動服務,並使用 sudo fail2ban-client status sshd 檢查 jail 狀態。其 jail 語法與 Ubuntu 24.04 的 fail2ban SSH 設定 所使用的相同。僅套件來源與封鎖動作 (ban action) 有所不同。

修補更新比連接埠更重要

一台變更過 SSH 連接埠但四個月未套用安全性更新的伺服器,其安全性遠低於一台使用 22 埠且每晚自動修補的伺服器。在取得 root 權限的當下,請順手啟用自動更新:Rocky Linux 與 AlmaLinux 的自動 dnf 更新 說明了計時器設定,以及下載更新與自動套用之間的選擇。安裝更新並不會自動重啟正在執行舊版程式碼的 daemon,因此當 openssh-server 或其連結的函式庫有更新時,花一分鐘檢查哪些服務需要重啟或重新開機是非常值得的。

FAQ

在 Rocky Linux 上修改連接埠後,為什麼 sshd 無法啟動?

通常是因為缺少 SELinux 連接埠標籤。sshd 在 sshd_t 網域中受限執行,且原則僅允許其綁定標記為 ssh_port_t 的連接埠,預設僅限 22 埠。核心會拒絕綁定請求,導致 daemon 無法監聽並直接退出,此時 journalctl -u sshd 會記錄類似 error: Bind to port 2222 on 0.0.0.0 failed: Permission denied. 的訊息。請使用您的連接埠號碼執行 sudo semanage port -a -t ssh_port_t -p tcp 2222,隨後重啟服務即可。若找不到 semanage,請先安裝 policycoreutils-python-utils。

如果 SELinux 處於 permissive 模式,我還需要使用 semanage 嗎?

需要。在 permissive 模式下,系統會記錄拒絕存取的事件但仍允許綁定,因此變更看起來像是成功了,但標籤實際上並未設定。一旦有人執行 setenforce 1,或是系統以 SELINUX=enforcing 模式在 /etc/selinux/config 中啟動,sshd 就會停止在該連接埠上啟動。新增標籤只需一個指令,即可避免未來發生難以排查的啟動失敗問題。

連接埠標籤已設定且 sshd 正在執行,為什麼連線仍會逾時?

daemon 正常執行代表 SELinux 已通過驗證,封包是在進入過程中被丟棄。請檢查 sudo firewall-cmd --list-ports 是否包含您的連接埠,並確認在執行 --permanent 規則後已執行 firewall-cmd --reload,因為永久規則不會自動套用到執行中的防火牆。接著檢查 VPS 前端的外部網路防火牆控制面板。這是第二個常見的阻擋點,且作業系統內部的日誌無法顯示此類阻擋。

除了 22 埠,我應該使用哪個連接埠?

任何 1024 到 65535 之間的閒置 TCP 連接埠皆可。在正式伺服器上應避免使用 2222 與 22222,因為掃描器在嘗試 22 埠後會立即掃描這些連接埠。請使用 sudo ss -tlnp 確認該號碼未被佔用,並使用 sudo semanage port -l 確認 SELinux 原則未將其指派給其他服務,同時避開未來可能安裝的服務所使用的連接埠。選擇一個高位且不易記憶的數字即可,因為您只需將其寫入 ~/.ssh/config 一次,之後便無需再手動輸入。