> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/di-18-zhang-xi-tong-guan-li/di-18.8-jie-ntp-shi-jian-tong-bu-yu-shi-qu.md).

# 18.8 NTP 时间同步与时区

NTP 协议由 David Mills 于 1985 年提出（RFC 958），现行标准为 NTPv4（RFC 5905）。

在 FreeBSD 中，可使用内置的 ntpd 来同步系统时钟，也可通过 Ports 安装 chrony 等替代实现。

## 时区

时间同步首先需正确设置系统时区。

### 全局时区

设置系统时区有以下几种方式：

| 方法             | 操作                                                    |
| -------------- | ----------------------------------------------------- |
| 用户分级设置环境变量     | 在 Shell 配置文件或 `~/.login_conf` 中设置 `TZ` 变量             |
| `bsdconfig` 工具 | 通过 `bsdconfig` 的 `8 Timezone` 菜单交互式设置                 |
| 命令行直接设置        | `cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime` |

### 时间服务文件结构

```sh
/
├── usr
│   └── share
│       └── zoneinfo
│           └── Asia
│               └── Shanghai           # 北京时间文件
└── etc
    ├── localtime                     # 系统本地时间文件
    ├── wall_cmos_clock               # RTC 时钟设置标记
    └── ntp.conf                       # NTP 服务配置文件
```

### 用户级时区

除了全局时区设置，每个用户也可单独设置时区，在用户的 Shell 配置文件或者用户分级文件中设置 `TZ` 变量即可。

* sh、Bash、Zsh

```sh
export TZ=CST-8             # 设置时区为中国标准时间（CST-8）
# 或
export TZ=Asia/Shanghai      # 设置时区为北京时间
```

* csh

```sh
setenv TZ CST-8             # 在 Shell 环境中设置时区为中国标准时间（CST-8）
# 或
setenv TZ "Asia/Shanghai"   # 在 Shell 环境中设置时区为北京时间
```

### 将 RTC 时间视为地方时

RTC（Real-Time Clock，实时时钟）是计算机主板上的硬件时钟，用于在系统关机后保持时间。

`adjkerntz` 用于维护内核时钟（始终为 UTC）与实时时钟（可能为地方时）之间的正确关系，并在时区变更时更新内核时区偏移量。

**/etc/wall\_cmos\_clock** 文件存在则表示将系统的实时时钟视为地方时，不存在则表示将实时时钟视为 UTC 时间。

创建空文件 **/etc/wall\_cmos\_clock** 文件可兼容 Windows 时间设置，避免产生 8 小时时差：

```sh
# touch /etc/wall_cmos_clock
```

重启系统使该设置生效。

查看当前 CMOS 时钟设置：

```sh
# sysctl machdep.wall_cmos_clock
machdep.wall_cmos_clock: 1
```

## NTP 时间服务

时区设置完成后，需要配置和启用时间同步服务。

ntpd 与其网络对等方通过 UDP 数据包通信。计算机与 NTP 对等方之间的任何防火墙，必须配置为允许 UDP 数据包通过端口 123 进出。

> **注意**
>
> 部分互联网接入提供商和网络设备会阻止低端口号的通信，致使应答数据包无法送达本机，进而导致 NTP 功能异常。

### NTP 配置文件

ntpd 通过读取 **/etc/ntp.conf** 文件来确定要查询的 NTP 服务器。建议选择多个 NTP 服务器，以防止其中某个服务器无法访问或其时钟不可靠。ntpd 会根据接收到的响应，优先选择可靠的服务器，而将不可靠的服务器排除。

