将平台项目恢复到自托管
Restore your database from the Supabase platform to a self-hosted instance.
本指南将引导你将数据库从 Supabase 平台项目恢复到 自托管的 Docker 实例。这里不涉及传输存储对象或重新部署 edge 函数。
🌐 This guide walks you through restoring your database from a Supabase platform project to a self-hosted Docker instance. Transferring storage objects or redeploying edge functions is not covered here.
在你开始之前 #
🌐 Before you begin
你需要:
🌐 You need:
- 一个新的自托管 Supabase 实例(Docker 设置指南)
- Supabase CLI 已安装(或使用
npx supabase) - 已安装 Docker Desktop(命令行工具所需)
psql已安装(官方安装指南)- 你的 Supabase 数据库密码(适用于平台和自托管)
步骤1:获取你的平台连接字符串 #
🌐 Step 1: Get your platform connection string
在你管理的 Supabase 项目仪表板上,点击 Connect 并复制连接字符串(使用会话池或直接连接)。
🌐 On your managed Supabase project dashboard, click Connect and copy the connection string (use the session pooler or direct connection).
步骤 2:备份你的平台数据库 #
🌐 Step 2: Back up your platform database
将角色、架构和数据导出为三个单独的 SQL 文件:
🌐 Export roles, schema, and data as three separate SQL files:
1supabase db dump --db-url "[CONNECTION_STRING]" -f roles.sql --role-only1supabase db dump --db-url "[CONNECTION_STRING]" -f schema.sql1supabase db dump --db-url "[CONNECTION_STRING]" -f data.sql --use-copy --data-only这会生成在不同 Postgres 版本之间兼容的 SQL 文件。
🌐 This produces SQL files that are compatible across Postgres versions.
使用 supabase db dump 实际上会执行 pg_dump,但会应用 Supabase 特有的过滤——它会排除内部 schema、去掉保留角色,并增加幂等的 IF NOT EXISTS 条款。直接使用原生 pg_dump 会包含 Supabase 内部内容,并且在恢复时可能导致权限错误。CLI 需要 Docker,因为它是在 Supabase Postgres 镜像的容器中运行 pg_dump,而不是依赖本地安装的 Postgres。
🌐 Using supabase db dump executes pg_dump under the hood but applies Supabase-specific filtering - it excludes internal schemas, strips reserved roles, and adds idempotent IF NOT EXISTS clauses. Using raw pg_dump directly will include Supabase internals and cause permission errors during restore. CLI requires Docker because it runs pg_dump inside a container from the Supabase Postgres image rather than requiring a local Postgres installation.
步骤3:准备你自己的自托管实例 #
🌐 Step 3: Prepare your self-hosted instance
在恢复之前,请检查你自托管实例上的以下内容:
🌐 Before restoring, check the following on your self-hosted instance:
- 扩展:启用你的 Supabase 项目使用的任何非默认扩展。你可以通过在托管数据库上查询
select * from pg_extension;来查看哪些扩展是激活状态的(或者在仪表板中查看数据库扩展)。
步骤4:恢复到你自己的数据库 #
🌐 Step 4: Restore to your self-hosted database
连接到你自己托管的 Postgres 并恢复导出的文件。自托管 Supabase 的默认连接字符串是:
🌐 Connect to your self-hosted Postgres and restore the dump files. The default connection string for self-hosted Supabase is:
1postgres://postgres.your-tenant-id:[POSTGRES_PASSWORD]@[your-domain]:5432/postgres其中 [POSTGRES_PASSWORD] 是你自托管的 .env 文件中 POSTGRES_PASSWORD 的值。
🌐 Where [POSTGRES_PASSWORD] is the value of POSTGRES_PASSWORD in your self-hosted .env file.
根据你是在 VPS 上自托管 Supabase 还是在本地运行,对于 [your-domain],你可以使用你的域名、服务器 IP 或 localhost。
🌐 Use your domain name, your server IP, or localhost for [your-domain] depending on whether you are running self-hosted Supabase on a VPS, or locally.
运行 psql 来恢复:
🌐 Run psql to restore:
1psql \2 --single-transaction \3 --variable ON_ERROR_STOP=1 \4 --file roles.sql \5 --file schema.sql \6 --command 'SET session_replication_role = replica' \7 --file data.sql \8 --dbname "postgres://postgres.your-tenant-id:[POSTGRES_PASSWORD]@[your-domain]:5432/postgres"将 session_replication_role 设置为 replica 会在数据导入时禁用触发器,避免列被双重加密等问题。
🌐 Setting session_replication_role to replica disables triggers during the data import, preventing issues like double-encryption of columns.
步骤5:核实恢复情况 #
🌐 Step 5: Verify the restore
连接到你自建的数据库并进行一些检查:
🌐 Connect to your self-hosted database and run a few checks:
1psql "postgres://postgres.your-tenant-id:[POSTGRES_PASSWORD]@[your-domain]:5432/postgres"1-- Check your tables are present2\dt public.*34-- Verify row counts on key tables5SELECT count(*) FROM auth.users;67-- Check extensions8SELECT * FROM pg_extension;恢复中包括什么,不包括什么 #
🌐 What's included in the restore and what's not
数据库导出包括你的模式、数据、角色、RLS 策略、数据库函数、触发器和 auth.users。不过,有几件事情需要在你自建的实例上单独配置:
🌐 The database dump includes your schema, data, roles, RLS policies, database functions, triggers, and auth.users. However, several things require separate configuration on your self-hosted instance:
| 需要手动设置 | 如何配置 |
|---|---|
| JWT 密钥和 API 密钥 | 生成新的并更新 .env |
| 认证提供商设置(OAuth、Apple 等) | 在 .env 中配置 GOTRUE_EXTERNAL_* 变量 |
| Edge 函数 | 手动复制到你自托管的实例 |
| 存储对象 | 单独传输(本指南不涉及) |
| SMTP / 邮件设置 | 在 .env 中配置 SMTP_* 变量 |
| 自定义域名和 DNS | 将你的 DNS 指向自托管服务器 |
身份验证注意事项 #
🌐 Auth considerations
你的 auth.users 表和相关数据已经包含在数据库导出中,所以用户账户得以保留。不过:
🌐 Your auth.users table and related data are included in the database dump, so user accounts are preserved. However:
- JWT 密钥不同,你的平台和自托管实例之间不一样。平台项目发的现有令牌将无效。用户需要重新登录。
- 社交认证提供商(Apple、Google、GitHub 等)需要在你自托管的
.env文件中进行配置。设置相关的GOTRUE_EXTERNAL_*变量。查看 Auth 仓库的 README 了解所有可用选项。 - 你在 OAuth 提供商控制台(Apple Developer、Google Cloud Console 等)中的 重定向 URL 必须更新为指向你自托管的主机名,而不是
*.supabase.co。
Postgres 版本兼容性 #
🌐 Postgres version compatibility
托管的 Supabase 可能运行的 Postgres 版本比自托管的 Docker 镜像更新(托管版是 Postgres 17,而自托管默认是 Postgres 15)。supabase db dump 命令会生成可在主要 Postgres 版本上使用的普通 SQL 文件。
🌐 Managed Supabase may run a newer Postgres version (Postgres 17) than the self-hosted Docker image (currently it's Postgres 15 by default). The supabase db dump command produces plain SQL files that work across major Postgres versions.
如果你的托管项目使用的是 Postgres 17,考虑在自托管部署中也从 Postgres 17 开始。有关设置说明,请参见 Postgres 17 指南。
🌐 If your managed project runs Postgres 17, consider starting your self-hosted deployment with Postgres 17 as well. See the Postgres 17 guide for setup instructions.
记住:
🌐 Keep in mind:
- 数据导出可能包含仅适用于 Postgres 17 的设置,或者引用在自托管环境中尚不存在的新版本认证和存储中的表/列。请参阅故障排除部分的版本不匹配。
- 先在测试的自托管实例上运行恢复,以找出任何不兼容的地方。
- 确认你使用的所有扩展在自托管的 Postgres 版本上都可用。
故障排除 #
🌐 Troubleshooting
平台和自托管版本不匹配 #
🌐 Version mismatches between platform and self-hosted
这个平台可能运行比自托管更新的 Postgres 版本(17 对比 15)和更新的认证服务版本。数据导出可能包含在你新的自托管实例中不存在的设置、表或列。
🌐 The platform may run a newer Postgres version (17 vs 15) and newer Auth service versions than self-hosted. The data dump can contain settings, tables, or columns that don't exist on your new self-hosted instance.
data.sql 中的常见问题:
SET transaction_timeout = 0- 一个只适用于 Postgres 17 的设置,在 Postgres 15 上会失败COPY对于自建环境中不存在的表的语句(例如,auth.oauth_clients、storage.buckets_vectors、storage.vector_indexes)COPY语句在较新的 Auth 版本中增加了列(例如,auth.flow_state带有oauth_client_state_id、linking_target_id)
**解决方法:**在恢复之前编辑 data.sql:
1# Comment out PG17-only transaction_timeout2sed -i 's/^SET transaction_timeout/-- &/' data.sql对于缺少的表或列不匹配,先注释掉相关的 COPY ... FROM stdin; 行及其对应的 \. 结束符。先在没有 --single-transaction 的情况下运行恢复,以找出所有错误,然后修复它们,再用 --single-transaction 进行最终恢复。
🌐 For missing tables or column mismatches, comment out the relevant COPY ... FROM stdin; line and its corresponding \. terminator. Run the restore without --single-transaction first to identify all failures, then fix them and run the final restore with --single-transaction.
保持你的自托管配置最新可以尽量减少这些漏洞。
🌐 Keeping your self-hosted configuration up to date will minimize these gaps.
扩展不可用 #
🌐 Extension not available
如果恢复失败是因为某个扩展不可用,请检查它是否在你的自托管 Postgres 版本上受支持。你可以使用以下命令列出可用的扩展:
🌐 If the restore fails because an extension isn't available, check whether it's supported on your self-hosted Postgres version. You can list available extensions with:
1select * from pg_available_extensions;连接被拒绝 #
🌐 Connection refused
确保你的自托管 Postgres 端口可以访问。在默认的自托管 Supabase 设置中,用户是 postgres.your-tenant-id,Supavisor 端口是 5432。
🌐 Make sure your self-hosted Postgres port is accessible. In the default self-hosted Supabase setup, the user is postgres.your-tenant-id with Supavisor on port 5432.
旧版工作室配置 #
🌐 Legacy Studio configuration
在自托管的 Supabase 中,Studio 历史上使用 supabase_admin 角色(超级用户)而不是 postgres。通过 Studio 用户界面创建的对象归 supabase_admin 所有。检查你的 docker-compose.yml 配置 看看 POSTGRES_USER_READ_WRITE 是否设置为 postgres。
🌐 Studio in self-hosted Supabase historically used supabase_admin role (superuser) instead of postgres. Objects created via Studio UI were owned by supabase_admin. Check your docker-compose.yml configuration to see if POSTGRES_USER_READ_WRITE is set to postgres.
自定义角色缺少密码 #
🌐 Custom roles missing passwords
如果你在平台项目中为自定义数据库角色设置了 LOGIN 属性,它们的密码不会包含在转储中。恢复后需要手动设置它们:
🌐 If you created custom database roles with the LOGIN attribute on your platform project, their passwords are not included in the dump. Set them manually after restore:
1ALTER ROLE your_custom_role WITH PASSWORD 'new-password';额外资源 #
🌐 Additional resources