资讯动态

内网NTP时间服务器搭建:以本地时钟为源的chrony/ntpd配置指南

发布时间:2026/10/16 6:58:26 来源:尧图企业网站定制
做内网运维这行时间同步是永远绕不开的坎。服务器日志对不上、监控曲线错位、数据库集群脑裂十有八九都是时间不一致闹的。大家都习惯让服务器去公网NTP服务器拉时间但总有那么些环境不给外网、或者安全要求高到不允许任何外部连接。这时候最靠谱的办法就是自己搭一台“以本地时钟为源的时间服务器”让它只靠自身的硬件时钟维持时间然后向整个局域网发布授时服务。这东西听上去不复杂不就是把本地时间共享出去嘛但真动手做起来坑比想象中多本地时钟漂移怎么算、NTP同步层级怎么设、为什么客户端死活同步不上我都会在这篇文章里展开讲清楚顺便把两种主流的配置方案和排障记录一并交出来。1. 方案定调为什么本地时钟能撑起一台NTP服务器1.1 本地时钟源的适用场景大多数教程里教的是“NTP客户端怎么从上游同步”也就是把服务器当成一个中转站自己先去互联网上对时再把对好的时间转手发给内网设备。这种方式没什么问题但前提是你得能出网。现实中我遇到过的场景包括某单位的内网安全区业务系统与互联网物理隔离某个临时搭建的测试环境外网线路还没接通还有一些实验室设备厂商要求必须在无外部时间源的环境下独立运行。这些地方同样需要标准时间而且日志和审计都要求时间线一致所以“以本地时钟为源”的授时服务器就成了刚需。它在协议层面没有任何特殊之处依然是标准的NTP服务只是把自己的硬件时钟当成了权威参考源不依赖任何上游网络时间源。1.2 本地时钟的误差从哪来、能压到多少在说配置之前得先把底层的东西聊明白本地时钟的误差究竟是怎么产生的。普通计算机主板上那颗RTC芯片内部是一个石英晶振。石英晶振有一个特性频率会随着温度变化而漂移同时芯片本身还有一个老化率——用久了频率会慢慢偏移。普通RTC的日误差大概在1到10秒听上去很不靠谱但如果经过NTP软件的驯服和频率补偿情况会好很多。NTP服务会记录下本机晶振与真实时间的偏差率单位是ppm百万分之一一秒钟偏1ppm累积一天大约是0.0864秒。这个偏差率被记录在driftfile里之后服务会持续修正本地时钟的长期稳定性就能维持得相当好。1.3 三条技术路线的取舍我做过几种不同精度档次的本地时间源简单列一下方便你按需求和预算选方案硬件投入短期精度长期稳定性适合场景纯RTC芯片方案零成本用服务器主板自带时钟秒级需定期人工校准内网一般设备、日志时间统一外接高稳晶振OCXO/TCXO中低成本加个小模块毫秒级几个月不用管实验室、无外网的工业系统GPS授时模块辅助校准百元级需要天线微秒到毫秒级长期稳定无人值守、要求高精度的内网这里有一个概念需要明确即使挂了GPS模块这台机器对外提供的依然是“本地基准时间”GPS只是用来驯服本地晶振的不是让这台服务器去当公网客户端的普通节点。对外发布的NTP源仍然在这台机器上也就是“本地时钟本源”。2. 动手前的准备机器选型与首次校时2.1 当时间服务器需要什么样的硬件很多朋友以为跑NTP服务得配一台高档服务器真不用。NTP本身消耗极小一台旧笔记本、一块开源单板计算机都能扛得住几百台客户端的授时请求。我更看重的是另外三样东西。第一是电源稳定性。电源波动会直接影响晶振的工作状态进而影响频率准确度。一台接了UPS、长期稳定运行的机器比性能强但电源毛糙的机器靠谱得多。第二是网络稳定性。NTP走UDP 123端口服务端需要持续响应客户端请求网卡不稳定会导致客户端拿到的回复延迟大进而产生偏移误判。第三是硬件时钟RTC的电池状态。主板上那颗纽扣电池没电了服务器一断电重启时间就直接退回出厂年份这是最容易翻车的地方。2.2 首次初始化把“起点”校准确任何NTP服务器第一次上线前都必须先把系统时间校准到一个尽可能接近真实时间的状态否则后面全是白搭。很多新手上来就配好服务然后启动结果客户端问了一遍拿到了一个差半个多小时的时间瞬间一堆服务报错。如果有临时外网权限最简单的方式是用系统自带的校时工具同步一次时间然后断开外网。命令参考# 使用chrony临时同步一次然后停止外部源 chronyc makestep # 或者传统一点的ntpdate方式未安装chrony的环境 ntpdate pool.ntp.org如果完全没外网只能用人工的方式。建议用手机上的标准时间作为参照通过date命令手动设置date -s 2024-05-20 14:30:00这里有个小教训手动设置之后系统时间虽然对了但硬件RTC里的值还没更新重启后又会跳回去。所以必须同时把系统时间写回硬件时钟用下面这条命令hwclock --systohc如果这一布经常忘记建议在crontab里加一条定期同步的规则把系统时间周期性地写回RTC避免断电丢时间。2.3 用NTP守护进程自动记录频率误差刚才提到了driftfile这个文件很关键。它的作用就是让NTP服务“记住”本机晶振的偏差率。第一次启动时服务还没有任何参考数据只能凭系统时钟硬顶。运行一段时间后服务会对比本地时钟和时间源的差值估算出偏差率写入driftfile。之后每次启动服务都会读取这个文件直接用补偿后的频率来维持时间。这个机制就相当于你请了一位熟悉这台机器脾气的老师傅他知道这台机器每分钟会快多少毫秒然后在每次报时前自动扣掉这部分误差。所以driftfile一定要配置正确而且给服务写入权限不然每次重启都得重新学习一遍精度自然上不去。3. 两种主流配置落地chrony与ntpd3.1 现代环境首选chrony的local方案chrony是现在绝大多数发行版的默认NTP实现它的优势在于同步速度快、对网络抖动不敏感而且配置语法比老ntpd清爽。以本机为源配置相当简练。编辑/etc/chrony.conf把默认从互联网同步的server或pool指令全部注释掉然后加几行关键配置# 不连接任何外部时间源注释掉所有server/pool行 # 声明本机为本地权威时间源stratum设为10 local stratum 10 # 允许局域网内所有客户端访问按实际网段调整 allow 192.168.0.0/16 # 记录晶振频率漂移修正值 driftfile /var/lib/chrony/drift # 允许本机系统时间根据NTP平滑调整 makestep 1 3local stratum 10这条指令的意思是当chrony没有可用的外部参考源时它可以把本机当前系统时间作为时间基准以stratum 10的层级对外提供服务。Stratum是NTP的层级概念stratum 0是原子钟和GPS这种硬件时钟stratum 1是直接连接stratum 0设备的时间服务器层数越大代表离权威源越远。这里为什么设为10而不设为1因为本地RTC时钟的精度不足以支撑更高级别的声明万一以后内网还接了更精准的时间源这个“备胎”不会混淆客户端的优先级。配置完成后重启服务并查看状态systemctl restart chronyd systemctl status chronyd chronyc tracking如果能看到Leap status : Normal并且Stratum一栏显示10就说明服务已经把自己当成时间源了。3.2 老系统兼容方案ntpd的本地参考时钟虽然chrony已经是事实标准但很多老系统、低配嵌入式环境还在用经典的ntpd。ntpd里实现“以本地时钟为源”的语法更直白一些它通过127.127.1.0这个特殊地址引用本机的本地时钟驱动。编辑/etc/ntp.conf# 使用本地时钟作为时间源 server 127.127.1.0 # 指定本地时钟的stratum层级 fudge 127.127.1.0 stratum 8 # 记录漂移修正 driftfile /var/lib/ntp/drift # 禁止所有远程管理只允许局域网客户端查询 restrict default nomodify notrap nopeer noquery restrict 192.168.0.0 mask 255.255.255.0 nomodify notrap这里的关键在于127.127.1.0并不是一个真实的IP地址它是ntpd内置的“本地时钟伪设备”的标识。fudge指令用来给它补充参数最常用的就是指定stratum级别。我习惯设在8左右既比真实公网服务器层级低又能让局域网客户端把它纳入同步源。启动ntpd之后用ntpq -p查看ntpq -p如果看到类似LOCAL(1)的条目并且前面有*号说明本地时钟已经被选为同步源服务正常。有一点要特别提醒ntpd在本地时钟模式下启动初期会有一个所谓的“哄骗”阶段。它会先进入超时等待状态直到本地时钟被认为足够稳定之后才开始服务。如果刚启动就去查状态可能会看到没有同步源这时候等几分钟再复查就行了。3.3 进阶玩法接一条GPS授时模块当“本地基准”很多人觉得本地时钟不靠谱担心精度不够。其实想要高精度完全可以在“本地”这个框架内做升级最常用的方案是接一条串口GPS授时模块。过程并不复杂。将GPS模块通过USB转串口接到服务器上安装gpsd套件让它读取NMEA协议输出的时间报文然后通过共享内存SHM接口把时间喂给chrony。在/etc/chrony.conf里加一行refclock SHM 0 offset 0.5 refid GPS precision 1e-1 poll 3这条指令的意思是从共享内存0号通道读取gpsd写入的参考时间offset 0.5用于补偿串口和线缆带来的固定延迟refid GPS是给这个参考源起个便于识别的名字。这里的思路其实还是“本地时钟为源”GPS信号只是作为校准器chrony持续用GPS信号驯服系统时钟最终对客户端公布的仍然是本机的NTP服务。装上GPS授时模块后这台本地时间服务器的精度能达到毫秒甚至微秒级别而且长期不用管。适合那种“不仅要求独立还要求准”的场景。如果你用的系统是老ntpd同样的参考源配置方式稍有不同需要使用NMEA驱动的地址和fudge参数相对麻烦一些。3.4 防火墙、监听与权限收紧不管用哪种服务NTP默认监听UDP 123端口防火墙要提前放行。以常见的firewalld和ufw为例# firewalld firewall-cmd --add-servicentp --permanent firewall-cmd --reload # ufw ufw allow 123/udp权限这块也容易踩坑。NTP服务应当以普通用户身份运行通过restrict指令收紧客户端权限只允许查询禁止修改和远程管理。尤其注意不要开放noquery否则客户端连查询都会被拒。这类服务器最好只跑NTP一个服务不要顺便挂别的业务减少系统负载波动对时间精度的影响。4. 客户端接入Linux、Windows与验证方法4.1 Linux客户端一分钟接入客户端配置要简单得多。以chrony为例编辑/etc/chrony.conf把默认的互联网源注释掉加上内网时间服务器的地址# 指向本地时间服务器 server 192.168.1.10 iburst # 其他配置保持默认这里iburst参数很实用它让chrony在刚启动时快速发送一串请求能够在几秒内完成首次同步而不是慢慢等它按默认节奏轮询。改完重启服务手动触发同步systemctl restart chronyd chronyc makestep用timedatectl验证timedatectl关键看两行NTP synchronized: yes和Time zone。如果显示yes说明设备已经在使用NTP服务同步时间。4.2 Windows内网客户端配置Windows客户端可以走图形界面也可以直接改注册表。图形界面路径是控制面板 → 日期和时间 → Internet时间 → 更改设置 → 在服务器输入框里填内网时间服务器IP然后点击“立即更新”。这条路适用于单台机器手动配置。如果有一批Windows机器要批量接入建议用组策略或命令行直接改注册表。命令行方式参考w32tm /config /manualpeerlist:192.168.1.10 /syncfromflags:manual /update net stop w32time net start w32time w32tm /resync这里有个Windows特有的坑默认的Windows时间服务W32Time在普通工作站上被设计为“非关键服务”如果它检测不到能同步的源就会跳过不会主动报错。所以批量化配置后一定要抽查几台机器执行w32tm /query /status确认“Source”一栏是不是你搭的时间服务器IP。4.3 如何证明时间真的同步上了配置完成不等于工作正常我在排查问题的时候从来不会只看客户端有没有显示“已同步”而是会从服务器端和客户端交叉验证。服务器端执行chronyc sources -v chronyc trackingchronyc sources -v能看到当前的参考源情况chronyc tracking会显示本机系统时间的修正进程。客户端执行同样的命令重点看Stratum这一栏——它应该比服务器端的数字大。如果服务器是stratum 10客户端显示stratum 11或类似层级就是正常的。精确一点的测量可以用clockdiff命令clockdiff -o 192.168.1.10如果局域网网络质量好同步完成后的offset应该在几十毫秒以内好的情况下能打到个位数毫秒。我自己测试过同一交换机下的设备稳定状态偏移在0.1ms级别的场景也见过不过那需要服务器端源本身就非常干净。5. 实战排查那些翻过车的问题5.1 服务器明明在跑客户端却连接拒绝这个问题我在很多环境里都遇到过症状是客户端执行chronyc makestep后报错或者日志里出现连接失败。排查顺序要固定。先看服务进程在不在systemctl status chronyd确认状态是active。再看端口监听ss -ulpn | grep 123确认UDP 123被正常监听。然后看防火墙规则iptables -L -n | grep 123或者直接用tcpdump抓包看UDP 123的流量是否从一端发出、另一端无回应。过程中最不起眼的一个坑是服务器开启了多网卡NTP服务只默认监听了一个IP。如果客户端访问的地址不是服务监听的地址就会出现客户端请求发过来了服务却毫无反应的情况。解决办法是在chrony配置里显式指定监听地址比如bindaddress 192.168.1.105.2 客户端同步后时间反而跳变这个情况更像是配置逻辑错误而不是服务故障。常见于两种操作不当一是客户端把服务器当成了唯一源但同时服务器端local指令配置的层级太低客户端在校验时产生了误判二是服务端在系统时间本身偏差很大的情况下配置了过于激进的makestep策略结果把客户端直接“带偏”了。我的处理习惯是服务器端第一次部署前必须手动把时间校到秒级以内同时把chrony的makestep策略调得保守一些比如默认只在启动后前三次同步时允许大步进。客户端那边则可以用默认策略让它快速跟上服务器。另外如果内网有不止一台时间服务器客户端配置时不要把多台来源放在同一份配置里除非你能保证这些源之间是相互一致且没有形成环路的。5.3 GPS模块有数据但服务不认进阶玩法里最常见的坑是GPS模块已经通过串口输出了数据gpsmon命令也能看到NMEA报文但chrony却始终认为GPS参考源是离线状态。这类问题多半出在共享内存的权限上。gpsd写共享内存的进程和chrony读取共享内存的进程必须都具备相同权限并且操作的是同一段共享内存编号。排查时可以用ls -l /var/run/shm/检查共享内存文件的属主和权限。另一个常见坑是串口芯片的驱动加载问题USB转串口的芯片在某些内核版本下会识别成不同的设备节点比如/dev/ttyUSB0和/dev/ttyUSB1之间跳变。建议用一个固定的udev规则把模块绑定到稳定的设备节点。最后是天线摆放。GPS授时模块的天线必须放在能接收到卫星信号的位置不能放在金属机箱内部或者玻璃窗贴上信号衰减严重的地方。模块通电后gpsmon里能看到卫星数量和定位状态如果一直是0颗卫星就别指望时间能出来——这种时候先解决天线和馈线的问题。5.4 电源与硬件时钟的连环坑把这个问题放在最后讲是因为它最具隐蔽性。有一台服务器时间服务器运行了几个月都很稳定突然某天客户端全部报错一查服务器系统时间竟然跳到了几个月前。第一反应以为是漂移结果发现是主板电池没电了。系统在运行期间NTP一直维持着时间但一旦断电再开机BIOS里的硬件时钟复位到某个出厂默认时间加载时系统时间就也跟着变了。解决思路分两步。第一步是换上新的CR2032纽扣电池花几块钱的事。第二步是在系统里多重保险开启rtcsync功能让服务定期把系统时间写回硬件时钟。以chrony为例rtcsync默认开启在/etc/chrony.conf里确保没有被注释掉就行。另外还有一个值得养成的习惯整个时间服务器最好配上UPS。频繁的突然断电对扳机供电的稳定性是长期伤害而且断电重启的过程很容易触发RTC复位。我目前维护的这台时间服务器已经连续跑了快一年半有UPS兜底之后再也没出现过于硬件时钟相关的幺蛾子。做这个项目到后期我最深的体会是以本地时钟为源的时间服务器技术难点根本不在配置那一行行命令而在于怎么把“持续校准”和“提前兜底”这套心思落到实处。只要把首次校时、漂移记录、权限收紧、硬件可靠性这几件事想明白一台普通Linux机器就能变成整个内网最靠谱的“钟表铺”。这套方案我已经在不同环境里验证过多次实操下来成本低、效果好至少到目前为止那些曾经因为时间错位而查得焦头烂额的日志问题在我负责的网络里再没有复现过。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