Phân biệt lỗi SSH Connection Refused và Timed Out
Lỗi Connection Refused nghĩa là dịch vụ SSH trên server không chạy, trong khi Timed Out báo hiệu firewall chặn gói tin. Xem cách kiểm tra chính xác để xử lý nhanh.
Ý nghĩa của "Connection refused" và "Connection timed out" trong SSH
Lỗi SSH connection refused và SSH connection timed out là hai trạng thái thất bại trái ngược nhau, vì vậy cách khắc phục lỗi này không bao giờ áp dụng được cho lỗi kia. Refused nghĩa là gói tin của bạn đã đến được máy chủ và kernel của máy chủ trả lời rằng "không có tiến trình nào đang lắng nghe tại đây". Timed out nghĩa là gói tin của bạn không đến được bất kỳ ai có thể phản hồi, nên client của bạn đã chờ đợi và bỏ cuộc. Refused là vấn đề về dịch vụ trên máy chủ. Timed out là vấn đề về đường truyền phía trước máy chủ.
Hãy đọc chính xác dòng thông báo mà client của bạn hiển thị, vì cách diễn đạt đó chính là toàn bộ chẩn đoán.
ssh: connect to host 203.0.113.10 port 22: Connection refused
ssh: connect to host 203.0.113.10 port 22: Connection timed outThời gian phản hồi là manh mối thứ hai. Refused xuất hiện ngay lập tức, chỉ trong khoảng thời gian của một vòng lặp truyền tin (round trip). Timed out sẽ treo trong nhiều giây trước khi hiển thị thông báo, vì client liên tục gửi lại gói tin trước khi bỏ cuộc. macOS hiển thị Operation timed out cho cùng một tình trạng này. Nếu giao thức này còn mới với bạn, cách SSH hoạt động và vai trò của sshd là kiến thức nền tảng mà hướng dẫn này mặc định bạn đã nắm rõ.
Tại sao "Connection refused" lại là tin tốt
Refused là một tín hiệu reset của TCP (transmission control protocol). Client của bạn gửi gói tin SYN đến cổng 22. Nó đi qua internet, đến network stack của server, và kernel không tìm thấy socket nào đang lắng nghe trên cổng đó, nên nó trả về một gói tin RST (reset). SSH client của bạn chuyển đổi gói RST đó thành thông báo Connection refused.
Gói tin phản hồi đó chứng minh được rất nhiều điều. Địa chỉ đã đúng. Host đang bật và định tuyến tốt. Không có thiết bị nào trên đường truyền âm thầm hủy lưu lượng đến cổng đó, vì đã có phản hồi từ phía bên kia. Vì vậy, mọi nghi phạm còn lại đều nằm trên chính server đó.
sshdkhông chạy, do khởi động thất bại hoặc chưa được enable.sshdđang lắng nghe trên một cổng khác, thường là sau khi thay đổi cấu hình bảo mật.sshdchỉ bind vào một địa chỉ, ví dụListenAddress 127.0.0.1, nên chỉ có bản thân server mới truy cập được.- Firewall được thiết lập để reject thay vì drop, nên firewall gửi gói RST thay cho host. Hành động
rejectcủa ufw và rule nftables kết thúc bằngreject with tcp resetđều thực hiện việc này.
Còn một trường hợp trông giống như trên nhưng thực tế không phải: bạn đã nhập nhầm địa chỉ của một host khác đang hoạt động. Host đó trả lời gói SYN của bạn, không có SSH trên cổng 22, và từ chối bạn một cách lịch sự. Hãy xác nhận lại địa chỉ trước khi tốn hàng giờ trên sai server. Hiểu rõ cổng lắng nghe thực sự là gì trên Linux sẽ giúp bạn đọc phần này nhanh hơn.
Cách khắc phục lỗi Connection refused
Bạn không thể sửa lỗi này qua SSH vì chính SSH đang bị hỏng. Hãy mở web console hoặc serial console của nhà cung cấp, đăng nhập vào đó, rồi thực hiện các lệnh sau.
systemctl status ssh
sudo ss -tlnp
sudo sshd -T | grep -Ei '^(port|listenaddress|addressfamily)'systemctl status ssh sử dụng tên unit trên Ubuntu và Debian. Trên RHEL và các bản phân phối tương tự như AlmaLinux, unit là sshd. ss -tlnp liệt kê mọi TCP socket đang ở trạng thái listening cùng với tiến trình sở hữu nó; đây là thông tin chính xác nhất: nếu không có dòng nào đề cập đến sshd, nghĩa là không có gì đang lắng nghe, bất kể file cấu hình khai báo ra sao. sshd -T in ra cấu hình thực tế sau khi mọi file Include được gộp lại, đây là nơi một cổng bị bỏ quên trong /etc/ssh/sshd_config.d/ sẽ lộ diện.
Đọc kỹ cột địa chỉ. 0.0.0.0:22 nghĩa là mọi địa chỉ IPv4 trên máy. [::]:22 nghĩa là mọi địa chỉ IPv6. 127.0.0.1:22 nghĩa là chỉ loopback, vì vậy mọi kết nối từ xa đến nó đều bị từ chối trong khi kết nối cục bộ bằng ssh localhost vẫn hoạt động bình thường.
Nếu không có gì đang lắng nghe, hãy khởi động service và đọc thông báo lỗi khi nó không thể khởi chạy.
sudo sshd -t
sudo systemctl enable --now ssh
sudo journalctl -u ssh -n 50 --no-pagersshd -t phân tích cú pháp cấu hình và in ra file cùng số dòng chứa chỉ thị sai mà không ảnh hưởng đến service đang chạy. Hãy chạy lệnh này trước mỗi lần restart, vì một cấu hình bị từ chối sẽ khiến sshd thoát ngay khi khởi động và kết nối tiếp theo của bạn sẽ bị từ chối.
Bẫy socket activation trên Ubuntu
Ubuntu 24.04 phát hành kèm một systemd socket unit cho OpenSSH. Khi unit này được enable, systemd sẽ giữ cổng lắng nghe và khởi chạy sshd cho mỗi kết nối, vì vậy Port 2222 trong sshd_config không có tác dụng gì và máy chủ vẫn phản hồi trên cổng cũ. Hãy kiểm tra chế độ hiện tại của bạn trước khi chỉnh sửa bất kỳ thứ gì.
systemctl is-enabled ssh.socket
systemctl status ssh.socketNếu socket đang được enable, hãy thiết lập cổng trong socket unit thay vì trong sshd_config.
sudo systemctl edit ssh.socket[Socket]
ListenStream=
ListenStream=2222Dòng ListenStream= để trống là bắt buộc, vì các thiết lập dạng danh sách của systemd sẽ cộng dồn vào cấu hình hiện có. Nếu bỏ qua dòng này, máy chủ sẽ lắng nghe trên cả hai cổng. Áp dụng thay đổi bằng sudo systemctl daemon-reload và sudo systemctl restart ssh.socket, sau đó xác nhận bằng sudo ss -tlnp rằng cổng mới là cổng đang được giữ. Thay đổi cổng là một bước thông thường trong tăng cường bảo mật SSH trên VPS, và đây cũng là bước khiến người dùng bị khóa khỏi hệ thống thường xuyên nhất.
Tại sao "Connection timed out" nghĩa là không có phản hồi
Timeout là sự im lặng. Client của bạn đã gửi gói tin SYN, thử gửi lại vài lần trong khoảng một hoặc hai phút, nhưng không nhận lại được bất kỳ gói tin nào. Không có thông tin nào về server được xác nhận ở đây, vì không có tín hiệu nào từ server được ghi nhận.
Sự im lặng chính là kết quả của quy tắc DROP, và việc drop gói tin là hành động có chủ đích. Một phản hồi từ chối (reject) sẽ báo cho bất kỳ ai đang quét mạng biết rằng host đó tồn tại, vì vậy ufw và firewall của mọi nhà cung cấp cloud đều hủy các gói tin không mong muốn và không gửi lại bất cứ thứ gì. Lỗi timeout thường là do firewall đang thực hiện nhiệm vụ trên cổng mà bạn muốn mở.
- Địa chỉ sai: bản ghi DNS vẫn trỏ về server mà bạn đã cài đặt lại, hoặc lỗi đánh máy dẫn đến một địa chỉ không ai sử dụng.
- Host không hoạt động: đã tắt nguồn, hoặc đang trong quá trình reboot. Việc nhà cung cấp tạm ngưng dịch vụ do vấn đề thanh toán cũng trông giống hệt như vậy từ bên ngoài.
- Firewall trên host drop cổng 22, thường là do
ufw enableđã chạy trước khi bất kỳ quy tắc cho phép (allow) nào được thiết lập. - Firewall của nhà cung cấp đặt trước instance đã drop gói tin, và hệ điều hành không bao giờ nhìn thấy gói tin đó.
- Mạng của chính bạn chặn cổng 22 chiều đi, điều này rất phổ biến tại các kết nối văn phòng và khách sạn.
Chạy kiểm tra từ phía bên kia của kết nối
Đây là sai lầm gây tốn thời gian nhất. Bạn không thể chẩn đoán gói tin bị drop từ bên trong máy chủ mà gói tin đó không tới được. Nếu bạn có thể đăng nhập để chạy lệnh, thì bạn đã không gặp vấn đề này. Mọi lệnh trong phần này đều chạy trên máy tính của bạn.
getent hosts vps.example.com
ssh -G vps.example.com | grep -Ei '^(hostname|port|user)'
ssh -vvv -o ConnectTimeout=10 user@vps.example.com
nc -vz -w 5 203.0.113.10 22getent hosts hiển thị địa chỉ mà máy của bạn thực sự sẽ sử dụng, giúp phát hiện bản ghi DNS cũ trong vài giây. ssh -G in ra các thiết lập mà client của bạn áp dụng sau khi đọc ~/.ssh/config, nhờ đó phát hiện một block Host cũ đang âm thầm ghi đè hostname, port hoặc user. ssh -vvv cho thấy nỗ lực kết nối đã đi được đến đâu: dòng cuối cùng về việc kết nối tới địa chỉ theo sau bởi một khoảng dừng dài nghĩa là timeout, trong khi dòng báo phiên bản OpenSSH từ xa nghĩa là TCP đã thành công và vấn đề thực sự của bạn nằm ở xác thực. Trên Windows, Test-NetConnection 203.0.113.10 -Port 22 trong PowerShell thay thế cho nc.
Hãy kiểm tra port, đừng kiểm tra host. Một lệnh ping thất bại không chứng minh được gì, vì nhiều nhà cung cấp lọc ICMP (internet control message protocol) tại biên mạng. Một lệnh ping thành công cũng không chứng minh được gì, vì nó không cho biết gì về port 22.
Sau đó, hãy thay đổi biến số duy nhất mà không lệnh nào có thể thay đổi giúp bạn: mạng của bạn. Thử lại từ một điểm phát sóng di động (hotspot). Nếu hotspot kết nối được còn mạng tại bàn làm việc thì không, thì block nằm ở phía mạng của bạn, hoặc địa chỉ IP văn phòng của bạn đã bị chặn trên máy chủ.
Firewall của nhà cung cấp mà bạn không thấy được từ server
Hầu hết các bảng điều khiển VPS đều cung cấp một network firewall, đôi khi được gọi là security group hoặc cloud firewall, chạy ở phía trước instance của bạn và duy trì danh sách quy tắc riêng. ufw status trên server không thể thấy được firewall này, đó là lý do tại sao câu nói "nhưng tôi đã mở cổng 22 rồi mà" lại phổ biến đến vậy. Hãy mở bảng điều khiển và đọc danh sách đó trước khi bạn viết lại bất kỳ quy tắc nào trên máy chủ.
Một lệnh duy nhất sẽ giải quyết vấn đề này, và nó cần quyền truy cập console. Hãy chạy lệnh trên server, sau đó thử kết nối từ laptop của bạn trong khi lệnh vẫn đang chạy.
sudo tcpdump -ni any tcp port 22Nếu không có gì xuất hiện trong khi client của bạn đang cố kết nối, các gói tin đã bị loại bỏ trước khi đến được hệ điều hành, vì vậy lỗi nằm ở firewall của nhà cung cấp hoặc đường truyền đến host. Nếu các gói tin SYN đến được nhưng không có phản hồi nào được gửi đi, việc chặn nằm ở cục bộ và thuộc về ufw hoặc nftables. Bài kiểm tra đơn giản đó chia nhánh timeout làm đôi, đó là lý do tại sao việc truy cập vào console rất đáng giá.
Thứ tự ufw, IPv6 và việc tự khóa quyền truy cập
Sai lầm về thứ tự trong ufw khiến nhiều người bị khóa quyền truy cập hơn bất kỳ vấn đề nào khác tại đây. sudo ufw enable áp dụng chính sách mặc định là từ chối mọi kết nối đến (deny incoming) ngay lập tức, vì vậy nếu không có rule cho SSH, phiên làm việc hiện tại của bạn vẫn duy trì nhờ trạng thái kết nối đã thiết lập (established state), trong khi mọi kết nối mới đều bị timeout. Hãy cho phép (allow) trước, sau đó mới bật (enable).
sudo ufw allow OpenSSH
sudo ufw status verboseProfile ứng dụng OpenSSH chỉ bao gồm cổng 22. Nếu bạn định chuyển SSH sang cổng 2222, rule bạn cần là sudo ufw allow 2222/tcp, hãy thêm nó trước khi thay đổi cổng thay vì sau đó. Bộ rule đầy đủ hơn được đề cập trong các kiến thức cơ bản về tường lửa ufw cho VPS, và thứ tự an toàn là một phần của những việc cần làm trong mười phút đầu tiên trên một VPS mới.
IPv6 tạo ra lỗi timeout có cảm giác như rất khó hiểu. Nếu hostname có bản ghi AAAA, client của bạn sẽ ưu tiên thử IPv6 trước, vì vậy một máy chủ thiếu rule cho IPv6 sẽ bị treo trong khi kết nối qua IPv4 vẫn hoạt động bình thường. Hãy tách biệt hai giao thức này bằng tay.
ssh -4 user@vps.example.com
ssh -6 user@vps.example.comNếu -4 kết nối được còn -6 thì không, cách khắc phục nằm ở các rule IPv6 trên máy chủ, và mở cùng một cổng cho IPv6 trong ufw sẽ hướng dẫn bạn thực hiện việc này.
Bạn cũng có thể đã tự khóa chính mình. fail2ban theo dõi log xác thực và chèn một rule tường lửa để chặn các địa chỉ đăng nhập thất bại nhiều lần, vì vậy một key sai hoặc một script chạy ngầm thử lại liên tục có thể khóa toàn bộ địa chỉ IP của văn phòng bạn. Một lệnh cấm dạng drop sẽ trông giống như lỗi timeout. Một lệnh cấm dạng reject sẽ trả về No route to host. Từ console:
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 198.51.100.24Thêm địa chỉ của bạn vào ignoreip là một phần của cấu hình fail2ban hoạt động trên Ubuntu 24.04.
Các lỗi không thuộc dạng từ chối hoặc quá thời gian
No route to host nghĩa là một thông báo ICMP unreachable đã phản hồi lại. Hoặc máy của bạn không có route đến mạng đó, hoặc một thiết bị trên đường truyền đã phản hồi bằng thông báo từ chối hành chính (administrative rejection), đây chính là kết quả khi gặp rule REJECT trong iptables.
Network is unreachable là thông báo từ chính máy của bạn. Máy không có route cho họ địa chỉ đó, đây là phản hồi thường gặp khi hostname chỉ phân giải ra địa chỉ IPv6 trong khi kết nối chỉ hỗ trợ IPv4.
kex_exchange_identification: Connection closed by remote host nghĩa là TCP đã kết nối thành công nhưng server ngắt kết nối trước khi quá trình trao đổi khóa hoàn tất. Cổng đang mở và sshd vẫn hoạt động, vì vậy hãy kiểm tra tải của server, kiểm tra MaxStartups, hoặc kiểm tra xem có lệnh cấm (ban) nào được áp dụng ngay khi bạn đang kết nối hay không.
Permission denied (publickey) nghĩa là bạn đã đến bước xác thực nhưng thất bại tại đó. Mạng và firewall đều bình thường, vì vậy các hướng dẫn trong tài liệu này không áp dụng cho trường hợp này. Hãy chuyển sang khắc phục lỗi Permission denied (publickey) trên SSH.
Cách truy cập lại và tránh bị khóa lần thứ hai
Mọi nhà cung cấp VPS nghiêm túc đều cung cấp một console không phụ thuộc vào mạng của guest: serial console hoặc màn hình VNC trên trình duyệt. Console đó là đường cứu hộ cho cả hai nhánh của hướng dẫn này, vì nó vẫn hoạt động khi sshd bị dừng và khi quy tắc firewall loại bỏ mọi kết nối. Hãy tìm nó trong bảng điều khiển, đăng nhập với quyền root hoặc người dùng bình thường của bạn, sau đó chạy các bước kiểm tra ở trên. Nếu bạn chưa bao giờ đặt mật khẩu root, hầu hết các bảng điều khiển đều có thể reset mật khẩu cho bạn.
Khi không có console, phương án dự phòng là chế độ rescue của nhà cung cấp. Nó khởi động một hệ thống khôi phục nhỏ và mount ổ đĩa của bạn, để bạn có thể chỉnh sửa /etc/ssh/sshd_config hoặc xóa quy tắc firewall ngoại tuyến rồi khởi động lại.
Hai thói quen giúp ngăn chặn việc bị khóa lần sau. Hãy luôn giữ một phiên SSH thứ hai mở bất cứ khi nào bạn chỉnh sửa sshd hoặc firewall, vì phiên đó vẫn duy trì trạng thái đã thiết lập trong khi bạn kiểm tra phiên mới. Và hãy tự tạo một lệnh hoàn tác tự động trước khi thực hiện thay đổi firewall rủi ro.
sudo systemd-run --unit=ufw-rollback --on-active=10min /usr/sbin/ufw disable
sudo systemctl stop ufw-rollback.timerDòng đầu tiên lên lịch cho ufw tự tắt sau mười phút. Áp dụng các quy tắc mới của bạn, mở một phiên SSH mới để xác nhận chúng hoạt động, sau đó chạy dòng thứ hai để hủy lệnh hoàn tác. Nếu bạn lỡ tay tự khóa mình, hãy đợi mười phút và firewall sẽ tự tắt. Nó sẽ để server ở trạng thái không lọc cho đến khi bạn bật lại ufw, vì vậy hãy chỉ sử dụng cách này khi bạn đang ngồi trước bàn phím chứ không phải là một thiết lập vĩnh viễn.
Thứ tự thực hiện công việc
- Đọc nội dung lỗi và lưu ý thời gian xuất hiện lỗi.
- Refused: truy cập console và kiểm tra
sudo ss -tlnpđể xem socket đang lắng nghe, cổng và địa chỉ mà nó đang bind. - Timed out: từ máy của bạn, xác nhận lại địa chỉ, sau đó kiểm tra firewall của nhà cung cấp trong bảng điều khiển, rồi kiểm tra firewall trên máy chủ.
- Không phải hai trường hợp trên: bạn đã có kết nối TCP, vì vậy hãy coi đây là vấn đề về xác thực hoặc tải của máy chủ, không phải vấn đề mạng.
FAQ
Tại sao SSH báo "Connection refused" trong khi sshd đang chạy?
Vì thông báo từ chối đến từ socket, không phải từ service, và một tiến trình sshd đang chạy vẫn có thể từ chối kết nối của bạn. Hãy mở console của nhà cung cấp và chạy sudo ss -tlnp. Một socket trên 127.0.0.1:22 sẽ từ chối mọi client từ xa vì nó chỉ bind vào loopback. Một socket trên cổng khác sẽ từ chối bất kỳ ai vẫn đang cố kết nối vào cổng 22. Nếu bạn đang sử dụng systemd socket activation, cổng sẽ được lấy từ ssh.socket chứ không phải từ sshd_config, vì vậy hãy kiểm tra cả systemctl is-enabled ssh.socket. Một rule reject trong ufw cũng sẽ trả về thông báo từ chối thay cho host, vì vậy hãy đọc sudo ufw status verbose trước khi đưa ra kết luận.
Tại sao SSH bị timeout trong khi ufw đã cho phép cổng 22?
Vì timeout nghĩa là không có phản hồi nào được gửi lại, và ufw không phải là firewall duy nhất trên đường truyền. Hầu hết các bảng điều khiển VPS đều chạy một network firewall phía trước instance, và hệ điều hành sẽ không bao giờ thấy được những gì firewall đó chặn. Từ console, hãy chạy sudo tcpdump -ni any tcp port 22 và thử kết nối từ laptop của bạn trong khi lệnh này đang chạy. Nếu không có gói tin nào đến nghĩa là việc chặn xảy ra ở phía upstream, trong bảng điều khiển. Nếu gói tin đến nhưng không có phản hồi gửi đi nghĩa là việc chặn xảy ra cục bộ, trong ufw hoặc nftables.
Ping thất bại có nghĩa là VPS của tôi đã sập không?
Không. Nhiều nhà cung cấp lọc ICMP tại biên mạng, vì vậy một máy chủ đang phục vụ lưu lượng bình thường vẫn có thể bỏ qua mọi gói tin ping bạn gửi. Một lần ping thành công cũng không có ý nghĩa nhiều, vì nó không cho biết cổng 22 có đang mở hay không. Hãy kiểm tra chính cổng đó bằng nc -vz -w 5 203.0.113.10 22 từ máy của bạn, hoặc bằng Test-NetConnection 203.0.113.10 -Port 22 trong PowerShell trên Windows.
Tôi đã đổi cổng SSH và giờ không kết nối được. Chuyện gì đã xảy ra?
Có hai nguyên nhân chính gây ra lỗi này. Nếu firewall chưa được thêm rule cho cổng mới, các nỗ lực kết nối vào cổng mới sẽ bị timeout trong khi cổng 22 báo từ chối, vì vậy sudo ufw allow 2222/tcp cần được thực hiện trước khi đổi cổng chứ không phải sau đó. Nếu máy chủ sử dụng systemd socket activation cho SSH, Port 2222 trong sshd_config sẽ bị bỏ qua và systemd vẫn giữ cổng cũ, điều mà bạn có thể xác nhận bằng systemctl is-enabled ssh.socket. Hãy khôi phục thông qua console của nhà cung cấp, sửa lỗi tương ứng, sau đó kết nối bằng ssh -p 2222 user@203.0.113.10 khi sudo ss -tlnp hiển thị socket mới.