查询的 `server` 可以是本地网络中的服务器，ISP 提供的服务器，或者从 [公开可访问的 NTP 服务器列表](https://support.ntp.org/Servers/WebHome) 中选择。选择公共 NTP 服务器时，应选择与地理位置接近的服务器，并查看其使用政策。FreeBSD 也提供由项目维护的服务器池，如 `0.freebsd.pool.ntp.org`。

关键字 `pool` 配置从服务器池中选择一到多个服务器。可以参考 [公开的 NTP 服务器池列表](https://support.ntp.org/Servers/NTPPoolServers)，按地理区域组织。

编辑 **/etc/ntp.conf** 文件，添加附加时钟服务器（源代码位于 **usr.sbin/ntp/ntpd/ntp.conf**）：

```ini
# 添加 FreeBSD 服务器池，直到有 3 到 6 个有效的服务器
tos minclock 3 maxclock 6
pool 0.freebsd.pool.ntp.org iburst
pool 2.freebsd.pool.ntp.org iburst

# 禁止 ntpq 控制/查询访问。仅允许根据此文件中的 pool 和 server 语句添加对等方
restrict default limited kod nomodify notrap noquery nopeer
restrict source  limited kod nomodify notrap noquery

# 允许来自本地主机的查询和控制访问
restrict 127.0.0.1
restrict ::1

# 添加特定的服务器
server time.windows.com iburst        # 配置 Windows 时间服务器

# 使用本地的闰秒文件
leapfile "/var/db/ntpd.leap-seconds.list"
```

以下为示例中所用关键字的简要说明。

默认情况下，NTP 服务器对任何网络主机都可访问。

* 关键字 `tos` 控制 Ntpd 自动从配置的时间池（pools）中添加 `maxclock - 1` 台服务器；如有必要，最多可能会添加多达 `maxclock * 2` 台服务器，以确保每时每刻至少有 `minclock` 台服务器提供着良好且一致的时间。
* 关键字 `restrict` 控制哪些系统可访问服务器。格式为 `restrict 地址 [mask 具体掩码] [ippeerlimit 具体对等体访问数量限制（整数）] [标志1 标志2...]`。
  * 可包含多个 `restrict` 条目，每个条目都会根据前面的声明细化访问限制：按最长匹配原则，先按地址降序、随后按掩码降序。示例中的值授予本地系统完全的查询和控制访问权限，同时仅允许远程系统查询时间；
  * 关键字 `default`：未指定 mask 时，等同于所有 IP 地址，即 `0.0.0.0 mask 0.0.0.0`；
  * 关键字 `source`：模板限制规则，自动与既有规则动态关联；
  * 关键字 `limited`：如果数据包的发送间隔违反了 `discard`（限流机制）命令中指定的下限要求，则拒绝服务。同时，为了记录客户端的历史行为，**监控功能** 将始终保持激活状态。
  * 关键字 `kod`：发生速率违规时，系统有时会发送一个“死亡之吻”（KoD）数据包。如果不设置该标志，则不会发送任何响应。
  * 关键字 `nomodify`：拒绝 `ntpq` 和 `ntpdc` 中那些尝试修改服务器状态（即运行时的重新配置）的查询请求。但允许那些仅返回信息的查询请求。
  * 关键字 `notrap`：拒绝向匹配的主机提供模式 6（mode 6）控制消息陷阱（trap）服务（一种过时的不安全的服务）。
  * 关键字 `noquery`：拒绝 `ntpq` 和 `ntpdc` 的查询请求。时间同步服务不受此影响。
  * 关键字 `nopeer`：拒绝那些在没有身份验证的情况下，会导致建立新关联的数据包。因此，同时使用 `pool` 指令来获取时间服务器的用户，需要额外配置一行不含 `nopeer` 标志的规则（如本例中的 `restrict source limited kod nomodify notrap noquery`）。
* 关键字 `server` 指定要查询的具体某个服务器。该文件可包含多个 `server` 关键字，每行列出一个服务器。
  * 关键字 `iburst` 指示 ntpd 在服务器不可达时与服务器进行 8 次快速数据包交换（每次间隔 2 秒），加快系统获取初始时间同步的速度。
* 关键字 `pool` 指定服务器池。ntpd 会根据需要从该池中添加一到多个服务器，以达到 `tos minclock` 值所指定的对等方数量。
* 关键字 `leapfile` 指定闰秒的信息文件的位置。该文件会通过 periodic(8) 自动更新（**/etc/periodic/daily/480.leapfile-ntpd**）。

### 时间信息查看

显示当前系统日期和时间：

```sh
$ date
2025年 3月22日 星期六 15时27分29秒 CST
```

### 设置并启动 NTP 服务

要使 ntpd 开机自启，可执行以下命令，无需重启系统：

```sh
# service ntpd enable
```

启动 NTP 服务：

```sh
# service ntpd start
```

允许 ntpd 在启动时一次性调整任意偏差：

```sh
# sysrc ntpd_sync_on_start="YES"
```

默认情况下，若时钟偏差超过 1000 秒，ntpd 会记录错误信息并退出。该选项用于绕过此限制，在无电池供电的实时时钟系统中尤为有用。

保护 ntpd 守护进程不会因内存不足（OOM）而被系统终止：

```sh
# sysrc ntpd_oomprotect="YES"
```

### ntpd 命令

首先临时停止现有的 ntpd 服务，以防止既有服务阻碍时间同步。

```sh
# service ntpd onestop
```

系统重启后服务将继续运行，也可以手动重新启用 ntpd 服务。

使用 `time.windows.com` 服务器更新系统时间。

```sh
# ntpd -q -g time.windows.com
```

| 选项   | 作用             |
| ---- | -------------- |
| `-q` | 同步一次并退出        |
| `-g` | 允许一次性进行大幅度时间调整 |

NTP 服务器以位置参数方式指定，无需选项标记。

系统时间与 NTP 服务器偏差超过 1000 秒时，ntpd 默认拒绝修正并退出，需使用 `-g` 选项强制执行修正。

## 非特权用户 ntpd

FreeBSD 中，可由非特权用户启动并运行 `ntpd` 服务，该功能依赖策略模块 mac\_ntpd(4)。

启动脚本 **/etc/rc.d/ntpd** 将首先检查 NTP 配置。如果条件允许，它会加载模块 mac\_ntpd，随后以非特权用户 ntpd（用户 ID 123）启动 ntpd。

配置包含与文件相关的选项时，启动脚本不会自动以 ntpd 用户身份启动 ntpd，以避免文件和目录访问问题。

要手动配置以 ntpd 用户运行 ntpd 服务，必须：

* 确保 ntpd 用户有权访问配置中指定的所有文件和目录。
* 加载 mac\_ntpd 模块或将其编译到内核中。
* 在 **/etc/rc.conf** 中设置 `ntpd_user="ntpd"`。

## 参考文献

* FreeBSD Project. adjkerntz(8)\[EB/OL]. \[2026-04-24]. <https://man.freebsd.org/cgi/man.cgi?query=adjkerntz&sektion=8>. 系统时区调整工具手册页。

## 课后习题

1. NTP 服务安全加固（如启用认证、限制查询来源），记录加固措施及其对时间同步精度的影响。
2. 配置硬件 RTC 时钟的时区设置（UTC 与本地时间），分析双系统场景下 RTC 时区不一致导致的时间偏移问题。
3. 搭建一个本地 NTP 时间服务器，配置其为局域网内其他设备提供时间同步服务，记录服务器与客户端的配置流程。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/di-18-zhang-xi-tong-guan-li/di-18.8-jie-ntp-shi-jian-tong-bu-yu-shi-qu.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
