5.4. Networking: Đồng bộ thời gian và SSH server/client
Mục lục
- 1. Clock drift và NTP server
- 2. Đặt time zone bằng timedatectl
- 3. Bật đồng bộ NTP với systemd-timesyncd
- 4. Tinh chỉnh file timesyncd và kiểm tra trạng thái
- 5. Cấu hình SSH daemon
- 6. Cấu hình SSH client
- 7. Đăng nhập bằng SSH key
- 8. known_hosts và fingerprint của server
1. Clock drift và NTP server
Đồng hồ phần cứng trong máy tính không chính xác tuyệt đối. Chúng chạy lệch dần khỏi thời gian thật, hiện tượng gọi là drift. Sau vài ngày, thời gian thật là 12 giờ 5 giây trong khi server lại hiển thị 12 giờ 6 giây: nó đã drift lên trước một giây.
Server cần một đồng hồ chính xác. Nhưng ngày nay gần như không còn ai phải tự tay đặt lại đồng hồ: điện thoại, laptop và server bằng cách nào đó đều biết đúng giờ, vì chúng định kỳ lấy thời gian chính xác từ Internet. Nguồn cấp đó là các time server, cụ thể hơn là NTP server, với NTP viết tắt của Network Time Protocol.
Phần lớn hệ điều hành hiện đại đều có sẵn software đồng bộ thời gian. Trên Ubuntu, công cụ mặc định nằm trong bộ utility của systemd và có tên systemd-timesyncd.
2. Đặt time zone bằng timedatectl
Trước khi học cách dùng utility đồng bộ, có một việc phải xử lý trước. Thế giới thật có rất nhiều time zone: lúc ở Đức là 1 giờ 47 thì ở Singapore đã là 7 giờ 47. Một server dựng ở Đức có thể được cấu hình sẵn theo zone đó.
Giờ tưởng tượng một đội vận hành có server ở năm quốc gia khác nhau. Việc đọc log trở nên rối: phải liên tục cộng hay trừ vài giờ để biết một event được log vào lúc nào, quy chiếu về giờ của nước mình. Vì vậy việc đầu tiên nên làm sau khi dựng một server là đặt cho nó một time zone cụ thể, tốt nhất là time zone nơi mình sống hoặc nơi đặt văn phòng chính của công ty.
Mọi thao tác liên quan tới thời gian đều làm bằng utility timedatectl. Xem danh sách time zone có sẵn:
timedatectl list-timezones
# Output (rút gọn):
Africa/Abidjan
America/Chicago
America/Los_Angeles
Asia/Singapore
Europe/Berlin
Danh sách rất dài, duyệt được bằng phím Page Up và Page Down, hoặc bằng các phím mũi tên, và thoát bằng cách nhấn Q. Các zone được ghi theo quy ước: tên lục địa trước, rồi dấu gạch chéo, rồi tên một thành phố, thường là thủ đô của một quốc gia hoặc một bang.
Đặt time zone sang Los Angeles:
sudo timedatectl set-timezone America/Los_Angeles
Chú ý khi tên thành phố có hai từ: hai từ đó phân cách bằng dấu gạch dưới, không phải dấu cách. Kiểm tra thay đổi đã có hiệu lực hay chưa chỉ cần gọi lệnh không kèm tham số:
timedatectl
# Output (minh họa):
Local time: Fri 2026-10-24 03:21:48 PDT
Universal time: Fri 2026-10-24 10:21:48 UTC
RTC time: Fri 2026-10-24 10:21:48
Time zone: America/Los_Angeles (PDT, -0700)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no
Time zone đã đổi, và Local time hiện giờ hiện tại ở Los Angeles. Output này còn trả lời một câu hỏi nữa: dòng NTP service cho biết có service NTP nào đang hoạt động hay không.
3. Bật đồng bộ NTP với systemd-timesyncd
Gặp một server mà timedatectl báo NTP service inactive thì xử lý theo hai bước. Trước tiên cài utility systemd-timesyncd:
sudo apt install systemd-timesyncd
Trên nhiều bản Ubuntu, package này đã có sẵn và apt sẽ báo lại như vậy. Sau đó bảo timedatectl bật đồng bộ với các NTP server:
sudo timedatectl set-ntp true
Gọi lại timedatectl không kèm tham số để xem NTP service đã active hay chưa. Và kiểm tra chính service đó:
systemctl status systemd-timesyncd
# Output (rút gọn):
● systemd-timesyncd.service - Network Time Synchronization
Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; preset: enabled)
Active: active (running)
Status: "Contacted time server 185.125.190.56:123 (ntp.ubuntu.com)."
Output phải cho thấy service đang active và được enable để tự khởi động lúc boot. Kèm đó là vài dòng log cho biết nó đang dùng NTP server nào. Phần systemctl và trạng thái service nói kỹ hơn ở Part 3.1: Boot, systemd service và bash script.
4. Tinh chỉnh file timesyncd và kiểm tra trạng thái
Đổi thiết lập của systemd-timesyncd thì sửa file /etc/systemd/timesyncd.conf:
sudo vim /etc/systemd/timesyncd.conf
Muốn chỉ rõ nó phải dùng NTP server nào thì uncomment dòng NTP bằng cách bỏ dấu thăng ở đầu, rồi liệt kê nhiều server trên cùng một dòng:
[Time]
NTP=0.us.pool.ntp.org 1.us.pool.ntp.org
#FallbackNTP=ntp.ubuntu.com
#RootDistanceMaxSec=5
#PollIntervalMinSec=32
#PollIntervalMaxSec=2048
Định dạng hostname của các NTP server này đi theo một khuôn khá cố định. Website chính của NTP đặt tại ntp.org, và các NTP server được tham chiếu qua subdomain, chẳng hạn us.pool.ntp.org, trong đó us là mã quốc gia của Hoa Kỳ. Mỗi tập hợp NTP server lại được gán một subdomain con nữa, biểu diễn bằng một con số đếm từ 0 trở lên: tập đầu tiên là 0.us.pool.ntp.org, tập thứ hai là 1.us.pool.ntp.org, và tiếp tục như vậy.
Những dòng còn comment phía dưới cho thấy giá trị mặc định của timesyncd:
FallbackNTPđược dùng khi dòngNTPkhông khai gì cả. Đó cũng chính là nguồn đang được dùng trước khi dòngNTPđược uncomment.RootDistanceMaxSecquy định thời gian tối đa, tính theo giây, mà NTP server được phép dùng để gửi dữ liệu mạng về máy này. Vượt mức đó thìtimesyncdchuyển sang một NTP server khác.- Hai giá trị poll interval quy định bao lâu
timesyncdliên hệ NTP server một lần. Ở đây mức tối thiểu là 32 giây và mức tối đa là 2048 giây, nghĩa là nó phải đợi ít nhất 32 giây mới xin dữ liệu mới, nhưng cũng không được đợi quá 2048 giây. Sau request đầu tiên,timesyncdtự điều chỉnh poll interval trong khoảng giữa hai mức đó, nên giá trị thực tế có thể là một con số bất kỳ như 248 giây. Nó chọn dựa trên mức drift mà nó quan sát được: đồng hồ server ít lệch thì nó poll thưa hơn.
Lưu file rồi restart service để áp dụng thiết lập mới:
sudo systemctl restart systemd-timesyncd
Hai lệnh con dành cho timesync
Gõ timedatectl, thêm một dấu cách, rồi nhấn phím Tab hai lần sẽ hiện ra vài lệnh con hữu dụng, trong đó có show-timesync và timesync-status. Kiểm tra xem các NTP server vừa khai có đang được dùng hay không:
timedatectl show-timesync
# Output (rút gọn):
SystemNTPServers=0.us.pool.ntp.org 1.us.pool.ntp.org
FallbackNTPServers=ntp.ubuntu.com
ServerName=0.us.pool.ntp.org
Và lệnh còn lại cho biết cả poll interval hiện tại lẫn root distance của NTP server đang dùng:
timedatectl timesync-status
# Output (rút gọn):
Server: 162.159.200.1 (0.us.pool.ntp.org)
Poll interval: 1min 4s (min: 32s; max 34min 8s)
Root distance: 2.168ms (max: 5s)
5. Cấu hình SSH daemon
Quản lý server Linux từ xa cần hai thứ: một SSH client trên máy local, và một SSH daemon chạy trên server Linux ở xa. SSH daemon còn được gọi là SSH server, vì nó phục vụ request của người dùng. Có client chạy ở local là nối được tới OpenSSH daemon đang chạy trên server.
File cấu hình của daemon nằm ở /etc/ssh/sshd_config. Chú ý chữ d trong tên file: nó ở đó vì file cấu hình này thuộc về SSHD daemon. Cũng có một file cấu hình cho SSH client, tên ssh_config, không có chữ d sau ssh. Đây là khác biệt nhỏ nhưng phải nhớ khi sửa cấu hình SSH, vì một hệ điều hành Linux thường chứa cả hai chương trình: SSH client và SSH daemon.
Mở file cấu hình của daemon:
sudo vim /etc/ssh/sshd_config
Port, address family và địa chỉ listen
Thiết lập quan trọng đầu tiên là số port mà SSH daemon nhận kết nối đi vào. Dòng này đang được comment nên không có hiệu lực, nhưng nó cho biết port mặc định là 22. Muốn đổi thì uncomment bằng cách xóa dấu thăng ở đầu rồi đổi số:
#Port 22
AddressFamily any
#ListenAddress 0.0.0.0
Dòng tiếp theo là AddressFamily any. Tên thiết lập này hơi tối nghĩa, nhưng nó mở ra cơ hội để thực hành cách tra thêm thông tin về các option trong file cấu hình. Thoát editor rồi mở manual của sshd_config:
man sshd_config
Gõ dấu gạch chéo rồi nhập Family sẽ dẫn tới phần mô tả. Hiểu ra rằng thiết lập này cho phép chọn protocol IP nào được bật cho SSH daemon: any bật cả IPv4 lẫn IPv6, inet chỉ bật IPv4, và inet6 chỉ bật IPv6.
Manual mở bằng pager less, nên nhấn N để nhảy tới lần khớp tiếp theo. Tìm chữ password xuyên suốt tài liệu rồi nhấn N vài lần sẽ tới PasswordAuthentication, kèm mô tả rằng nó quy định có cho phép xác thực bằng password hay không, và mặc định là yes.
Quay lại file cấu hình. Chỉ muốn nhận kết nối trên IPv4 thì uncomment dòng kia và đổi giá trị; muốn chỉ IPv6 thì đổi thành inet6:
AddressFamily inet
Mặc định SSH daemon chờ kết nối đi vào trên mọi IP mà nó có. Nhưng giả sử server có hai IP: 203.0.113.1 nối với Internet, và 10.11.12.9 chỉ nối với mạng nội bộ ở office. Nếu SSH chỉ nên tiếp cận được bởi nhân viên bên trong tòa nhà, tức trên mạng nội bộ đó, thì bảo daemon chỉ listen trên đúng IP đó:
ListenAddress 10.11.12.9
Root login và hai cơ chế xác thực password
Một option nữa rất hay được tinh chỉnh là PermitRootLogin. Mặc định nó cho user root đăng nhập, nhưng chỉ khi việc xác thực không dùng password, chẳng hạn dùng SSH key. Đó là lý do giá trị mặc định ở đây là prohibit-password. Muốn cấm hẳn user root đăng nhập qua SSH thì đổi thành:
PermitRootLogin no
SSH hỗ trợ nhiều cơ chế đăng nhập, nhưng hai cái phổ biến nhất là password và SSH key. Cuộn xuống sẽ thấy hai dòng liên quan tới password, và khác biệt giữa chúng rất tinh tế:
PasswordAuthentication no
KbdInteractiveAuthentication no
Mặc định việc đăng nhập bằng password được cho phép, nhưng một số người quản trị thích tắt nó đi bằng cách đặt PasswordAuthentication thành no. Chỉ có điều vẫn còn một option khác có thể khiến việc đăng nhập bằng password tiếp tục khả thi, nằm xa hơn phía dưới, là KbdInteractiveAuthentication.
Phân biệt hai cái: với PasswordAuthentication yes, user đăng nhập được bằng password, nhưng SSH daemon không kiểm tra xem password đó có được gõ trên bàn phím hay không. User có thể dùng một cách tự động để gửi password mà không hề gõ trên bàn phím. KbdInteractiveAuthentication thì ngược lại, nó bảo đảm user thật sự gõ password trong lúc đăng nhập.
Vậy tắt cả hai, cả keyboard-interactive authentication lẫn password authentication, là tắt hẳn việc đăng nhập bằng password: user chỉ còn đăng nhập được bằng SSH key, thứ thường an toàn hơn password rất nhiều. SSH key về bản chất là các file chứa một đoạn mã rất dài và duy nhất bên trong. Chỉ người có đoạn mã duy nhất đó mới đăng nhập được với tư cách user tương ứng.
X11 forwarding và override theo từng user
Trên Linux có thể chạy một ứng dụng đồ họa trên server nhưng hiện cửa sổ của nó trên màn hình máy local. Về cơ bản nó giống TeamViewer, nhưng dành cho một cửa sổ ứng dụng thay vì toàn bộ desktop. Cơ chế này gọi là X11Forwarding, và trong file cấu hình nó đang được bật:
X11Forwarding yes
Những thiết lập vừa xem đều là global, tức áp cho mọi user tìm cách đăng nhập qua SSH. Nhưng định nghĩa thiết lập riêng cho từng user cũng được. Giả sử dùng thiết lập global PasswordAuthentication no, nghĩa là không user nào đăng nhập được mà không có key. Giờ cần một ngoại lệ cho đúng một user tên aaron. Cuộn xuống cuối file sẽ thấy một ví dụ về cách làm việc này, dưới tiêu đề nói về việc override thiết lập theo từng user:
Match User aaron
PasswordAuthentication yes
Khối này tạo một ngoại lệ cho aaron: user này đăng nhập được bằng password của mình, còn mọi user khác thì không.
File trong sshd_config.d có thể ghi đè cấu hình chính
Mỗi lần đổi file cấu hình này đều phải reload SSH daemon để nó áp dụng thiết lập mới:
sudo systemctl reload ssh
Và còn một chỗ dễ mắc bẫy: một số file bổ sung có thể ghi đè chính thiết lập vừa thêm. Có trường hợp sửa file cấu hình chính rồi mà vẫn không tắt được việc đăng nhập bằng password, nguyên nhân nằm trong thư mục sshd_config.d:
sudo cat /etc/ssh/sshd_config.d/50-cloud-init.conf
# Output:
PasswordAuthentication yes
Vậy dù PasswordAuthentication đã được đặt thành no ở file chính, file cấu hình bổ sung này được nạp sau và bật lại việc xác thực bằng password. Nên việc cần làm trước là soi thư mục đó, bảo đảm không có gì xung đột với thiết lập mình muốn.
6. Cấu hình SSH client
Phía nhận đã xong, giờ sang nửa còn lại của câu chuyện: phía kết nối tới server, tức SSH client. Nó cũng có những cấu hình điều chỉnh được.
Windows 10, macOS và các hệ điều hành Linux đều có sẵn SSH client cài đặt trước. Trên Windows thì mở Command Prompt, còn trên macOS và Linux thì mở terminal, rồi gõ ssh, và lúc đó SSH client, một chương trình chạy trên text, được thực thi.
Client giữ một số file trong thư mục .ssh của mỗi user. Nếu user đang đăng nhập có home directory ở /home/jeremy thì các file đó nằm ở /home/jeremy/.ssh. Dấu ~ chỉ là lối viết tắt cho cùng đường dẫn ấy. Điều này đúng với các hệ điều hành kiểu Unix như Linux hay macOS; trên Windows, thư mục này nằm ở C:\Users\Jeremy\.ssh.
Trên Linux thường không có file cấu hình nào được tạo sẵn cho SSH client, hiểu theo nghĩa cấu hình riêng của từng user. Lý do là có một file cấu hình cho SSH client, nhưng nó áp global cho mọi user trên máy.
Tạo cấu hình client riêng cho một user
Tạo một cấu hình riêng cho user hiện tại cần đúng một file tên config đặt trong thư mục .ssh. Xem những option đặt được vào file đó bằng manual, lưu ý tên không có chữ d sau ssh:
man ssh_config
Mỗi lần đăng nhập vào một SSH server đều phải gõ một lệnh dạng:
Quản một hai ba server thì không sao. Nhưng phải nối tới nhiều server hơn thì rất dễ quên username và IP nào đi với kết nối nào. File config giải quyết việc đó:
vim ~/.ssh/config
Nội dung đặt một cái tên gợi nhớ cho server, kèm IP và username thật của nó:
Host myserver
HostName 10.0.0.186
User jeremy
Làm theo thì thay IP bằng IP của server mình, và thay jeremy bằng username của mình. Lưu file xong phải đổi quyền, vì SSH client yêu cầu file này không được user khác đọc được, vì lý do bảo mật:
chmod 600 ~/.ssh/config
Giờ không cần nhớ IP và username của từng server nữa, chỉ cần nhớ cái tên đã khai ở Host:
ssh myserver
# Output (rút gọn):
The authenticity of host '10.0.0.186 (10.0.0.186)' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Lần đầu kết nối thì client chưa nhận ra fingerprint của server, trả lời yes là vào được. Phần phân quyền file và ý nghĩa 600 nói kỹ ở Part 2.2: Phân quyền file và permission đặc biệt.
Thiết lập client áp cho mọi user
Thiết lập client áp cho toàn máy nằm ở file ssh_config. Các dòng trong đó đang được comment, nhưng chúng cho biết giá trị mặc định, chẳng hạn Port 22, nghĩa là theo mặc định SSH client sẽ nối tới port 22 trên server ở xa.
Giả sử mạng nội bộ của một tổ chức dùng số port khác là 229, thì uncomment dòng đó và đổi số:
Port 229
Từ lúc đó, bất cứ ai dùng SSH client cài trên máy Linux này, khi gõ ssh jeremy@<IP>, cũng được nối tới port 229 trên server ở xa thay vì port 22.
Chỉ có điều sửa trực tiếp file này không được khuyến khích, vì một bản upgrade của SSH client sau này có thể ghi đè thay đổi. Cách tốt hơn là thêm một file cấu hình mới vào thư mục dành riêng cho việc đó, cũng chính là thư mục đã nhắc ở phần daemon:
sudo vim /etc/ssh/ssh_config.d/99-custom.conf
Rồi khai port mặc định mới ở đây. Cách này giữ được thiết lập tùy biến cho toàn bộ user mà không đụng vào file do package quản lý.
7. Đăng nhập bằng SSH key
Muốn đăng nhập bằng SSH key thay cho password thì trước tiên phải sinh một cặp private key và public key ở phía client, tức trên máy local. Lệnh sinh cặp key chạy giống nhau trên macOS, Windows và Linux:
ssh-keygen
# Output (rút gọn):
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/jeremy/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/jeremy/.ssh/id_ed25519
Your public key has been saved in /home/jeremy/.ssh/id_ed25519.pub
Ở các prompt cứ nhấn Enter là được, kể cả prompt hỏi passphrase. Nhưng trên một hệ thống thật thì nên chọn một passphrase. Passphrase là một password dùng để mã hóa SSH private key, và nó bảo vệ cho tình huống có người lấy được file đó: không có password thì họ không giải mã được file chứa key, nên vẫn không đăng nhập được vào server.
Kết quả là hai file: id_ed25519 là private key, và id_ed25519.pub là public key.
Muốn đăng nhập vào server bằng private key thì phải copy public key lên server đó, và có hai cách.
Cách dễ nhất là chạy một lệnh ngay trên máy local:
ssh-copy-id [email protected]
# Output (rút gọn):
Number of key(s) added: 1
and check to make sure that only the key(s) you wanted were added.
Nội dung của file id_ed25519.pub được copy sang home directory của user jeremy trên server và lưu vào một file tên ~/.ssh/authorized_keys. Thử đăng nhập lại thì vào được ngay, và kiểm tra file đó sẽ thấy key của mình trong đó.
File authorized_keys chứa được rất nhiều public key. Nếu có ba nhân viên cần đăng nhập với tư cách jeremy vào server này thì thêm cả ba public key của họ vào file đó.
Khi ssh-copy-id không dùng được
Đôi khi lệnh ssh-copy-id không dùng được. Lúc đó cách thay thế là tự sửa file authorized_keys bằng tay. Từ máy client, copy nội dung public key, vốn nằm ở file .pub trên máy local:
cat ~/.ssh/id_ed25519.pub
Rồi SSH vào server và dán nội dung đó vào file:
vim ~/.ssh/authorized_keys
Lưu file xong thì đổi quyền của nó:
chmod 600 ~/.ssh/authorized_keys
Xong. Từ lúc này, ai giữ private key tương ứng với public key vừa thêm đều đăng nhập được qua SSH vào account của user đó.
Một lưu ý về passphrase: ở ví dụ trên chỉ nhấn Enter khi được hỏi passphrase, nên ssh vào máy được trực tiếp, không bị hỏi gì. Cách đó không nên làm. Đặt một passphrase thì muốn vào server phải có đồng thời cả file key lẫn passphrase.
8. known_hosts và fingerprint của server
Còn một file quan trọng nữa trong thư mục .ssh. Lần đầu đăng nhập vào một SSH server luôn gặp thông báo rằng không xác lập được tính xác thực của host. Sau khi fingerprint đó được chấp nhận, nó được lưu vào một file tên known_hosts.
Lần đăng nhập sau thì vào thẳng, không hỏi lại, vì SSH client so fingerprint nó đã lưu với fingerprint mà server công bố. Hai cái khớp nhau nghĩa là đang nối tới đúng server cũ. Không khớp thì hoặc có ai đang giả danh server, hoặc, trong tình huống phổ biến hơn nhiều, người ta vừa cài lại hệ điều hành cho server đó. Vì lý do bảo mật, SSH client sẽ không cho đăng nhập khi fingerprint không khớp.
Xóa một fingerprint cũ khỏi file đó bằng:
ssh-keygen -R 10.0.0.251
Lệnh này xóa fingerprint đã lưu cho server có địa chỉ IP 10.0.0.251, và lần kết nối tới thì client lại hỏi fingerprint như lần đầu. Muốn xóa toàn bộ fingerprint vì lý do nào đó thì xóa thẳng cả file:
rm ~/.ssh/known_hosts
Thói quen đáng giữ khi vận hành: cảnh báo fingerprint không khớp đừng bao giờ bỏ qua theo phản xạ. Trước khi chạy ssh-keygen -R, phải biết chắc server đó vừa được cài lại hay vừa đổi key, vì cùng một cảnh báo cũng là dấu hiệu của một kết nối đang bị chen giữa.
Đây là mục cuối của domain Networking. Các domain khác của kỳ thi tiếp nối ở Part 6.1: Phân vùng, swap, file system và mount, và toàn bộ lộ trình ôn thi tổng hợp ở Part 7: Tổng kết khóa học và tài liệu ôn thi.
Nguồn tham khảo
Nguồn gốc: Khóa "Prep Course - Linux Foundation Certified System Administrator (LFCS) Certification" — phần "5. Networking" (đồng bộ thời gian với NTP và systemd-timesyncd, cấu hình SSH server và SSH client, đăng nhập bằng SSH key), nền tảng KodeKloud. Giảng viên: Jeremy Morgan và Alexandru Andrei.