Bitpoll 0.11.0 配置参数详解

Bitpoll 0.11.0 配置面逐项详解:settings_local 覆盖机制、SECRET_KEY/加密键、DATABASES 接 PostgreSQL、注册与匿名/实名两层开关、邮件、日历互通、OIDC/LDAP 扩展位,含运行时生效值实测回显与五则排障。

Bitpoll自托管DjangoPostgreSQLPython2026/11/01

Bitpoll 0.11.0 配置参数详解

本文基于 Bitpoll 0.11.0 官方源码(仓库 master 快照)与 2026-11-01 实测环境的运行时生效值,逐项讲清配置面。所有「生效值」回显均为实测照抄。部署流程见《Bitpoll 0.11.0 Compose 部署实战》。

一、配置加载机制

Bitpoll 是标准 Django 项目,配置分两层:

  1. 默认层:bitpoll/settings.py,随发行包内置,定义了全部默认值(数据库默认 SQLite、时区 Europe/Berlin、语言 de-de 等)。
  2. 本地层: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_ENABLEDTrueTrue是否开放自助注册。False 时注册入口关闭,账户由管理员建
GROUP_MANAGEMENT= REGISTER_ENABLEDTrue用户分组管理(邀请组、组内私有投票)。与 OPENID_ENABLED 互斥,同开直接 ImproperlyConfigured 拒绝启动
POLL_CREATION_REQUIRES_LOGINFalseFalse建投票是否要求登录。内网防滥用建议改 True
POLL_CREATION_ACCOUNT_WEBSITE / _NAME"https://example.org" / "Example"默认未登录被拦时提示「去 XX 注册」的引导链接与文案
PUBLIC_POLLSTrueTrue公开投票列表页是否可见

每投票层(源码 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_SLUGSTrue允许手填投票短链接(如 /poll/weekly-meeting/)。对外传播友好,但可被枚举,敏感场景关
DEFAULT_RANDOM_SLUG'true'新建投票默认走随机 slug(注意此值是字符串形态,前端 JS 读取)
ANTI_SPAM_CHALLENGE_TTL604800(7 天)反垃圾质询的有效时长
DATA_UPLOAD_MAX_NUMBER_FIELDS10000默认层已调大,容纳「几百选项 × 几十投票人」的大表单提交,勿改小否则大投票保存 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_ENABLEDTrueTrueCalDAV 集成总开关,关闭后 caldav/ 路由不注册
CALENDAR_MAX_TOKENS22每用户可生成的日历授权令牌数上限
CALENDAR_FILL_RATE500500日历填充速率限制

开启后可把「可投票时段」以日历订阅方式接入外部日历应用(依赖 caldav、icalendar)。

十、进阶扩展位

样例文件预留四类扩展,全部经 settings_local.py 注入:

  1. Sentry 监控:INSTALLED_APPS_LOCAL = ['raven.contrib.django.raven_compat'](发行版镜像内已带 sentry 配置文件痕迹)。
  2. JS/CSS 压缩:PIPELINE_LOCAL['JS_COMPRESSOR'] = 'pipeline.compressors.uglifyjs.UglifyJSCompressor' 等,需系统装对应压缩器;默认 PIPELINE_ENABLED = False 不压缩。
  3. OpenID Connect 登录:OPENID_ENABLED = True + OPENID_ISSUER/CLIENT_ID/CLIENT_SECRET/SCOPE/USER_MAPPER/ADMIN_GROUPS 一组,接入企业 SSO(样例给了 Keycloak 形态)。与 GROUP_MANAGEMENT 互斥。
  4. 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) 的合并逻辑在默认层末尾,本地层只需给增量列表。

十一、排障实录

  1. 全站 400 DisallowedHost:ALLOWED_HOSTS 未设(默认 [])时任何访问都 400,错误页提示 Invalid HTTP_HOST header。解决:写入实际域名/IP。示例期临时 ['*']。
  2. 数据莫名丢失/重启后投票消失:沿用默认 SQLite 且数据文件在应用包内,每次升级重灌即丢。解决:上线第一件事就是按第三节把 DATABASES 指向外部 PostgreSQL,数据目录独立挂载。
  3. 启动即崩 ImproperlyConfigured: You can't use both OPENID_ENABLED and GROUP_MANAGEMENT:源码 urls.py 的显式互斥检查。解决:二选一——要 SSO 就 GROUP_MANAGEMENT = False,要分组邀请就放弃 OIDC。
  4. 改了 settings.py 不生效:本地层是软链挂载,确认改的是 run/config/settings.py 本体而非镜像内文件;且 uWSGI prefork 进程需重启应用服务才会重新 import。用第一节的 shell 命令对比重启前后生效值即可定位。
  5. 大投票保存报 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 命令详解》。

Bitpoll 0.11.0 配置参数详解 - Quzuo