Ubuntu 24.04 自托管 SpacetimeDB 完整指南:systemd 服务、Nginx 反向代理与 HTTPS 实战
2026/9/13 19:39:49 网站建设 项目流程

Ubuntu 24.04 自托管 SpacetimeDB 完整指南:systemd 服务、Nginx 反向代理与 HTTPS 实战

【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB

本指南以 SpacetimeDB 1.12.0 官方自托管文档为主体,完整讲解如何在 Ubuntu 24.04 服务器上从零搭建一个生产可用的 SpacetimeDB 实例:创建专属系统用户、以 systemd 守护进程常驻运行、用 Nginx 反向代理按路由粒度控制访问范围、通过 Let's Encrypt 免费证书启用 HTTPS,并覆盖版本升级与常见故障排查。读完本文,你将具备独立部署并安全暴露一个可被官方 CLI 与各语言 SDK 正常访问的自托管 SpacetimeDB 服务端能力。

前置条件

开始前请确保满足以下条件:

  • 一台全新的 Ubuntu 24.04 服务器(VM 或任意云实例均可);
  • 一个已解析到该服务器公网 IP 的域名(例如example.com),HTTPS 证书签发依赖域名;
  • 服务器上的sudo权限。

整篇部署的核心思路是:SpacetimeDB 服务进程只监听本机回环地址127.0.0.1:3000,对外流量统一由 Nginx 承担,并在 Nginx 层按 URL 路由决定哪些 API 暴露给公网、哪些仅限本机使用。

Step 1:创建专属用户并安装 SpacetimeDB

出于安全考虑,SpacetimeDB 不应以 root 身份运行,而是使用一个独立的系统用户,并将数据目录固定在一个专用路径下:

sudo mkdir /stdb sudo useradd --system spacetimedb sudo chown -R spacetimedb:spacetimedb /stdb

随后以spacetimedb用户身份运行官方安装脚本。安装脚本接受--root-dir--yes参数:前者指定所有 SpacetimeDB 文件的存放根目录(本例为/stdb),后者跳过交互确认:

sudo -u spacetimedb bash -c 'curl -sSf https://install.spacetimedb.com | sh -s -- --root-dir /stdb --yes'

从源码看,--root-dir是 CLI 的全局选项,定义于 crates/cli/src/main.rs,其作用是「存储所有 spacetime 文件的根目录」。CLI 在启动时会根据该目录构造完整路径集(数据目录、配置目录、二进制目录等,见 crates/cli/src/main.rs)。安装完成后,可执行文件即位于/stdb/spacetime

Step 2:创建 Systemd 服务并开机自启

编写服务单元文件

为了让 SpacetimeDB 在服务器重启后自动运行、崩溃后自动拉起,使用 systemd 托管是标准做法。先创建服务文件:

sudo nano /etc/systemd/system/spacetimedb.service

写入如下内容:

[Unit] Description=SpacetimeDB Server After=network.target [Service] ExecStart=/stdb/spacetime --root-dir=/stdb start --listen-addr='127.0.0.1:3000' Restart=always User=spacetimedb WorkingDirectory=/stdb [Install] WantedBy=multi-user.target

配置要点说明:

  • User=spacetimedb:以非 root 的专属用户运行,与 Step 1 的目录归属保持一致;
  • WorkingDirectory=/stdb:服务的工作目录;
  • After=network.target:保证网络就绪后再启动服务;
  • Restart=always:进程异常退出后自动重启。

这里的spacetime start命令值得深入理解。从 crates/cli/src/subcommands/start.rs 的源码可以看到,CLI 的start子命令实际上会解析出目标版本二进制spacetimedb-standalone,并为其拼装start --data-dir <数据目录> --jwt-key-dir <配置目录>参数后执行替换式启动(Unix 下通过execvp直接接管当前进程)。而真正监听端口的参数最终由 standalone 服务解析:--listen-addr(别名-l)的默认值为0.0.0.0:3000,含义是监听所有网卡的 3000 端口,见 crates/standalone/src/subcommands/start.rs。

