BounCA 0.4.8 配置参数详解
逐项真机验证 services.yaml 六大段参数(secret/psql/email/superuser_signup/admin/key_algorithm/crl_distribution_url 等)与 Nginx/uWSGI 配置:含 yamlreader 列表叠加合并、DisallowedHost 两态调试、psql 端口故障注入、SAN 裸域名规则与 500 排障,附生产环境配置模板。
BounCA 0.4.8 配置参数详解
目标:把 BounCA 0.4.8 的全部运行参数讲透——services.yaml 六大配置段、Django 内置常量、Nginx 站点与 uWSGI 进程模型,每一项关键参数都给出真机改配置→重启→观测行为的生效验证(含错误页形态、算法切换、注册策略、数据库故障注入),并给出生产配置模板与排障实录。部署过程见《Ubuntu 22.04 安装 BounCA 0.4.8 指南》。
一、环境信息
实测机与 B1 相同:Ubuntu 22.04.5 LTS、BounCA 0.4.8(/srv/www/bounca)、PostgreSQL 14.24、Nginx 1.18.0、uWSGI 2.0.20,服务器内网地址 10.89.70.10,应用以 www-data 运行。本文所有「验证」均为真机操作:修改 /etc/bounca/services.yaml → systemctl restart uwsgi → 发起请求观测行为,回显照抄。
二、前置条件
已完成《Ubuntu 22.04 安装 BounCA 0.4.8 指南》全流程。BounCA 的行为由三份配置共同决定:
| 文件 | 层 | 内容 |
|---|---|---|
/etc/bounca/services.yaml | 应用主配置(人工维护) | 六大段:psql / django / admin / mail / certificate-engine / registration |
/etc/nginx/sites-available/bounca | 接入层 | 前端静态托管 + /api、/admin 反代 uWSGI socket |
/etc/uwsgi/apps-available/bounca.ini | 进程层 | WSGI 进程模型、运行身份、socket 路径 |
三、参数查看与修改方式
3.1 配置加载链(源码级 + 实测)
bounca/settings.py 通过 yamlreader.yaml_load 按从低到高顺序合并三份文件(v0.4.8 起「Better parsing of services.yaml」):
/srv/www/bounca/etc/bounca/services.yaml.defaults(内置默认,最低)/srv/www/bounca/etc/bounca/services.yaml(应用内,一般不存在)/etc/bounca/services.yaml(运维主配置,最高)
关键实测发现(容易踩坑):yamlreader 对字典逐键覆盖,但对列表是拼接合并而非替换。实测把 /etc/bounca/services.yaml 的 django.hosts 改成只剩 - localhost,运行时读取结果:
$ env/bin/python manage.py shell -c "from django.conf import settings; print(settings.ALLOWED_HOSTS)"
['localhost', '127.0.0.1', 'localhost']
内置 defaults 里的 localhost、127.0.0.1 始终生效,/etc 层只能追加条目、无法移除默认条目(重复项无害)。同理适用于所有列表型配置。
3.2 修改与生效方式
- 编辑
/etc/bounca/services.yaml(YAML 语法,段名大小写敏感,布尔用True/False); - 应用配置在 Python 进程导入时读取一次,必须重启进程才生效:
systemctl restart uwsgi; - 启动即校验:段缺失或 secret 未改会直接抛
ValueError拒绝启动(见 8.3); - 校验运行时取值:
manage.py shell -c "from django.conf import settings; print(settings.XXX)"。
四、参数总览
| 配置段/文件 | 参数 | 作用 | 默认值 |
|---|---|---|---|
| psql | dbname / username / password / host / port | PostgreSQL 连接四要素+端口 | bounca / bounca / changeit / postgres / 5432 |
| django | debug | 调试模式(错误页形态、CORS 放开) | False |
| django | secret_key | Django 会话/CSRF 签名密钥 | 占位串(必须改) |
| django | hosts | Django ALLOWED_HOSTS 白名单 | [localhost, 127.0.0.1] |
| admin | enabled | 是否挂载 /admin、/grappelli 路由 | True |
| admin | superuser_signup | 是否开放 /accounts/signup/ 超管注册表单 | True(defaults) |
| host / port / username / password / connection | SMTP 服务器与加密方式(none/tls/ssl) | localhost / 无 | |
| admin / from | 管理员告警收件地址、发件地址 | admin@example.com / no-reply@example.com | |
| certificate-engine | key_algorithm | 密钥算法 rsa 或 ed25519 | rsa |
| registration | email_verification | 注册邮箱验证策略 off/optional/mandatory | off |
| settings.py 常量 | CRL_UPDATE_DAYS_FUTURE | CRL 有效期天数 | 365 |
| settings.py 常量 | EMAIL_EXPIRATION_WARNING_DAYS | 证书到期提醒提前天数(0.4.8 新增) | 30 |
| Nginx | server_name / location /static / uwsgi_pass / uwsgi_*_timeout | 接入层 | 见 5.8 |
| uWSGI ini | processes / thread / socket / uid / chdir / home | 进程模型 | 8 / 4 / 见 5.9 |
五、核心参数分类详解
5.1 psql 段:数据库连接
psql:
dbname: bounca
username: bounca
password: q1w2e3r4
host: 127.0.0.1
port: 5432
- 缺任一必需键(dbname/username/password/host)启动即抛
ValueError: Key 'xxx' not found in 'psql' section;连不上库时 Web 侧统一 500、命令行抛OperationalError。 - 生效验证(端口故障注入):把
port改成 5433 重启后,管理后台返回 500;命令行侧报错:
psycopg2.OperationalError: connection to server at "127.0.0.1", port 5433 failed: Connection refused
django.db.utils.OperationalError: connection to server at "127.0.0.1", port 5433 failed: Connection refused
恢复 5432 重启后 /admin/login/ 回到 200。BounCA 仅支持 PostgreSQL(ENGINE=django.db.backends.postgresql_psycopg2),连接复用 CONN_MAX_AGE=10 秒。
5.2 django 段:调试与安全基线
debug(默认 False)。实测对比两种错误形态——伪造 Host: evil.example.com 请求 /admin/login/:
debug: False:精简错误页(143 字节,不泄露任何配置):
<!doctype html>
<html lang="en">
<head>
<title>Bad Request (400)</title>
</head>
<body>
<h1>Bad Request (400)</h1><p></p>
debug: True:Django 调试页,直接回显敏感信息(截取命中关键词):
DisallowedHost at /
Invalid HTTP_HOST header ...
DEBUG = True
ALLOWED_HOSTS
同时 debug=True 时 404 也变成带 URLconf 的调试页(Page not found at /),且 CORS_ORIGIN_ALLOW_ALL=True、日志切到 ./logs/。生产必须 False。
secret_key:占位串不改直接拒绝启动(实测回显见 8.3)。生成方式 python3 -c "import secrets; print(secrets.token_urlsafe(48))";更换后所有会话/Cookie 失效。
hosts:ALLOWED_HOSTS 白名单,语义见 3.1(只能追加)。未列入名单的 Host 访问 Django 路由(/api、/admin)被拒 400;但注意 location / 的前端静态文件由 Nginx 直接返回、不经过该白名单。实测把白名单缩减为 localhost 后,127.0.0.1 仍被放行(defaults 叠加),而 evil.example.com 被拒。
5.3 admin 段:管理后台开关
enabled(默认 True)。实测改为 False 重启:
$ curl -s -o /dev/null -w "%{http_code}\n" -H "Host: localhost" http://127.0.0.1/admin/login/
404
/admin/ 整体下线。安全注意(实测):同一状态下 /grappelli/ 仍返回 200(grappelli 后台资源路由未被同开关拦住),若以内网封禁为策略,建议在 Nginx 层同步 location /grappelli { return 404; }。
superuser_signup:True 时开放 /accounts/signup/ 超管自注册表单与 /accounts/login/ 跳转(实测两路由 200)。官方 README 声明该表单仅在库中无任何用户时可用(空库首装场景),日常应保持 False。
5.4 mail 段:SMTP 与告警
mail:
host: localhost
# port: 587
# username: <user>
# password: <password>
# connection: none # none / tls / ssl
admin: admin@example.com
from: no-reply@example.com
connection: tls→EMAIL_USE_TLS=True、默认端口 587;ssl→EMAIL_USE_SSL=True、默认端口 465;不配则明文 25。admin同时是ADMINS配置:DEBUG=False 下出现 500 时 Django 会尝试向该地址发告警邮件——所以mail段在生产必须可用,否则故障告警静默丢失。- 生效验证(间接实证):
registration.email_verification: mandatory且本机无 SMTP 时,注册请求在发送验证邮件环节报 500(回显见 5.6);证明 mail 段被真实使用。证书到期提醒(0.4.8,EMAIL_EXPIRATION_WARNING_DAYS=30)与 CRL 巡检命令同样走该通道。
5.5 certificate-engine 段:密钥算法
certificate-engine:
key_algorithm: rsa # 或 ed25519
生效验证(算法切换实测):改为 ed25519 重启后经 API 签发根证书,下载私钥用 openssl 核验:
$ openssl pkey -in root-ed.key -text -noout | head -2
ED25519 Private-Key:
priv:
切回 rsa 后签发的证书:
$ openssl x509 -in gitlab.lab.internal.pem -noout -text | grep Public-Key
Public-Key: (2048 bit)
规律(与 services.yaml.example 注释一致):rsa 下根/中间 CA 4096 位、叶子证书 2048 位;ed25519 全链现代算法但兼容性差(官方提示 macOS 等场景支持不佳),不确定就保持 rsa。算法是全局开关,切换后仅影响新签发的证书。
5.6 registration 段:注册邮箱验证
email_verification 三态实测(注册端点 POST /api/v1/auth/registration/):
- off(默认):不需要 email,注册即返回会话 key:
{"key":"d84e1e208d1aba6cb06dceb3683301f020424dcd"}
http=201
- mandatory:不带 email 直接 400:
{"email":["This field is required."]}
http=400
带 email 但 SMTP 不可用(本机无邮件服务)→ 500(验证邮件发送失败):
<!doctype html>
<html lang="en">
<head>
<title>Server Error (500)</title>
</head>
结论:mandatory/optional 必须先保证 5.4 的 SMTP 可用,否则注册功能整体瘫痪;内网无邮件服务就保持 off。
5.7 settings.py 内置常量
| 常量 | 值 | 实证 |
|---|---|---|
CRL_UPDATE_DAYS_FUTURE | 365 | 吊销客户端证书后续签 CRL,openssl crl -text 显示 Last Update: Oct 28 04:51:37 2026 GMT / Next Update: Oct 28 04:52:40 2027 GMT,恰为 +365 天 |
EMAIL_EXPIRATION_WARNING_DAYS | 30 | 0.4.8 changelog「Send email when certificate is about to expire (Default 30 days)」;send_expire_email 管理命令按此阈值筛选(实测见 D 篇) |
TIME_ZONE | Europe/Amsterdam | 硬编码,注意与北京时间差 6~7 小时,读日志/报表时换算 |
CRL 更新入口 | API PUT /api/v1/certificates/<pk>/crl | 0.4.5 起「Generate CRL file updates via button」 |
5.8 Nginx 站点参数(/etc/nginx/sites-available/bounca)
发行包模板关键段:
server {
listen 80;
listen [::]:80;
server_name _; # 发行包默认写死 bounca,必须改
location /static {
root /srv/www/bounca/media; # 注意 root 指向 media,URL 前缀是 /static
include mime.types;
}
location /api {
include uwsgi_params;
uwsgi_read_timeout 9600; # 证书签发耗时长,超时放宽到 160 分钟
uwsgi_send_timeout 9600;
uwsgi_pass unix://run/uwsgi/app/bounca/socket;
}
location /admin { ... 同上 uwsgi_pass ... }
location / {
root /srv/www/bounca/front/dist; # Vuetify 预构建前端
include mime.types;
try_files $uri $uri/ /index.html;
}
}
- 生效验证:
/返回front/dist的index.html(不经过 Django,因此 Host 白名单不拦截静态页);/static/admin/css/base.css200;/api/200。404 排障时先分清「Nginx 404」还是「Django 404」。 - 启用 HTTPS:模板内已带注释好的 443 ssl 段(
ssl_certificate /etc/nginx/ssl/fullchain.pem),放开并注释 80 段即可。
5.9 uWSGI 进程参数(/etc/uwsgi/apps-available/bounca.ini)
[uwsgi]
thread=4
master=1
processes=8
vacuum=true
uid = www-data
gid = www-data
chmod-socket = 700
chown-socket = www-data
socket = /run/uwsgi/app/bounca/socket
logto = /var/log/uwsgi/bounca.log
chdir = /srv/www/bounca
home = /srv/www/bounca/env
module = bounca.wsgi:application
env = DJANGO_SETTINGS_MODULE=bounca.settings
生效验证:8 个 worker 进程全部拉起(ps 计 10 个 uwsgi 进程 = 1 master + 8 worker + 计数差),socket 属主 www-data:
# ls -l /run/uwsgi/app/bounca/
-rw-r--r-- 1 root root 5 Oct 28 04:03 pid
srwx------ 1 www-data root 0 Oct 28 04:03 socket
调优建议:processes 按 2×CPU 起步(证书签发是 CPU 密集型 RSA 运算),小内存主机同步下调;logto 目录需对 www-data 可写,属主不对是「worker 起不来/no python application found」的高频原因。
六、生产配置模板
适用基线:2 vCPU / 4GB 内存 / 40GB SSD 的单机内网 CA,数十个中间证书、千级叶子证书规模。
/etc/bounca/services.yaml:
psql:
dbname: bounca
username: bounca
password: '<强口令>'
host: 127.0.0.1
port: 5432
admin:
enabled: True
superuser_signup: False # 空库首装设 True 建号后立即改回
django:
debug: False
secret_key: '<python3 -c "import secrets; print(secrets.token_urlsafe(48))" 生成>'
hosts:
- ca.example.internal # 实际访问域名(defaults 的 localhost/127.0.0.1 始终叠加生效)
mail:
host: smtp.example.internal
port: 587
username: bounca@example.internal
password: '<SMTP口令>'
connection: tls
admin: sre@example.internal
from: no-reply@example.internal
certificate-engine:
key_algorithm: rsa
registration:
email_verification: off # 邮箱验证改 mandatory 前先确认 SMTP 通
/etc/uwsgi/apps-available/bounca.ini 差异项:processes=4(2C 机型)、其余保持默认。
Nginx 差异项:server_name ca.example.internal;,并追加 /grappelli 封禁(见 5.3);启用 443 ssl 段。
七、常见问题(排障实录)
Q1:/etc/bounca/services.yaml 里删掉 django.hosts 的条目不生效?
yamlreader 对列表做拼接合并:defaults 的 localhost、127.0.0.1 恒在(实测 print(settings.ALLOWED_HOSTS) 输出 ['localhost', '127.0.0.1', 'localhost'])。只增不删,重复无害。
Q2:改了 services.yaml 没效果?
配置在进程导入时读取,改完必须 systemctl restart uwsgi(Nginx 配置同理 restart nginx)。
Q3:启动报 ValueError: No 'psql' section found in services.yaml / Set an unique secret key in services.yaml
前者:/etc/bounca/services.yaml 缺失或段名写错,只剩内置 defaults(无 psql/mail/registration 段)——实测移走该文件后 manage.py migrate 即抛此错。后者:secret_key 仍是发行包占位串。两者都直接拒绝启动,属设计行为。
Q4:DisallowedHost: Invalid HTTP_HOST header 'xxx'
访问域名不在 ALLOWED_HOSTS。注意静态前端(location /)不受影响,被拒的是 /api、/admin;往 django.hosts 追加实际域名即可。
Q5:SAN 传 DNS:gitlab.lab.internal 这类带冒号前缀,接口 500/502?
实测定位:DN 字段白名单正则不允许冒号,且校验失败的报错消息里含 % 与 ^,Django ValidationError 做消息格式化时抛 ValueError: unsupported format character '^'(0.4.8 源码 certificate_engine/ssl/certificate.py 的 [@#$%^&+=_,-.] 消息串)。SAN 应传裸域名或 IP(如 gitlab.lab.internal、10.89.70.20),引擎按 DNSName/IPAddress 自动识别(实测裸名签发 201 成功)。
Q6:注册接口 500?
email_verification 为 mandatory/optional 但 SMTP 不可用(实测本机无邮件服务时 500)。先修 mail 段或临时回退 off。
Q7:管理后台 404 但想临时开?
admin.enabled: True + 重启;注意 /grappelli/ 不会被该开关关闭,封禁需 Nginx 层处理。
八、参考链接
外部来源:
- 官方 README(v0.4.8 发行包)配置与安装章节
- 发行包模板:
etc/bounca/services.yaml.example、etc/nginx/bounca、etc/uwsgi/bounca.ini bounca/settings.py(v0.4.8 源码,配置加载与常量定义)- yamlreader 库文档(合并语义):https://pypi.org/project/yamlreader/
本系列其他篇目:
- 组件定位与选型对比:《BounCA 介绍与选型指南》
- 安装与部署全流程实测:《Ubuntu 22.04 安装 BounCA 0.4.8 指南》
- CLI 与证书签发/吊销/备份实测:《BounCA 0.4.8 常用 CLI 命令与工具详解》