Alf.io 2.0-M5-2609 配置参数详解

深入讲解 Alf.io 2.0-M5-2609 的四层配置体系(属性文件、环境变量、JVM 参数与数据库四级业务配置),逐键给出 21 分类 164 个配置键的实测当前值与说明,全部命令与回显实测于 Ubuntu 22.04。

Alf.ioAlf.io票务2026/10/23

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 四层配置载体与生效优先级

实测归纳的四层载体如下表(优先级从高到低,上层覆盖下层):

层级载体位置典型内容生效方式
1JVM 启动参数systemd 单元 ExecStart 行-Xms256m -Xmx512msystemctl daemon-reload && systemctl restart alfio
2环境变量systemd 单元或启动命令前缀SERVER_PORT=8096重启进程(标准 Spring Boot 宽松绑定,SERVER_PORT 即 server.port)
3外部属性文件/opt/alfio/application.propertiesdatasource.*、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.urljdbc:postgresql://localhost:5432/alfio外部文件JDBC 连接串,仅支持 PostgreSQL
datasource.usernamealfio外部文件数据库账号
datasource.passwordq1w2e3r4外部文件数据库口令(测试口令,生产必换)
alfio.base-urlhttps://alfio.example.local外部文件对外基础地址,重定向与链接生成依据
server.port / SERVER_PORT8080(内置默认,未显式写)内置/环境变量HTTP 监听端口,实测可覆盖为 8096
logging.level.rootwarnjar 内置根日志级别
logging.level.alfioinfojar 内置应用日志级别
server.servlet.session.timeout2hjar 内置会话超时
server.servlet.session.cookie.http-onlytruejar 内置会话 Cookie 防脚本读取
server.compression.enabledtruejar 内置响应压缩
server.forward-headers-strategynativejar 内置信任反代 X-Forwarded-* 头
server.shutdowngracefuljar 内置优雅停机
spring.application.nameAlf.iojar 内置应用名
-Xms / -Xmx256m / 512msystemd ExecStartJVM 初始/最大堆

解读:日常运维改动频率最高的是前四行与端口/堆参数;jar 内置默认一般不动,需要覆盖时写进外部文件即可(3.2 节)。

4.2 平台业务配置:21 分类 164 键总览

这一层的 164 个键按 21 个分类组织(3.6 节实测统计)。分类一览与本文详解章节对应如下:

