It didn't take me long to get tired of resetting the system clock on my cheapo PC. Not only did it drift pretty badly, needing resetting every three or four weeks in order to keep halfway decent time, but every time I booted (at least during Daylight Savings Time), the clock would be off by nearly an hour. So, in November of 2000, I learned how to run anNTP time server under Linux. Since I figured I was not the only one with this problem, I then sat down and wrote this page.
Table of contents
- Automatic system clock setting with NTP
- Table of contents
- About NTP and time service in general
- Installing NTP software
- Synchronizing the clock with NTP
- Random tricks
About NTP and time service in generalNTP stands for "Network Time Protocol," and is a UDP-based (i.e. connectionless) protocol for synchronizing system clocks over the Internet. With sufficient care and the right hardware (I am told), it is possible to synchronize the machines on a local-area network within tens of microseconds of Universal Time Coordinated (UTC), the official time kept by standards agencies using atomic clocks. (For the truly hard core, version 3 of the NTP protocol itself is described in RFC1305.)
With the rather minimal effort I have expended, it is possible to keep the system clock on my very basic AMD K6 within a second of UTC (worst case), which is far more accuracy than I'll ever need for any practical reason. More important, it makes damn sure I'll never ever have to reset the stupid system clock by hand. Throughout this document, I assume that you have similar interests and accuracy requirements. If you require greater accuracy, e.g. on the order of milliseconds, or if you wish to synchronize a subnet of machines, then you'll probably need to study the NTP configuration notes in some detail.
Systems with the most accurate time have at least one interface to a radio clock that receives timebase signals from a transmitter operated by one of the aforementioned agencies. These systems are called "stratum 1," and any computer that synchronizes itself to one or more stratum 1 servers is said to operate at stratum 2, and so on for stratum 3 and higher. Since NTP is a very lightweight protocol, a server at any level can easily support thousands of simultaneous clients (in other words, the "fanout" is high), so it is rarely necessary to go higher than stratum 4. Stratum 1 servers are not usually available for service to the casual home computer user, but there are a number of stratum 2 and 3 servers that are open to the public. I have set my computer up to provide stratum 3 service to anyone that requests it.For several years now, most Unix and GNU/Linux systems have come with some version of the NTP software installed, so the rest of this section is for people with older systems; most users can skip to the next section.
Installing NTP on UnixIf you are not fortunate enough to have NTP included as part of your system, you will need to download the tarball and compile it yourself, but fortunately this is not hard. Get the latest version from the download area on the Time Server site at http://www.ntp.org/. As of June 2004, the latest production version was 4.2.0, dated 15-Oct-2003.
Installation on Linux is straightforward; it's simply a matter of doing
./configure make make installonce you've unpacked the tarball and changed to that directory. This installs the following binaries into the /usr/local/bin directory.The links will take you to the HTML equivalent of man pages for each program; these are also included on the tarball.
Getting an NTP client for other operating systemsThe National Institute of Standards and Technology keeps a Publishers of Time and Frequency Software page with about 50 entries, mostly for Windows, but some for the Macintosh and other more exotic species. The links page on the NTP site has some pointers to other information.
Note, however, that MacOS 8.5 or later (Classic at any rate) already has a built-in NTP client. Just go to the "Date & Time" control panel, and enable it. They already have the addresses of three Apple servers built in. Unfortunately, it only allows you to specify one server. And it seems to require numeric IP addresses, which makes it difficult to use servers such as mine that get their addresses reassigned periodically. (The OSX implementation and interface are probably completely different; I'd bet OSX uses the standard free Unix NTP software.)
There may be other clients out there as well; you can do a search for "macintosh ntp client" or "windows ntp client", if you're feeling adventurous.This section addresses NTP configuration, assuming that you have already downloaded and installed the requisite software. There are two approaches:
- Create a cron job that resets the clock periodically from a set of external servers.
- Run a daemon process that adjusts the clock continuously, querying servers as needed to stay on track.
rogers@alp> rpm -qa | grep -i ntp yast2-ntp-client-2.8.10-26 xntp-4.1.1-286 rogers@alp>On a recent GNU/Linux distro, you should see a package named "ntp" or "xntp" with a version of 4 or greater. ("yast2-ntp-client" is a client configuration interface for the GUI control panel; it's a SuSE thing.) If not, you may still be able to install this from distribution media, or from the vendor's Web site.
In any case, before taking either route, you must pick a set of NTP servers that are willing to provide time service. Using more than one server is desirable for the sake of redundancy, in case of host downtime or network outages. (Using more than two improves accuracy -- the more the better, up to a point -- but two servers are quite adequate for one-second accuracy.) See the Public NTP Time Servers page (http://www.eecis.udel.edu/~mills/ntp/servers.html). Other resources are listed on the Network Time Protocol (NTP) project site. You are welcome to use rgrjr.dyndns.org as one of the NTP servers with which you synchronize, and you might want to pick another stratum 2 or 3 machine from the Public NTP Time Servers page (http://www.eecis.udel.edu/~mills/ntp/servers.html). Be sure to read the ground rules first before picking a server, and notify the contact person if requested. And if you do use my machine, please send me an email to let me know.
Note that it is best to refer to time servers by domain name (e.g. rgrjr.dyndns.org), rather than IP address (e.g. 192.168.3.5), since IP addresses are often reassigned. In fact, a large site may even use an alias (CNAME record) such as "time.bu.edu" to point to a designated time server host; the server can then be moved to a different host with minimal disruption simply by reassigning the alias. Other hosts, such as mine, have dynamically-assigned IP addresses that may change on short notice (which is why I use the free dyndns.org dynamic DNS service to give myself a portable DNS name).The following instructions work for YAST2 under SuSE 9.0 and subsequent releases. Something similar is probably provided in other recent GNU/Linux distros; poking around in the KDE "Control Center" (or the Gnome equivalent) is probably a good bet.
- Invoke "Control Center" from the "K menu."
- Select "YaST2 modules" => "Network Services" => "NTP client". This will required you to supply the root password (assuming you are not already logged in as root).
- Tick the selection to start the NTP daemon on boot.
- Click "Add" to add servers one by one.
- Click "Finish" to start.
Resetting the clock periodically with ntpdateIf you have decided to set via ntpdate, then it is best to do this in two places: In the startup scripts, so that the clock gets started right when you boot up, and in a cron job, so that it stays right if you keep the machine up for more than a few days. You can also run it manually from the command line (as root) to set the clock immediately.
In both places, the command you need is the same:
ntpdate -s server1 [server2 ...]This simply tells ntpdate to set the system clock using time information from the various servers supplied by name on the command line. The -s option causes ntpdate to direct its output to the system logging facility; if you do not specify this in a command run by cron, the output will be emailed to you, which is likely to become annoying after a few occurrences. Of course, you need to run this as root to actually set the clock, though for testing purposes you can use the -q option to ntpdate to query the server(s) as an ordinary user without attempting to set the time.
The setup procedure is as follows:
- Once you have chosen time servers, try "ntpdate server1 [server2 ...]" on the command line to verify that the packets can get through in both directions. If ntpdateseems to hang, complaining that no servers are usable, but the servers all respond to ping, then you should read the "Opening up a firewall for an NTP client" section below.
- As root, add the following crontab line:
30 4 * * * ntpdate -s server1 [server2 ...]This schedules the update for every night at 04:30, at which time the network should be about as quiet as it gets. See the "Resetting the clock periodically via cron"section for further details.
- Also as root, add ntpdate to the correct (system-dependent) boot script. See the "Using ntpdate at boot time" section for further details.
- Periodically, you should inspect the system log for messages from ntpdate. If ntpdate has to change the clock in large jumps too frequently (where "large" probably means more than a minute), then you might consider increasing the frequencing of the cron job. For instance, replacing the "4" in the crontab line above with "4,10,16,22" would cause the update to happen four times per day at half past the stated hours.
Resetting the clock at boot time with ntpdateThe system clock is initialized from the hardware clock by the /etc/init.d/boot.clock script. (At least this is true in SuSE 8.1 and later; when booting Red Hat Linux 6.x, the system clock is initialized by /etc/rc.d/rc.sysinit instead.) Unfortunately, when this runs, the network has not yet been fully initialized, so it is not possible to query servers. Instead, it is better to run ntpdate from the /etc/init.d/boot.local script (called /etc/rc.d/rc.local in older versions), which is run as the very last thing when booting up (in run levels 2, 3, and 5, which is appropriate). Setting the system clock twice like this may leave it off by a bit during boot, but the amount by which it is off can be limited for the next boot by resetting the hardware clock after initializing the system clock from the NTP servers. You can do all of this by adding the following two lines to the end of your/etc/init.d/boot.local script (after replacing the server names):
ntpdate -sb server1 [server2 ...] hwclock --systohcThe next time you boot, the hardware clock will only be off by the amount of drift between boots. (You should first check to see that you have hwclock on your system.)
The "-b" option forces the system clock to be set in one jump, rather than attempting to slew it gradually, and is recommended by the ntpdate documentation page when booting.
Note that this double clock setting procedure is essentially equivalent to what the standard boot-time startup scripts for ntpd do, so making the clock jump back and forth at boot time can't be all that bad. (It can make the log files harder to decipher, though.)
Unfortunately, the system boot scripts are very vendor-dependent, so this recipe may not work for your configuration. If there is an /etc/init.d/rc.local 2or/etc/init.d/boot.local script, it probably works the same way; otherwise, you will need to figure out something different for your flavor of Linux/*BSD/etc.
[Further disclaimer: Since I need a different setup in order to run a server, I haven't ever actually tried this startup scheme myself. If you find a bug in this "recipe," please let me know. -- rgr, 24-Nov-00.]"cron" is the name of the Unix facility for running periodic jobs. The "cron daemon" is started at boot time, and looks in "crontab files" for instructions. These files can be examined and modified via the crontab program. (For more information on their format, do "man 5 crontab".)As root, do
crontab -u root -eThis will fire up an editor with a copy of root's existing crontab file; you must then add a line for ntpdate that describes when and how to run it. For example, to run ntpdatedaily at 1:23 AM (local time), add the following lines (after replacing the server names):
# Daily time update at 1:23AM 23 1 * * * ntpdate -s server1 [server2 ...]The "*"'s in the day-of-month, month, and day-of-week fields indicate that those time periods should not be consulted when setting the time. The "-s" option tells ntpdate to use the system logging facilities for messages instead of the standard output, and is suggested by the ntpdate documentation page when running ntpdate as a cron job. (Otherwise, the cron daemon will send you the output in what would become a tedious daily email message.)
Hint: For best results, you should pick a random time that no one else is likely to have chosen. If everybody chose 1:23AM, then once all clients were synchronized, the servers would suffer a flood of NTP packets every day at that time, and accuracy would suffer.
Don't forget to save the edited crontab file before exiting the editor. The next morning, you should examine the log file (probably /var/log/messages) to ensure that ntpdateran successfully.
For more information, see the crontab(1) man page, and for instructions on how to select a different editor. See the crontab(8) page for more information on the crontab file format.Even if you never offer the service to anyone else, running ntpd will make your clock even more accurate, compared to calling ntpdate as a cron job. That is because ntpdeffectively adjusts the clock continuously, as opposed to just at the cron intervals. And ntpd adjustments are more stable (in the control systems theory sense) because it is in charge of the adjustment intervals, and can also collect a clock drift history to use in deciding when and how much to adjust.
- Create an /etc/ntp.conf file that names your servers. Each server should appear on a "server" line by itself, like this:
server server1 server server2 . . .There are many other ntpd configuration options, but this is all that is necessary to get started.
- Create an /etc/init.d/ntpd start/stop script, and link it to the appropriate run levels so that ntpd starts on boot. (If the NTP tarball doesn't come with something suitable, you can start with this /etc/init.d/ntpd script, which I used to use under RedHat 6.x; you'll have to tweak it to get it to work with a "modern" GNU/Linux distro. I don't have an up-to-date version because I am now using the SuSE-supported xntpd package.)
- Do "/etc/init.d/ntpd start" to get it going. This should do a manual reset before starting the server,
- Check the logs for messages confirming that ntpd started without error.
- You can also do ntptime to find out what the kernel knows about the current time, but be aware that ntptime will report an error until the clock is "synchronized," which takes about half an hour after the daemon starts.
Running an NTP serverFortunately, this is no harder than using ntpd to maintain your clock, with the possible exception of punching a hole of the right shape through the firewall. Once you have it running, here are some things you can do to verify that clients can access it:
- Before performing client testing, be sure that ntptime on the client reports synchronization. Until that happens, the server will tell clients not to trust its notion of the time.
- Use "ntpdate -q" to verify that the server is listening. Do this on the server first, to make sure it's really running, and then on the client; if the client can get an answer, then you're in business.
- If ntpdate fails on the client, use nmap to determine whether packets can get through to port 123 on the server:
nmap -sU -p123 server1If this reports that UDP port 123 is open, then you have a client problem.
- If nmap determines that the port is closed, or doesn't get a response at all, then you have a networking problem, which could be the fault of the server, the client, or some router in between. First, ensure that basic networking works between client and server (i.e. make sure nothing is unplugged). Then perform nmap scans at intermediate points until you identify the box that is blocking 123/UDP traffic, and configure it to let such traffic pass. Configuring some of these boxes to log 123/UDP packets will help pin it down; logging on the server itself will tell you whether the query or the response is getting lost.
- Manual reset:
- To reset the time manually from the NTP servers mentioned in the /etc/ntp.conf file:
ntpdate `perl -ane 'print "$F " if $F eq "server";' /etc/ntp.conf`This only works if ntpd isn't running.
- Find out what time it really is:
- Just run ntptime from the command line. If you are running an NTP server, it will tell you the time down to microsecond precision, along with an estimate of maximum error and estimated (most likely) error.
- Loss of synchronization while burning CDs.
- For what it's worth, ntpd on my wimpy 300MHz system reports "synchronisation lost" and steps the clock by up to 20 or 30 seconds after I burn 50MB or more to CD. The time steps are always positive when this happens, so I imagine this just means that the kernel has lost some timer interrupts while it's dealing with the CD hardware, and needs to catch up, so the time while it's out of synch should be brief.
Opening up a firewall for an NTP serverFortunately, the NTP server always uses UDP port 123, so it is only necessary to accept input packets destined from that port, and to permit outgoing packages coming from that port.In iptables, this is a piece of cake:
iptables -A OUTPUT -p UDP -s `hostname -i` --source-port ntp -j ACCEPT iptables -A INPUT -p UDP -d `hostname -i` --destination-port ntp -j ACCEPTHowever, if you experience startup problems, you should check to see whether your /etc/init.d/ntpd startup script (or /etc/init.d/xntpd) uses the -u option to select an unprivileged port when initializing the system time, which makes it look like a client. If so, you must either follow the client instructions below, or change the startup script to drop the -u option.
Opening up a firewall for an NTP clientIf your NTP client machine is behind a firewall, you need to be sure that packets to and from remote NTP servers can get through. When ntpdate queries a server, it sends a series of UDP packets (the default is four), each of which is addressed to UDP port 123 on the remote machine and bears a quasi-random source port, call it X, as the return address on the local machine. Responses are returned with a destination port of X on the local machine and a source port of 123 on the remote machine. In order for the query to succeed, both packets must be able to traverse the firewall. If there is outbound package filtering, it simply needs to let out all UDP packets destined for port 123 on any machine. I don't use outbound filtering (except to block X11 connections).
Inbound filtering is trickier. If you let through any UDP packet with a source port of 123, then a cracker could potentially abuse this by sending UDP packets with a source port of 123 to an arbitrary target port on your machine. There are two ways to deal with this:
- Restrict incoming IP addresses to just those servers of interest. This certainly narrows the opportunity for abuse considerably, but is inconvenient to implement if server addresses might change arbitrarily. And it still allows unrestricted access to your UDP ports for users on those machines.
- Restrict the destination to a non-priviledged port, and use the "-u" option to ntpdate to tell it to use only non-priviledged source ports when it sends out queries. By long-standing Unix convention, priviledged ports are those below 1024, so this means refusing UDP packets addressed to a port below 1024 even if the source port is 123. But this notion of "priviledge" is only a convention and is somewhat meaningless for single-user machines, except that it does mean that security-critical services such as file service (NFS) and remote configuration (BOOTP, SNMP) tend to be implemented on the low-numbered ports, especially in the Unix world.
In order to implement the second option, I have the following line in my firewall setup script:
iptables -A INPUT -p UDP -s 0.0.0.0/0 --source-port ntp \ -d `hostname -i` --destination-port 1025: -j ACCEPTThis is just an example; it will not work as described above without the rest of the setup script as well. And if you choose this route, you will then need to be careful what services you make available on the high ports. Despite the drawback, I prefer this option.