本教程刻意将其设为127.0.0.1:3000,即只监听回环地址——这是后续 Nginx 反向代理安全模型的前提:公网流量无法直连 3000 端口,所有入口请求都必须经过 Nginx 的路由过滤。

start子命令还支持在cli.toml中持久化默认监听地址(listen_addr = "0.0.0.0:4000"),显式传入的--listen-addr优先级更高,可覆盖配置文件默认值。

启用并启动服务

sudo systemctl enable spacetimedb sudo systemctl start spacetimedb

检查运行状态:

sudo systemctl status spacetimedb

Step 3:安装并配置 Nginx 反向代理

安装 Nginx

sudo apt update sudo apt install nginx -y

编写反向代理配置

创建一个新的站点配置文件:

sudo nano /etc/nginx/sites-available/spacetimedb

写入以下内容,务必把example.com替换成你自己的域名:

server { listen 80; server_name example.com; ######################################### # By default SpacetimeDB is completely open so that anyone can publish to it. If you want to block # users from creating new databases you should keep this section commented out. Otherwise, if you # want to open it up (probably for dev environments) then you can uncomment this section and then # also comment out the location / section below. ######################################### # location / { # proxy_pass http://localhost:3000; # proxy_http_version 1.1; # proxy_set_header Upgrade $http_upgrade; # proxy_set_header Connection "Upgrade"; # proxy_set_header Host $host; # } # Anyone can subscribe to any database. # Note: This is the only section *required* for the websocket to function properly. Clients will # be able to create identities, call reducers, and subscribe to tables through this websocket. location ~ ^/v1/database/[^/]+/subscribe$ { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; } # Log streaming benefits from longer read timeout and disabled buffering location ~ ^/v1/database/[^/]+/logs$ { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_buffering off; proxy_read_timeout 3600s; } # Uncomment this section to allow all HTTP reducer calls # location ~ ^/v1/[^/]+/call/[^/]+$ { # proxy_pass http://localhost:3000; # proxy_http_version 1.1; # proxy_set_header Upgrade $http_upgrade; # proxy_set_header Connection "Upgrade"; # proxy_set_header Host $host; # } # Uncomment this section to allow all HTTP sql requests # location ~ ^/v1/[^/]+/sql$ { # proxy_pass http://localhost:3000; # proxy_http_version 1.1; # proxy_set_header Upgrade $http_upgrade; # proxy_set_header Connection "Upgrade"; # proxy_set_header Host $host; # } # NOTE: This is required for the typescript sdk to function, it is optional # for the rust and the C# SDKs. location /v1/identity { proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; } # Block all other routes explicitly. Only localhost can use these routes. If you want to open your # server up so that anyone can publish to it you should comment this section out. location / { allow 127.0.0.1; deny all; } }

这份配置是自托管部署中最重要的安全边界,逐段拆解其含义:

1. 全量放行的注释块(location /,默认关闭)

注释中明确指出:SpacetimeDB 默认是完全开放的,任何人只要知道地址就能向实例发布(publish)数据库。若你希望保留「人人可发布」的能力(例如纯开发环境),可以取消这段注释,同时注释掉底部的拦截段。但对生产环境,务必保持关闭。

2. WebSocket 订阅路由(/v1/database/<db>/subscribe,必需)

这段是 WebSocket 功能正常运转的唯一必需配置。官方注释强调:客户端正是通过这个 WebSocket 通道创建身份(identity)、调用 reducer、订阅表数据的。因此无论采取何种安全策略,这段都必须保留。它使用 Nginx 的Upgrade/Connection头完成 WebSocket 协议升级的透传,对应 SpacetimeDB 客户端 API 中的订阅路由。

3. 日志流路由(/v1/database/<db>/logs

spacetime logs命令通过该路由流式拉取数据库日志。日志流是长时间连接的 SSE 场景,因此需要禁用缓冲(proxy_buffering off)并拉长读取超时(proxy_read_timeout 3600s),防止 Nginx 缓冲或超时切断日志推送。

4. HTTP reducer 调用路由(/v1/<db>/call/<reducer>,默认关闭)

Rust/C# 客户端通常通过 WebSocket 调用 reducer,但 HTTP 形式同样存在。若你希望允许通过纯 HTTP 调用 reducer,取消这段注释即可。

5. HTTP SQL 查询路由(/v1/<db>/sql,默认关闭)

对应spacetime sql命令与 HTTP SQL 接口。默认关闭以缩小攻击面。

6. 身份路由(/v1/identity,必需)

官方注释特别指出:TypeScript SDK 的正常运行依赖该路由(Rust 与 C# SDK 则为可选)。TypeScript 客户端创建/登录身份走 HTTP 接口,因此生产环境若需支持 TS 客户端,这段必须保留。

7. 兜底拦截(location /

其余所有路由仅允许本机(127.0.0.1)访问、其余来源一律拒绝。这样从公网角度看,实例只暴露了订阅、日志、身份三条最小必要路由,而publishsqlcall等管理/写路径全部被挡在 Nginx 层之外——从源码结构看,这与 CLI 各子命令的调用路径(发布、SQL 等均需访问管理类 API)是一致的,从而有效阻止远程用户向你的实例发布数据库。

启用站点并重启 Nginx

sudo ln -s /etc/nginx/sites-available/spacetimedb /etc/nginx/sites-enabled/ sudo systemctl restart nginx

配置防火墙

确保防火墙放行 Nginx 的完整流量(80/443):

sudo ufw allow 'Nginx Full' sudo ufw reload

Step 4:使用 Let's Encrypt 加密 HTTPS

安装 Certbot

sudo apt install certbot python3-certbot-nginx -y

申请 SSL 证书

运行以下命令,将example.com替换为你自己的域名:

sudo certbot --nginx -d example.com

Certbot 会自动完成以下工作:校验域名所有权、向 Let's Encrypt 申请证书、修改 Nginx 配置以启用 TLS 并配置 HTTP→HTTPS 跳转。完成后重启 Nginx 应用变更:

sudo systemctl restart nginx

证书自动续期

Certbot 安装时会自动注册一个续期定时器。验证其处于激活状态:

sudo systemctl status certbot.timer

Let's Encrypt 证书有效期约为 90 天,该定时器会在到期前自动续期并重载 Nginx。

Step 5:验证安装并接入 CLI

在本地开发机上执行以下命令,把新服务器注册到 CLI 的服务器配置中(example.com替换为你的域名):

spacetime server add self-hosted --url https://example.com

关于server add背后的行为,从 crates/cli/src/subcommands/server.rs 的源码可以确认:

  • 它会向服务器请求并打印指纹(fingerprint)并保存,用于后续连接时的身份校验;
  • 若服务器未运行或网络不通,会给出明确提示,并支持--no-fingerprint跳过指纹获取;
  • 支持-d/--default将该服务器设为默认,以及spacetime server listspacetime server set-defaultspacetime server ping(内部请求/v1/ping,见 crates/cli/src/subcommands/server.rs)等配套管理命令。

如何向受保护实例发布模块

正如 Nginx 配置注释所强调的:由于生产配置默认拦截了公网publish路径,远程直接spacetime publish会失败。官方推荐的发布流程是:本地构建出 WASM 模块 →scp拷贝到服务器 → 在服务器本机(绕过 Nginx 的127.0.0.1白名单)以本地服务器身份发布:

spacetime build scp target/wasm32-unknown-unknown/release/spacetime_module.wasm ubuntu@<host>:/home/ubuntu/ ssh ubuntu@<host> spacetime publish -s local --bin-path spacetime_module.wasm <database-name>

上述命令中的spacetime build会调用本仓库模板中常见的 Rust 模块构建流程(产物为wasm32-unknown-unknown目标下的spacetime_module.wasm)。可以将这三条命令封装成 shell 脚本以简化流程,也可以将其集成进 GitHub Actions 等 CI,在特定事件(如 PR 合入主分支)触发自动发布。若在 Step 3 中取消了/v1/publish限制(即开放远程发布),则无需此流程,可直接远程spacetime publish

Step 6:升级 SpacetimeDB 版本

升级到最新版本

先停止服务,再执行升级:

sudo systemctl stop spacetimedb
sudo -u spacetimedb -i -- spacetime --root-dir=/stdb version upgrade

从源码实现看,spacetime version子命令会调用独立的多调用二进制spacetimedb-update,并将--root-dir原样透传(见 crates/cli/src/subcommands/version.rs)。升级过程会先向发布源解析最新版本,下载对应架构的预编译归档(优先 GitHub Release,失败时自动回退到镜像源),解压到版本目录后切换当前版本(见 crates/update/src/cli/upgrade.rs)。

安装指定版本

如需固定到某个特定版本号:

sudo -u spacetimedb -i -- spacetime --root-dir=/stdb install <version-number>

install子命令支持--edition(默认standalone)、--use(安装后立即切换)等参数,并将二进制安装到以版本号命名的目录下(见 crates/update/src/cli/install.rs)。

最后重启服务使新版本生效:

sudo systemctl start spacetimedb

建议升级后回到 Step 5 的验证流程,确认实例与各 SDK 客户端兼容。

Step 7:常见故障排查

SpacetimeDB 服务启动失败

先查看服务日志定位错误:

sudo journalctl -u spacetimedb --no-pager | tail -20

确认二进制文件权限正确:

sudo ls -lah /stdb/spacetime

若缺少可执行权限(例如安装后权限被意外修改),补充执行位:

sudo chmod +x /stdb/spacetime

另外结合 crates/standalone/src/subcommands/start.rs 的实现,服务启动时还会检查端口占用:若 3000 端口已被其他进程占用,会明确报错并提示「请释放端口或通过--listen-addr指定其他端口」。这与 systemd 服务文件中--listen-addr的配置直接相关,排查时可留意是否有进程抢占端口。

Let's Encrypt 证书续期异常

手动执行一次续期演练(dry-run),观察错误输出:

sudo certbot renew --dry-run

常见原因包括域名 DNS 解析失效、防火墙未放行 80/443 端口(回看 Step 3 的 ufw 配置)等。

Nginx 启动失败

先用测试命令校验配置语法:

sudo nginx -t

再查看 Nginx 日志:

sudo journalctl -u nginx --no-pager | tail -20

附:基于 config.toml 的生产调优方向

SpacetimeDB 1.12.0 的 standalone 实例支持通过配置文件进一步调优。仓库中的示例配置 crates/standalone/config.toml 完整展示了可用配置段,生产部署时可参考其中的核心项:

  • [logs]:默认日志级别与 directives 过滤规则(示例中spacetimedb=debugspacetimedb_commitlog=info等),可按需收紧为ERROR以减少日志量;
  • [wasm]/[v8]:每个数据库的 WASM 过程实例池 / JS isolate 池大小,省略时按系统核心数自动决定,适用于模块并发量较高的场景;
  • [v8-heap-policy]:V8 堆检查频率与 GC 触发阈值(heap-gc-trigger-fractionheap-limit-mb等),主要影响 TypeScript 模块的堆管理;
  • [websocket]ping-interval(心跳间隔)与idle-timeout(空闲超时),可配合 Nginx 的proxy_read_timeout一并调整,避免长连接被中间层切断;
  • [commitlog]:预写日志段的max-segment-sizewrite-buffer-size等持久化参数,影响写放大与刷盘频率。

该配置文件的解析与加载路径位于 standalone 服务启动逻辑中(见 crates/standalone/src/subcommands/start.rs 的ConfigFile结构)。

小结

至此,一套生产可用的自托管 SpacetimeDB 部署已完成:spacetimedb系统用户 + systemd 守护 + 仅监听回环地址的服务进程 + Nginx 按路由白名单反向代理 + Let's Encrypt HTTPS 全覆盖。这套模型的核心安全思想是「最小暴露」:通过 Nginx 兜底拦截,公网只能访问订阅、日志与身份这三条必要路由,而发布、SQL 等管理操作保留在本机或受控流程内,兼顾了安全性与各语言 SDK 的正常工作(尤其 TypeScript 客户端依赖的/v1/identity路由)。如需进一步了解 CLI 服务器管理的更多细节,可阅读 crates/cli/src/subcommands/server.rs 的源码;部署相关文档的现行版本可参考 docs/docs/00300-resources 目录。

【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询