# 站点与用户变量

全站设置，以及模板和集成可以引用的加密变量。

最后校对于 2026-10-10

这页办完你会得到：一条存在库里、界面上看不到明文的凭证，以及一条从通知媒介引用它的路径； 外加一份「站点设置里每个字段管什么」的对照。

两件事都在 **系统配置** 下面，但用途完全不同：变量设置存的是**值**（多半是凭证）， 站点设置调的是**这套系统长什么样、怎么记日志**。

## 1. 新建一个变量[​](#1-新建一个变量 "1. 新建一个变量的直接链接")

**系统配置 → 变量设置**（`/system/variable-settings`），右上角 **创 建**。

![变量设置](https://n9e.github.io/zh/img/docs/security/variables.zh.webp)![变量设置](https://n9e.github.io/zh/img/docs/security/variables.zh.dark.webp)

| 字段     | 说明                                                       |
| -------- | ---------------------------------------------------------- |
| 变量名   | 必填，全局唯一。命名规则见下文                             |
| 是否加密 | 开关。打开之后「变量值」变成密码输入框                     |
| 变量值   | 必填                                                       |
| 备注     | 建议写清楚「谁在用、从哪儿申请的」——之后没人能再看到值本身 |

预期结果：列表里多一行，列为变量名、变量值、备注、操作。加密过的那行， **变量值列显示 `******`**，不是省略，是真的取不回来了。

## 2. 在通知媒介里引用它[​](#2-在通知媒介里引用它 "2. 在通知媒介里引用它的直接链接")

引用写法是 Go 模板的顶层字段，变量名前面加一个点：

```
{{.my_token}}
```

能用这个写法的地方有三处，别的地方不生效：

| 位置                        | 具体字段                            |
| --------------------------- | ----------------------------------- |
| **通知媒介** 的 HTTP 配置   | 请求地址、请求头、查询参数、请求体  |
| SMTP 配置                   | 邮件媒介的服务器配置                |
| **单点登录** 的六份配置正文 | LDAP、CAS、OIDC、OAuth2、钉钉、飞书 |

**数据源和大模型配置不在其中。** 它们的密码字段是各自表里的独立字段， 不走变量替换，只能在各自的编辑页里改。

改完变量不用重启：后端每 9 秒对一次变量的条数和更新时间，变了就重新拉一份解密快照。 拆开部署时（独立的 `n9e-alert`、`n9e-edge`）这些进程不自己解密， 而是回中心调 `/v1/n9e/user-variable/decrypt`，所以中心那边要开 `[HTTP.APIForService] Enable = true`。

## 3. 加密变量能做到什么，做不到什么[​](#3-加密变量能做到什么做不到什么 "3. 加密变量能做到什么，做不到什么的直接链接")

勾上「是否加密」之后，值在**浏览器里**就用 RSA 公钥加密好才发出去， 库里存的是密文。这对密钥是 center 启动时自动生成并存进库的， 和 `[HTTP.RSA] OpenRSA` 那个开关**没有关系**——后者管的是登录密码要不要加密传输， 关着也不影响加密变量。

它挡住的是：

* **顺手看见**：列表里是 `******`；编辑已有变量时值输入框是禁用的， 要换值得点 **重置密码** 重新填一遍；
* **落进日志**：渲染进请求头、查询参数、请求体的变量值， 在访问日志和通知记录里都会被替换成 `***`，不是靠字符串匹配，是拿掩码上下文重渲染一遍。

它挡不住的是**能读数据库的人**：私钥和它的口令跟密文存在同一张 `configs` 表里。 这层加密解决的是「运维界面上的凭证可见性」，不是「数据库泄露」。 真正的边界在数据库访问控制上。

权限上，这四个接口由 `/system/variable-settings` 权限点把守，**不是 `Admin` 专属**—— 这是系统配置里唯一的例外（见[角色与权限矩阵](https://n9e.github.io/zh/docs/security/roles.md)）。但改和删还要再过一道： 你得是 `Admin`，或者是这条变量的创建人，否则返回 403。

## 4. 命名规则与保留字[​](#4-命名规则与保留字 "4. 命名规则与保留字的直接链接")

变量名必须匹配 `^[a-zA-Z_][a-zA-Z0-9_]*$`——字母或下划线开头，后面只能是字母、数字、下划线。 重名会被直接拒绝。

另外两组名字是保留字，用了会在保存时报错：

| 保留字                                                            | 为什么                                                                   |
| ----------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `Scheme`、`Host`、`Hostname`、`Port`、`Path`、`Query`、`Fragment` | URL 解析用的字段名                                                       |
| `tpl`、`event`、`events`、`params`、`sendto`、`sendtos`           | 通知模板上下文里的内置顶层 key。同名变量在渲染时会被内置值盖掉，静默失效 |

## 5. 名字写错了会怎样[​](#5-名字写错了会怎样 "5. 名字写错了会怎样的直接链接")

不会报错。Go 模板对不存在的 key 一律渲染成空串，加上日志里那一段本来就被打成 `***`， 最终现象只剩「对端返回认证失败」，看不出是变量名拼错了。

后端会打一条 Warning 兜底，同一处只打一次：

```
notify http config "xxx" references undefined variable "my_tokne",

it renders as empty; check 变量配置 (system variable settings)
```

排查这类问题时，去 center 或 alert 进程的日志里搜 `references undefined variable`。

## 6. 站点设置里的字段[​](#6-站点设置里的字段 "6. 站点设置里的字段的直接链接")

**系统配置 → 站点设置**（`/system/site-settings`）。开源版里是这十个：

| 字段                     | 管什么                                                   |
| ------------------------ | -------------------------------------------------------- |
| 站点地址                 | 外部访问夜莺的地址，后端用它拼分享链接、通知里的跳转链接 |
| 默认访问地址             | 访问根路径 `/` 时跳到哪儿，默认 `/landing`               |
| 业务组展示模式           | 树形 / 列表                                              |
| 业务组分隔符             | 树形模式下按它切分组名，默认 `-`                         |
| 团队展示模式             | 树形 / 列表，默认列表                                    |
| 团队分隔符               | 同上，默认 `-`                                           |
| 即时查询的时序图图例管理 | 即时查询图例里显示哪几个统计值，默认 Last                |
| 开启 Access Log          | 打不打访问日志，默认关                                   |
| 打印请求 Body 路径       | 见下面这条                                               |
| 字体                     | 界面字体                                                 |

保存要求 `Admin`，保存后页面会自己刷新一次。

**「打印请求 Body 路径」要克制着用。** 列进来的每个路径，请求体会被整个写进访问日志。 它是排查表单提交的利器，也是把明文凭证写进磁盘的最快方式—— 登录、数据源、变量设置这类路径不要列。排查完记得删掉，别留在生产上。

## 下一步[​](#下一步 "下一步的直接链接")

* 变量在通知里怎么用：[通知媒介](https://n9e.github.io/zh/docs/notifications/dingtalk-feishu-wecom.md)
* 配置文件里的凭证怎么存密文：[密钥管理](https://n9e.github.io/zh/docs/security/secrets.md)
* 谁能进这两个页面：[角色与权限矩阵](https://n9e.github.io/zh/docs/security/roles.md)
