Ajenti 2.2.18 配置参数详解
Ajenti 2.2.18 配置体系逐项详解:/etc/ajenti 三个 YAML(config.yml/users.yml/smtp.yml)全参数语义与改-重启-验证闭环,scrypt 口令的 users 认证切换、ssl.force 的 name 拼 URL 陷阱、url_prefix 子路径发布、trusted_domains 不拦 Host 与 pwReset 由 provider 决定的实测纠偏、YAML 写坏崩溃实录与生产模板(2026-11-02 实测)。
Ajenti 2.2.18 配置参数详解
目标:逐项讲清 Ajenti 2.2.18 的
/etc/ajenti/配置体系(config.yml 主配置、users.yml 用户库、smtp.yml 邮件凭据),每个关键参数给出「修改 → 重启 → 实测验证」闭环回显。已在 Ubuntu 22.04 服务器 + Ajenti 2.2.18 实测通过。
Ajenti 没有数据库、没有环境变量配置面,全部行为由 /etc/ajenti/ 下最多三个 YAML 文件驱动:config.yml(主配置)、users.yml(provider 为 users 时的账号库)、smtp.yml(找回密码的邮件中继凭据)。组件定位见《Ajenti 介绍与选型指南》,从零部署见《Ajenti Docker Compose 部署指南》;本篇面向已跑起来的实例,回答"每个参数是什么、怎么改、改完怎么验证"。
一、环境信息
| 项目 | 取值 |
|---|---|
| 服务器操作系统 | Ubuntu 22.04(x86_64) |
| Ajenti 版本 | ajenti-panel 2.2.18(Python 3.11) |
| 配置目录 | /etc/ajenti/(config.yml、ajenti.pem;users.yml/smtp.yml 按需) |
| 日志目录 | /var/log/ajenti/(ajenti.log、crash-*.txt) |
| 服务监听 | 0.0.0.0:8000 HTTPS,宿主发布 8129 |
| 演示账号 | root / q1w2e3r4(provider: os) |
| 改配置生效方式 | 重启面板进程(无热加载) |
二、前置条件
- 面板已按《Ajenti Docker Compose 部署指南》部署并可登录(
curl -kIs https://localhost:8129/返回 302 跳转登录页); - 具备编辑
/etc/ajenti/config.yml的权限(本篇演示环境通过docker compose exec进入服务改文件——生产 systemd 形态直接 vi 即可); - 改完配置用重启进程生效,重启手段与所用托管形态一致(compose:
docker compose restart;systemd:systemctl restart ajenti)。
三、参数查看与修改方式
3.1 三个入口
- 文件直改:
/etc/ajenti/config.yml是唯一事实源,YAML 格式,改完重启进程; - 面板 Settings 页:settings 插件把主配置映射成图形界面(主题色、语言、会话时长、用户管理等),保存即写回 config.yml——非破坏式,不改你手写的其他键;
- 出厂对照:镜像内置的
/opt/ajenti-default-config.yml(主机 pip 安装形态对应ajenti-panel包内默认 config.yml)可与运行配置 diff。
3.2 修改与重启实测
以 name(面板标题)为例走一遍"改 → 重启 → 验证"闭环:
docker compose exec ajenti sed -i 's/^name: Ajenti Demo Server/name: Ajenti Ops Demo/' /etc/ajenti/config.yml
docker compose restart
curl -ks -c /tmp/rj -X POST https://localhost:8129/api/core/auth \
-H 'Content-Type: application/json' -d '{"mode":"normal","username":"root","password":"q1w2e3r4"}'
curl -kb /tmp/rj -s https://localhost:8129/api/core/identity
{"identity": {"user": "root", "uid": 0, "effective": 0, "elevation_allowed": true, "profile": {}}, "machine": {"name": "Ajenti Ops Demo", "hostname": "ajenti-demo"}, "color": "bluegrey"}
machine.name 即新值;/api/core/config 可回显整份运行配置,是逐项验证的通用通道。改回原值重启即恢复。
3.3 语法错误会怎样
YAML 写坏不会"带病运行",而是启动即崩、容器反复重启:
printf '\n ::: [broken: yaml\n' >> /etc/ajenti/config.yml
docker compose restart
docker ps
curl -k -s -o /dev/null -w '%{http_code}\n' https://localhost:8129/
ls -la data/logs/
ajenti-2.2.18-panel Restarting (0) 2 seconds ago
000
-rw-r--r-- 1 root root 2494 Nov 2 14:49 crash-2026-11-02-14h49.txt
崩溃详情写入 /var/log/ajenti/crash-<日期>-<时刻>h<分>.txt(注意:官方文档写 crash-DATE.log,2.2.18 代码实际生成 .txt)。修复实录见 7.3。
四、参数总览
以本环境出厂 config.yml 为基线(cat /etc/ajenti/config.yml 实测全文):
auth:
allow_sudo: true
emails: {}
provider: os
users_file: /etc/ajenti/users.yml
bind:
host: 0.0.0.0
mode: tcp
port: 8000
color: bluegrey
email:
enable: false
smtp:
password: ''
port: ''
server: ''
user: ''
language: en
max_sessions: 9
name: Ajenti Demo Server
restricted_user: nobody
session_max_time: 3600
ssl:
certificate: /etc/ajenti/ajenti.pem
client_auth:
certificates: []
enable: false
force: false
enable: true
force: false
fqdn_certificate: ''
trusted_domains: []
trusted_proxies: []
(与出厂文件的唯一差异是 ssl.certificate 由首启 ajenti-ssl-gen 回写——出厂为 '',生成证书后写入路径;把配置恢复成出厂值而证书文件仍在,面板反而起不来,见 7.5。)
总览表(默认值取自官方文档 man/config.rst 与包内默认 config.yml,2026-11-02 实查):
| 键 | 默认值 | 一句话作用 |
|---|---|---|
| auth.provider | os | 认证来源:os(系统账号)或 users(面板自管) |
| auth.allow_sudo | true | sudo 组成员可在面板内提权 |
| auth.users_file | /etc/ajenti/users.yml | users 模式的账号库路径 |
| bind.host | 0.0.0.0 | 监听 IP |
| bind.mode | tcp | tcp 或 unix(unix socket 文件) |
| bind.port | 8000 | 监听端口 |
| ssl.enable | true | 启用 HTTPS |
| ssl.certificate | /etc/ajenti/ajenti.pem | 服务端证书(含私钥的 PEM) |
| ssl.force | false | true 时另起 80 端口做 HTTP→HTTPS 跳转 |
| ssl.client_auth.* | 关 | 客户端证书登录 |
| email.enable | false | 邮件功能(配合 smtp.yml 做找回密码) |
| language | en(官方包默认 ru) | 界面语言 |
| logo | 官方 Logo 路径 | 自定义顶栏 logo |
| max_sessions | 99 | 同时在线会话数上限 |
| session_max_time | 3600 | 会话有效期(秒) |
| name | 主机名 | 面板标题 |
| restricted_user | nobody | 受限操作降权执行账号 |
| trusted_domains | [] | ≥2.2.1:合法 Origin/CORS 白名单(实测不拦 Host,见 5.6) |
| trusted_proxies | [] | ≥2.2.1:反代真实 IP 还原 |
| url_prefix | 空 | ≥2.2.18:反代子路径发布 |
| color | bluegrey | 主题副色(9 选 1) |
五、核心参数分类详解
5.1 bind 块:监听地址、模式与端口
官方语义:host 监听 IP、mode 取 tcp/unix、port 默认 8000。实测改端口 8000→8010:
docker compose exec ajenti sed -i 's/port: 8000/port: 8010/' /etc/ajenti/config.yml
docker compose restart
tail -3 data/logs/ajenti.log
curl -k -s -o /dev/null -w '%{http_code}\n' https://localhost:8129/
docker compose exec ajenti curl -ks -o /dev/null -w '%{http_code}\n' https://localhost:8010/
2026-11-02 14:47:45,666 INFO : Binding to [0.0.0.0]:8010
000
curl exit=35
302
服务内改监听即生效(日志行 Binding to [0.0.0.0]:8010);宿主 8129 映射的后端端口失听,curl 返回 000(exit=35 连接错误);容器内直连 8010 返回 302 证明面板本身健康。
⚠️ 注意:宿主发布端口在 compose 的
ports:里另配,改服务内端口后需同步8129:8010并up -d重建。
5.2 auth 块:os 与 users 双模式
provider: os——登录名/口令=系统账号(本实验 root/q1w2e3r4);provider: users——面板自管账号库users.yml,与系统口令隔离;allow_sudo: true——sudo 组用户可在面板终端里sudo -i提权;emails: {}——官方文档标注"暂未使用"。
实测切换到 users 模式:生成 scrypt 派生密钥 → 写 users.yml → 重启 → os 的 root 口令失效、users 账号可登录:
docker compose exec ajenti python3 -c "import scrypt, os; b=scrypt.encrypt(os.urandom(256),'q1w2e3r4',maxtime=1); print(b.hex()[:40])"
736372797074001200000008000000012087443a
(前缀 736372797074 即 "scrypt" 的 hex,与官方文档示例 736372797..... 吻合;把完整 hex 填入 users.yml 的 password 字段。)
写入 users.yml、把 auth.provider 从 os 切到 users 并重启后,新旧账号登录对照:
curl -ks -X POST https://localhost:8129/api/core/auth -H 'Content-Type: application/json' -d '{"mode":"normal","username":"admin","password":"q1w2e3r4"}'
curl -ks -X POST https://localhost:8129/api/core/auth -H 'Content-Type: application/json' -d '{"mode":"normal","username":"root","password":"q1w2e3r4"}'
curl -ks -X POST https://localhost:8129/api/core/auth -H 'Content-Type: application/json' -d '{"mode":"normal","username":"admin","password":"wrongpass"}'
curl -kb /tmp/ajcj -s https://localhost:8129/api/core/identity
{"success": true, "username": "admin"}
{"success": false, "error": null}
{"success": false, "error": null}
{"identity": {"user": "admin", "uid": 0, "effective": 0, "elevation_allowed": true, "profile": {"email": "admin@example.com", "fs_root": "/", "permissions": {"packages:install": false}, "uid": 0}}, "machine": {"name": "Ajenti Prod Demo", "hostname": "ajenti-demo"}, "color": "red"}
users 模式下:面板账号 admin 可登录(os 的系统账号 root 同时失效),identity 的 profile 带出 users.yml 里的全部自定义字段。
users.yml 结构逐键说明(password/permissions/uid/fs_root/email):
users:
admin:
email: admin@example.com
fs_root: /
password: 736372797074001200000008000000012087443a...
permissions:
packages:install: false
uid: 0
password:scrypt 派生密钥的 hex 串(生成方法见上),非明文;permissions:细粒度权限开关,键为<插件>:<动作>,false 即禁用该 API;uid:面板内映射的系统 UID(0=root);fs_root:filesystem/filemanager 插件的可见根目录;email:配合找回密码链路发给该用户。
💡 技术拓展:面板类软件的口令存储——
方案 代表 特点 复用系统 /etc/shadow Ajenti os 模式、Cockpit 零第二套口令;泄露半径=系统 root 自管 scrypt/bcrypt 库 Ajenti users 模式、1Panel 与系统隔离,可细粒度权限 客户端证书 Ajenti ssl.client_auth 免口令,浏览器需装个人证书 本系列实验 os 起步、5.2 实测切到 users——生产建议后者。
5.3 ssl 块:证书、force 与客户端证书
enable/certificate/fqdn_certificate/force/client_auth 逐键讲清;实测 force: true 后 80 端口跳转监听出现、HTTP 请求 301 到 HTTPS:
# 把 ssl 块的 force 置 true(注意别误改 client_auth.force)后重启
docker compose exec ajenti curl -sI http://localhost/
docker compose exec ajenti curl -s -o /dev/null -w '%{http_code} redirect=%{redirect_url}\n' http://localhost/somepath
grep 'redirection' data/logs/ajenti.log
HTTP/1.1 301 Move Permanently
Location: https://Ajenti Prod Demo:8000
Connection: close
Cache-control: private
Content-Length: 161
404 redirect=
2026-11-02 14:45:44,829 INFO : HTTP to HTTPS redirection activated to https://Ajenti Prod Demo:8000
⚠️ 注意(实测发现):跳转 Location 是用配置
name值拼出来的https://<name>:<port>——本例name: Ajenti Prod Demo含空格且非可解析主机名,浏览器拿到这种 Location 必然失败。启用force前务必把name设成真实域名(或前置反代自行做 HTTP→HTTPS)。fqdn_certificate是配合该场景的"按 FQDN 签发的证书"路径,留空即回退certificate。
5.4 email 块与 smtp.yml:找回密码链路
smtp.yml 四键(server/port/user/password,port 取 starttls 或 ssl)是发信中继凭据。实测纠偏:登录页"忘记密码"入口并不由 email.enable 决定,而是由 auth.provider 决定——源码级对照:
curl -ks https://localhost:8129/view/login/normal | grep pwReset # provider=users 时
curl -ks https://localhost:8129/view/login/normal | grep pwReset # provider=os 时
provider=users 时:angular.module('core').constant('pwReset', 'True');
provider=os 时: angular.module('core').constant('pwReset', 'False');
源码依据:aj/auth.py 中 OSAuthenticationProvider.pw_reset = False,ajenti_plugin_auth_users 中 UsersAuthenticationProvider.pw_reset = True,core 视图按 provider 取值注入页面。email.enable 改 true/false 均不改变该值(实测 false 时仍为 True);它只决定"用户点了忘记密码后,邮件能不能发出去"。/api/core/email 空响应、/api/core/reset-password 404——发信链路入口在 users 认证插件内。
5.5 全局外观与会话参数
name、language(en/zh 等)、color(9 个主题色枚举)、logo、session_max_time、max_sessions。实测 name 与 language 改动对响应的影响:
docker compose exec ajenti sed -i 's/^language: en/language: zh/' /etc/ajenti/config.yml
docker compose restart
curl -ks -c /tmp/rj -X POST https://localhost:8129/api/core/auth \
-H 'Content-Type: application/json' -d '{"mode":"normal","username":"root","password":"q1w2e3r4"}'
curl -kb /tmp/rj -s https://localhost:8129/api/core/config | python3 -c "import json,sys; d=json.load(sys.stdin); print('language =', d['language'])"
language = zh
name 改动反映在 /api/core/identity 的 machine.name(3.2 实测);color 同样经 identity 的 color 字段回显(5.2 实测 red);language 经 /api/core/config 回显并决定界面文案语言(/api/core/languages 可查支持列表)。session_max_time/max_sessions 无独立验证接口,以会话行为为准:超过 session_max_time 秒后旧 Cookie 调 identity 即失效。
5.6 反代与安全三键:trusted_domains / trusted_proxies / url_prefix
2.2.1 起新增的 Origin/CORS 白名单与 2.2.18 新增的子路径发布。实测 url_prefix: /ajenti(追加该顶层键后重启):
curl -k -s -o /dev/null -w 'GET / -> %{http_code}\n' https://localhost:8129/
curl -k -s -o /dev/null -w 'GET /ajenti -> %{http_code} redirect=%{redirect_url}\n' https://localhost:8129/ajenti
curl -k -s -o /dev/null -w 'login page -> %{http_code}\n' https://localhost:8129/ajenti/view/login/normal
curl -ks -X POST https://localhost:8129/ajenti/api/core/auth -H 'Content-Type: application/json' -d '{"mode":"normal","username":"root","password":"q1w2e3r4"}'
GET / -> 400
GET /ajenti -> 302 redirect=https://localhost:8129/ajenti/view/login/normal
login page -> 200
{"success": true, "username": "root"}
设了前缀后裸根路径反而 400,一切入口(含 API)都必须带 /ajenti 前缀——前置 nginx 用 location /ajenti/ { proxy_pass http://127.0.0.1:8129; } 原样透传即可。
trusted_domains 实测(设 ['https://localhost:8129'] 后重启):
curl -k -s -o /dev/null -w 'Host: evil -> %{http_code}\n' -H 'Host: evil.example.com' https://localhost:8129/
curl -k -s -o /dev/null -w 'normal -> %{http_code}\n' https://localhost:8129/
Host: evil -> 302
normal -> 302
💡 说明(实测纠偏):2.2.18 的
trusted_domains并不拦截非法 Host 请求(上测 evil Host 仍 302 正常响应)——它作用于浏览器侧 Origin/CORS 与 socket.io 连接校验,不是 Host 头防火墙。trusted_proxies则用于反代场景下按X-Forwarded-For还原真实客户端 IP(影响日志与 fail2ban 所见地址)。
六、生产配置模板
适用场景:1–2GB 内存 VPS、单运维人员、公网访问、前置 nginx 反代挂正式证书。要点:users 认证 + 强会话策略 + Origin 白名单 + 反代子路径 + fail2ban。
auth:
allow_sudo: false # 公网面板不给提权
provider: users # 与系统口令隔离(5.2 实测)
users_file: /etc/ajenti/users.yml
bind:
host: 127.0.0.1 # 只监听回环,公网入口交给 nginx
mode: tcp
port: 8000
color: bluegrey
email:
enable: true # 发信中继(users 模式下忘记密码链路才完整)
smtp:
server: smtp.example.com
port: starttls # 或 ssl
user: relay@example.com
password: '<中继口令>'
language: zh
max_sessions: 3
name: panel.example.com # 若启用 ssl.force,此值直接进跳转 URL(5.3 教训)
restricted_user: nobody
session_max_time: 1800
ssl:
certificate: /etc/ajenti/ajenti.pem # 反代终结 TLS 时面板仍要有一张可加载的证书
client_auth:
enable: false
force: false
trusted_domains:
- https://panel.example.com # Origin/CORS 白名单(5.6:不拦 Host)
trusted_proxies:
- 127.0.0.1 # 本机 nginx,还原真实客户端 IP
url_prefix: /ajenti # 反代子路径发布(5.6 实测 400/302/200 序列)
逐块解读:auth 用 users 模式 + 关 sudo,泄露半径不含系统口令;bind.host 收回到 127.0.0.1,8000/8129 都不直接暴露;ssl.force 保持 false,HTTP→HTTPS 跳转由 nginx 做(避免 5.3 的 name 拼 URL 陷阱);url_prefix 让面板挂在 https://panel.example.com/ajenti/ 下,与 nginx 其他站点共存;trusted_proxies 保证 ajenti.log 里的"Failed login from ... at IP"是真实来源 IP,fail2ban 过滤器才有意义。与出厂差异即 allow_sudo、provider、bind.host、email.*、language、max_sessions、session_max_time、trusted_domains、trusted_proxies、url_prefix 十处,其余键保持出厂值。
七、常见问题
7.1 官方包默认 language: ru
仓库默认 config.yml 写死 language: ru,首次部署界面是俄语;显式改 en/zh 并重启(实测回显见 5.5)。
7.2 改配置不生效
Ajenti 无热加载,一切以进程重启为准;compose 形态 docker compose restart,systemd 形态 systemctl restart ajenti。
7.3 YAML 写坏导致面板起不来
现象:进程退出/反复重启,/var/log/ajenti/ 下出现 crash-<日期>-<时刻>h<分>.txt(3.3 实录现场)。crash 文件自带完整环境快照与栈:
Ajenti bug report
Ajenti | 2.2.18
Platform | debian / debian / Linux 7.0.0-38-generic x86_64
Python | 3.11.18
Library | gevent 25.5.1 / greenlet 25.5.1 / psutil 7.2.2
Traceback:
File ".../aj/entry.py", line 39, in start
File ".../aj/core.py", line 108, in run
aj.config.load()
yaml.parser.ParserError: while parsing a block mapping
in "/etc/ajenti/config.yml", line 1, column 1
expected <block end>, but found '<block mapping start>'
in "/etc/ajenti/config.yml", line 35, column 3
修复:按报错行列号改好 config.yml,docker cp 进容器(或宿主直改 bind 文件)→ docker compose restart → docker ps 回到 Up → curl -k https://localhost:8129/ 恢复 302。
7.4 url_prefix 设了之后裸路径 400
带前缀发布后所有入口必须走 /ajenti(5.6 实测);书签、监控探测、反代 location 都要同步改,否则误判"面板挂了"。
7.5 恢复出厂配置反而起不来
把卷内 config.yml 覆盖回出厂文件(ssl.certificate: '')而 ajenti.pem 已存在时,面板崩溃:
context.load_cert_chain(certfile=fqdn_cert_path, keyfile=fqdn_cert_path)
FileNotFoundError: [Errno 2] No such file or directory
原因:entrypoint 只在 pem 缺失时才跑 ajenti-ssl-gen;pem 在而配置为空 → 无证书可加载。恢复:把 certificate: /etc/ajenti/ajenti.pem 写回(即首启回写的稳态值),或连 pem 一起删掉让它重新初始化。