分类键数主题详解章节
GENERAL31站点通用(含 BASE_URL、验证码、GA、安全头)5.1
MAIL24邮件通道与行为5.2
PAYMENT7支付通用(平台费、黑名单)5.3
PAYMENT_OFFLINE16银行转账/线下/Revolut5.4
PAYMENT_STRIPE8Stripe5.5
PAYMENT_PAYPAL6PayPal5.6
PAYMENT_MOLLIE7Mollie5.7
PAYMENT_SAFERPAY6Saferpay5.8
INVOICE9发票通用5.9
INVOICE_EU6欧盟 VAT/逆向征收5.10
RESERVATION_UI14预订流程 UI 行为5.11
WAITING_LIST4候补队列5.12
MAP3地图供应商5.13
ALFIO_PI5树莓派签到站5.14
PASS_INTEGRATION6Apple Wallet 票券5.15
WALLET_INTEGRATION4Google Wallet 票券5.15
RESERVATION_EMBED2前台嵌入5.16
IMPORT_ATTENDEE2参会者导入5.16
OPENID2OpenID 登录5.16
SUBSCRIPTIONS1订阅票5.16
TRANSLATIONS1文案覆盖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_URLhttps://alfio.example.localTEXT对外基础地址,后台必填项(basic),与 alfio.base-url 保持一致
RESERVATION_TIMEOUT空TEXT预订保留时长(分钟),超时自动释放
RESERVATION_MIN_TIMEOUT_AFTER_FAILED_PAYMENT空TEXT支付失败后至少保留的时长(分钟)
MAX_AMOUNT_OF_TICKETS_BY_RESERVATION5TEXT单笔预订最多票数(默认 5),已落库
SPECIAL_PRICE_CODE_LENGTH6TEXT特价/推广码长度(默认 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空TEXTGoogle Analytics 跟踪 ID
GOOGLE_ANALYTICS_ANONYMOUS_MODEtrueBOOLEANGA 匿名模式(无 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空TEXTreCAPTCHA v2 站点密钥
RECAPTCHA_SECRET空TEXTreCAPTCHA v2 服务端密钥
SECURITY_CSP_REPORT_ENABLED空BOOLEAN启用 Content-Security-Policy 上报(默认 false)
SECURITY_CSP_REPORT_URI空TEXTCSP 上报地址(默认 /report-csp-violation)
CF_TURNSTILE_ENABLED空BOOLEAN启用 Cloudflare Turnstile(默认 false)
CF_TURNSTILE_SITE_KEY空TEXTTurnstile 站点密钥
CF_TURNSTILE_SECRET_KEY空TEXTTurnstile 服务端密钥
CF_TURNSTILE_PRE_CLEARANCE空BOOLEAN使用 Turnstile 预清除模式(默认 false)

💡 技术拓展:验证码方案不止一种。Alf.io 内置两类——

方案原理/特点适用场景
reCAPTCHA v2Google 系,勾选框/图片挑战,键为 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空TEXTSMTP 主机(MAILER_TYPE=smtp 时生效)
SMTP_PORT空TEXTSMTP 端口
SMTP_PROTOCOL空TEXT协议(smtp 或 smtps)
SMTP_USERNAME空TEXTSMTP 用户名
SMTP_PASSWORD空TEXTSMTP 密码
SMTP_FROM_EMAIL空TEXT发件人地址
SMTP_PROPERTIES空TEXTAREA附加 SMTP 属性(JavaMail 属性串)
MAILGUN_KEY空TEXTMailgun API Key(MAILER_TYPE=mailgun 时生效)
MAILGUN_DOMAIN空TEXTMailgun 域名
MAILGUN_FROM空TEXTMailgun 发件人
MAILGUN_EU空BOOLEAN使用 Mailgun 欧盟区域
MAILJET_APIKEY_PUBLIC空TEXTMailjet 公钥(MAILER_TYPE=mailjet 时生效)
MAILJET_APIKEY_PRIVATE空TEXTMailjet 私钥
MAILJET_FROM空TEXTMailjet 发件人
SENDGRID_API_KEY空TEXTSendGrid API Key(MAILER_TYPE=sendgrid 时生效)
SENDGRID_FROM空TEXTSendGrid 发件人
ENABLE_HTML_EMAILS空BOOLEANHTML 邮件(默认 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 服务器,最通用已有邮件基础设施
MailgunHTTP API 托管发送,送达率高,支持 EU 区域不想维护 SMTP 的中小站
MailjetHTTP API 托管发送,欧洲服务商欧盟活动组织者
SendGridHTTP API 托管发送美区/大规模发送

本实例 MAILER_TYPE 为空,邮件发送处于禁用状态(这正是「票买了但收不到邮件」的首要排查点,见 7.6 节)。生产建议首选 SMTP 自有域名发送,退信可控。

5.3 PAYMENT:支付通用(7 键)

支付域的公共参数:平台费与支付方式黑名单。具体渠道在 5.4–5.8 节。

键实测当前值类型说明
ON_SITE_ENABLEDtrueBOOLEAN现场现金支付开关,已落库
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_OFFLINEBANK_TRANSFER_ENABLED 等否,填自己账户
现场支付PAYMENTON_SITE_ENABLED否
StripePAYMENT_STRIPESTRIPE_CC_ENABLED是,Stripe 账号
PayPalPAYMENT_PAYPALPAYPAL_ENABLED是,PayPal REST 应用
MolliePAYMENT_MOLLIEMOLLIE_CC_ENABLED是,Mollie 账号
SaferpayPAYMENT_SAFERPAYSAFERPAY_ENABLED是,Saferpay 终端
Revolut(对账)PAYMENT_OFFLINEREVOLUT_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_ENABLEDtrueBOOLEAN银行转账开关,已落库
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空TEXTRevolut API Key
REVOLUT_LIVE_MODE空BOOLEANRevolut 生产模式
REVOLUT_MANUAL_REVIEW空BOOLEAN交易人工核对(默认 true)

⚠️ 注意:银行转账要真正可用,除开关联开关外,BANK_ACCOUNT_OWNER 与 BANK_ACCOUNT_NR 必须填写,否则购票者在支付步骤看不到可执行的转账说明。

5.5 PAYMENT_STRIPE:Stripe(8 键)

键实测当前值类型说明
STRIPE_CC_ENABLEDtrueBOOLEANStripe 开关,已落库(还需密钥才算可用)
STRIPE_PUBLIC_KEY空TEXTStripe 公钥(pk_live/pk_test)
STRIPE_SECRET_KEY空TEXTStripe 私钥(sk_live/sk_test)
STRIPE_WEBHOOK_KEY空TEXT账户级事件 Webhook 签名密钥
STRIPE_WEBHOOK_PAYMENT_KEY空TEXT支付 Webhook 签名密钥
STRIPE_ENABLE_SCA空BOOLEAN启用强客户认证(SCA,欧洲卡合规)
STRIPE_CONNECT_CALLBACK空TEXTStripe Connect 回调地址
STRIPE_CONNECT_CLIENT_ID空TEXTStripe Connect Client ID

5.6 PAYMENT_PAYPAL:PayPal(6 键)

键实测当前值类型说明
PAYPAL_ENABLEDtrueBOOLEANPayPal 开关,已落库(还需 REST 凭据)
PAYPAL_CLIENT_ID空TEXTPayPal REST Client ID
PAYPAL_CLIENT_SECRET空TEXTPayPal 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空BOOLEANMollie 开关
MOLLIE_API_KEY空TEXTMollie API Key
MOLLIE_CONNECT_CLIENT_ID空TEXTMollie Connect Client ID
MOLLIE_CONNECT_CLIENT_SECRET空TEXTMollie Connect Client Secret
MOLLIE_CONNECT_PROFILE_ID空TEXTMollie Profile ID
MOLLIE_CONNECT_CALLBACK空TEXTMollie Connect 回调地址
MOLLIE_CONNECT_LIVE_MODE空BOOLEANMollie Connect 生产模式(默认 false)

5.8 PAYMENT_SAFERPAY:Saferpay(6 键)

键实测当前值类型说明
SAFERPAY_ENABLED空BOOLEANSaferpay 开关
SAFERPAY_CUSTOMER_ID空TEXTSaferpay 客户号
SAFERPAY_TERMINAL_ID空TEXTSaferpay 终端号
SAFERPAY_API_USERNAME空TEXTAPI 用户名
SAFERPAY_API_PASSWORD空TEXTAPI 密码
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空TEXTGoogle Maps Client API Key(需启用 JavaScript 与 Static Maps API)
MAPS_HERE_API_KEY空TEXTHERE 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空TEXTPass Type ID(形如 pass.com.exampleorg.events)
PASSBOOK_TEAM_IDENTIFIER空TEXTApple 开发者 Team ID
PASSBOOK_KEYSTORE空TEXTAREA证书库(base64 编码)
PASSBOOK_KEYSTORE_PASSWORD空TEXT证书库密码
PASSBOOK_PRIVATE_KEY_ALIAS空TEXT私钥别名
ENABLE_WALLET空BOOLEAN启用 Google Wallet(默认 false)
WALLET_ISSUER_IDENTIFIER空TEXTGoogle 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 WalletAndroid 钱包Google Wallet Issuer 账号 + 服务账号 JSON无证书,走服务账号签发

两套互不兼容,面向混合人群时都开;仅自办中小型活动时优先把短信/邮件票(PDF)做稳,钱包票属于锦上添花。

5.16 其余小分类(RESERVATION_EMBED / IMPORT_ATTENDEE / OPENID / SUBSCRIPTIONS / TRANSLATIONS,8 键)

键分类实测当前值类型说明
EMBED_ALLOWED_ORIGINSRESERVATION_EMBED空TEXTAREA允许嵌入预订流程的来源站点(换行分隔)
EMBED_POST_MESSAGE_ORIGINRESERVATION_EMBED空TEXT预订成功/取消后经 PostMessage 通知的嵌入方页面地址
CREATE_RESERVATION_FOR_EACH_IMPORTED_ATTENDEEIMPORT_ATTENDEE空BOOLEAN导入的每位参会者各建一条预订
SEND_TICKETS_AFTER_IMPORT_ATTENDEEIMPORT_ATTENDEE空BOOLEAN导入完成后自动发票
OPENID_PUBLIC_ENABLEDOPENID空BOOLEAN面向公众用户启用 OpenID 登录(默认 false)
OPENID_CONFIGURATION_JSONOPENID空TEXTAREAOpenID 提供方配置(JSON)
GENERATE_TICKETS_FOR_SUBSCRIPTIONSSUBSCRIPTIONS空BOOLEAN为订阅持有者自动生成并发送联名活动票
TRANSLATION_OVERRIDETRANSLATIONS空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 完成)

系统初始化后按此顺序补齐业务配置,全部为本文实测过的键:

  1. BASE_URL:对外地址(首次向导必填,未配置会导致活动创建直接报错,见 7.1 节)。
  2. MAILER_TYPE=smtp + SMTP_HOST、SMTP_PORT、SMTP_PROTOCOL、SMTP_USERNAME、SMTP_PASSWORD、SMTP_FROM_EMAIL:不配则所有邮件静默入队(见 7.6 节)。
  3. 支付开关:自托管起步建议 BANK_TRANSFER_ENABLED=true + BANK_ACCOUNT_OWNER + BANK_ACCOUNT_NR,不需要的渠道(如 PAYPAL_ENABLED、STRIPE_CC_ENABLED)改为 false 避免购票者选中后无法完成支付。
  4. MAX_AMOUNT_OF_TICKETS_BY_RESERVATION:按活动规模调整单笔限购(默认 5)。
  5. RESERVATION_TIMEOUT:预订保留分钟数,热门活动建议 15–30 分钟。
  6. 反爬:对外售票开启 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 命令)。

八、参考链接