配置外部服务
FeedLog 可以使用四类可选的外部服务:OAuth 登录、邮件、文件存储和模型接口。不配置这些服务也能运行实例,但相关功能可能会停用或改用备用方式,而且通常不会导致启动报错。下面分别说明需要配置什么、不配置时的实际行为,以及如何判断常见故障。完整的变量清单见代码仓库中的 docs/configuration.md。
登录方式
Google 和 GitHub 分别配置。只有同时设置同一组中的两个变量,对应的登录方式才会启用:
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=登录框只显示配置完整的方式。如果一组变量只设置了其中一个,对应的按钮不会出现。
**不配的话:**默认仍可使用邮箱和密码登录。
只有在没有配置任何 OAuth 服务商时,邮箱密码登录才会自动启用。如果给现有实例添加 Google 或 GitHub,重启后密码登录表单会消失。要同时保留两种登录方式,请设置 AUTH_EMAIL_ENABLED=true。
回调地址
在服务商处登记的回调地址必须与 FeedLog 实际发送的地址完全一致:
https://feedback.yourdomain.com/api/auth/callback/google
https://feedback.yourdomain.com/api/auth/callback/github协议、域名、端口和路径都必须匹配。请使用用户访问 FeedLog 时使用的公开地址。一个 GitHub OAuth App 只能设置一个回调地址,因此预发布环境需要单独创建 App。
在反向代理后面
FeedLog 默认从请求的 Host 头推断对外地址;如果代理设置了 X-Forwarded-Proto,则从该请求头读取协议。FeedLog 不会读取 X-Forwarded-Host。重启后的第一个请求所确定的地址会缓存在当前进程中。
代理保留原始 Host 时,这项推断可以正常工作,Caddy 和 Traefik 默认会这样处理。nginx 只配置 proxy_pass 时会把 Host 替换为上游地址。此后 FeedLog 生成的绝对地址会使用该内网地址,包括 OAuth 的 redirect_uri、密码重置和邮箱验证链接,以及通知邮件中的链接。如果健康检查在首个公开请求之前直接访问容器,FeedLog 也可能缓存容器的内网地址。
可以在代理中保留原始 Host(proxy_set_header Host $host;),也可以显式设置对外地址:
BETTER_AUTH_URL=https://feedback.yourdomain.com结尾不要带斜杠。对于反向代理后的部署,建议显式设置这个值。
常见错误
Google 报 redirect_uri_mismatch,或者 GitHub 报 "The redirect_uri is not associated with this application" —— 错误页面的地址中包含 FeedLog 发送的 redirect_uri,请将它原样登记。如果该值使用内网地址或以 http 开头,请修改代理配置,而不是 OAuth App。
登录完成后跳到了其他域名 —— FeedLog 推断出了错误的对外地址。请设置 BETTER_AUTH_URL。
Google 或 GitHub 的按钮没有出现 —— 对应的一组变量只设置了其中一个。
添加 OAuth 后密码登录消失了 —— 配置 OAuth 后默认会关闭密码登录。请设置 AUTH_EMAIL_ENABLED=true。
修改 AUTH_EMAIL_ENABLED 后应用无法启动 —— 如果关闭邮箱登录且没有配置任何 OAuth 服务商,启动检查会失败。注意,空值表示关闭,不表示未设置。
邮件
RESEND_API_KEY=
EMAIL_FROM=[email protected]
EMAIL_PROVIDER=resend # Optional; Resend is currently the only implemented provider目前只实现了 Resend。EMAIL_PROVIDER 用于按名称选择已注册的服务商,因此设置 RESEND_API_KEY 即可注册 Resend。
请将 EMAIL_FROM 设置为已经通过 Resend 域名验证的发件地址。如果不设置,邮件会使用 Resend 的公共 onboarding 地址发送,而该地址可能只允许向账号所有者本人发送邮件。
FeedLog 会发送以下五类邮件:
| 邮件 | 什么时候发 |
|---|---|
| 邮箱验证 | 有人注册新账号 |
| 密码重置 | 有人申请重置 |
| 密码已设置 | 用 OAuth 注册的账号新设了密码 |
| 工作区邀请 | 管理员邀请成员 |
| 通知 | 关注的反馈状态变了,或者收到了管理员的正式回复 |
通知会发送给关注这条反馈的人,包括作者和投过票的用户;工作区所有者、管理员以及触发该事件的用户除外。只有管理员选择公布状态变更时才会发送通知;仅修改状态不会发送邮件。FeedLog 不发送新反馈或新评论邮件。
**不配的话:**系统不会发送邮箱验证、密码重置和邀请邮件。通知邮件会写入日志,而不会发送给收件人([DEV EMAIL] to=… subject=…,后面跟着链接),并且不会返回错误。无法登录的用户不能通过密码重置恢复访问;管理员需要从成员页面手动复制邀请链接。
AUTH_EMAIL_VERIFY 控制登录前是否必须验证邮箱。未设置时,如果存在 RESEND_API_KEY,邮箱验证会自动启用。设置为 true 或 false 可以覆盖默认行为。
常见错误
只有账号所有者能收到邮件,其他人收不到 —— 未设置 EMAIL_FROM,当前使用的是 Resend 的公共 onboarding 发件地址。
没有收到邮件,也没有显示错误 —— 在启动日志中查找 Registered email provider: resend。如果注册的是 console,说明进程没有读取到 RESEND_API_KEY。
注册成功后无法登录 —— 设置了 AUTH_EMAIL_VERIFY=true,但没有配置邮件服务。账号已经创建,但系统不会发送验证链接,也不会将链接写入日志,因此无法完成邮箱验证。密码重置也不可用。
邮件中的链接指向了错误的域名 —— FeedLog 从 Host 头推断出了错误的对外地址。请设置 BETTER_AUTH_URL。无法获取这个值时,邀请链接会使用 http://localhost:3000。
文件存储
反馈和更新日志支持图片附件,单张图片不能超过 10 MB。存储方式和配置方法取决于部署平台;只有 Docker 和 Node 部署使用 S3_* 变量:
| 平台 | 存储 | 你要配的 |
|---|---|---|
| Docker / Node | S3 兼容存储,或本地磁盘 | S3_* |
| Vercel | Vercel Blob | 接一个 Blob store,token 会自动注入 |
| Cloudflare Workers | R2 | 在 wrangler.toml 里把存储桶绑定为 BLOB |
三个变量是必填的,另外两个至少要有一个:
S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=
S3_BUCKET=feedlog
S3_ENDPOINT=https://<account>.r2.cloudflarestorage.com # Non-AWS services
S3_REGION=us-east-1 # AWS S3FeedLog 支持 R2、MinIO、Backblaze、Wasabi、阿里云 OSS、腾讯云 COS、七牛等兼容 S3 协议的服务。凭据在运行时读取,因此更换密钥后只需重启应用,不需要重新构建。
存储桶不需要公开可读。文件存储在 <UPLOAD_PREFIX>/<工作区 id>/ 下,并通过 FeedLog 的 /api/files/ 路由读取。UPLOAD_PREFIX 默认为 uploads,可用于区分共用同一存储桶的多个环境。系统会保存每个文件的完整路径,因此以后修改前缀不会影响已有附件。
**在 Docker 上不配的话:**上传文件会写入容器内的 /app/.data/blob。如果 /app/.data 没有挂载卷,删除容器时也会删除这些文件;仓库中的 compose.yml 已包含该挂载。Vercel 和 Workers 不提供本地磁盘备用方案,因此未连接 Blob store 或未绑定 R2 时,上传会失败。
常见错误
上传成功,但重新部署后文件消失 —— 当前使用本地磁盘,而 /app/.data 没有挂载卷。
已经配置 S3,但文件仍写入本地磁盘 —— 只有同时设置 S3_ACCESS_KEY_ID、S3_SECRET_ACCESS_KEY 和 S3_BUCKET,系统才会注册 S3 服务;缺少变量时不会报错。请确认启动日志中存在 Registered blob provider: s3。
S3 disabled: set S3_REGION (for AWS) or S3_ENDPOINT (for R2/MinIO/OSS) —— 已设置三个必填变量,但没有设置 S3_REGION 或 S3_ENDPOINT,因此驱动无法确定主机名。
上传到阿里云 OSS 失败 —— 阿里云 OSS 可能要求使用 virtual-hosted 风格。保留 S3_BUCKET,并将 S3_ENDPOINT 指向包含 bucket 的域名:https://<bucket>.oss-cn-hangzhou.aliyuncs.com。
AI 功能
OPENAI_API_KEY=
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_TEXT_MODEL=OPENAI_API_KEY 决定是否启用 AI 功能。另外两个变量都有默认值,也不会单独生效,因此只设置 base URL 不会启用这些功能。
有三个功能使用模型接口。未配置 key 时,它们的行为如下:
| 功能 | 没有 key 时 |
|---|---|
| 相似反馈检测与搜索 | 改用 trigram 文本匹配 |
| 更新日志 AI 起草 | 按钮还在,点下去报错 |
| 反馈组件的消息识别 | 消息提交失败 |
有 key 时,新反馈会生成向量并按语义匹配,因此“用 Google 登不上”可以匹配“SSO 挂了”。没有 key 时,搜索会改用 PostgreSQL 的 trigram 文本距离。系统仍会返回最接近的结果,但只比较文字写法,可能漏掉表述不同的重复反馈。界面不会显示当前使用的是哪种匹配方式。
缺少 key 时,更新日志编辑器仍会显示 AI 起草按钮。管理员选择风格并开始生成后,对话框会显示 AI generation is not configured (OPENAI_API_KEY missing)。
反馈组件需要通过模型接口将用户消息转换为结构化反馈。没有 key 时,消息提交会失败,终端用户会看到 Could not send that. Please try again.。启用反馈组件前必须配置这个 key。
关闭 AI 时创建的反馈没有向量,FeedLog 之后也不会自动补充。这些反馈不会参与语义匹配,除非运行仓库中的 scripts/backfill-search.ts 补齐向量。
使用自托管模型接口
OPENAI_BASE_URL 接受兼容 OpenAI API 的接口,包括 LiteLLM 或 vLLM 网关、Ollama,以及其他服务商提供的接口。如果该接口运行在你的网络内,发送给模型的反馈内容也会保留在网络内。
同一个 base URL 同时用于对话请求和向量请求,因此指向单个部署的 Azure URL 只能支持其中一种请求。FeedLog 使用 text-embedding-3-large 请求 768 维向量,数据库字段也要求 768 维。如果接口不能返回这种格式,相似反馈检测会改用 trigram 文本匹配。OPENAI_TEXT_MODEL 只选择对话模型,不影响向量模型。
常见错误
更新日志编辑器显示 "AI generation is not configured" —— 进程没有读取到 OPENAI_API_KEY。在 Workers 上,它是 secret(wrangler secret put OPENAI_API_KEY),不是 [vars] 中的配置项。
添加 key 后,语义相似推荐中仍缺少旧反馈 —— 这些反馈创建时没有生成向量。请运行补齐脚本。
网关在一个功能上返回 404,另一个功能正常 —— base URL 指向了单个部署。请改用可以同时转发 /chat/completions 和 /embeddings 的网关。
反馈组件发送消息失败,界面只显示通用错误 —— 请在服务端日志中查看具体错误。