1. Overview
Linux applications require accurate and synchronized time to run properly. We can think of services such as high availability clusters, databases, etc. Therefore we need to synchronize the clocks of our systems using a reliable time source. To achieve that, we rely on the Network Time Protocol (NTP).
In this tutorial, we will learn how to configure and synchronize our system time using NTP on RHEL-based systems.
2. Server Time and Time Zones
On the Linux system, we have the hardware and the system clocks. The hardware clock also is known as the real-time clock (RTC). It runs independently from the kernel even while the server is shut down. Whereas the system clock is maintained by the OS.
During Linux boot time, the hardware clock updates the system clock. But the hardware clock is not reliable enough. For that reason, we use NTP to synchronize our system time from an external and more accurate time source.
Another key point to mention is that NTP is based on the UTC time zone. Hence we need to configure our system time zone appropriately.
First of all, let’s display with timedatectl our time information:
$ timedatectl
Local time: Fri 2022-04-29 14:24:42 EDT
Universal time: Fri 2022-04-29 18:24:42 UTC
RTC time: Fri 2022-04-29 18:24:42
Time zone: America/Toronto (EDT, -0400)
NTP enabled: no
NTP synchronized: no
RTC in local TZ: no
DST active: yes
Next DST change: DST ends (the clock jumps one hour backwards) at
Sun 2022-11-06 01:59:59 EDT
Sun 2022-11-06 01:00:00 EST
Then we can list all the available time zones using the command timedatectl list-timezones:
$ timedatectl list-timezones | grep "^Europe/"
Europe/Amsterdam
Europe/Andorra
Europe/Astrakhan
Europe/Athens
Europe/Belgrade
Europe/Berlin
...
We use the grep command to match all the lines starting with Europe/.
Finally, as a superuser, let’s set our local time zone and print the timedatectl output:
# timedatectl set-timezone Europe/Athens; timedatectl
Local time: Fri 2022-04-29 21:43:21 EEST
Universal time: Fri 2022-04-29 18:43:21 UTC
RTC time: Fri 2022-04-29 18:43:21
Time zone: Europe/Athens (EEST, +0300)
...
We notice that our Local time is now in the correct Time zone, while the default RTC time is in UTC.
3. Chrony Installation
The chrony suite provides NTP time synchronization. This package does not require regular polling of the NTP server. Therefore it can be suitable for environments with intermittent network or internet connections.
If the chrony package is not already installed, as the root user, we can run:
# dnf install chrony
Next, we will see how to configure chrony to synchronize our system time.
4. Chrony as NTP Client
4.1. Configuration
The chrony configuration file is /etc/chrony.conf. Let’s display the predefined NTP servers’ addresses:
$ grep ^server /etc/chrony.conf
server 0.gr.pool.ntp.org
server 1.gr.pool.ntp.org
server 2.gr.pool.ntp.org
server 3.gr.pool.ntp.org
Since our system “host1” has access to the internet, we can choose from the available public NTP pools from www.pool.ntp.org.
To illustrate, let’s replace the NTP servers with the ones of our choice based on our preferred time zone:
$ grep "server " /etc/chrony.conf
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
server 0.gr.pool.ntp.org iburst
server 1.gr.pool.ntp.org iburst
server 2.gr.pool.ntp.org iburst
server 3.gr.pool.ntp.org iburst
Using our text editor, we comment out the default NTP servers’ lines by inserting the # sign at the beginning. Then we add the new NTP addresses.
Note that we keep the iburst default option for quicker initial synchronization.
Next, let’s start and enable the service:
# systemctl start chronyd
# systemctl enable chronyd
In the above, systemctl with the enable option configures chronyd to start automatically after the server reboot.
Finally, let’s check the status of the chronyd service:
$ systemctl status chronyd
● chronyd.service - NTP client/server
Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2022-04-29 21:44:52 EEST; 26s ago
Now that chronyd is running, let’s explore how we can monitor our time synchronization.
4.2. Manage Time Synchronization
We can use the chronyc command to check the status of our NTP. Let’s run the command with the sources option and the -v flag for more verbose output:
$ chronyc sources -v
210 Number of sources = 4
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^- ipa225.1.tellas.gr 1 9 377 128 +65ms[ +65ms] +/- 560ms
^* nero.grnet.gr 1 9 377 397 -448us[ -298us] +/- 56ms
^+ ipa95.24.tellas.gr 3 8 377 131 +3252us[+3252us] +/- 90ms
^+ ns4.asda.gr 2 9 377 8 -642us[ -642us] +/- 87ms
Let’s understand the meaning of two important columns:
The S column gives us details about the state of the NTP source. The asterisk * means that our system is currently synchronized with nero.grnet.gr. Whereas the plus sign + indicates that two other servers can also be considered for synchronization.
The Stratum column takes a value in the range of 1 to 15. Time sources with lower values have higher accuracy.
We have seen that “host1” is syncing time with an NTP server on the internet. Let’s see next how we can enable NTP for another node which we will call “host2”.
5. Configuring the NTP Server
Unlike “host1”, “host2” can’t connect to the internet. To overcome the firewall restriction, we can provide time to “host2” on the local network. To demonstrate we set up chrony as an NTP server on “host1”.
From “host1”, let’s run the command firewall-cmd with the option –list-services:
# firewall-cmd --list-services
dhcpv6-client ftp ssh tftp
From the above, we see that the firewall does not allow the incoming NTP packets on the UDP port 123.
Therefore let’s run the firewall-cmd command with the options —permanent and —add-service:
# firewall-cmd --permanent --add-service ntp
success
We see that we have successfully added the rule and it is now persistent upon reboot.
Afterward, we load the new firewall rule with the reload option to make it active:
# firewall-cmd --reload
success
Following, we allow access to the NTP server from our local subnet:
$ grep ^allow /etc/chrony.conf
allow 192.168.5.1/24
Finally, let’s restart the chronyd service:
# systemctl restart chronyd
From “host2”, we update the server directive in the /etc/chrony.conf file:
$ grep ^server /etc/chrony.conf
server host1
Note that we use host1 as our timeserver. We map host1 to its IP address using the /etc/hosts file.
Lastly, to test our configuration, let’s pass the -d and -Q flags to the chronyd command. We use the -Q option to query the NTP server without adjusting the system clock:
$ chronyd -d -d -Q "server host1 iburst"
2022-04-29T22:21:13Z main.c:515:(main) chronyd version 3.4 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +SECHASH +IPV6 +DEBUG)
...
2022-04-29T22:21:13Z ntp_sources.c:479:(resolve_sources) resolving host1
2022-04-29T22:21:13Z ntp_sources.c:407:(name_resolve_handler) host1 resolved to 1 addrs
2022-04-29T22:21:13Z ntp_sources.c:380:(process_resolved_name) (1) 192.168.5.102
2022-04-29T22:21:13Z ntp_core.c:1176:(transmit_timeout) Transmit timeout for [192.168.5.102:123]
2022-04-29T22:21:13Z ntp_io.c:896:(NIO_SendPacket) Sent 48 bytes to 192.168.5.102:123 from [UNSPEC] fd 4
2022-04-29T22:21:13Z ntp_io.c:698:(process_message) Received 48 bytes from 192.168.5.102:123 to 192.168.5.103 fd=4 if=2 tss=1 delay=0.000089723
...
2022-04-29T22:21:15Z ntp_core.c:1176:(transmit_timeout) Transmit timeout for [192.168.5.102:123]
2022-04-29T22:21:15Z ntp_io.c:896:(NIO_SendPacket) Sent 48 bytes to 192.168.5.102:123 from [UNSPEC] fd 4
2022-04-29T22:21:15Z ntp_io.c:698:(process_message) Received 48 bytes from 192.168.5.102:123 to 192.168.5.103 fd=4 if=2 tss=1 delay=0.000085051
...
2022-04-29T22:21:17Z reference.c:905:(special_mode_sync) System clock wrong by 194.827846 seconds (ignored)
...
In the above command, we use the -d option twice to print the debugging messages to the terminal. Also, we specify the NTP server address as host1.
From the generated messages, we notice that the NTP server is replying to the client’s requests. However, the system time on the client deviates from the NTP server time. The offset is around 194 seconds.
Let’s see next how we can manually synchronize the time on “host2” with the NTP server on “host1”.
6. Updating Time Manually
We can set the system clock from the command line with chronyd. Let’s run it with -q option to update the clock:
$ chronyd -q "server host1 iburst"
2022-04-29T22:26:46Z chronyd version 3.4 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +SECHASH +IPV6 +DEBUG)
2022-04-29T22:26:50Z System clock wrong by 194.831537 seconds (step)
2022-04-29T22:26:50Z chronyd exiting
After the manual time update, we can print the measured offset again with chronyd -Q:
$ chronyd -Q "server host1 iburst"
...
2022-04-29T22:27:17Z System clock wrong by 0.001776 seconds (ignored)
...
From the above, we managed to reduce the offset between the system clock and the time of the NTP server.
7. Conclusion
In this article, we discussed the NTP service. We learned how to set our time zone appropriately and configure the NTP client and server for time synchronization.