自托管功能
Run and manage Edge Functions in your self-hosted Supabase instance.
在自托管的 Supabase 设置中,Edge Functions 能开箱即用。functions 服务、API 网关路由,以及一个 hello 示例函数都已经预配置好了。
🌐 Edge Functions work out of the box in a self-hosted Supabase setup. The functions service, API gateway routing, and a hello example function are all pre-configured.
在托管的 Supabase 平台上,Edge 函数会部署在多个区域。自托管的独立实例配置类似于标准的无服务器设置。
🌐 On managed Supabase platform, Edge Functions are deployed across multiple regions. Self-hosted standalone instance configuration resembles a standard serverless setup.
调用默认函数 #
🌐 Invoke the default function
默认的 hello 函数位于 volumes/functions/hello/index.ts。你可以在启动堆栈后立即调用它:
🌐 The default hello function is located at volumes/functions/hello/index.ts. You can invoke it immediately after starting your stack:
curl http://<your-domain>/functions/v1/hello \ --header 'apiKey: <sb_publishable/sb_secret key>'这会返回:
🌐 This returns:
{ "message": "Hello from Edge Functions!" }创建一个新函数 #
🌐 Create a new function
步骤 1:添加一个新的函数目录和函数代码 #
🌐 Step 1: Add a new function directory and the function code
mkdir -p volumes/functions/my-function &&touch volumes/functions/my-function/index.ts在 index.ts 中添加以下代码:
🌐 Add the following code to index.ts:
import { withSupabase } from '@supabase/server'export default { fetch: withSupabase({ auth: ['publishable', 'secret'] }, async (req) => { const { name } = await req.json() const message = `Hello, ${name}!` return Response.json({ message }) }),}auth 选项控制谁可以调用该函数。这个例子与默认的 hello 函数匹配,并且需要在 apikey 头中提供发布或密钥 API 键。'none' 接受所有请求,而 'user' 需要有效的用户 JWT。详情请查看 Edge Functions 认证指南。
🌐 The auth option controls who can call the function. This example matches the default hello function and requires a publishable or secret API key in the apikey header. 'none' accepts every request, and 'user' requires a valid user JWT. See the Edge Functions auth guide for details.
步骤2:重启函数服务以加载新函数 #
🌐 Step 2: Restart the functions service to pick up the new function
sh run.sh restart functions步骤 3:调用你的函数 #
🌐 Step 3: Invoke your function
curl -X POST http://<your-domain>/functions/v1/my-function \ -H 'apikey: <SUPABASE_PUBLISHABLE_KEY>' \ -H 'Content-Type: application/json' \ -d '{"name": "World"}'你应该能看到来自 my-function 的回复:
🌐 You should be able to see the response from my-function:
{ "message": "Hello, World!" }自定义环境变量 #
🌐 Custom environment variables
使用 env 文件(推荐) #
🌐 Using an env file (recommended)
对于多个变量或秘密,创建一个单独的环境文件,例如在你的 docker/ 目录下的 .env.functions:
🌐 For multiple variables or secrets, create a separate env file, e.g., .env.functions in your docker/ directory:
MY_CUSTOM_VAR=some-value在 docker-compose.yml 的 functions 服务中添加 env_file(env_file 中的变量先加载,然后 environment 的值优先):
🌐 Add env_file to the functions service in docker-compose.yml (variables in env_file load first, then environment values take precedence):
functions: env_file: - .env.functions environment: # ... existing variables ...如果 .env.functions 包含秘密信息,就别提交到版本控制里。把它加到你的 .gitignore 里吧。
🌐 Don't commit .env.functions to version control if it contains secrets. Add it to your .gitignore.
重启功能服务:
🌐 Restart the functions service:
sh run.sh recreate functions使用内联环境变量 #
🌐 Using inline environment variables
对于一个或两个变量,你可以直接在 docker-compose.yml 的 environment 下添加它们:
🌐 For one or two variables, you can add them directly under environment in docker-compose.yml:
functions: environment: # Custom variables MY_CUSTOM_VAR: ${MY_CUSTOM_VAR} # ... existing variables ...然后在你的主 .env 文件中定义 MY_CUSTOM_VAR,或者直接指定这个值。
🌐 Then define MY_CUSTOM_VAR in your main .env file, or specify the value directly.
在函数中访问变量 #
🌐 Accessing variables in functions
所有容器环境变量都会被 main/index.ts 转发到函数工作器。可以这样访问它们:
🌐 All container environment variables are forwarded to the function workers by main/index.ts. Access them with:
const = ..('MY_CUSTOM_VAR')从函数调用 Supabase 服务 #
🌐 Calling Supabase services from functions
函数服务预先配置了以下环境变量:
🌐 The functions service is pre-configured with the following environment variables:
| 变量 | 值 | 目的 |
|---|---|---|
SUPABASE_URL | http://api-gw:8000 | 内部 API 网关 URL |
SUPABASE_PUBLIC_URL | http(s)://<your-domain> | 从互联网访问 Supabase 的基础 URL |
JWT_SECRET | your-jwt-secret | JWT 的旧对称加密密钥 |
SUPABASE_ANON_KEY | your-anon-key | 客户端 API 密钥(anon 角色) |
SUPABASE_SERVICE_ROLE_KEY | your-service-role-key | 服务器端 API 密钥(service_role 角色) |
SUPABASE_DB_URL | postgresql://... | Postgres 连接字符串 |
SUPABASE_PUBLISHABLE_KEYS | {"default":"sb_publishable_...} | 新的可发布 API 密钥 |
SUPABASE_SECRET_KEYS | {"default":"sb_secret_...} | 新的秘密 API 密钥 |
SUPABASE_JWKS | {"keys":[{...}]} | 用于验证 Auth 签发的 JWT 的 JWKS |
这里有一个示例函数,使用 @supabase/server 提供的管理员客户端查询表格:
🌐 Here's an example function that queries a table using the admin client provided by @supabase/server:
import { withSupabase } from '@supabase/server'export default { fetch: withSupabase({ auth: 'secret' }, async (_req, ctx) => { // ctx.supabaseAdmin bypasses RLS. This function requires a secret // API key, so only server-to-server callers can reach it. const { data, error } = await ctx.supabaseAdmin.from('todos').select('*') return Response.json({ data, error }) }),}withSupabase 会读取上述环境变量中的 SUPABASE_URL、API 密钥和 SUPABASE_JWKS。你不需要自己去连接 createClient。
auth: 'user' 会根据 SUPABASE_JWKS 验证调用者的 JWT。如果你使用的是没有配置它的旧系统,请参阅 新的 API 密钥和非对称认证。
内部 URL 与外部 URL #
🌐 Internal vs external URLs
这是一个关键区别,会影响你在函数中如何构建 URL:
🌐 This is a key distinction that affects how you build URLs in your functions:
SUPABASE_URL包含一个内部的 Docker 网络主机名。可以在你的函数中用它向其他 Supabase 服务(Auth、Storage、通过 PostgREST 访问数据库)发起服务端调用。这就是 Supabase JS 客户端在函数内部应该使用的。SUPABASE_PUBLIC_URL是你 Supabase 实例的外部可访问 URL。如果你的函数需要构建 HTTP 客户端可以从外部访问的 URL,就使用它。
通过仪表板管理功能 #
🌐 Managing functions via dashboard
自托管工作室 挂载 与函数服务相同的 volumes/functions 目录。你可以通过 Edge Functions > Functions 界面查看有哪些可用的函数。
🌐 Self-hosted Studio mounts the same volumes/functions directory as the functions service. You can check what functions are available using Edge Functions > Functions UI.
把函数部署到远程服务器 #
🌐 Deploying functions to a remote server
要将函数部署到运行自托管 Supabase 的远程服务器,使用 scp 复制函数目录:
🌐 To deploy a function to a remote server running self-hosted Supabase, copy the function directory with scp:
scp -r ./my-function user@<your-domain>:/path/to/self-hosted/volumes/functions/然后在远程主机上重启函数服务:
🌐 Then restart the functions service on the remote host:
ssh user@<your-domain> 'cd /path/to/self-hosted && sh run.sh restart functions'从 Supabase 平台复制功能 #
🌐 Copying functions from Supabase platform
如果你在 Supabase 平台上已经有现有的函数,你可以下载它们并在你自己的托管实例上运行。获取函数源代码有两种方法:
🌐 If you have existing functions on Supabase platform, you can download them and run them on your self-hosted instance. There are two ways to get the function source code:
- 仪表板 - 在仪表板中打开功能详情,然后点击 下载。
- 本地开发 & CLI - 运行
supabase functions download <function-name> --project-ref <ref>下载源码。
使用 scp 将函数复制到你自托管实例的 volumes/functions/<function-name>/,然后重启函数服务。
更多详情,请参见:
🌐 For more details, see:
故障排除 #
🌐 Troubleshooting
404 NOT_FOUND#
请求的 URL 必须在 /functions/v1/ 后包含函数名称。例如,/functions/v1/hello。检查 volumes/functions/hello/ 是否存在对应的目录。
🌐 The request URL must include the function name after /functions/v1/. For example, /functions/v1/hello. Check that the corresponding directory exists at volumes/functions/hello/.
函数调用错误 #
🌐 Function invocation errors
检查 sb-error-code 响应头,并查看 Edge Functions 错误代码 了解错误详情。
🌐 Inspect the sb-error-code response header and see Edge Functions error codes for details about the error.
检查函数服务日志:
🌐 Check the functions service logs:
docker compose logs functions对于503 BOOT_ERROR,检查语法错误、无效的导入或缺失的依赖,这些都会阻止函数启动。
🌐 For 503 BOOT_ERROR, check for syntax errors, invalid imports, or missing dependencies that prevent the function from starting.
401 “无效的 JWT” #
🌐 401 "invalid JWT"
- 检查一下
FUNCTIONS_VERIFY_JWT是否符合你的意图(true或false)在.env中 - 如果启用了验证,可以在
Authorization: Bearer <token>中传递有效的 JWT(用户会话令牌或旧版 API 密钥),或者在apikey头中传递sb_publishable_*或sb_secret_*密钥。API 网关会将sb_密钥转换为内部 JWT,然后函数服务会进行验证。 - 验证非对称 JWT,包括已翻译的
sb_密钥,需要在docker-compose.yml的functions服务中设置SUPABASE_JWKS。请参阅 新 API 密钥和非对称认证。
编辑后函数代码的更改没有反映出来 #
🌐 Changes to function code not reflected after editing
重启功能服务:
🌐 Restart the functions service:
sh run.sh restart functions函数中不可用自定义环境变量 #
🌐 Custom env vars not available in functions
- 确认变量在
docker-compose.yml中已定义(在env_file或environment下) - 在更改配置后重新创建函数容器
- 检查变量名是否完全匹配(区分大小写)
使用以下命令重新创建容器:
🌐 Use the following command to recreate the container:
sh run.sh recreate functions内存或超时错误 #
🌐 Memory or timeout errors
volumes/functions/main/index.ts 的默认限制适用于每个工作线程:
🌐 The default limits in volumes/functions/main/index.ts apply to each worker:
| 设置 | 默认值 | 描述 |
|---|---|---|
memoryLimitMb | 150 MB | 最大内存使用量。 |
workerTimeoutMs | 400,000 毫秒 | 工作线程最长生命周期。 |
requestAbsentTimeoutMs | 60,000 毫秒 | 当没有待处理任务且 60 秒没有请求时,允许工作线程关闭。 |
要调整这些限制,请编辑 volumes/functions/main/index.ts 中的数值,然后重启功能服务。
🌐 To adjust these limits, edit the values in volumes/functions/main/index.ts and restart the functions service.
请求有一个单独的空闲超时,时间为150秒。这个参数在 docker-compose.yml 中的函数服务命令里由 --user-worker-request-idle-timeout 设置,值为 150000 毫秒。更改这个值后,需要重新创建函数容器。
🌐 Requests have a separate idle timeout of 150 seconds. This is set by --user-worker-request-idle-timeout in the functions service command in docker-compose.yml, with the value 150000 in milliseconds. Recreate the functions container after changing this value.
Envoy 网关 有单独的限制:160 秒的不活动时间和 410 秒的上游响应超时。
🌐 The Envoy gateway has separate limits of 160 seconds of inactivity and a 410-second upstream response timeout.
如果你使用可选的 Kong 网关,volumes/api/kong.yml 中的 read_timeout 会被设置为 160000 毫秒,允许函数服务的读取之间有 160 秒的空闲时间。
🌐 If you use the optional Kong gateway, read_timeout in volumes/api/kong.yml is set to 160000 milliseconds, allowing 160 seconds of inactivity between reads from the functions service.