Alf.io 2.0-M5-2609 配置参数详解
深入讲解 Alf.io 2.0-M5-2609 的四层配置体系(属性文件、环境变量、JVM 参数与数据库四级业务配置),逐键给出 21 分类 164 个配置键的实测当前值与说明,全部命令与回显实测于 Ubuntu 22.04。
Alf.io 2.0-M5-2609 配置参数详解
目标:完整讲清开源票务系统 Alf.io 2.0-M5-2609 的配置体系——文件层(
application.properties)、环境变量层、JVM 参数层与平台业务配置层(数据库四级层级)的查看、修改与验证方法,并逐条给出全部 164 个业务配置键的实测当前值与说明。全部命令与回显均在 Ubuntu 22.04.5 LTS 实测环境逐条执行验证,实测日期 2026-10-23。安装过程见 《Ubuntu 22.04 安装 Alf.io 2.0-M5-2609 指南》,产品背景与选型见 《Alf.io 2.0-M5-2609 介绍与选型指南》。
一、环境信息
本章列出版文所依赖的实测环境,保证后文每一项参数与回显都可对照复现。
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- Java 运行时:OpenJDK 17.0.20.1(
openjdk-17-jre-headless,另装有 JDK 诊断工具jcmd;Alf.io 要求 Java 17) - 数据库:PostgreSQL 14.24-0ubuntu0.22.04.1(Alf.io 仅支持 PostgreSQL 10 及以上)
- 反向代理:Nginx 1.18.0-6ubuntu14.21(对外 8443 端口 HTTPS 终结)
- Alf.io 版本:2.0-M5-2609(官方发布件
alfio-2.0-M5-2609-boot.jar,83,405,439 字节) - 部署目录:
/opt/alfio/,运行账号为专用系统账号alfio,systemd 服务名alfio.service - 端口:应用本体监听 8080,PostgreSQL 5432(仅本机回环),Nginx 对外 8443(HTTPS)
- 示例域名:
alfio.example.local(与安装篇一致,生产环境替换为真实域名) - 管理后台账号:
admin(首次启动自动生成随机密码,本实例实测为NNtHfOzVERRyVRB6j,登录后应立即修改) - 平台业务配置规模:21 个分类、164 个配置键(管理后台与配置 API 可见口径,实测于 2026-10-23)
二、前置条件
本章给出操作前必须确认的三件事:服务在跑、后台能登录、数据库能查。每一项都给出验证命令与实测回显。
2.1 服务健康检查
确认 Alf.io 与 PostgreSQL、Nginx 三个服务均处于运行状态:
systemctl is-active alfio postgresql nginx
实测输出:
active
再确认应用端口在监听,且首页可访问:
ss -ltn | grep -E ':(8080|5432|8443)'
curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\n' http://localhost:8080/
实测输出:
LISTEN 0 244 127.0.0.1:5432 0.0.0.0:*
LISTEN 0 50 *:8080 *:*
LISTEN 0 511 0.0.0.0:8443 0.0.0.0:*
302 -> https://localhost:8443/
💡 说明:
curl http://localhost:8080/返回 302 并指向https://localhost:8443/,这是alfio.base-url属性在起作用——应用把所有对外地址统一重定向到配置的基础 URL(详见 3.2 节与 7.2 节)。后文所有接口演示均走https://localhost:8443(Nginx HTTPS),与生产访问路径一致。
2.2 管理后台登录(命令行方式)
后文的配置读取与写入演示以管理后台 REST 接口为主,需要先用表单登录拿到会话。Alf.io 登录受 CSRF 保护,标准流程是「取登录页 → 提取 _csrf → 携带会话提交」:
B=https://localhost:8443
rm -f /tmp/cj.txt /tmp/auth.html
curl -sk -c /tmp/cj.txt $B/authentication -o /tmp/auth.html
CSRF=$(sed -n 's/.*name="_csrf" type="hidden" value="\([^"]*\)".*/\1/p' /tmp/auth.html | head -1)
curl -sk -b /tmp/cj.txt -c /tmp/cj.txt -o /dev/null -w 'login http=%{http_code}\n' -X POST $B/authenticate \
--data-urlencode 'username=admin' --data-urlencode 'password=NNtHfOzVERRyVRB6j' \
--data-urlencode "_csrf=$CSRF"
curl -sk -b /tmp/cj.txt $B/authentication-status
实测输出(_csrf 每次会话不同,登录成功后状态接口返回当前身份):
login http=302
{"authenticated":true,"username":"admin","alfioVersion":"2.0-M5-2609","demoModeEnabled":false,"devModeEnabled":false,"prodModeEnabled":true}
💡 说明:
login http=302是登录成功后的重定向(302 到/admin/),并非失败;authentication-status返回的 JSON 里prodModeEnabled:true表示当前是生产模式(非演示模式)。密码请替换为你自己实例首次启动时生成的随机密码;忘记密码可按安装篇 8.2 节重新生成。
2.3 数据库访问
平台业务配置存储在 PostgreSQL 的 alfio 库中。确认可以用 alfio 账号连库并读取配置表:
PGPASSWORD=q1w2e3r4 psql -h localhost -U alfio -d alfio -t -c 'select count(*) from configuration'
实测输出:
12
💡 说明:
configuration表当前 12 行,即系统级已落库的配置键(清单见 3.5 节)。q1w2e3r4是安装篇创建数据库角色时设定的测试口令,生产环境务必更换。
三、配置体系与查看修改方式
Alf.io 的配置分散在四个载体上,必须先分清「改哪一层、哪一层说了算」,否则经常出现「改了不生效」。本章逐层给出查看与修改方法,全部实测。
3.1 四层配置载体与生效优先级
实测归纳的四层载体如下表(优先级从高到低,上层覆盖下层):
| 层级 | 载体 | 位置 | 典型内容 | 生效方式 |
|---|---|---|---|---|
| 1 | JVM 启动参数 | systemd 单元 ExecStart 行 | -Xms256m -Xmx512m | systemctl daemon-reload && systemctl restart alfio |
| 2 | 环境变量 | systemd 单元或启动命令前缀 | SERVER_PORT=8096 | 重启进程(标准 Spring Boot 宽松绑定,SERVER_PORT 即 server.port) |
| 3 | 外部属性文件 | /opt/alfio/application.properties | datasource.*、alfio.base-url | 重启进程 |
| 4 | 平台业务配置 | PostgreSQL alfio 库 5 张配置表,后台 UI / 配置 API 可改 | BASE_URL、邮件、支付、发票等 164 键 | 保存即生效(无需重启) |
💡 技术拓展:把配置放在哪里是所有服务端软件都要回答的问题。常见方案对比——
方案 原理/特点 适用场景 本地属性文件 随机器存放,版本管理靠运维自己,改完要重启 单机部署、变更频率低 环境变量 进程级注入,不落盘,云原生环境常用 临时覆盖、秘密注入、12-Factor 应用 数据库内配置 应用自带管理界面与层级覆盖,改完即生效 业务参数、多租户分级配置 外部配置中心 Spring Cloud Config、Nacos、Apollo 等集中下发 微服务集群、多环境统一管理 Alf.io 作为单体 Spring Boot 应用(jar 清单实测
Spring-Boot-Version: 3.5.16),实际采用「属性文件 + 环境变量(基础设施层)+ 数据库分级配置(业务层)」的组合,不依赖外部配置中心。
关键差异在于:1–3 层属于「进程级」配置,改动需要重启且全实例唯一;第 4 层是 Alf.io 自带的业务配置体系,支持按「系统 → 组织 → 活动 → 票种」四级覆盖,保存即生效。数据源、站点地址这类基础设施参数在文件层,业务规则(支付、邮件、发票)在平台层。
3.2 层三:外部属性文件 /opt/alfio/application.properties
这是安装时手工创建的文件(安装篇 4.5 节),位于部署目录、与 jar 同级。Spring Boot 启动时会自动加载「工作目录下的 application.properties」(systemd 单元 WorkingDirectory=/opt/alfio),并覆盖 jar 内置同名配置。实测内容:
cat /opt/alfio/application.properties
实测输出:
# Alf.io external configuration
datasource.url=jdbc:postgresql://localhost:5432/alfio
datasource.username=alfio
datasource.password=q1w2e3r4
alfio.base-url=https://alfio.example.local
逐项说明:
datasource.url:JDBC 连接串,指向本机 PostgreSQL 的alfio库;改主机/端口/库名都在这里。datasource.username/datasource.password:数据库账号口令,必须与CREATE ROLE alfio LOGIN PASSWORD设定一致,否则启动即报FATAL: password authentication failed(排障见安装篇 8.1 节)。alfio.base-url:对外基础地址,决定邮件里的链接、支付回调、二维码内容与前台重定向。必须与用户实际访问地址一致(含协议),否则会出现「8080 直连被 302」与「支付回调地址不对」两类问题。
要追加文件层参数(例如长期改端口、调日志级别),直接编辑该文件后重启服务即可:
echo 'server.port=8096' >> /opt/alfio/application.properties
systemctl restart alfio
ss -ltn | grep 8096
⚠️ 注意:演示后记得删除该行恢复 8080(
sed -i '/^server.port=8096$/d' /opt/alfio/application.properties && systemctl restart alfio)。本章 3.4 节的SERVER_PORT实测与之等价,读者二选一即可,勿同时设置。
3.3 jar 内置默认属性(只读参考)
发布件内部自带一份默认 application.properties,是「什么都不配」时的兜底值。用 unzip -p 直接读取 jar 内文件,不落盘:
unzip -p /opt/alfio/alfio-2.0-M5-2609-boot.jar BOOT-INF/classes/application.properties
实测输出:
#Fri Sep 18 08:53:25 CEST 2026
logging.level.alfio=info
server.compression.enabled=true
server.forward-headers-strategy=native
spring.application.name=Alf.io
alfio.version=2.0-M5-2609
server.servlet.session.timeout=2h
alfio.build-ts=2026-09-18T06\:53\:25.284959982Z[UTC]
server.servlet.session.cookie.http-only=true
server.shutdown=graceful
logging.level.root=warn
逐项说明:
logging.level.root=warn/logging.level.alfio=info:日志级别,根日志 warn、应用包 info;排障时可在外部文件里把logging.level.alfio提到debug。server.compression.enabled=true:响应压缩开启。server.forward-headers-strategy=native:信任反向代理传递的X-Forwarded-*头(Nginx 反代 HTTPS 的关键,安装篇 7.1 节的 Nginx 配置依赖它)。server.servlet.session.timeout=2h:会话超时 2 小时。server.servlet.session.cookie.http-only=true:会话 Cookie 禁止 JavaScript 读取。server.shutdown=graceful:优雅停机(systemd 停服时等待在途请求完成)。alfio.version/alfio.build-ts:构建版本号与构建时间戳,属构建指纹,无需修改。
3.4 层二:环境变量覆盖(SERVER_PORT 实测)
环境变量的优先级高于属性文件,适合「不改文件、临时验证」场景。以下实测把监听端口从 8080 切到 8096:
systemctl stop alfio
su alfio -s /bin/bash -c "cd /opt/alfio && SERVER_PORT=8096 java -Xms256m -Xmx512m -jar alfio-2.0-M5-2609-boot.jar &"
sleep 12
ss -ltn | grep 8096
实测输出(输出节选,实测首尾):
>> powered by Spring Boot
2026-10-23T13:37:00.887Z INFO 14192 --- [Alf.io] [ main] a.c.SpringBootLauncher : Starting SpringBootLauncher v2.0-M5-2609 using Java 17.0.20.1 with PID 14192 (/opt/alfio/alfio-2.0-M5-2609-boot.jar started by alfio in /opt/alfio)
2026-10-23T13:37:04.459Z INFO 14192 --- [Alf.io] [ main] a.c.SpringBootLauncher : Started SpringBootLauncher in 3.989 seconds (process running for 4.927)
LISTEN 0 50 *:8096 *:*
验证完成后恢复 systemd 托管:
pkill -f 'SERVER_PORT=8096'
sleep 2
systemctl start alfio
systemctl is-active alfio
ss -ltn | grep 8080
实测输出:
active
LISTEN 0 50 *:8080 *:*
⚠️ 注意一:
SERVER_PORT与server.port是 Spring Boot 宽松绑定关系(环境变量把点写成下划线、去中划线、全大写),即SERVER_PORT=8096等价于server.port=8096。常用可覆盖项如DATASOURCE_PASSWORD、ALFIO_BASE_URL同理。⚠️ 注意二:在脚本或一次性包装命令里执行
pkill -f 'SERVER_PORT=8096'时,包装命令自身的命令行也包含该模式,可能把自己一起杀掉;交互终端手工执行无此问题,脚本里建议改用kill $(pgrep -f 'alfio-2.0-M5-2609-boot.jar')。
3.5 层四:平台业务配置(数据库四级层级)
业务参数(站点、邮件、支付、发票、签到等 164 个键)由 Alf.io 自行管理,落库在 PostgreSQL 的 5 张配置表,按「系统 → 组织 → 活动 → 票种」四级覆盖,取值时从最具体层级向上回溯。查看这 5 张表:
PGPASSWORD=q1w2e3r4 psql -h localhost -U alfio -d alfio -c "\dt configuration*"
实测输出:
List of relations
Schema | Name | Type | Owner
--------+---------------------------------+-------+-------
public | configuration | table | alfio
public | configuration_event | table | alfio
public | configuration_organization | table | alfio
public | configuration_purchase_context | table | alfio
public | configuration_ticket_category | table | alfio
(5 rows)
五张表与四级层级的对应关系(configuration 即系统级):
| 表名 | 层级 | 主键维度 |
|---|---|---|
configuration | 系统(SYSTEM) | c_key 全局唯一 |
configuration_organization | 组织(ORGANIZATION) | organization_id_fk + c_key 唯一 |
configuration_event | 活动(EVENT) | organization_id_fk + event_id_fk + c_key 唯一 |
configuration_purchase_context | 活动上下文(EVENT/SUBSCRIPTION 统一口径) | 组织 + 上下文 + 键 |
configuration_ticket_category | 票种(CATEGORY) | 组织 + 活动 + 票种 + 键 |
以组织级表为例,看真实表结构(含行级安全策略):
PGPASSWORD=q1w2e3r4 psql -h localhost -U alfio -d alfio -c '\d configuration_organization'
实测输出:
Table "public.configuration_organization"
Column | Type | Collation | Nullable | Default
--------------------+-------------------------+-----------+----------+--------------------------------------------------------
id | integer | | not null | nextval('configuration_organization_id_seq'::regclass)
organization_id_fk | integer | | not null |
c_key | character varying(255) | | not null |
c_value | text | | not null |
description | character varying(2048) | | |
Indexes:
"configuration_organization_pkey" PRIMARY KEY, btree (id)
"unique_configuration_organization" UNIQUE CONSTRAINT, btree (organization_id_fk, c_key)
Foreign-key constraints:
"configuration_organization_organization_id_fk_fkey" FOREIGN KEY (organization_id_fk) REFERENCES organization(id)
Policies (forced row security enabled):
POLICY "configuration_organization_access_policy"
USING (alfio_check_row_access(organization_id_fk))
WITH CHECK (alfio_check_row_access(organization_id_fk))
系统级当前已落库的全部键(本实例实测 12 行,含演示过程中产生的值):
PGPASSWORD=q1w2e3r4 psql -h localhost -U alfio -d alfio \
-c 'select id, c_key, left(c_value,45) as c_value from configuration order by id'
实测输出:
id | c_key | c_value
----+--------------------------------------+-----------------------------------------------
1 | MAX_AMOUNT_OF_TICKETS_BY_RESERVATION | 5
2 | SPECIAL_PRICE_CODE_LENGTH | 6
5 | BANK_TRANSFER_ENABLED | true
6 | PAYPAL_ENABLED | true
7 | ON_SITE_ENABLED | true
8 | STRIPE_CC_ENABLED | true
9 | EU_COUNTRIES_LIST | BE,EL,LT,PT,BG,ES,LU,RO,CZ,FR,HU,SI,DK,HR,MT,
11 | GOOGLE_ANALYTICS_ANONYMOUS_MODE | true
12 | INIT_COMPLETED | true
13 | SYSTEM_API_KEY | 122dkat5oxp5x7ckbcg53ncu8kb5aj2m1x32eygvhpxvi
14 | BASE_URL | https://alfio.example.local
15 | ANNOUNCEMENT_BANNER_CONTENT |
(12 rows)
逐项解读:
- 系统级默认落库 8 键(id 1–11:单笔限购数、特价码长度、四类支付开关、欧盟国家清单、GA 匿名模式),是初始化时写入的出厂值。
INIT_COMPLETED=true(id 12)是「初始化已完成」标记,管理员凭据丢失需重新生成时的关键键(见 7.7 节)。SYSTEM_API_KEY(id 13)是本实例实测调用 v1 系统 API 时生成的系统级密钥(截取展示),属敏感凭据,生产环境严禁外泄。BASE_URL(id 14)与文件层alfio.base-url保持一致,二者都要配(缺平台键会在活动创建时直接报错,见 7.1 节)。ANNOUNCEMENT_BANNER_CONTENT(id 15)是 3.6 节演示「设置 → 清空」后留下的空值行——注意清空只是置空字符串,行仍在库中。
业务配置的修改有两条路径:管理后台 UI(设置页逐分类表单,即官方文档 Basic Configuration 向导的完整形态)与配置 REST API。API 路径的实测演示见 3.6 节;全部键的清单与说明见第四、五章。
3.6 配置 REST API 实测:读取、单键、批量写入
配置 API 走管理后台会话(2.2 节登录)。三个最常用的端点逐一实测。
读取全量配置(带每个键的定义、当前值、层级、控件类型),返回约 41 KB JSON:
curl -sk -b /tmp/cj.txt https://localhost:8443/admin/api/configuration/load -o /tmp/cfgload.json
wc -c /tmp/cfgload.json
实测输出:
41216 /tmp/cfgload.json
用 Python 统计分类与键数(写入文档的第四、五章总表即来自这份实测数据):
python3 - <<'PYEOF'
import json
d = json.load(open('/tmp/cfgload.json'))
total = 0
for cat in sorted(d.keys(), key=lambda k: -len(d[k])):
print(f'{cat}\t{len(d[cat])}')
total += len(d[cat])
print('TOTAL', total)
PYEOF
实测输出:
GENERAL 31
MAIL 24
PAYMENT_OFFLINE 16
RESERVATION_UI 14
INVOICE 9
PAYMENT_STRIPE 8
PAYMENT 7
PAYMENT_MOLLIE 7
PASS_INTEGRATION 6
INVOICE_EU 6
PAYMENT_SAFERPAY 6
PAYMENT_PAYPAL 6
ALFIO_PI 5
WALLET_INTEGRATION 4
WAITING_LIST 4
MAP 3
RESERVATION_EMBED 2
IMPORT_ATTENDEE 2
OPENID 2
SUBSCRIPTIONS 1
TRANSLATIONS 1
TOTAL 164
单键读取(活动层级端点 /admin/api/configuration/events/{eventSlug}/single/{key})。对未在该活动层级覆盖、且无内置默认值的键返回 204 无响应体:
curl -sk -w '\nhttp=%{http_code}\n' -b /tmp/cj.txt \
'https://localhost:8443/admin/api/configuration/events/democonf2026/single/BASE_URL'
实测输出:
http=204
对有内置默认值的同类键(MAX_AMOUNT_OF_TICKETS_BY_RESERVATION,默认 5),同端点直接返回生效值:
curl -sk -w '\nhttp=%{http_code}\n' -b /tmp/cj.txt \
'https://localhost:8443/admin/api/configuration/events/democonf2026/single/MAX_AMOUNT_OF_TICKETS_BY_RESERVATION'
实测输出:
"5"
http=200
批量写入用 POST /admin/api/configuration/update-bulk,请求体按分类分组,必须携带 CSRF 头(X-CSRF-TOKEN,值取后台页 <meta name="_csrf">)。实测设置公告横幅内容:
CSRF=$(curl -sk -b /tmp/cj.txt https://localhost:8443/admin/ | sed -n 's/.*name="_csrf" content="\([^"]*\)".*/\1/p' | head -1)
curl -sk -w '\nhttp=%{http_code}\n' -b /tmp/cj.txt -H "X-CSRF-TOKEN: $CSRF" -H 'Content-Type: application/json' \
-X POST https://localhost:8443/admin/api/configuration/update-bulk \
-d '{"GENERAL":[{"key":"ANNOUNCEMENT_BANNER_CONTENT","value":"Maintenance window on Sunday"}]}'
实测输出:
true
http=200
三路验证:API 读回、数据库落库,然后清空并复核。
curl -sk -b /tmp/cj.txt https://localhost:8443/admin/api/configuration/load -o /tmp/cfgload2.json
python3 -c 'import json; d=json.load(open("/tmp/cfgload2.json")); print([x for x in d["GENERAL"] if x["key"]=="ANNOUNCEMENT_BANNER_CONTENT"][0])'
PGPASSWORD=q1w2e3r4 psql -h localhost -U alfio -d alfio \
-c "select id, c_key, c_value from configuration where c_key = 'ANNOUNCEMENT_BANNER_CONTENT'"
实测输出:
{"id": 15, "key": "ANNOUNCEMENT_BANNER_CONTENT", "value": "Maintenance window on Sunday", "configurationPathLevel": "SYSTEM", "description": "Announcement banner content", "configurationKey": "ANNOUNCEMENT_BANNER_CONTENT", "basic": false, "internal": false, "componentType": "TEXTAREA"}
id | c_key | c_value
----+-----------------------------+------------------------------
15 | ANNOUNCEMENT_BANNER_CONTENT | Maintenance window on Sunday
(1 row)
curl -sk -w '\nhttp=%{http_code}\n' -b /tmp/cj.txt -H "X-CSRF-TOKEN: $CSRF" -H 'Content-Type: application/json' \
-X POST https://localhost:8443/admin/api/configuration/update-bulk \
-d '{"GENERAL":[{"key":"ANNOUNCEMENT_BANNER_CONTENT","value":""}]}'
实测输出:
true
http=200
再次读回确认清空结果:
curl -sk -b /tmp/cj.txt https://localhost:8443/admin/api/configuration/load -o /tmp/cfgload3.json
python3 -c 'import json; d=json.load(open("/tmp/cfgload3.json")); print([x for x in d["GENERAL"] if x["key"]=="ANNOUNCEMENT_BANNER_CONTENT"][0])'
实测输出:
{"id": 15, "key": "ANNOUNCEMENT_BANNER_CONTENT", "value": "", "configurationPathLevel": "SYSTEM", "description": "Announcement banner content", "configurationKey": "ANNOUNCEMENT_BANNER_CONTENT", "basic": false, "internal": false, "componentType": "TEXTAREA"}
💡 说明:每条配置项的 JSON 里
configurationPathLevel表示该值的归属层级(本例全部为 SYSTEM 级落库),componentType是后台 UI 的控件类型(TEXT 输入框、TEXTAREA 文本域、BOOLEAN 开关、LIST 下拉),basic:true表示它属于首次配置向导的必填项(实测只有BASE_URL与MAILER_TYPE两键为 basic)。清空键只是把值置为空字符串,行保留(见 7.4 节)。
3.7 层一:JVM 堆参数(位置与生效验证)
JVM 参数在 systemd 单元的 ExecStart 行,本实例为 -Xms256m -Xmx512m。查看单元与生效值:
grep -E 'User=|WorkingDirectory=|ExecStart=' /etc/systemd/system/alfio.service
实测输出:
User=alfio
WorkingDirectory=/opt/alfio
ExecStart=/usr/bin/java -Xms256m -Xmx512m -jar /opt/alfio/alfio-2.0-M5-2609-boot.jar
用 JDK 诊断工具 jcmd 核对运行中进程的实际生效堆参数(先取主进程 PID,再读 VM 旗标与命令行):
PID=$(pgrep -f 'alfio-2.0-M5-2609-boot.jar' | head -1)
jcmd $PID VM.flags | grep -oE '(Initial|Max)HeapSize=[0-9]+'
jcmd $PID VM.command_line
实测输出(256MB = 268435456,512MB = 536870912):
InitialHeapSize=268435456
MaxHeapSize=536870912
14318:
VM Arguments:
jvm_args: -Xms256m -Xmx512m
⚠️ 注意:
pgrep -f匹配到多个 PID 时jcmd会对每个 PID 依次执行,混入手工启动的进程会报错;请先pgrep -af确认只剩 systemd 托管的主进程。调整堆内存的完整改法与ps -ef验证方式见 《Ubuntu 22.04 安装 Alf.io 2.0-M5-2609 指南》7.2 节,本文不重复。
四、参数总览
本章把全部参数按「文件/环境层」与「平台业务层」两张总表给出,作为第五章逐键详解的索引。
4.1 文件与环境层参数速查
这一层的键由 Spring Boot 框架与 Alf.io 自身约定,实测取值如下(jar 内置默认值即 3.3 节回显):
| 参数 | 实测值 | 层级来源 | 说明 |
|---|---|---|---|
datasource.url | jdbc:postgresql://localhost:5432/alfio | 外部文件 | JDBC 连接串,仅支持 PostgreSQL |
datasource.username | alfio | 外部文件 | 数据库账号 |
datasource.password | q1w2e3r4 | 外部文件 | 数据库口令(测试口令,生产必换) |
alfio.base-url | https://alfio.example.local | 外部文件 | 对外基础地址,重定向与链接生成依据 |
server.port / SERVER_PORT | 8080(内置默认,未显式写) | 内置/环境变量 | HTTP 监听端口,实测可覆盖为 8096 |
logging.level.root | warn | jar 内置 | 根日志级别 |
logging.level.alfio | info | jar 内置 | 应用日志级别 |
server.servlet.session.timeout | 2h | jar 内置 | 会话超时 |
server.servlet.session.cookie.http-only | true | jar 内置 | 会话 Cookie 防脚本读取 |
server.compression.enabled | true | jar 内置 | 响应压缩 |
server.forward-headers-strategy | native | jar 内置 | 信任反代 X-Forwarded-* 头 |
server.shutdown | graceful | jar 内置 | 优雅停机 |
spring.application.name | Alf.io | jar 内置 | 应用名 |
-Xms / -Xmx | 256m / 512m | systemd ExecStart | JVM 初始/最大堆 |
解读:日常运维改动频率最高的是前四行与端口/堆参数;jar 内置默认一般不动,需要覆盖时写进外部文件即可(3.2 节)。
4.2 平台业务配置:21 分类 164 键总览
这一层的 164 个键按 21 个分类组织(3.6 节实测统计)。分类一览与本文详解章节对应如下:
| 分类 | 键数 | 主题 | 详解章节 |
|---|---|---|---|
| GENERAL | 31 | 站点通用(含 BASE_URL、验证码、GA、安全头) | 5.1 |
| 24 | 邮件通道与行为 | 5.2 | |
| PAYMENT | 7 | 支付通用(平台费、黑名单) | 5.3 |
| PAYMENT_OFFLINE | 16 | 银行转账/线下/Revolut | 5.4 |
| PAYMENT_STRIPE | 8 | Stripe | 5.5 |
| PAYMENT_PAYPAL | 6 | PayPal | 5.6 |
| PAYMENT_MOLLIE | 7 | Mollie | 5.7 |
| PAYMENT_SAFERPAY | 6 | Saferpay | 5.8 |
| INVOICE | 9 | 发票通用 | 5.9 |
| INVOICE_EU | 6 | 欧盟 VAT/逆向征收 | 5.10 |
| RESERVATION_UI | 14 | 预订流程 UI 行为 | 5.11 |
| WAITING_LIST | 4 | 候补队列 | 5.12 |
| MAP | 3 | 地图供应商 | 5.13 |
| ALFIO_PI | 5 | 树莓派签到站 | 5.14 |
| PASS_INTEGRATION | 6 | Apple Wallet 票券 | 5.15 |
| WALLET_INTEGRATION | 4 | Google Wallet 票券 | 5.15 |
| RESERVATION_EMBED | 2 | 前台嵌入 | 5.16 |
| IMPORT_ATTENDEE | 2 | 参会者导入 | 5.16 |
| OPENID | 2 | OpenID 登录 | 5.16 |
| SUBSCRIPTIONS | 1 | 订阅票 | 5.16 |
| TRANSLATIONS | 1 | 文案覆盖 | 5.16 |
解读:支付类 6 个分类合计 50 键,是最大的功能域;邮件 24 键次之。没有接入的支付/邮件渠道保持默认关闭即可,不必逐键研究。
4.3 配置层级(configurationPathLevel)语义
每个键在每个层级都可以独立取值,取值时按「票种 → 活动 → 组织 → 系统」的顺序向上找到最近一个显式设置的层级。实测系统中全部 164 键当前都只有 SYSTEM 级值(组织/活动/票种三张表均为 0 行):
PGPASSWORD=q1w2e3r4 psql -h localhost -U alfio -d alfio -t -c \
"select 'configuration' as t, count(*) from configuration union all select 'configuration_organization', count(*) from configuration_organization union all select 'configuration_event', count(*) from configuration_event union all select 'configuration_purchase_context', count(*) from configuration_purchase_context union all select 'configuration_ticket_category', count(*) from configuration_ticket_category"
实测输出:
configuration | 12
configuration_organization | 0
configuration_event | 0
configuration_purchase_context | 0
configuration_ticket_category | 0
(5 rows)
后台 UI 中,同一批键在「系统设置」「组织设置」「活动设置」「票种设置」四处出现,分别在对应层级写入对应表;某层级清空即回退到上一层级取值。API 侧的活动级单键读取行为见 3.6 节实测(未覆盖且无默认值时返回 204)。
五、核心参数分类详解
本章逐分类列出全部 164 键。「实测当前值」列来自 3.6 节 /admin/api/configuration/load 接口(2026-10-23 实测);空值表示未显式设置、按官方内置默认运行(「说明」列注明已知默认值);「类型」列为后台控件类型。布尔开关类键在未设置时,false/true 以后台表单渲染出的默认为准,说明列的 default 即官方定义。
5.1 GENERAL:站点通用(31 键)
站点级行为集合,含首次配置必填的 BASE_URL、登录/选票验证码、Google Analytics 与安全响应头上报。
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| BASE_URL | https://alfio.example.local | TEXT | 对外基础地址,后台必填项(basic),与 alfio.base-url 保持一致 |
| RESERVATION_TIMEOUT | 空 | TEXT | 预订保留时长(分钟),超时自动释放 |
| RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT | 空 | TEXT | 支付失败后至少保留的时长(分钟) |
| MAX_AMOUNT_OF_TICKETS_BY_RESERVATION | 5 | TEXT | 单笔预订最多票数(默认 5),已落库 |
| SPECIAL_PRICE_CODE_LENGTH | 6 | TEXT | 特价/推广码长度(默认 6),已落库 |
| ANNOUNCEMENT_BANNER_CONTENT | 空 | TEXTAREA | 前台公告横幅内容(3.6 节实测写入/清空对象) |
| APPLY_TAX_TO_CATEGORY | 空 | BOOLEAN | 票种是否应用税费(默认 true) |
| ASSIGNMENT_REMINDER_START | 空 | TEXT | 活动前多少天开始发送实名提醒 |
| ASSIGNMENT_REMINDER_INTERVAL | 空 | TEXT | 实名提醒之间的静默天数 |
| BASE_CUSTOM_CSS | 空 | TEXTAREA | 全站自定义 CSS |
| EVENT_CUSTOM_CSS | 空 | TEXTAREA | 活动级自定义 CSS |
| CHECK_IN_STATS | 空 | BOOLEAN | 移动签到 App 内显示签到统计 |
| DEMO_MODE_ACCOUNT_EXPIRATION_DAYS | 空 | TEXT | 演示模式账号过期天数 |
| DESCRIPTION_MAXLENGTH | 空 | TEXT | 活动描述最大字符数(默认 4000) |
| DISPLAY_STATS_IN_EVENT_DETAIL | 空 | BOOLEAN | 活动详情页显示售票统计 |
| ENABLE_CAPTCHA_FOR_LOGIN | 空 | BOOLEAN | 后台登录启用验证码(默认 true) |
| GOOGLE_ANALYTICS_KEY | 空 | TEXT | Google Analytics 跟踪 ID |
| GOOGLE_ANALYTICS_ANONYMOUS_MODE | true | BOOLEAN | GA 匿名模式(无 Cookie、IP 打码),已落库 |
| GLOBAL_PRIVACY_POLICY | 空 | TEXT | 全站隐私政策链接(活动列表展示) |
| GLOBAL_TERMS | 空 | TEXT | 全站条款链接(活动列表展示) |
| NOTIFY_ALL_FAILED_PAYMENT_ATTEMPTS | 空 | BOOLEAN | 所有失败支付尝试都发通知(取决于渠道,默认 false) |
| NOTIFY_ORGANIZER_ON_RESERVATION | 空 | BOOLEAN | 有人预订时通知组织者(默认 true) |
| OPTIONAL_DATA_REMINDER_ENABLED | 空 | BOOLEAN | 补充可选信息提醒(默认 false) |
| RECAPTCHA_API_KEY | 空 | TEXT | reCAPTCHA v2 站点密钥 |
| RECAPTCHA_SECRET | 空 | TEXT | reCAPTCHA v2 服务端密钥 |
| SECURITY_CSP_REPORT_ENABLED | 空 | BOOLEAN | 启用 Content-Security-Policy 上报(默认 false) |
| SECURITY_CSP_REPORT_URI | 空 | TEXT | CSP 上报地址(默认 /report-csp-violation) |
| CF_TURNSTILE_ENABLED | 空 | BOOLEAN | 启用 Cloudflare Turnstile(默认 false) |
| CF_TURNSTILE_SITE_KEY | 空 | TEXT | Turnstile 站点密钥 |
| CF_TURNSTILE_SECRET_KEY | 空 | TEXT | Turnstile 服务端密钥 |
| CF_TURNSTILE_PRE_CLEARANCE | 空 | BOOLEAN | 使用 Turnstile 预清除模式(默认 false) |
💡 技术拓展:验证码方案不止一种。Alf.io 内置两类——
方案 原理/特点 适用场景 reCAPTCHA v2 Google 系,勾选框/图片挑战,键为 RECAPTCHA_API_KEY+RECAPTCHA_SECRET面向大众的活动站 Cloudflare Turnstile 无感质询,隐私友好,键为 CF_TURNSTILE_*四键已用 Cloudflare CDN 的站点 验证码生效点由三处开关控制:后台登录(默认开)、选票(默认关)、线下支付/免费票(默认关)。本实例两者均未配置,仅保持登录验证码默认开。
5.2 MAIL:邮件通道与行为(24 键)
Alf.io 的票券、收据、提醒全部依赖邮件,未配置邮件通道时系统只入队不发送。通道由 MAILER_TYPE 决定:
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| MAILER_TYPE | 空 | TEXT | 邮件通道类型(basic 必填项);官方说明「不设置则默认禁用」 |
| SMTP_HOST | 空 | TEXT | SMTP 主机(MAILER_TYPE=smtp 时生效) |
| SMTP_PORT | 空 | TEXT | SMTP 端口 |
| SMTP_PROTOCOL | 空 | TEXT | 协议(smtp 或 smtps) |
| SMTP_USERNAME | 空 | TEXT | SMTP 用户名 |
| SMTP_PASSWORD | 空 | TEXT | SMTP 密码 |
| SMTP_FROM_EMAIL | 空 | TEXT | 发件人地址 |
| SMTP_PROPERTIES | 空 | TEXTAREA | 附加 SMTP 属性(JavaMail 属性串) |
| MAILGUN_KEY | 空 | TEXT | Mailgun API Key(MAILER_TYPE=mailgun 时生效) |
| MAILGUN_DOMAIN | 空 | TEXT | Mailgun 域名 |
| MAILGUN_FROM | 空 | TEXT | Mailgun 发件人 |
| MAILGUN_EU | 空 | BOOLEAN | 使用 Mailgun 欧盟区域 |
| MAILJET_APIKEY_PUBLIC | 空 | TEXT | Mailjet 公钥(MAILER_TYPE=mailjet 时生效) |
| MAILJET_APIKEY_PRIVATE | 空 | TEXT | Mailjet 私钥 |
| MAILJET_FROM | 空 | TEXT | Mailjet 发件人 |
| SENDGRID_API_KEY | 空 | TEXT | SendGrid API Key(MAILER_TYPE=sendgrid 时生效) |
| SENDGRID_FROM | 空 | TEXT | SendGrid 发件人 |
| ENABLE_HTML_EMAILS | 空 | BOOLEAN | HTML 邮件(默认 true;关闭仅发纯文本) |
| MAIL_REPLY_TO | 空 | TEXT | 全局 Reply-To 地址 |
| MAIL_SET_ORG_REPLY_TO | 空 | BOOLEAN | 以组织者邮箱作为 Reply-To(默认 false) |
| MAIL_SYSTEM_NOTIFICATION_CC | 空 | TEXT | 系统通知邮件的附加抄送 |
| MAIL_FOOTER | 空 | TEXTAREA | 邮件页脚 |
| MAIL_ATTEMPTS_COUNT | 空 | TEXT | 单封邮件最大尝试次数(默认 10) |
| MAX_EMAIL_PER_CYCLE | 空 | TEXT | 每个发送周期(5 秒)处理的邮件数 |
💡 技术拓展:邮件通道四种内置实现的取舍——
通道 原理/特点 适用场景 SMTP 直连自建/服务商 SMTP 服务器,最通用 已有邮件基础设施 Mailgun HTTP API 托管发送,送达率高,支持 EU 区域 不想维护 SMTP 的中小站 Mailjet HTTP API 托管发送,欧洲服务商 欧盟活动组织者 SendGrid HTTP API 托管发送 美区/大规模发送 本实例
MAILER_TYPE为空,邮件发送处于禁用状态(这正是「票买了但收不到邮件」的首要排查点,见 7.6 节)。生产建议首选 SMTP 自有域名发送,退信可控。
5.3 PAYMENT:支付通用(7 键)
支付域的公共参数:平台费与支付方式黑名单。具体渠道在 5.4–5.8 节。
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| ON_SITE_ENABLED | true | BOOLEAN | 现场现金支付开关,已落库 |
| PAYMENT_METHODS_BLACKLIST | 空 | TEXT | 支付方式黑名单(逗号分隔) |
| PLATFORM_MODE_ENABLED | 空 | BOOLEAN | 启用平台模式(Alf.io 代收票款、向组织者收平台费的模式) |
| PLATFORM_FIXED_FEE | 空 | TEXT | 每张票固定平台费 |
| PLATFORM_PERCENTAGE_FEE | 空 | TEXT | 每张票比例平台费(百分比) |
| PLATFORM_MINIMUM_FEE | 空 | TEXT | 平台费下限 |
| PLATFORM_MAXIMUM_FEE | 空 | TEXT | 平台费上限 |
💡 技术拓展:Alf.io 支持的收款形态与键位对照——
形态 分类 开关键 是否需要外部账号 银行转账(含延后确认) PAYMENT_OFFLINE BANK_TRANSFER_ENABLED 等 否,填自己账户 现场支付 PAYMENT ON_SITE_ENABLED 否 Stripe PAYMENT_STRIPE STRIPE_CC_ENABLED 是,Stripe 账号 PayPal PAYMENT_PAYPAL PAYPAL_ENABLED 是,PayPal REST 应用 Mollie PAYMENT_MOLLIE MOLLIE_CC_ENABLED 是,Mollie 账号 Saferpay PAYMENT_SAFERPAY SAFERPAY_ENABLED 是,Saferpay 终端 Revolut(对账) PAYMENT_OFFLINE REVOLUT_ENABLED 是,Revolut API 官方 API 的支付方式枚举实测有九种:
PAYPAL, CUSTOM_OFFLINE, ON_SITE, NONE, STRIPE, MOLLIE, ADMIN, OFFLINE, SAFERPAY(注意银行转账写作OFFLINE,没有BANK_TRANSFER这个枚举值——传错会直接 400,见 7.1 节实例)。自托管场景最常用「银行转账 + 现场支付」零成本起步,量起来后再接网关。
5.4 PAYMENT_OFFLINE:银行转账/线下/Revolut(16 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| BANK_TRANSFER_ENABLED | true | BOOLEAN | 银行转账开关,已落库 |
| BANK_ACCOUNT_OWNER | 空 | TEXTAREA | 收款账户名(展示给购票者) |
| BANK_ACCOUNT_NR | 空 | TEXT | 收款账号/IBAN |
| OFFLINE_PAYMENT_DAYS | 空 | TEXT | 线下支付最宽限期(天) |
| OFFLINE_PAYMENT_BUSINESS_DAYS | 空 | BOOLEAN | 宽限期只按工作日计算(周一至五) |
| OFFLINE_REMINDER_HOURS | 空 | TEXT | 到期前多少小时发提醒邮件 |
| AUTOMATIC_REMOVAL_EXPIRED_OFFLINE_PAYMENT | 空 | BOOLEAN | 逾期自动取消预订(默认 false) |
| DEFERRED_BANK_TRANSFER_ENABLED | 空 | BOOLEAN | 手动发送付款说明(延后转账模式,默认 false) |
| DEFERRED_BANK_TRANSFER_SEND_CONFIRMATION_EMAIL | 空 | BOOLEAN | 延后转账发送确认邮件(默认 true) |
| SHOW_ONLY_BASIC_INSTRUCTIONS | 空 | BOOLEAN | 只展示基础付款说明(默认 false) |
| PARTIAL_RESERVATION_ID_LENGTH | 空 | TEXT | 部分预订 ID 长度 |
| ENABLE_CAPTCHA_FOR_OFFLINE_PAYMENTS | 空 | BOOLEAN | 线下支付/免费票启用验证码(默认 false) |
| REVOLUT_ENABLED | 空 | BOOLEAN | 启用 Revolut 对账集成 |
| REVOLUT_API_KEY | 空 | TEXT | Revolut API Key |
| REVOLUT_LIVE_MODE | 空 | BOOLEAN | Revolut 生产模式 |
| REVOLUT_MANUAL_REVIEW | 空 | BOOLEAN | 交易人工核对(默认 true) |
⚠️ 注意:银行转账要真正可用,除开关联开关外,
BANK_ACCOUNT_OWNER与BANK_ACCOUNT_NR必须填写,否则购票者在支付步骤看不到可执行的转账说明。
5.5 PAYMENT_STRIPE:Stripe(8 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| STRIPE_CC_ENABLED | true | BOOLEAN | Stripe 开关,已落库(还需密钥才算可用) |
| STRIPE_PUBLIC_KEY | 空 | TEXT | Stripe 公钥(pk_live/pk_test) |
| STRIPE_SECRET_KEY | 空 | TEXT | Stripe 私钥(sk_live/sk_test) |
| STRIPE_WEBHOOK_KEY | 空 | TEXT | 账户级事件 Webhook 签名密钥 |
| STRIPE_WEBHOOK_PAYMENT_KEY | 空 | TEXT | 支付 Webhook 签名密钥 |
| STRIPE_ENABLE_SCA | 空 | BOOLEAN | 启用强客户认证(SCA,欧洲卡合规) |
| STRIPE_CONNECT_CALLBACK | 空 | TEXT | Stripe Connect 回调地址 |
| STRIPE_CONNECT_CLIENT_ID | 空 | TEXT | Stripe Connect Client ID |
5.6 PAYMENT_PAYPAL:PayPal(6 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| PAYPAL_ENABLED | true | BOOLEAN | PayPal 开关,已落库(还需 REST 凭据) |
| PAYPAL_CLIENT_ID | 空 | TEXT | PayPal REST Client ID |
| PAYPAL_CLIENT_SECRET | 空 | TEXT | PayPal REST Client Secret |
| PAYPAL_LIVE_MODE | 空 | BOOLEAN | 生产模式(默认沙箱) |
| PAYPAL_DEMO_MODE_USERNAME | 空 | TEXT | 演示模式用户名 |
| PAYPAL_DEMO_MODE_PASSWORD | 空 | TEXT | 演示模式密码 |
5.7 PAYMENT_MOLLIE:Mollie(7 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| MOLLIE_CC_ENABLED | 空 | BOOLEAN | Mollie 开关 |
| MOLLIE_API_KEY | 空 | TEXT | Mollie API Key |
| MOLLIE_CONNECT_CLIENT_ID | 空 | TEXT | Mollie Connect Client ID |
| MOLLIE_CONNECT_CLIENT_SECRET | 空 | TEXT | Mollie Connect Client Secret |
| MOLLIE_CONNECT_PROFILE_ID | 空 | TEXT | Mollie Profile ID |
| MOLLIE_CONNECT_CALLBACK | 空 | TEXT | Mollie Connect 回调地址 |
| MOLLIE_CONNECT_LIVE_MODE | 空 | BOOLEAN | Mollie Connect 生产模式(默认 false) |
5.8 PAYMENT_SAFERPAY:Saferpay(6 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| SAFERPAY_ENABLED | 空 | BOOLEAN | Saferpay 开关 |
| SAFERPAY_CUSTOMER_ID | 空 | TEXT | Saferpay 客户号 |
| SAFERPAY_TERMINAL_ID | 空 | TEXT | Saferpay 终端号 |
| SAFERPAY_API_USERNAME | 空 | TEXT | API 用户名 |
| SAFERPAY_API_PASSWORD | 空 | TEXT | API 密码 |
| SAFERPAY_LIVE_MODE | 空 | BOOLEAN | 生产模式(默认 false) |
5.9 INVOICE:发票通用(9 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| INVOICE_ADDRESS | 空 | TEXTAREA | 发票抬头的收款方地址 |
| VAT_NR | 空 | TEXT | 卖方 VAT 税号 |
| VAT_NUMBER_IS_REQUIRED | 空 | BOOLEAN | 企业客户必填 VAT/GST 号(默认 false) |
| INVOICE_NUMBER_PATTERN | 空 | TEXT | 发票号格式模板(如 INVOICE-%d) |
| GENERATE_ONLY_INVOICE | 空 | BOOLEAN | 已付预订一律生成发票(默认 false) |
| REUSE_INVOICE_NUMBER_FOR_CREDIT_NOTE | 空 | BOOLEAN | 贷记单复用发票号(默认 true) |
| USE_INVOICE_NUMBER_AS_ID | 空 | BOOLEAN | 对外引用用发票号而非预订 ID |
| ENABLE_ITALY_E_INVOICING | 空 | BOOLEAN | 意大利电子发票(默认 false) |
| ITALY_E_INVOICING_SEND_PROFORMA | 空 | BOOLEAN | 意大利电子发票先发形式发票(默认 false) |
5.10 INVOICE_EU:欧盟 VAT 与逆向征收(6 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| ENABLE_EU_VAT_DIRECTIVE | 空 | BOOLEAN | 启用欧盟 VAT 逆向征收(默认 false) |
| COUNTRY_OF_BUSINESS | 空 | LIST | 组织注册国(可与活动所在国不同) |
| APPLY_VAT_FOREIGN_BUSINESS | 空 | BOOLEAN | 对境外 B2B 客户征收 VAT(默认 true) |
| ENABLE_REVERSE_CHARGE_IN_PERSON | 空 | BOOLEAN | 线下票启用逆向征收(覆盖全局开关) |
| ENABLE_REVERSE_CHARGE_ONLINE | 空 | BOOLEAN | 线上票启用逆向征收(覆盖全局开关) |
| ENABLE_VIES_VALIDATION | 空 | BOOLEAN | 通过欧盟 VIES 服务校验 VAT 号(默认 true) |
5.11 RESERVATION_UI:预订流程 UI 行为(14 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| ALLOW_TICKET_DOWNLOAD | 空 | BOOLEAN | 允许下载 PDF 票(默认 true) |
| ALLOW_FREE_TICKETS_CANCELLATION | 空 | BOOLEAN | 免费票允许取消(默认 false) |
| SEND_TICKETS_AUTOMATICALLY | 空 | BOOLEAN | 确认后自动向参会者发票(默认 true) |
| SEND_RESERVATION_EMAIL_IF_NECESSARY | 空 | BOOLEAN | 仅在有交易或需补联系人信息时才发预订邮件 |
| ENABLE_TICKET_TRANSFER | 空 | BOOLEAN | 允许确认后转让票(默认 true) |
| ENABLE_ATTENDEE_AUTOCOMPLETE | 空 | BOOLEAN | 单票预订时参会者信息自动补全(默认 true) |
| FORCE_TICKET_OWNER_ASSIGNMENT_AT_RESERVATION | 空 | BOOLEAN | 预订时强制实名 |
| DISPLAY_DISCOUNT_CODE_BOX | 空 | BOOLEAN | 活动页显示优惠码输入框(默认 true) |
| USE_PARTNER_CODE_INSTEAD_OF_PROMOTIONAL | 空 | BOOLEAN | 文案改用「Partner Code」(默认 false) |
| DISPLAY_EXPIRED_CATEGORIES | 空 | BOOLEAN | 活动页显示已售罄/过期票种(默认 true) |
| DISPLAY_TICKETS_LEFT_INDICATOR | 空 | BOOLEAN | 显示余票数(默认 false) |
| ENABLE_CUSTOMER_REFERENCE | 空 | BOOLEAN | 联系信息中启用客户参考号(采购单)字段(默认 false) |
| INCLUDE_CHECK_IN_URL_ICAL | 空 | BOOLEAN | 线上票的 iCal 邀请中包含签到链接 |
| ENABLE_CAPTCHA_FOR_TICKET_SELECTION | 空 | BOOLEAN | 选票时启用验证码(默认 false) |
5.12 WAITING_LIST:候补队列(4 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| ENABLE_WAITING_QUEUE | 空 | BOOLEAN | 售罄时启用候补名单(默认 false) |
| ENABLE_WAITING_QUEUE_NOTIFICATION | 空 | BOOLEAN | 有人加入候补时邮件通知组织者 |
| ENABLE_PRE_REGISTRATION | 空 | BOOLEAN | 启用预售登记(默认 false) |
| WAITING_QUEUE_RESERVATION_TIMEOUT | 空 | TEXT | 候补转预订后的保留时长(小时) |
5.13 MAP:地图供应商(3 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| MAPS_PROVIDER | 空 | TEXT | 地图供应商(None、Google、Here),默认 None 即不启用地图 |
| MAPS_CLIENT_API_KEY | 空 | TEXT | Google Maps Client API Key(需启用 JavaScript 与 Static Maps API) |
| MAPS_HERE_API_KEY | 空 | TEXT | HERE Maps API Key |
5.14 ALFIO_PI:树莓派签到站(5 键)
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| ALFIO_PI_INTEGRATION_ENABLED | 空 | BOOLEAN | 启用 alf.io-PI 集成(默认 true) |
| OFFLINE_CHECKIN_ENABLED | 空 | BOOLEAN | 离线签到(默认 true) |
| LABEL_PRINTING_ENABLED | 空 | BOOLEAN | 胸卡打印(默认 true) |
| LABEL_LAYOUT | 空 | TEXTAREA | 胸卡版式定义 |
| CHECK_IN_COLOR_CONFIGURATION | 空 | TEXTAREA | 票种签到颜色配置 |
5.15 PASS_INTEGRATION 与 WALLET_INTEGRATION:手机钱包票券(10 键)
Apple(Pass/Passbook)与 Google Wallet 两套凭证体系,均默认关闭,启用需要向对应平台申请证书/账号:
| 键 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|
| ENABLE_PASS | 空 | BOOLEAN | 启用 Apple Wallet(默认 false) |
| PASSBOOK_TYPE_IDENTIFIER | 空 | TEXT | Pass Type ID(形如 pass.com.exampleorg.events) |
| PASSBOOK_TEAM_IDENTIFIER | 空 | TEXT | Apple 开发者 Team ID |
| PASSBOOK_KEYSTORE | 空 | TEXTAREA | 证书库(base64 编码) |
| PASSBOOK_KEYSTORE_PASSWORD | 空 | TEXT | 证书库密码 |
| PASSBOOK_PRIVATE_KEY_ALIAS | 空 | TEXT | 私钥别名 |
| ENABLE_WALLET | 空 | BOOLEAN | 启用 Google Wallet(默认 false) |
| WALLET_ISSUER_IDENTIFIER | 空 | TEXT | Google Wallet Issuer ID |
| WALLET_SERVICE_ACCOUNT_KEY | 空 | TEXTAREA | 服务账号 JSON 密钥 |
| WALLET_OVERWRITE_PREVIOUS_CLASSES_AND_EVENTS | 空 | BOOLEAN | 修改后覆盖既有 Class/Event 定义 |
💡 技术拓展:两大手机钱包票券的对比——
方案 平台 前置材料 环境限制 Apple Wallet(Pass) iOS 钱包 Apple 开发者账号 + Pass Type ID 证书 证书年审,Keystore/密码/别名三件套 Google Wallet Android 钱包 Google Wallet Issuer 账号 + 服务账号 JSON 无证书,走服务账号签发 两套互不兼容,面向混合人群时都开;仅自办中小型活动时优先把短信/邮件票(PDF)做稳,钱包票属于锦上添花。
5.16 其余小分类(RESERVATION_EMBED / IMPORT_ATTENDEE / OPENID / SUBSCRIPTIONS / TRANSLATIONS,8 键)
| 键 | 分类 | 实测当前值 | 类型 | 说明 |
|---|---|---|---|---|
| EMBED_ALLOWED_ORIGINS | RESERVATION_EMBED | 空 | TEXTAREA | 允许嵌入预订流程的来源站点(换行分隔) |
| EMBED_POST_MESSAGE_ORIGIN | RESERVATION_EMBED | 空 | TEXT | 预订成功/取消后经 PostMessage 通知的嵌入方页面地址 |
| CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEE | IMPORT_ATTENDEE | 空 | BOOLEAN | 导入的每位参会者各建一条预订 |
| SEND_TICKETS_AFTER_IMPORT_ATTENDEE | IMPORT_ATTENDEE | 空 | BOOLEAN | 导入完成后自动发票 |
| OPENID_PUBLIC_ENABLED | OPENID | 空 | BOOLEAN | 面向公众用户启用 OpenID 登录(默认 false) |
| OPENID_CONFIGURATION_JSON | OPENID | 空 | TEXTAREA | OpenID 提供方配置(JSON) |
| GENERATE_TICKETS_FOR_SUBSCRIPTIONS | SUBSCRIPTIONS | 空 | BOOLEAN | 为订阅持有者自动生成并发送联名活动票 |
| TRANSLATION_OVERRIDE | TRANSLATIONS | 空 | TEXTAREA | 界面文案覆盖(JSON) |
六、生产配置模板
以下模板面向「中小型会议/演出,2 vCPU、8GB 内存、NVMe 磁盘,Nginx 单机反代,银行转账 + 现场收款为主」的场景,文件层与平台层分开给出。全部键名与取值方式均为本文实测覆盖过的。
6.1 文件层 /opt/alfio/application.properties 模板
# Alf.io external configuration
# 数据源(仅支持 PostgreSQL)
datasource.url=jdbc:postgresql://localhost:5432/alfio
datasource.username=alfio
datasource.password=q1w2e3r4
# 对外地址:与 DNS/Nginx 一致,用户实际访问什么就写什么
alfio.base-url=https://alfio.example.local
# 监听端口(默认 8080,保持回环由 Nginx 反代时不改)
# server.port=8080
# 日志:应用包 info,排障时可临时提为 debug
logging.level.alfio=info
# 会话与压缩维持内置默认即可,如需覆盖再写
# server.servlet.session.timeout=2h
⚠️ 注意:注释掉的行仅为备查示例,启用时去掉行首
#并重启服务(systemctl restart alfio)。datasource.password与alfio.base-url两行是启动必需项,缺一不可。
6.2 systemd 单元模板(含 JVM 内存)
[Unit]
Description=Alf.io ticket reservation system
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=alfio
WorkingDirectory=/opt/alfio
ExecStart=/usr/bin/java -Xms256m -Xmx512m -jar /opt/alfio/alfio-2.0-M5-2609-boot.jar
SuccessExitStatus=143
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
逐项说明:-Xms256m -Xmx512m 将堆限制在 256–512MB(8GB 内存机器上留足给 PostgreSQL 与系统缓存);活动规模大(单场 5000 票以上、高并发开抢)时按 1GB 上调 -Xmx 并等比加内存。SuccessExitStatus=143 让 systemd 把 SIGTERM 退出视为正常,配合内置 server.shutdown=graceful 实现优雅停机。
6.3 平台层必配清单(后台 UI 或 update-bulk API 完成)
系统初始化后按此顺序补齐业务配置,全部为本文实测过的键:
BASE_URL:对外地址(首次向导必填,未配置会导致活动创建直接报错,见 7.1 节)。MAILER_TYPE=smtp+SMTP_HOST、SMTP_PORT、SMTP_PROTOCOL、SMTP_USERNAME、SMTP_PASSWORD、SMTP_FROM_EMAIL:不配则所有邮件静默入队(见 7.6 节)。- 支付开关:自托管起步建议
BANK_TRANSFER_ENABLED=true+BANK_ACCOUNT_OWNER+BANK_ACCOUNT_NR,不需要的渠道(如PAYPAL_ENABLED、STRIPE_CC_ENABLED)改为false避免购票者选中后无法完成支付。 MAX_AMOUNT_OF_TICKETS_BY_RESERVATION:按活动规模调整单笔限购(默认 5)。RESERVATION_TIMEOUT:预订保留分钟数,热门活动建议 15–30 分钟。- 反爬:对外售票开启
ENABLE_CAPTCHA_FOR_TICKET_SELECTION=true并配置 Turnstile 或 reCAPTCHA 密钥对。
批量写入示例(一次设置多个键,沿用 3.6 节实测的 API 形态):
CSRF=$(curl -sk -b /tmp/cj.txt https://localhost:8443/admin/ | sed -n 's/.*name="_csrf" content="\([^"]*\)".*/\1/p' | head -1)
curl -sk -w '\nhttp=%{http_code}\n' -b /tmp/cj.txt -H "X-CSRF-TOKEN: $CSRF" -H 'Content-Type: application/json' \
-X POST https://localhost:8443/admin/api/configuration/update-bulk \
-d '{"GENERAL":[{"key":"RESERVATION_TIMEOUT","value":"30"},{"key":"MAX_AMOUNT_OF_TICKETS_BY_RESERVATION","value":"5"}]}'
实测输出(与 3.6 节同构,写入成功返回布尔):
true
http=200
6.4 修改生效与验证流程
平台层(数据库)配置保存即生效,无需重启;文件层/环境变量/JVM 改动后执行:
systemctl restart alfio
systemctl is-active alfio
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8080/
实测输出:
active
302
💡 说明:
302即首页重定向到alfio.base-url(2.1 节同源行为),代表应用已正常对外服务。
七、常见问题
以下问题全部来自本实例实测过程,按「现象 → 定位 → 解决」组织。
Q1:通过 API 创建活动报 500 Mandatory configuration key BASE_URL not present,怎么办?
现象:POST /api/v1/admin/event/create 返回 500,响应体含 Mandatory configuration key BASE_URL not present。
定位:系统级 BASE_URL 平台键未配置。注意它独立于文件层的 alfio.base-url——文件层只管应用自身的重定向与链接,业务层 BASE_URL 是活动元数据的必需键。
解决:会话登录后用 update-bulk 补齐(实测以 https://alfio.example.local 落库,随后创建活动即成功):
CSRF=$(curl -sk -b /tmp/cj.txt https://localhost:8443/admin/ | sed -n 's/.*name="_csrf" content="\([^"]*\)".*/\1/p' | head -1)
curl -sk -w '\nhttp=%{http_code}\n' -b /tmp/cj.txt -H "X-CSRF-TOKEN: $CSRF" -H 'Content-Type: application/json' \
-X POST https://localhost:8443/admin/api/configuration/update-bulk \
-d '{"GENERAL":[{"key":"BASE_URL","value":"https://alfio.example.local"}]}'
PGPASSWORD=q1w2e3r4 psql -h localhost -U alfio -d alfio -t -c "select id, c_key, c_value from configuration where c_key='BASE_URL'"
实测输出:
true
http=200
14 | BASE_URL | https://alfio.example.local
Q2:本机 curl http://localhost:8080/ 被重定向到 8443,是配置错了吗?
现象:直连 8080 返回 302,Location 指向 https://localhost:8443/admin/。
定位:alfio.base-url=https://alfio.example.local 决定了应用对外的统一地址,所有入口都会归一到该地址(2.1 节实测 302 -> https://localhost:8443/)。这是设计行为,不是故障。
解决:本机调试直接走 https://localhost:8443(Nginx,自签证书加 -k);生产环境把 alfio.base-url 改为真实域名并同步更新平台层 BASE_URL 即可。
Q3:API 调用频繁返回 302,或写入操作报 CSRF 失败,怎么排查?
现象:携带了 Cookie 的请求仍被 302 到登录页;或 POST 返回 302/404(/session-expired)。
定位:Alf.io 的会话 Cookie 实测带 Secure 标志(响应头形如 Set-Cookie: ALFIO_SESSION=NWQ3NDRhNTUtZDU3Ni00ZGIzLWFlZWUtZWRiYjIzMWYxZjg4; Path=/; Secure; HttpOnly; SameSite=Strict),HTTP 明文连接上不会回传,等于会话丢失;写入类请求另需 CSRF 头。
解决:一律走 HTTPS 入口(生产经 Nginx 8443);CSRF 取值有三种实测可用方式——登录页隐藏域 _csrf(表单登录用)、后台页 <meta name="_csrf"> 转 X-CSRF-TOKEN 头(管理 API 用)、/api/v2/public/** 响应头 XSRF-TOKEN 转 X-CSRF-TOKEN 头(公开 API 用)。
Q4:把某个键的值清空后,数据库里怎么还有这行?
现象:update-bulk 传空值「删除」配置后,configuration 表行仍在。
定位与说明:实测(3.6 节)清空操作把 c_value 置为空字符串、行保留(value: ""),这正是平台的「恢复到内置默认」语义——空值即未设置,取值回退到内置默认或上级层级。属正常行为,无需手工删行。
Q5:活动级单键接口返回 204 是坏了吗?
现象:GET /admin/api/configuration/events/{slug}/single/{key} 返回 204 无响应体。
定位与说明:204 表示该键未在活动层级显式覆盖(3.6 节实测 BASE_URL、SPECIAL_PRICE_CODE_LENGTH、RESERVATION_TIMEOUT、ANNOUNCEMENT_BANNER_CONTENT 均为 204);有内置默认值的键(实测 MAX_AMOUNT_OF_TICKETS_BY_RESERVATION)返回默认生效值。想改活动级值,用该层级的 update-bulk 接口或后台活动设置页写入后即可读到 200。
Q6:票卖出去了,购票者说没收到邮件?
现象:预订成功但无邮件;数据库 email_message 表有排队记录。
定位:MAILER_TYPE 为空——官方定义「不设置则默认禁用」,此时邮件只入队不发送。
解决:按 6.3 节第 2 步配置 SMTP 最小集,后台保存即可(平台层配置无需重启)。补配后排队邮件会按 MAX_EMAIL_PER_CYCLE(默认每 5 秒一批)逐步发出;历史积压在后台邮件页面可查看状态。
Q7:想重新生成管理员密码,重启后报唯一键冲突 unique_username,怎么办?
现象:仅删除 INIT_COMPLETED 标记后重启,启动失败,日志报 ERROR: duplicate key value violates unique constraint "unique_username"、Detail: Key (username)=(admin) already exists.。
定位:重新初始化会再次插入 admin 账号,旧账号还在 ba_user 表中就会撞唯一约束。
解决:先备份数据库,再同时删除初始化标记与 admin 账号行,重启后走完整初始化并生成新密码(实测日志 here the generated admin credentials: 下一行即新密码):
PGPASSWORD=q1w2e3r4 psql -h localhost -U alfio -d alfio \
-c "delete from ba_user where username='admin'" \
-c "delete from configuration where c_key='INIT_COMPLETED'"
systemctl restart alfio
journalctl -u alfio --no-pager | grep -A1 'generated admin credentials' | tail -2
实测输出(删除 1 行、重启后生成新凭据):
DELETE 1
here the generated admin credentials:
NNtHfOzVERRyVRB6j
⚠️ 注意:该操作会重置管理员账号,其余业务数据(活动、订单)不受影响,但请务必先备份(安装篇 7.4 节的
pg_dump命令)。
八、参考链接
- Alf.io 官方网站:https://alf.io/
- 官方文档(Basic Configuration / Event Setup / Configuration 各章节):https://alf.io/docs/
- GitHub 仓库(源码中
application.properties默认值与配置键定义):https://github.com/alfio-event/alf.io - 版本发布页(2.0-M5-2609):https://github.com/alfio-event/alf.io/releases
- 站内相关文档:《Alf.io 2.0-M5-2609 介绍与选型指南》、《Ubuntu 22.04 安装 Alf.io 2.0-M5-2609 指南》