❤️ AZDIGI chính thức cập nhật hệ thống blog mới hoàn chỉnh. Tuy nhiên có thể một số bài viết bị sai lệch hình ảnh, hãy ấn nút Báo cáo bài viết ở cuối bài để AZDIGI cập nhật trong thời gian nhanh nhất. Chân thành cám ơn.
SSH là cánh cửa chính để bạn truy cập vào VPS. Nhưng cũng chính vì vậy mà nó trở thành mục tiêu đầu tiên mà attacker nhắm tới. Một con VPS mới dựng, chưa kịp cài gì, đã có thể nhận hàng nghìn lượt dò mật khẩu mỗi ngày trên port 22.

Trong bài này, mình sẽ đi qua từng bước bảo vệ SSH, từ cơ bản tới nâng cao. Mỗi bước đều có giải thích tại sao cần làm, không chỉ làm theo kiểu copy-paste mù quáng.
Tại sao SSH là mục tiêu số 1?
Nếu bạn bật SSH trên port mặc định (22) với password authentication, chỉ cần vài phút là bot scanner đã tìm thấy server của bạn. Chúng chạy tự động 24/7 trên toàn bộ dải IP public, thử đăng nhập với những combo username/password phổ biến như root:123456, admin:password, ubuntu:ubuntu.
Có hai kiểu tấn công chính nhắm vào SSH:
- Dò mật khẩu: Thử hàng triệu password khác nhau cho đến khi trúng. Nếu password yếu, chỉ là vấn đề thời gian.
- Credential stuffing: Dùng database username/password bị leak từ các vụ data breach khác để thử trên SSH. Nếu bạn dùng lại password, nguy cơ rất cao.
Bạn có thể kiểm tra ngay bằng cách xem log authentication trên server:
# Ubuntu/Debian
grep "Failed password" /var/log/auth.log | tail -20
# AlmaLinux/RHEL
grep "Failed password" /var/log/secure | tail -20
Nếu thấy hàng trăm dòng từ những IP lạ, đó chính là bot đang quét server của bạn. Tin tốt là với vài bước cấu hình đúng, bạn có thể chặn gần như toàn bộ các kiểu tấn công này.
Bước 1: Tạo SSH Key Ed25519
Bước đầu tiên và quan trọng nhất: chuyển từ đăng nhập bằng password sang SSH key. Với SSH key, server chỉ cho phép đăng nhập nếu bạn có private key tương ứng. Không có key thì không vào được, dù biết password cũng vô dụng.
Mình khuyến nghị dùng Ed25519 thay vì RSA. Ed25519 dựa trên elliptic curve, cho key ngắn hơn (256-bit) nhưng bảo mật tương đương RSA 3072-bit, và tốc độ ký/xác thực nhanh hơn đáng kể.
Tạo key trên máy local
Chạy lệnh sau trên máy tính cá nhân (không phải trên VPS):
ssh-keygen -t ed25519 -C "your-email@example.com"
Khi được hỏi passphrase, mình khuyên bạn nên đặt một passphrase. Nó hoạt động như lớp bảo vệ thứ hai cho private key, phòng trường hợp máy local bị truy cập trái phép.
Sau khi tạo xong, bạn sẽ có hai file:
~/.ssh/id_ed25519: Private key (giữ kín, không chia sẻ)~/.ssh/id_ed25519.pub: Public key (đưa lên server)
Copy public key lên VPS
Cách nhanh nhất là dùng ssh-copy-id:
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server-ip
Nếu ssh-copy-id không có sẵn (ví dụ trên Windows), bạn copy thủ công:
# Xem nội dung public key
cat ~/.ssh/id_ed25519.pub
# SSH vào server, sau đó thêm key
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "nội-dung-public-key" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
Test thử đăng nhập bằng key:
ssh -i ~/.ssh/id_ed25519 user@your-server-ip
Nếu vào được mà không bị hỏi password (chỉ hỏi passphrase nếu bạn đã đặt), tức là key đã hoạt động đúng.
Lưu ý: Đừng vội tắt password authentication ở bước này. Hãy chắc chắn SSH key hoạt động rồi mới tắt, nếu không bạn có thể tự khoá mình ra khỏi server.
Bước 2: Tắt password authentication
Sau khi đã xác nhận SSH key hoạt động, bước tiếp theo là tắt hoàn toàn việc đăng nhập bằng password. Đây là bước quan trọng nhất để chặn dò mật khẩu, vì không còn password để mà đoán nữa.
Mở file cấu hình SSH:
sudo nano /etc/ssh/sshd_config
Tìm và chỉnh các dòng sau:
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
Lưu ý: Nếu bạn định cài 2FA ở phần sau, hãy giữ UsePAM yes và ChallengeResponseAuthentication yes. Mình sẽ giải thích chi tiết ở phần 2FA bên dưới.
Restart SSH để áp dụng:
sudo systemctl restart sshd
Quan trọng: Giữ session SSH hiện tại mở, mở thêm một terminal mới để test đăng nhập. Nếu vào được bình thường bằng key, mọi thứ đã ổn. Nếu không vào được, bạn vẫn còn session cũ để sửa lại.
Bước 3: Đổi port SSH
Đổi port SSH từ 22 sang port khác là một biện pháp gây tranh cãi. Về mặt kỹ thuật, đây là “security through obscurity” và không thực sự tăng bảo mật, vì attacker có thể scan toàn bộ port để tìm SSH.
Tuy nhiên, trên thực tế nó rất hiệu quả để giảm noise. Phần lớn bot chỉ quét port 22, nên việc đổi port sẽ loại bỏ hàng nghìn lượt dò mật khẩu mỗi ngày. Log sạch hơn, dễ phát hiện các cuộc tấn công thực sự hơn.
Chỉnh trong /etc/ssh/sshd_config:
Port 2222
Chọn port trong khoảng 1024-65535, tránh các port đã dùng bởi service khác (như 3306 cho MySQL, 8080 cho web).
Cấu hình firewall cho port mới
Trước khi restart SSH, hãy mở port mới trên firewall. Nếu quên bước này, bạn sẽ tự khoá mình ra khỏi server.
# Ubuntu/Debian (UFW)
sudo ufw allow 2222/tcp
sudo ufw reload
# AlmaLinux/RHEL (firewalld)
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
AlmaLinux: Cấu hình SELinux
Trên AlmaLinux và các distro RHEL-based, SELinux mặc định chỉ cho phép SSH chạy trên port 22. Nếu bạn đổi port mà không cập nhật SELinux, SSH sẽ không start được.
# Cài policycoreutils nếu chưa có
sudo dnf install -y policycoreutils-python-utils
# Cho phép SSH trên port mới
sudo semanage port -a -t ssh_port_t -p tcp 2222
# Kiểm tra lại
sudo semanage port -l | grep ssh
Sau khi đã mở firewall (và cấu hình SELinux nếu dùng AlmaLinux), restart SSH:
sudo systemctl restart sshd
Test kết nối trên port mới:
ssh -p 2222 user@your-server-ip
Bước 4: Tắt root login
Account root có trên mọi Linux server, nên attacker luôn thử username này đầu tiên. Tắt root login buộc attacker phải đoán cả username lẫn password, tăng độ khó lên đáng kể.
Trước khi tắt, hãy đảm bảo bạn đã có một user thường với quyền sudo:
# Tạo user mới (nếu chưa có)
sudo adduser deploy
sudo usermod -aG sudo deploy # Ubuntu/Debian
sudo usermod -aG wheel deploy # AlmaLinux/RHEL
# Copy SSH key sang user mới
sudo mkdir -p /home/deploy/.ssh
sudo cp ~/.ssh/authorized_keys /home/deploy/.ssh/
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
Test login vào user mới, xác nhận chạy sudo được, rồi mới tắt root login:
# Trong /etc/ssh/sshd_config
PermitRootLogin no
Bước 5: Giới hạn user được phép SSH
Mặc định, mọi user trên hệ thống đều có thể SSH vào (nếu có password hoặc key). Bạn nên giới hạn chỉ những user cần thiết mới được SSH.
# Cho phép theo user cụ thể
AllowUsers deploy admin
# Hoặc cho phép theo group
AllowGroups sshusers
Nếu dùng AllowGroups, bạn cần tạo group và thêm user vào:
sudo groupadd sshusers
sudo usermod -aG sshusers deploy
sudo usermod -aG sshusers admin
Khi đã set AllowUsers hoặc AllowGroups, bất kỳ user nào không nằm trong danh sách sẽ bị từ chối SSH ngay lập tức, kể cả có đúng password hay key.
Bước 6: Giới hạn tần suất và giới hạn đăng nhập
Ngay cả khi đã chuyển sang key-based authentication, vẫn nên giới hạn số lần thử đăng nhập thất bại. Điều này giảm thiểu rủi ro và giữ log sạch sẽ.
# Số lần auth thất bại tối đa trước khi bị ngắt kết nối
MaxAuthTries 3
# Thời gian tối đa để hoàn thành đăng nhập (giây)
LoginGraceTime 30
MaxAuthTries 3 nghĩa là sau 3 lần thử sai, connection bị drop. Mặc định là 6, giảm xuống 3 đủ cho người dùng bình thường nhưng khó hơn cho dò mật khẩu.
LoginGraceTime 30 nghĩa là nếu sau 30 giây chưa đăng nhập xong, connection tự đóng. Mặc định là 120 giây, quá lâu và lãng phí tài nguyên.
Bước 7: Timeout session idle
Session SSH bỏ quên (mở terminal rồi đi ăn, đi ngủ) là rủi ro bảo mật. Nếu ai đó truy cập được máy tính của bạn, họ có sẵn một session SSH đang mở vào server.
# Server gửi keep-alive mỗi 300 giây (5 phút)
ClientAliveInterval 300
# Sau 2 lần không nhận được response, ngắt kết nối
ClientAliveCountMax 2
Với cấu hình trên, nếu không có hoạt động gì trong 10 phút (300 giây × 2 lần), session SSH sẽ tự động bị ngắt. Bạn điều chỉnh thời gian tuỳ theo nhu cầu, nhưng không nên để quá 30 phút.
Bước 8: Tắt các tính năng không cần thiết
SSH có nhiều tính năng forwarding tiện lợi, nhưng trên server production, hầu hết không cần và có thể bị lợi dụng để tạo tunnel trái phép.
# Tắt X11 forwarding (chạy GUI app qua SSH)
X11Forwarding no
# Tắt agent forwarding (forward SSH key qua server)
AllowAgentForwarding no
# Tắt TCP forwarding (tạo tunnel qua SSH)
AllowTcpForwarding no
# Tắt stream local forwarding (Unix socket forwarding)
AllowStreamLocalForwarding no
# Tắt tunnel device forwarding
PermitTunnel no
Giải thích từng mục:
- X11Forwarding: Cho phép chạy app đồ hoạ từ server hiển thị trên máy local. Server không có GUI thì không cần.
- AgentForwarding: Cho phép forward SSH key agent qua server để SSH tiếp sang server khác. Tiện nhưng nếu server bị compromise, attacker có thể dùng key agent của bạn.
- TCPForwarding: Cho phép tạo SSH tunnel (port forwarding). Attacker có thể dùng để bypass firewall hoặc truy cập internal service.
Lưu ý: Nếu bạn đang dùng SSH tunnel cho mục đích cụ thể (như truy cập database nội bộ), hãy giữ AllowTcpForwarding yes và giới hạn bằng cách khác.
Bước 9: Thêm SSH Banner cảnh báo
SSH banner hiển thị thông báo trước khi người dùng đăng nhập. Về mặt pháp lý, có banner cảnh báo “unauthorized access is prohibited” giúp bạn có cơ sở nếu cần xử lý sự cố. Về mặt tâm lý, nó cũng làm attacker cẩn thận hơn.
Tạo file banner:
sudo nano /etc/ssh/banner
Nội dung ví dụ:
*********************************************
* WARNING: Unauthorized access prohibited *
* All connections are monitored and logged *
*********************************************
Thêm vào /etc/ssh/sshd_config:
Banner /etc/ssh/banner
Mỗi lần SSH vào, thông báo này sẽ hiển thị trước khi login prompt.
Bước 10: Cài 2FA với Google Authenticator
Thêm một lớp xác thực nữa bằng OTP (One-Time Password) từ app Google Authenticator hoặc tương tự. Với 2FA, để SSH vào server cần cả SSH key lẫn mã OTP từ điện thoại. Ngay cả khi private key bị lộ, attacker vẫn không vào được.
Cài đặt Google Authenticator
# Ubuntu/Debian
sudo apt install -y libpam-google-authenticator
# AlmaLinux/RHEL
sudo dnf install -y epel-release
sudo dnf install -y google-authenticator
Chạy lệnh cấu hình với user mà bạn dùng để SSH (không phải root):
google-authenticator
Lệnh này sẽ hỏi bạn một loạt câu hỏi. Mình khuyến nghị trả lời như sau:
- Time-based tokens? →
y(dùng TOTP, chuẩn phổ biến nhất) - Update .google_authenticator file? →
y - Disallow multiple uses of same token? →
y(chống replay attack) - Increase time skew window? →
n(giữ window nhỏ, bảo mật hơn) - Enable giới hạn tần suất? →
y(giới hạn 3 lần thử mỗi 30 giây)
Lệnh sẽ hiển thị QR code và emergency scratch codes. Quét QR bằng Google Authenticator (hoặc Authy, 1Password) trên điện thoại. Ghi lại emergency codes vào nơi an toàn, đây là cách duy nhất để vào server nếu mất điện thoại.
Cấu hình PAM
Mở file PAM cho SSH:
sudo nano /etc/pam.d/sshd
Thêm dòng sau vào cuối file:
auth required pam_google_authenticator.so
Cấu hình sshd_config cho 2FA
Để 2FA hoạt động cùng SSH key, bạn cần chỉnh /etc/ssh/sshd_config:
# Bật ChallengeResponse và PAM
ChallengeResponseAuthentication yes
UsePAM yes
# Yêu cầu cả publickey VÀ keyboard-interactive (OTP)
AuthenticationMethods publickey,keyboard-interactive
Dòng AuthenticationMethods là chìa khoá. Dấu phẩy giữa publickey và keyboard-interactive nghĩa là cần cả hai (AND), không phải một trong hai (OR).
Restart SSH:
sudo systemctl restart sshd
Test 2FA
Mở terminal mới và thử SSH vào. Bạn sẽ thấy sau khi xác thực key, server hỏi thêm verification code:
$ ssh -p 2222 deploy@your-server-ip
Authenticated with partial success.
Verification code: ______
Nhập mã 6 số từ Google Authenticator trên điện thoại. Nếu đúng, bạn sẽ vào được server.
Quan trọng: Luôn giữ session SSH cũ mở khi test 2FA. Nếu cấu hình sai, bạn vẫn có session cũ để sửa. Tắt session cũ chỉ khi đã chắc chắn 2FA hoạt động đúng.
Bước 11: Kiểm tra và xác nhận cấu hình
Sau khi đã chỉnh xong tất cả, hãy kiểm tra cấu hình trước khi áp dụng.
Kiểm tra cú pháp sshd_config
# Kiểm tra cú pháp, nếu không báo lỗi tức là OK
sudo sshd -t
# Xem toàn bộ config đang active (bao gồm cả giá trị mặc định)
sudo sshd -T
Nếu sshd -t báo lỗi, sửa lại trước khi restart. Nếu không có output gì, tức là config hợp lệ.
Kiểm tra SSH đang listen đúng port
sudo ss -tlnp | grep ssh
Output mong đợi (nếu dùng port 2222):
LISTEN 0 128 0.0.0.0:2222 0.0.0.0:* users:(("sshd",pid=1234,fd=3))
LISTEN 0 128 [::]:2222 [::]:* users:(("sshd",pid=1234,fd=4))
Test đăng nhập
Chạy từng bước kiểm tra:
# Test 1: Login bằng key + 2FA (phải thành công)
ssh -p 2222 deploy@your-server-ip
# Test 2: Login bằng password (phải bị từ chối)
ssh -p 2222 -o PubkeyAuthentication=no deploy@your-server-ip
# Test 3: Login bằng root (phải bị từ chối)
ssh -p 2222 root@your-server-ip
# Test 4: Login trên port cũ (phải bị từ chối nếu đã đóng)
ssh -p 22 deploy@your-server-ip
File sshd_config mẫu (hardened)
Dưới đây là file /etc/ssh/sshd_config mẫu đã áp dụng tất cả các bước ở trên. Bạn có thể dùng làm tham khảo, nhưng hãy đọc hiểu từng dòng trước khi áp dụng vào server thực tế.
# === Port và Protocol ===
Port 2222
Protocol 2
AddressFamily any
# === Authentication ===
PermitRootLogin no
MaxAuthTries 3
LoginGraceTime 30
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
# Tắt password authentication
PasswordAuthentication no
PermitEmptyPasswords no
# 2FA config
ChallengeResponseAuthentication yes
UsePAM yes
AuthenticationMethods publickey,keyboard-interactive
# === User/Group restriction ===
AllowUsers deploy admin
# AllowGroups sshusers
# === Session ===
ClientAliveInterval 300
ClientAliveCountMax 2
# === Disable forwarding ===
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
AllowStreamLocalForwarding no
PermitTunnel no
# === Misc ===
Banner /etc/ssh/banner
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
MaxSessions 3
MaxStartups 3:50:10
# === Logging ===
SyslogFacility AUTH
LogLevel VERBOSE
Giải thích thêm một số option:
MaxSessions 3: Giới hạn tối đa 3 session cùng lúc trên một connection.MaxStartups 3:50:10: Khi có 3 connection chưa authenticated đồng thời, bắt đầu drop 50% connection mới. Khi lên 10, drop 100%. Rất hiệu quả chống dò mật khẩu hàng loạt.LogLevel VERBOSE: Log chi tiết hơn mặc định, ghi lại cả key fingerprint khi đăng nhập, tiện cho audit.
Checkpoint cuối bài
Trước khi chuyển sang bài tiếp theo trong series, hãy chạy qua checklist sau:
- ☐ SSH key Ed25519 đã tạo và đang hoạt động
- ☐ Password authentication đã tắt
- ☐ Root login đã tắt
- ☐ SSH đang chạy trên port mới (không phải 22)
- ☐ Chỉ user cần thiết mới được SSH
- ☐ 2FA đã cài và test thành công
- ☐ Firewall đã mở đúng port (và SELinux nếu dùng AlmaLinux)
- ☐
sshd -tkhông báo lỗi - ☐ Emergency scratch codes đã lưu ở nơi an toàn
Nếu tất cả đều OK, SSH trên server của bạn đã được hardened khá kỹ. Dò mật khẩu gần như không còn tác dụng khi password authentication đã tắt, 2FA thêm lớp bảo vệ cho trường hợp key bị lộ, và các cấu hình giới hạn tần suất giới hạn mọi hành vi bất thường.
Bài tiếp theo trong series, mình sẽ hướng dẫn cấu hình Firewall chi tiết với UFW và firewalld, kết hợp thêm Fail2Ban để tự động ban IP tấn công.
Có thể bạn cần xem thêm
- Checklist bảo mật VPS Linux - 15 bước thiết yếu
- SSH an toàn qua Tailscale: Bảo vệ VPS không cần mở port 22
- User và Permission nâng cao trên Linux VPS - Least Privilege
- Tổng quan bảo mật VPS Linux - Hiểu rõ mối nguy trước khi phòng thủ
- Backup và phục hồi sự cố cho VPS Linux - Kế hoạch toàn diện
- Những cách bảo mật SSH nên làm
Về tác giả
Trần Thắng
Chuyên gia tại AZDIGI với nhiều năm kinh nghiệm trong lĩnh vực web hosting và quản trị hệ thống.