Bitpoll 0.11.0 配置参数详解
Bitpoll 0.11.0 配置面逐项详解:settings_local 覆盖机制、SECRET_KEY/加密键、DATABASES 接 PostgreSQL、注册与匿名/实名两层开关、邮件、日历互通、OIDC/LDAP 扩展位,含运行时生效值实测回显与五则排障。
Bitpoll 0.11.0 配置参数详解
本文基于 Bitpoll 0.11.0 官方源码(仓库 master 快照)与 2026-11-01 实测环境的运行时生效值,逐项讲清配置面。所有「生效值」回显均为实测照抄。部署流程见《Bitpoll 0.11.0 Compose 部署实战》。
一、配置加载机制
Bitpoll 是标准 Django 项目,配置分两层:
- 默认层:
bitpoll/settings.py,随发行包内置,定义了全部默认值(数据库默认 SQLite、时区 Europe/Berlin、语言 de-de 等)。 - 本地层:
bitpoll/settings_local.py。默认层最后一行from .settings_local import *把本地层的全部大写变量整体覆盖到默认值上。
官方发行形态把本地层做成挂载点:入口脚本执行 ln -sf /opt/config/settings.py /opt/bitpoll/bitpoll/settings_local.py——即运维只需维护挂载目录里的 settings.py 一个文件,官方样例 bitpoll/settings_local.sample.py 就是它的起点。改配置后重启应用进程生效,无需重建任何产物。
验证生效值的标准手段(实测):
docker compose exec -T bitpoll python3 /opt/bitpoll/manage.py shell -c "
from django.conf import settings as s
for k in ['SITE_NAME','BASE_URL','ALLOWED_HOSTS','DEBUG','REGISTER_ENABLED','GROUP_MANAGEMENT','POLL_CREATION_REQUIRES_LOGIN','PUBLIC_POLLS','CALENDAR_ENABLED','CALENDAR_MAX_TOKENS','CALENDAR_FILL_RATE','ANTI_SPAM_CHALLENGE_TTL','CSP_REPORT_ONLY','TIME_ZONE','LANGUAGE_CODE','ALLOW_CUSTOM_SLUGS','DEFAULT_RANDOM_SLUG','MAIL_SIGNATURE','TEAM_EMAIL','HOME_URL','IMPRINT_URL','PRIVACY_URL','EMAIL_BACKEND','DEFAULT_FROM_EMAIL','OPENID_ENABLED','USE_TZ']:
print(k, '=', repr(getattr(s,k,'<unset>')))
from django.db import connection
print('DB ENGINE =', settings.DATABASES['default']['ENGINE'], '| HOST =', settings.DATABASES['default']['HOST'])
"
实测回显(本文示例环境):
SITE_NAME = 'Bitpoll'
BASE_URL = 'http://127.0.0.1:8136'
ALLOWED_HOSTS = ['*']
DEBUG = False
REGISTER_ENABLED = True
GROUP_MANAGEMENT = True
POLL_CREATION_REQUIRES_LOGIN = False
PUBLIC_POLLS = True
CALENDAR_ENABLED = True
CALENDAR_MAX_TOKENS = 2
CALENDAR_FILL_RATE = 500
ANTI_SPAM_CHALLENGE_TTL = 604800
CSP_REPORT_ONLY = True
TIME_ZONE = 'Asia/Shanghai'
LANGUAGE_CODE = 'en-us'
ALLOW_CUSTOM_SLUGS = True
DEFAULT_RANDOM_SLUG = 'true'
MAIL_SIGNATURE = 'Bitpoll Team'
TEAM_EMAIL = 'mail@example.com'
HOME_URL = 'https://example.com'
IMPRINT_URL = ''
PRIVACY_URL = ''
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
DEFAULT_FROM_EMAIL = 'bitpoll@quzuo.net'
OPENID_ENABLED = False
USE_TZ = True
DB ENGINE = django.db.backends.postgresql | HOST = db
二、安全根参数
SECRET_KEY
Django 会话签名与密码重置 token 的根密钥。官方样例留 '...' 占位,必须改为随机值,生成方式:python3 -c "from django.core.management.utils import get_random_secret_key as k; print(k())"。泄露后果:攻击者可伪造任意用户会话 cookie。变更后所有在线会话失效(用户重新登录即可)。
FIELD_ENCRYPTION_KEY
加密存储敏感字段(如受邀者邮箱)的密钥,用项目自带命令生成:
docker compose exec -T bitpoll python3 /opt/bitpoll/manage.py generate_encryption_key
输出即为可直接粘贴的 base64 串(样例注释给出的形态 this+is+an+example+key+please+generate+one+=)。注意:更换此 key 会导致已加密数据无法解密,初始化时定稿,之后不要动。
DEBUG
生产必须 False。True 时错误页带堆栈与配置转储,且静态走 DEBUG 通道,属于信息泄露面。
ALLOWED_HOSTS
默认 [],非 DEBUG 模式下任何 Host 头都不匹配 → 全站 400。至少写入实际域名与本机访问地址;示例环境用 ['*'] 图方便,生产务必收紧为白名单,如 ['poll.example.com', '192.168.1.10']。
HTTPS 三件套
样例注释明确:站点走 HTTPS 时启用
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
默认层另有 CSRF_COOKIE_HTTPONLY = True(内置,无需设置)。不加 HTTPS 时保持注释状态,否则浏览器端 cookie 直接不发。
CSP 内容安全策略
django-simple-csp 中间件自动注入 Content-Security-Policy-Report-Only 头(部署篇 8.1 回显可见)。两个参数:
CSP_REPORT_ONLY:默认True(只报告不拦截)。确认业务无 CSP 冲突后改False转为强制拦截。CSP_REPORT_URL:违规上报地址,默认空。
三、数据库配置
默认层是 SQLite:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
官方配置面没有 DATABASE_URL 环境变量机制,数据库一律用 DATABASES 字典在 settings.py 里显式覆盖。生产接 PostgreSQL 的实测写法:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'bitpoll',
'USER': 'bitpoll',
'PASSWORD': 'bitpoll',
'HOST': 'db',
'PORT': '5432',
}
}
HOST 填数据库服务的网络名(Compose 内即服务名 db)。密码建议从环境变量读入再拼进字典(文件顶部 import os,用 os.environ['DB_PASSWORD']),避免明文落盘。忘记改这段的直接后果见第十一节排障 2。
四、站点标识与外观
| 参数 | 默认值 | 说明 |
|---|---|---|
SITE_NAME | 'Bitpoll' | 页面标题后缀与品牌名,如回显 <title>Create poll - Bitpoll</title> |
BASE_URL | 'https://bitpoll.mafiasi.de' | 本站根地址,通知邮件里的投票链接由它拼出,必须改为实际对外地址 |
HOME_URL / HOME_URL_NAME | "https://example.com" / "Dashboard" | 导航栏首页链接与文案;设成你的主站与名称,或留空隐藏 |
IMPRINT_URL / IMPRINT_TEXT | "" / 内置 HTML | 法律 imprint 页:URL 非空则外链,否则渲染 IMPRINT_TEXT |
PRIVACY_URL | "" | 隐私政策外链;留空用内置模板 base/privacy.html |
URL_PREFIX | '' | 站点挂在子路径(如 /bitpoll)时设置,反代与模板路径同步适配 |
五、语言与时区
LANGUAGE_CODE:默认de-de,示例改'en-us';中文界面在LANGUAGES元组中并不存在(官方翻译列表为 de/en/it),界面以英/德为主。TIME_ZONE:默认Europe/Berlin,示例改'Asia/Shanghai'。它决定整天/时段投票选项的展示与生成时区,USE_TZ = True(默认)时存储仍为 UTC。LOCALE_PATHS:指向发行包内locale/目录,一般无需改动。
时区改动实测生效(第一节回显 TIME_ZONE = 'Asia/Shanghai')。注意:改 TIME_ZONE 不回溯已有投票的选项时间语义,建议在投空前定稿。
六、注册与访问门槛(匿名/实名开关)
这是选型时最关心的一组,分「全局」与「每投票」两层:
全局层
| 参数 | 默认 | 实测值 | 作用 |
|---|---|---|---|
REGISTER_ENABLED | True | True | 是否开放自助注册。False 时注册入口关闭,账户由管理员建 |
GROUP_MANAGEMENT | = REGISTER_ENABLED | True | 用户分组管理(邀请组、组内私有投票)。与 OPENID_ENABLED 互斥,同开直接 ImproperlyConfigured 拒绝启动 |
POLL_CREATION_REQUIRES_LOGIN | False | False | 建投票是否要求登录。内网防滥用建议改 True |
POLL_CREATION_ACCOUNT_WEBSITE / _NAME | "https://example.org" / "Example" | 默认 | 未登录被拦时提示「去 XX 注册」的引导链接与文案 |
PUBLIC_POLLS | True | True | 公开投票列表页是否可见 |
每投票层(源码 poll/models.py 实测核对)
anonymous_allowed = models.BooleanField(default=True)
public_listening = models.BooleanField(default=False)
- 匿名/实名不是全局开关:创建投票时的「允许匿名」勾选落到
poll.anonymous_allowed(默认 True),投票人可匿名或署名;vote.anonymous标记单票是否匿名。 public_listening:控制未登录者能否「旁听」查看结果。- 私有受邀投票由创建页的访问类型决定(配合
GROUP_MANAGEMENT的组邀请体系)。
治理建议:外网公开实例保持默认;内部协调实例设 POLL_CREATION_REQUIRES_LOGIN = True + REGISTER_ENABLED = False(账户由管理员用 CLI 批量建,见 CLI 篇),即可做到「全员实名、入口收敛」。
七、投票行为参数
| 参数 | 默认 | 说明 |
|---|---|---|
ALLOW_CUSTOM_SLUGS | True | 允许手填投票短链接(如 /poll/weekly-meeting/)。对外传播友好,但可被枚举,敏感场景关 |
DEFAULT_RANDOM_SLUG | 'true' | 新建投票默认走随机 slug(注意此值是字符串形态,前端 JS 读取) |
ANTI_SPAM_CHALLENGE_TTL | 604800(7 天) | 反垃圾质询的有效时长 |
DATA_UPLOAD_MAX_NUMBER_FIELDS | 10000 | 默认层已调大,容纳「几百选项 × 几十投票人」的大表单提交,勿改小否则大投票保存 400 |
| 评论限流 | — | 0.9 起由 django-token-bucket 按 IP 令牌桶限评论速率,无独立参数面 |
八、邮件参数
投票创建、结果变更、日历邀请都靠邮件触达,Django 邮件面全量可用:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # 测试期:打到进程日志
DEFAULT_FROM_EMAIL = 'bitpoll@quzuo.net'
生产切换 SMTP 示例:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.example.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'poll@example.com'
EMAIL_HOST_PASSWORD = os.environ['SMTP_PASSWORD']
另有两个署名参数:MAIL_SIGNATURE(默认 'Bitpoll Team',邮件落款)与 TEAM_EMAIL(默认 mail@example.com,联系邮箱)。console 后端的邮件内容可在应用进程日志里直接看到,是验证「提醒邮件是否触发」的最简手段。
九、日历互通参数
| 参数 | 默认 | 实测 | 说明 |
|---|---|---|---|
CALENDAR_ENABLED | True | True | CalDAV 集成总开关,关闭后 caldav/ 路由不注册 |
CALENDAR_MAX_TOKENS | 2 | 2 | 每用户可生成的日历授权令牌数上限 |
CALENDAR_FILL_RATE | 500 | 500 | 日历填充速率限制 |
开启后可把「可投票时段」以日历订阅方式接入外部日历应用(依赖 caldav、icalendar)。
十、进阶扩展位
样例文件预留四类扩展,全部经 settings_local.py 注入:
- Sentry 监控:
INSTALLED_APPS_LOCAL = ['raven.contrib.django.raven_compat'](发行版镜像内已带 sentry 配置文件痕迹)。 - JS/CSS 压缩:
PIPELINE_LOCAL['JS_COMPRESSOR'] = 'pipeline.compressors.uglifyjs.UglifyJSCompressor'等,需系统装对应压缩器;默认PIPELINE_ENABLED = False不压缩。 - OpenID Connect 登录:
OPENID_ENABLED = True+OPENID_ISSUER/CLIENT_ID/CLIENT_SECRET/SCOPE/USER_MAPPER/ADMIN_GROUPS一组,接入企业 SSO(样例给了 Keycloak 形态)。与GROUP_MANAGEMENT互斥。 - LDAP 登录:
django_auth_ldap全套参数(AUTH_LDAP_SERVER_URI、AUTH_LDAP_USER_SEARCH、AUTH_LDAP_USER_FLAGS_BY_GROUP等),可把域账号直接映射为is_staff/is_superuser。
INSTALLED_APPS += INSTALLED_APPS_LOCAL、MIDDLEWARE += MIDDLEWARE_LOCAL、PIPELINE.update(PIPELINE_LOCAL) 的合并逻辑在默认层末尾,本地层只需给增量列表。
十一、排障实录
- 全站 400 DisallowedHost:
ALLOWED_HOSTS未设(默认[])时任何访问都 400,错误页提示Invalid HTTP_HOST header。解决:写入实际域名/IP。示例期临时['*']。 - 数据莫名丢失/重启后投票消失:沿用默认 SQLite 且数据文件在应用包内,每次升级重灌即丢。解决:上线第一件事就是按第三节把
DATABASES指向外部 PostgreSQL,数据目录独立挂载。 - 启动即崩
ImproperlyConfigured: You can't use both OPENID_ENABLED and GROUP_MANAGEMENT:源码 urls.py 的显式互斥检查。解决:二选一——要 SSO 就GROUP_MANAGEMENT = False,要分组邀请就放弃 OIDC。 - 改了
settings.py不生效:本地层是软链挂载,确认改的是run/config/settings.py本体而非镜像内文件;且 uWSGI prefork 进程需重启应用服务才会重新 import。用第一节的 shell 命令对比重启前后生效值即可定位。 - 大投票保存报 400:选项 × 投票人矩阵字段数超过
DATA_UPLOAD_MAX_NUMBER_FIELDS(默认层已调到 10000,若本地层误覆盖回 Django 默认 1000 就会触发)。保持默认层值或按需更大。
十二、生产基线示例
综合以上,一台对外服务的生产实例最小配置(可直接替换部署篇 4.1 的示例文件):
import os
SECRET_KEY = os.environ['SECRET_KEY']
FIELD_ENCRYPTION_KEY = os.environ['FIELD_ENCRYPTION_KEY']
DEBUG = False
ALLOWED_HOSTS = ['poll.example.com']
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SITE_NAME = '团队投票'
BASE_URL = 'https://poll.example.com'
TIME_ZONE = 'Asia/Shanghai'
LANGUAGE_CODE = 'en-us'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'bitpoll',
'USER': 'bitpoll',
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': 'db',
'PORT': '5432',
}
}
REGISTER_ENABLED = False
POLL_CREATION_REQUIRES_LOGIN = True
PUBLIC_POLLS = False
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.example.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'poll@example.com'
EMAIL_HOST_PASSWORD = os.environ['SMTP_PASSWORD']
DEFAULT_FROM_EMAIL = 'poll@example.com'
MAIL_SIGNATURE = '平台组'
TEAM_EMAIL = 'ops@example.com'
CSP_REPORT_ONLY = False
密钥类全部走环境变量注入(部署篇的 keys.env),配置文件本体可安全入库审计。命令行运维见本专栏《Bitpoll 0.11.0 常用 CLI 命令详解》。