利用 HTTP 网页同步服务器时间

我常买 Linux VPS,有一套统一的初始化配置,一条条命令复制粘贴执行很有感觉。其中包括利用 NTP 进行时钟同步。但是有些服务商会屏蔽 NTP 协议,可能是出于安全原因。于是得另寻他法。

稍微搜了一下,发现有两条路,都是利用现有 HTTP 服务进行同步的。一种利用响应体(response body),一种利用响应头(response header)。很有意思。

利用响应体

如果一个网页的内容是某种格式的时间,那么我们可以直接传给 date 程序设置系统时间。如 Slime 给出了命令:

curl http://time.akamai.com/?iso | xargs date -s

著名 CDN 服务商 Akamai 在这个地址下以 ISO 格式响应当前时间,用命令获取它,通过管道作为 date -s 的参数传递过去。其中 curl、xargs、date 都是 Linux 服务器常备的程序或命令,所以可以毫无压力地使用。

利用响应头

上述获取响应体设置时间的方式固然巧妙,Akamai 算是大厂,服务可用性也很高,但你知道其实几乎所有 HTTP 服务都会在响应头返回时间吗?可以用浏览器开发者工具、抓包工具或者 curl 命令来验证,比如请求闪星空间首页:

$ curl -I --http1.1 https://shansing.com
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 29 Aug 2021 11:30:02 GMT
Content-Type: text/html; charset=UTF-8
...

其中有 Date header,且为当前时间。多试几个网站或网页,能得到一样的结果。这不是巧合。RFC 2616 规定,服务器除出错或没有时钟等情形外,必须(MUST)按此特定格式返回 Date header,且应当(SHOULD)尽可能贴合消息生成的时间,我们一般就可以理解为当前时间。获取这个值也能帮助校正服务器时间。

已经有程序写好了,叫 htpdate。根据说明编译安装

wget -O htpdate-1.2.6.tar.gz https://github.com/angeloc/htpdate/archive/refs/tags/v1.2.6.tar.gz
tar zxvf htpdate-1.2.6.tar.gz
cd htpdate-1.2.6
make && make install

然后就可以执行了。指定多个 URL 可以提高准确性,比如:

htpdate -a -t http://www.google.com http://www.baidu.com http://www.cloudflare.com

更多用法可执行 man htpdate 查看(英文)。

结语

NTP 其实会考虑网络时延,它假设收发所用时间是相等的,以此减少网络传输带来的延迟。但本文介绍的两种方法都不考虑延迟:获取响应体的方式很明显没有考虑,而 htpdate 尽管相对完善,可以使系统时间平滑改变(-a)也可以突变(-s),但设计上也是忽略网络延迟的。

所以,在要求不严格的情况下,可以用这些方式替代 NTP 同步系统时间。但如果有更高要求,服务器又屏蔽了 UDP 123 端口连出,也许可以考虑 NTP 代理、自建 chrony 之类的解决方案。

若无特别说明,本文系原创,遵循 署名-非商业性使用 3.0 (CC BY-NC 3.0) 协议,转载文章请注明来自【闪星空间】,或链接上原文地址:http://shansing.com/read/499/

2 条评论

  1. 如果不需要多个域名校准,倒是可以直接一行 bash 实现类似功能
    date -s "$(curl http://www.baidu.com -I -s | grep Date | awk '{first = $1; $1 = ""; print $0;}')" && hwclock --systohc

    1. 如果要支持 HTTP/2,你还得忽略 Date 的大小写。

发表评论»

NO SPAMS! 不要发垃圾评论哦!

表情