在 Cloudflare Containers 上以 Pollinations 为唯一登录方托管 Open WebUI:OAuth 2.1 集成、无 Docker 镜像策略与运维实战

📅 发布时间:2026/10/14 17:32:14
在 Cloudflare Containers 上以 Pollinations 为唯一登录方托管 Open WebUI:OAuth 2.1 集成、无 Docker 镜像策略与运维实战
AI 应用媒体生成后端前端【免费下载链接】pollinationsYour Friendly Open-Source Gen-AI Platform项目地址https://gitcode.com/gh_mirrors/po/pollinations点击查看免费下载本篇技术指南围绕 apps/openwebui 的完整实现展开该应用将开源聊天前端 Open WebUI 托管在 Cloudflare Containers 上把 Pollinations 账号体系作为唯一登录入口让用户用自己的钱包Pollen 余额为每一次对话付费。读完本文你将掌握这套架构的文件布局、OAuth 2.1 PKCE 登录链路的底层实现、配置只种入一次的机制、MCP 工具服务器与内建工具的冲突处理以及镜像更新、容器重启、区域约束和完整部署流程。项目概览一个自带钱包计费的托管 Open WebUI该应用托管了开源项目 Open WebUI但把 Pollinations 作为其唯一登录提供方用户使用 Pollinations 账号登录授权同意页consent screen会铸造一把带预算的sk_密钥Open WebUI 以auth_type: system_oauth将这把密钥按用户转发给gen.pollinations.ai因此每次聊天都从登录用户自己的钱包扣费而不是消耗某个共享账户的额度。当前有两个运行环境公网https://openwebui.pollinations.ai源站https://openwebui.myceli.ai预发布staginghttps://openwebui-staging.elliot-b6e.workers.dev登录协议为 OAuth 2.1 授权码authorization code PKCE面向 Pollinations 环境的 Enter URL 做发现使用公开客户端public client无 client secret。发现文档是 RFC 8414 的授权服务器元数据Pollinations 侧不提供openid-configuration别名。布局七份文件各司其职整个应用由以下文件构成职责划分非常清晰文件职责worker.jsContainer 类把 Open WebUI 的每个设置暴露为环境变量并附带一个 keepalive 定时任务ui-defaults.js新用户第一眼看到的固定模型、提示建议与横幅scripts/apply-ui-defaults.mjs通过 admin API 把这些默认值写入已存在的数据库wrangler.jsonc容器预构建镜像、自定义域名、staging 环境配置scripts/push-image.sh把上游镜像镜像到 Cloudflare registryscripts/push-secrets.mjs把secrets/secrets.vars.jsonsops 加密推送到 Workerdeploy.json被production分支上的Deploy / Applications工作流自动拾取依赖关系见 package.json运行时依赖只有cloudflare/containers^0.3.7开发依赖是wrangler^4.110.0Node 要求22。npm scripts 提供了checkwrangler deploy --dry-run、deploy、deploy:staging、push-secrets、push-secrets:staging、push-image、containers:list与containers:images等运维入口。无 Dockerfile 的镜像策略这个项目没有 Dockerfile。原因很直接Cloudflare Containers 无法直接拉取ghcr.io因此上游的-slim镜像需要先一次性推送到registry.cloudflare.com再由 wrangler.jsonc 引用。这样本地和 CI 的部署都不需要 DockerCI 也从不构建镜像。镜像推送由 scripts/push-image.sh 完成核心步骤# 需要一个 Docker daemon本机没有的话可指向 monitoring-agents 的 EC2 Docker Engine DOCKER_HOSTssh://community-monitor npm run push-image -- 0.11.3 # push-image.sh 内部执行 # docker pull --platform linux/amd64 ghcr.io/open-webui/open-webui:v0.11.3-slim # docker tag ... open-webui:0.11.3-slim # npx wrangler containers push open-webui:0.11.3-slim注意脚本把拉取平台固定为linux/amd64注释说明这是因为 Containers 运行在 amd64即便 EC2 机器本身是 arm64。推送完成后脚本会提示把wrangler.jsonc中两个环境production 与 staging的containers[].image更新为registry.cloudflare.com/b6ec751c0862027ba269faf7029b2501/open-webui:0.11.3-slim。容器配置中还包含max_instances: 1单实例、生产instance_type: standard-4、stagingstandard-1、constraints.regions: [ENAM]以及 Durable Object 绑定OPENWEBUI迁移标记new_sqlite_classes: [OpenWebUIContainer]。worker.js 中OpenWebUIContainer类定义了defaultPort 8080、requiredPorts [8080]、sleepAfter 30m容器 30 分钟无请求即休眠。状态管理Postgres 是唯一真相磁盘是易失的容器磁盘每次休眠sleep后都会被清空所以所有持久状态都放在 Postgres 中monitoring-agents机器上的一个实例承载openwebui与openwebui_staging两个数据库。DATABASE_URL里存有用户、聊天记录、配置以及 pgvector 向量存储VECTOR_DB: pgvector。有两个易被忽略的边界条件上传文件仍在本机磁盘上重启后不保留当上传文件变得重要时应通过STORAGE_PROVIDERs3切到 R2。RAG 嵌入在本地完成使用随镜像捆绑的sentence-transformers/all-MiniLM-L6-v2即不设置RAG_EMBEDDING_ENGINE。这是因为 RAG、图片、音频子系统都用单一静态密钥认证而不是聊天连接所用的每用户 OAuth token——若把它们指向 gen会把所有用户的文档计费到同一个钱包。本地嵌入的代价是重启后需要向临时磁盘下载约 90 MB 模型。密钥按环境放在 secrets/secrets.vars.jsonsops 加密只有两个WEBUI_SECRET_KEY会话签名密钥更改会登出所有用户DATABASE_URLPostgres 连接串staging 用独立数据库。scripts/push-secrets.mjs 会强制校验这两个密钥都存在然后通过wrangler secret bulk写入对应环境--env staging或 production。登录链路Pollinations OAuth 2.1 PKCE 的完整闭环Open WebUI 侧的身份配置全部集中在 worker.js 的envVars中ENABLE_OAUTH_SIGNUP: true # 允许通过 OAuth 注册 OAUTH_PROVIDER_NAME: Pollinations OAUTH_CLIENT_ID: 来自 varspk_ 开头 OAUTH_CLIENT_SECRET: # 必须保持为空见下文 OAUTH_CODE_CHALLENGE_METHOD: S256 OPENID_PROVIDER_URL: ${ENTER_URL}/.well-known/oauth-authorization-server OPENID_REDIRECT_URI: ${WEBUI_URL}/oauth/oidc/callback OAUTH_SCOPES: profile OAUTH_USERNAME_CLAIM: name OAUTH_EMAIL_CLAIM: email OAUTH_PICTURE_CLAIM: picture OAUTH_AUTHORIZE_PARAMS: {expiry: 365, budget: 20} OAUTH_MERGE_ACCOUNTS_BY_EMAIL: true OAUTH_AUTO_REDIRECT: true ENABLE_LOGIN_FORM: false # Pollinations 是唯一入口 ENABLE_PASSWORD_AUTH: false ENABLE_SIGNUP: false DEFAULT_USER_ROLE: user # 有 Pollinations 账号即可聊天用各自 pollen 付费从 enter.pollinations.ai/src/routes/well-known.ts 的源码可以看到发现文档的真实内容它只声明authorization_codePKCE与device_code两种 grantcode_challenge_methods_supported: [S256]、token_endpoint_auth_methods_supported: [none]——这正是公开客户端、无 secret协议契约的服务器侧体现也解释了为什么OAUTH_CLIENT_SECRET必须为空一旦配置了 secretauthlib 会切换为 Basic 认证并丢弃 token 请求中的client_id而 Pollinations 的 token 端点会拒绝这种请求。授权码交换的底层实现在 enter.pollinations.ai/src/routes/oauth.tsPOST /api/oauth/codeconsent 页在浏览器中铸造sk_后交给服务器服务器把密钥绑定到单次使用的授权码并存入 KVTTL 10 分钟同时用精确匹配校验redirect_uri是否在该client_id的注册白名单内POST /api/oauth/token执行 RFC 7636 §4.6 的 PKCE S256 校验BASE64URL(SHA256(verifier)) challenge先用后验地销毁授权码OAuth 2.1 单次使用语义并校验client_id与redirect_uri完全一致响应带Cache-Control: no-storeGET /api/oauth/userinfo返回用户资料名称、邮箱、头像。OAUTH_AUTHORIZE_PARAMS中的expiry: 365天与budget: 20决定了 consent 铸造的sk_的有效期限365 天与花粉预算20这直接构成每次聊天都从用户钱包扣费的计费上限。注意协议没有 refresh grant因此 consent 密钥过期expiry就是 API 访问的重新登录周期。配置变量只在首次启动时种入Open WebUI 的DEFAULT_CONFIGOPENAI_API_CONFIGS、TOOL_SERVER_CONNECTIONS等只在键缺失时才写入 Postgres 的config表Config.seed_defaults只插入新键Config.get优先读取已存储的行。因此修改已启动数据库上的某个环境变量不会生效——需要直接改存储的行或调用存在对应 admin API 的接口例如POST /api/v1/retrieval/embedding/update既写配置又重建内存中的 embedding 函数而裸UPDATE做不到。排查某个键的实际值可以直连 Postgresssh community-monitor sudo docker exec openwebui-postgres \ psql -U openwebui -d openwebui -c \ \select key, value::text from config where key tool_server.connections;\两个环境的模型后端配置也不相同见 wrangler.jsonc生产用 Chat CompletionsAPI_TYPE: chat_completionsGEN_URL: https://gen.pollinations.ai/v1并注册了MCP_URL: https://mcp.pollinations.ai/staging用 Responses API 且ENABLE_RESPONSES_API_STATEFULfalse只连 staging 的 Gen 与 EnterMCP_URL为空不接外部 MCP 工具服务器两者都通过MODEL_IDS: []发现完整模型目录300 条目含媒体与社区模型。另外标题、标签和追问建议走的是task.model.external配置worker.js 中种入值为openai/gpt-5.4-nano注释说明故意选用非推理模型——早期用 gpt-5-nano 时每次标题/标签/追问调用要消耗 256–1024 个推理 token、耗时 3–12 秒而不是用户当前选中的聊天模型。这个全局设置对已有用户同样生效对已存在的 staging 数据库还需要同步更新openai.api_base_urls、openai.api_configsapi_type与model_ids和tool_server.connections以匹配 staging 配置保留用户/聊天与无关设置然后重启 staging 容器。staging 的OAUTH_CLIENT_ID必须在 staging Enter 中注册——production 的客户端注册不会自动出现在 staging。新用户看到什么模型钉选、建议与横幅由于连接背后的目录有 300 条目含媒体和社区模型ui-defaults.js 负责塑造新用户的第一分钟体验四个不需要付费余额的日常模型被钉选给尚未自选钉选的用户新聊天默认落在openai/gpt-5.4-nano选择器其余部分保持 gen 返回的顺序离开目录的模型 ID 会自动消失。四个模型为openai/gpt-5.4-nano、openai/gpt-6-luna、openai/gpt-6.1-sol、moonshotai/kimi-k3四条提示建议替换掉上游默认上游是关于期权交易和儿童美术的一条可关闭的横幅直接链接到用户自己的余额与充值页${ENTER_URL}/pollen与${ENTER_URL}/top-up文案明确告知聊天与生成使用你自己的 Pollen移除分享到 Open WebUI Community按钮它会把聊天上传到 openwebui.com也不启用盲评 arena 模型。这些默认值由 worker.js 以DEFAULT_MODELS、DEFAULT_PINNED_MODELS、DEFAULT_PROMPT_SUGGESTIONS、WEBUI_BANNERS等环境变量种入。由于上一节所述的只种一次机制已启动过的数据库会保留旧值要改现有安装用 admin API 脚本OWUI_URLhttps://openwebui.pollinations.ai OWUI_ENTER_URLhttps://enter.pollinations.ai OWUI_TOKENadmin key node scripts/apply-ui-defaults.mjsscripts/apply-ui-defaults.mjs 的关键细节是先读后写它依次对/api/v1/configs/models、/configs/suggestions、/configs/banners、/auths/admin/config、/evaluations/config做GET 当前值 → 合并后再 PUT/POST避免把DEFAULT_MODEL_METADATA内建工具关闭开关见下节重置掉。脚本需要 admin key 或 JWT执行后无需重启容器用户下一次页面加载即可看到变化且不会覆盖用户自己的钉选和设置。MCP 工具服务器与内建工具一个容易踩的坑https://mcp.pollinations.ai/端点就是根路径/mcp会 404被注册为 Open WebUI 的 MCP 工具服务器使用与模型连接相同的auth_type: system_oauth每用户 consent 密钥因此由工具调用发起的生成同样记在登录用户账上。配置中有两个容易漏掉的字段见 worker.jsconfig.enable必须为trueconfig.access_grants必须携带显式的公开读授权——空的授权列表意味着仅管理员可用而不是所有人可用。worker.js 中的写法是principal_type: user、principal_id: *、permission: read。与这个按聊天可选opt-in的 MCP 服务器不同Open WebUI 的内建工具时间、聊天历史、ask_user 等不是可选的除非模型声明meta.capabilities.builtin_tools: false否则 UI 发出的每个请求都会被附加这些工具 spec上游utils/middleware.py的行为。从连接拉取的模型在model表中没有对应行唯一的手段是全局默认DEFAULT_MODEL_METADATA/models.default_metadata上游utils/models.py会整体套用到这些模型上。本项目将其设为{capabilities: {builtin_tools: false}}否则所有拒绝tools字段的托管 Agent 和社区模型都会在每次 UI 聊天时报 400。另外models.base_models_cache为falseConfig.get_many每次请求都读行所以修改这条配置行立即生效对已有聊天和用户同样适用无需重启容器、无需逐聊天迁移。重启容器为什么不能只跑wrangler deployContainer 类的envVars只在容器启动时应用而wrangler deploy不会重启正在运行的实例更短的sleepAfter也不会。要强制换一个新容器必须删除容器应用后重新部署。用户、聊天和配置都留在 Postgres但临时磁盘上的上传文件会丢失所以重启前要检查文件npx wrangler containers list # 找到 app id npx wrangler containers delete ID npx wrangler deploy --env staging # 删除后第一次尝试可能因 Durable Object 失败重试一次新容器冷启动需要几分钟拉取约 1.5 GB 镜像。生产环境的部署半段必须走Deploy / Applications见下节。更新镜像与部署流程更新上游镜像版本的完整链路是先用 Docker daemon 执行DOCKER_HOSTssh://community-monitor npm run push-image -- 0.11.3把新版本推入 Cloudflare registry再同步把 wrangler.jsonc 中两个环境的containers[].image改掉。常规部署命令按 package.json 的 scriptsnpm ci npm run check # dry run先干跑 npm run deploy:staging npm run push-secrets:staging # 预发布 npm run deploy npm run push-secrets # 生产CI 在 production 分支上自动执行push-secrets用 sops 解密secrets/secrets.vars.json后交给 push-secrets.mjs 推送。生产部署由 .github/workflows/deploy-applications.yml 驱动任何影响apps/**等路径的 push 到production分支都会触发且强制要求从production分支部署main永不部署也支持workflow_dispatch手动指定应用名。每个应用的deploy.json被 operations/deployment 的发现脚本拾取openwebui 的 deploy.json 声明了install: npm ci、deploy: npm run check npm run deploy npm run push-secrets以及两个/health端点的部署后验证verify。部署作业按应用路径设置并发锁并依据credentials: myceli选择对应的 Cloudflare API token。放置约束为什么容器必须固定在 ENAM容器被约束在ENAM区域containers[].constraints.regions因为 Postgres 位于 AWS us-east-1。如果不加约束Cloudflare 会在唤醒请求最近的位置启动容器实测容器跑到了拉脱维亚的 Riga每次数据库会话就要付出约 3 次跨大西洋往返约 0.45 秒导致每个页面加载慢到约 20 秒。加上约束后staging 上 2026-09-16 的实测/health/db从 0.9 秒降到 0.3 秒。需要特别注意的是变更约束不会移动正在运行的容器见 wrangler.jsonc 的注释而是滚动部署单实例到新区域——期间约 5 分钟会出现 500/503因为要等 1.5 GB 镜像冷启动。这也是max_instances: 1与每 5 分钟一次 keepalive crontriggers.crons: [*/5 * * * *]见 worker.js 的scheduledhandler它请求/health以重置sleepAfter计时共同构成的单实例保活策略。Pollinations 侧的登录前置条件最后要让这套登录链路跑通Pollinations 侧必须满足以下硬性要求App Keypk_需注册精确的 redirect URIhttps://openwebui.pollinations.ai/oauth/oidc/callback以及 staging 对应的回调非 loopback 的重定向必须走 HTTPS。服务器侧 oauth.ts 会按白名单做包含 query 的精确匹配校验OAUTH_CLIENT_SECRET必须保持为空原因已在登录链路一节说明authlib 会退化为 Basic 认证并丢弃client_idOAUTH_SCOPESprofile邮箱只有在请求了profilescope 时才返回用户在 consent 页取消勾选 profile 将无法登录没有 refresh grantconsent 密钥的过期时间OAUTH_AUTHORIZE_PARAMS.expiry就是 API 访问的重新登录周期。小结这个应用展示了在 Cloudflare Containers 上托管第三方 Web 前端的完整范式用预推送镜像绕开ghcr.io拉取限制、用 Postgres pgvector 支撑无状态容器、用 OAuth 2.1 PKCERFC 8414 发现 单次使用授权码把登录与计费绑定到用户钱包、用只种入一次的配置策略与 admin API 脚本管理既有安装并用区域约束避免跨大西洋数据库往返。对任何希望自带模型后端 自带账号计费地托管 Open WebUI 的团队而言apps/openwebui 的每一份配置与脚本都是一份可直接对照的实战样本。赞分享AI 应用媒体生成后端前端【免费下载链接】pollinationsYour Friendly Open-Source Gen-AI Platform项目地址https://gitcode.com/gh_mirrors/po/pollinations点击查看免费下载相关推荐Bitnami Containers镜像策略ImagePolicyWebhook镜像策略实战指南还在为容器镜像安全而烦恼担心生产环境部署了有问题的镜像本文将带你深入了解Bitnami容器镜像的安全策略并通过ImagePolicyWebhook实现自动云原生供应链安全应用安全Pulse v6 自托管商业 GA 一致性付费运行时分发与 Docker 镜像策略演进记录Pulse v6 自托管商业 GA 一致性付费运行时分发与 Docker 镜像策略演进记录 本文梳理 Pulse v6 自托管商业 GA 阶段一项关键的发布治可观测性运维后端OpenSEO 在 Cloudflare 上的自托管部署一条命令搞定 D1/KV/R2 与 Cloudflare Access 登录门禁OpenSEO 在 Cloudflare 上的自托管部署一条命令搞定 D1/KV/R2 与 Cloudflare Access 登录门禁 OpenSEO开源后端前端MCP 服务数据分析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考