screenpipe-gateway 企业查询网关部署指南:写只读归档、离线令牌认证与访问审计
【免费下载链接】screenpipeYC (S26) | Open Computer History | Record your screen continuously locally and provide context to your agents (Claude, Codex, Openclaw, Hermes, Runner...)项目地址: https://gitcode.com/GitHub_Trending/sc/screenpipe
本指南面向需要**自行运行 screenpipe 企业查询网关(query gateway)**的运维与安全工程师,完整讲解从容器拉取、环境变量配置、AWS/MinIO 存储接入,到签名策略(signed policy)离线认证、访问日志审计、故障排查与容量规划的整套实战流程。读完本文,你将掌握如何在自有基础设施上安全地部署这个"唯一读取归档"的查询入口,并理解其写只读信任模型下的每一个安全边界。本文以 crates/screenpipe-gateway/README.md 为骨架,结合本仓库源码逐项印证实现细节。
一、先理解信任模型:为什么网关是"唯一的读取主体"
screenpipe 的桌面端会持续在本机录制屏幕与音频,并把 OCR 文本、转写内容等批量上传到客户自有的 S3 兼容对象存储桶(archive bucket)。Screenpipe 侧只持有写权限(s3:PutObject),从不给自己配置回读路径;而网关(gateway)正是唯一被授权读取该归档的组件——明文索引、查询日志、搜索结果全部落在你控制的基础设施上。
从 Cargo.toml 的描述可以看到该 crate 的定位:"Customer-run query gateway: polls the write-only telemetry archive bucket, ingests batches into SQLite+FTS, and serves the enterprise v1 REST surface inside the customer's network."即:轮询只写归档桶 → 将批次摄入 SQLite+FTS 索引 → 在客户网络内部提供 enterprise v1 REST 接口。
本文只讨论"如何跑这个容器";关于信任模型的完整论证(为什么归档是只写的、签名策略包含什么、Screenpipe 能/不能看到什么),README 明确指向了网站仓库的信任模型文档,属于设计文档范畴,不在本文展开。
二、部署前置条件:四条红线(先读再动手)
| 前置条件 | 说明 |
|---|---|
| 归档桶绝不能公开 | 在归档桶上开启 S3 Block Public Access(或你所用云厂商的等价能力),最好在账号级开启。一个世界可读的桶会摧毁整个模型,而且拒绝金丝雀(denial canary)不会提醒你——它使用 Screenpipe 的只写凭据探测,验证的是"我们(Screenpipe)读不了",对匿名访问是否开放一无所知。这是唯一一种会悄悄把"只写归档"变成"公开归档"的误配置。 |
| 网关端口必须私有 | 网关二进制只提供明文 HTTP,完全没有 TLS 支持(见第七节)。必须把它绑定在只有你自己的客户端和反向代理能触达的位置。 |
| 索引是明文,且属于你 | gateway.db包含你整个设备群上传内容的解码明文——OCR 文本、转写、记忆(见第六节)。加密卷、是否备份、何时清除都由你决定。Screenpipe 无法访问它,也无法替你清除:仪表盘里的POST /api/enterprise/storage/wipe只清托管侧元数据和托管对象,刻意不触碰客户自有存储与本索引。 |
| 时钟纪律 | 签名策略带有效窗口。主机时钟偏差超过几分钟,每次查询都会 503。必须运行 NTP。 |
源码层面,配置解析器 config.rs 明确实现了"空字符串即未设置"的规则(blank values read as unset),并且必填变量缺失时直接返回GatewayError::Config,这正是 README 所说"硬性启动错误(hard boot errors)"的实现。
三、容器镜像:拉取、校验与自建
公开镜像位于公共 registry,无需 registry 凭据、IAM 配置或白名单:
docker pull ghcr.io/screenpipe/screenpipe-gateway:0.4.29务必钉住版本,最好钉住 digest。:latest会漂移。GHCR 没有不可变标签设置,版本标签只能靠发布策略保护(发布任务拒绝覆盖已存在的标签)而非 registry 本身。digest 是唯一无法被重新指向的引用:
docker pull ghcr.io/screenpipe/screenpipe-gateway@sha256:<digest>每一份发布的镜像都携带签名构建溯源证明(signed build provenance attestation),把该 digest 绑定到产生它的 workflow run 与 commit。部署前请校验:
gh attestation verify oci://ghcr.io/screenpipe/screenpipe-gateway:0.4.29 \ --repo screenpipe/screenpipe自行构建同样完全支持——源码公开且构建不需要任何密钥:
# Build context 是 REPO ROOT——需要工作区清单 docker build -f crates/screenpipe-gateway/Dockerfile -t screenpipe-gateway .镜像内部结构(来自 Dockerfile)
- 基础镜像选
debian:bookworm-slim(约 75MB)而非静态 musl/scratch 镜像:依赖闭包恰好只有一个 C 依赖(内置 SQLite +sqlite-vec),而sqlite-vec0.1.3 在 musl 下无法编译。 - 镜像自带
ca-certificates(TLS 到 S3 与控制平面)和curl(健康检查),以非 root 用户screenpipe运行,EXPOSE 3040。 - uid/gid 固定为 999:999,与面向客户的 Fargate 模板中 EFS access point 的 PosixUser 保持一致。
- 发布镜像只含一个二进制
screenpipe-gateway,不带任何配置;所有凭据都在运行时通过环境变量注入(见第四节)。 - compose 演示用的合成设备播种器(seeder)与策略签名 fixture 属于测试专用,位于单独的
--target e2e镜像中,永不发布——seeder 会写入归档桶,绝不能指向生产环境。 - 镜像目前是
linux/amd64;在 Graviton/arm64 主机上暂时需要自行从源码构建。
四、配置:全部旋钮都是环境变量(12-factor,无配置文件)
配置解析集中在 config.rs 的GatewayConfig::from_lookup。缺失必填变量、任何配错的认证姿态都会导致硬启动错误——网关拒绝在半配置状态下运行。
必填
| 变量 | 含义 |
|---|---|
SCREENPIPE_GATEWAY_LICENSE_ID | 你组织的 license id。对象键内嵌它(enterprise-telemetry/{license_id}/…),每次查询的租户范围由该值推导,而非由策略推导——见第八节。 |
SCREENPIPE_GATEWAY_S3_BUCKET | 归档桶。 |
认证姿态(三选一,见第八节)
| 变量 | 含义 |
|---|---|
SCREENPIPE_GATEWAY_POLICY_PUBKEY_B64 | Base64 编码的 ed25519 公钥,钉住策略签名者。设置它即开启 bearer 认证。从GET /api/enterprise/gateway/policy-key获取。 |
SCREENPIPE_GATEWAY_CONTROL_PLANE | 控制平面 origin(如https://screenpi.pe),开启 enroll → 策略拉取 → 心跳循环。…_CONTROL_PLANE_BASE是接受的别名;两者都设置时规范名优先(config.rs 中有专门测试the_control_plane_base_alias_is_accepted_and_loses_to_the_canonical_name保证这一点)。 |
SCREENPIPE_GATEWAY_ENROLLMENT_TOKEN | 短 TTL、单次使用的sge_令牌,在仪表盘网关面板中铸造。仅首次启动需要——它换来的长期凭据会被持久化(第六节),下次重启时该令牌按设计已过期。 |
SCREENPIPE_GATEWAY_POLICY_PATH | 有控制平面时:冷启动缓存,拉取结果原子写入,因此控制平面故障期间重启仍能带着最后已知良好策略启动。无控制平面时:策略来源,每个轮询间隔重新读取(气隙/运维托管姿态)。 |
SCREENPIPE_GATEWAY_CONTROL_PLANE_ALLOW_HTTP | 1/true允许非回环主机上的明文http://控制平面。默认关闭,且每次启动都会记一条 ERROR:明文下长期sgw_凭据会在每次拉取与心跳中裸奔,路径上的攻击者可替换策略信封。回环地址无需此逃生舱(config.rs 测试要求只有1/true能开启,0/false/no/拼写错误一律保持关闭)。 |
存储
| 变量 | 默认值 | 含义 |
|---|---|---|
SCREENPIPE_GATEWAY_S3_ENDPOINT | AWS | S3 兼容存储(MinIO、R2)的自定义 endpoint。 |
SCREENPIPE_GATEWAY_S3_REGION | us-east-1 | — |
SCREENPIPE_GATEWAY_S3_ACCESS_KEY_ID/…_SECRET_ACCESS_KEY | 未设置 | 静态凭据。在 AWS 上两者都保持未设置——此时 provider chain 会拾取 task/instance role,即第四节描述的姿态。 |
SCREENPIPE_GATEWAY_S3_ALLOW_HTTP | 关闭 | 允许明文http://endpoint(compose 中的 MinIO)。 |
SCREENPIPE_GATEWAY_KEY_PREFIX | 未设置 | 存储绑定可选的前缀。API 可见的键永不包含它。 |
SCREENPIPE_GATEWAY_DATA_DIR | /data | 索引、快照、凭据与策略缓存存放处(第六节)。必须是持久卷。 |
节奏与绑定
| 变量 | 默认值 | 说明 |
|---|---|---|
SCREENPIPE_GATEWAY_BIND | 0.0.0.0:3040 | 明文。见第七节。 |
SCREENPIPE_GATEWAY_POLL_SECONDS | 30 | S3 摄入节奏——多久拾取一次新批次。下限 1s(设 0 会让 LIST 循环忙转)。这不是策略节奏;混淆两者会把策略刷新频率提高 10 倍。config.rs 中MIN_POLL_SECONDS = 1并对0做了 floor。 |
SCREENPIPE_GATEWAY_HEARTBEAT_SECONDS | 60 | 向控制平面汇报存活与游标。下限 1s。config.rs 注释解释了原因:tokio::time::interval对零周期会panic,而该 panic 发生在被派生的控制平面任务内部,会悄悄杀死策略刷新——因此专门有测试a_zero_heartbeat_cadence_is_floored_not_passed_to_tokio守护这个下限。 |
SCREENPIPE_GATEWAY_POLICY_REFRESH_SECONDS | 未设置 | 正常情况保持未设置。节奏来自控制平面通告的policy_refresh_seconds(300s)。下限 30s,上限为策略有效窗口的一半。 |
RUST_LOG | info,sqlx=warn | info会输出每条查询的访问日志(第九节)。 |
关于布尔旋钮的统一规则,config.rs 中env_flag的实现是:1/true(任意大小写)为开,其余一切(包括0、拼写错误)为关,所有布尔开关共用一套形状。
五、AWS 部署:角色、桶策略与任务定义
不要手搓这套配置。网关所需的 IAM 角色(只读访问你归档前缀下恰好那部分)、桶策略、以及可用的 ECS/Fargate 任务定义,在网站仓库的docs/gateway-aws-role.md(SCR-293)中,是一键 CloudFormation 流程的单一事实来源。保持SCREENPIPE_GATEWAY_S3_ACCESS_KEY_ID/…_SECRET_ACCESS_KEY未设置,以便使用任务角色。
最小权限原则:网关需要的仅仅是归档桶上的s3:GetObject+s3:ListBucket,仅此而已。Screenpipe 侧持有的只是只写(s3:PutObject)凭据。
六、MinIO / 本地部署 / 其他 S3 兼容存储
供应商中立是刻意设计:S3 设置只镜像任何 S3 兼容部署所需,不多不少。因此非 AWS 部署是手动配置路径——一键模板仅限 AWS。
一份可直接工作的配置,逐字取自 compose 测试环境(e2e/docker-compose.yml):
environment: SCREENPIPE_GATEWAY_LICENSE_ID: lic-e2e SCREENPIPE_GATEWAY_S3_BUCKET: screenpipe-archive SCREENPIPE_GATEWAY_S3_ENDPOINT: http://minio:9000 SCREENPIPE_GATEWAY_S3_REGION: us-east-1 SCREENPIPE_GATEWAY_S3_ACCESS_KEY_ID: screenpipe SCREENPIPE_GATEWAY_S3_SECRET_ACCESS_KEY: screenpipe-e2e-secret SCREENPIPE_GATEWAY_S3_ALLOW_HTTP: "1" # plain http to MinIO SCREENPIPE_GATEWAY_DATA_DIR: /data SCREENPIPE_GATEWAY_BIND: 0.0.0.0:3040 volumes: - gateway-data:/data真实本地部署的注意事项:
- 为网关铸造一个只读用户。Screenpipe 只持有只写(
s3:PutObject)凭据;网关需要的是归档桶上的s3:GetObject+s3:ListBucket,别无其他。 S3_ALLOW_HTTP=1只用于私有网络。明文下,归档批次——也就是内容本身——在网络上裸奔。- MinIO 需要 path-style 寻址,上面的 endpoint 形式已自动选择。
- 拒绝金丝雀从控制平面针对你的 endpoint 运行。如果你的 MinIO 从控制平面不可达,金丝雀报告
error而非pass,网关会停留在registered状态而不会翻转为active。
从 e2e 配置可以看到完整的演示链路:minio(扮演客户只写归档桶)→create-bucket用mc建桶 →seed(扮演两个只写模式的桌面设备)→gateway(客户运行的查询网关,轮询间隔被调成 2s 便于演示)。入口脚本是 e2e/run.sh,另有带认证姿态的 e2e/docker-compose.auth.yml。
七、磁盘上的状态,以及如何清除
所有内容都位于$SCREENPIPE_GATEWAY_DATA_DIR(/data)下:
| 路径 | 是什么 | 如果删除 |
|---|---|---|
gateway.db(+-wal、-shm) | SQLite 索引:每条摄入记录的解码明文,加上其上方的 FTS 索引,加上gateway_ingested_objects记账表。 | 网关会在下一次轮询时从 S3 重新摄入整个归档。无数据丢失,但会完整重读(并重新下载)整个桶。 |
snapshots/ | 从批次中提取、由/frames/{device}/{frame}提供的帧图。 | 这些帧在重新摄入前 404。 |
gateway-registration.json | 长期sgw_控制平面凭据,权限0600。 | 网关将无法心跳或拉取策略,且无法自行重新注册:必须在仪表盘铸造新的 enrollment token。不要在不同网关间复制该文件——每次/register都会吊销上一个网关行。 |
policy.json(若设置了POLICY_PATH) | 已验证的策略信封,用作冷启动缓存。 | 无害;下次拉取会重写它。但控制平面故障期间的重启将无缓存可回退。 |
清除索引
明文索引属于你,所以清除它是一次不涉及 Screenpipe 的本地操作:
# compose 方式 docker compose stop gateway docker volume rm <project>_gateway-data # 例如 e2e_gateway-data docker compose up -d gateway # 或保留凭据、免去重新注册 docker compose exec gateway sh -c 'rm -rf /data/gateway.db* /data/snapshots' docker compose restart gateway有两点必须清楚:
- 这不会删除归档桶里的任何内容。桶是系统的记录源(system of record);网关会从中重新摄入。要真正移除内容,你必须按自己的生命周期策略删除自己桶里的对象。
- 仪表盘的存储清除按钮不触碰这里。它只清托管元数据行和托管对象;客户自有存储与本索引明确不在其触及范围内。
八、TLS:二进制只有明文
该二进制是纯明文。它绑定一个普通 TCP 监听器并提供 HTTP;没有 TLS、没有证书配置、没有https模式。这不是一个可以绕过的疏漏,而是一个必须满足的部署要求:
- 在它前面终结 TLS:带 ACM 证书的 ALB/NLB、nginx/Caddy/Envoy,或 service mesh sidecar。客户端指向代理。
- 让网关本身无法被其他东西触达——
SCREENPIPE_GATEWAY_BIND=127.0.0.1:3040并在同一主机放代理,或使用只允许代理进入的安全组/网络策略。 - 不要向你不控制的网络发布 3040 端口。它服务的所有内容——搜索结果、记录文本、通过
/files/{key}返回的原始归档对象——都是明文归档内容。
如果跳过这一步,失败是无声的:一切工作正常,而你整个设备群的屏幕文本正以未加密状态穿过你的内网。
九、认证姿态,与策略新鲜度/故障的权衡
三种姿态,中间那种是试点(pilot)应该跑的:
| 姿态 | 环境变量 | 行为 |
|---|---|---|
| 控制平面(随发布提供) | POLICY_PUBKEY_B64+CONTROL_PLANE(首次启动加ENROLLMENT_TOKEN) | 注册一次,按通告节奏拉取并验证签名策略,心跳上报真实摄入游标。仪表盘的吊销在一个刷新周期内到达网关。 |
| 运维托管文件 | POLICY_PUBKEY_B64+POLICY_PATH,无控制平面 | 文件是来源,每个轮询间隔重读。适用于气隙部署。你有责任投递新鲜信封——陈旧文件会失败关闭(fail closed),且该姿态下时钟偏差无法诊断。 |
| 未认证(M1 演示) | 两者皆无 | 每个/api/enterprise/v1/*路由都无令牌应答。网关每次启动都会把它记为 ERROR。只在完全受控的私有网络上、且仅用于演示时才可以接受。 |
只设置POLICY_PUBKEY_B64而没有控制平面或策略路径是启动错误:网关不会去猜认证姿态。这一逻辑在 main.rs 中直接体现:POLICY_PUBKEY_B64已设置但CONTROL_PLANE/POLICY_PATH皆无时,直接return Err(...)——"refusing to guess an auth posture"。
权衡:两个窗口
有两个窗口共同决定暴露面——刷新节奏(吊销的令牌还能用多久)与策略有效窗口(控制平面故障能持续多久而网关仍继续服务)。缩短一个就会加长对另一个的暴露。规范值、理由与环境变量覆盖,README 明确刻意不在本文重复("安全窗口的副本多一份都是浪费"),而是指向网站仓库与信任模型文档。
网关如何使用它们是本文该说的部分:
- 策略超过有效窗口 →每个受作用域路由 503,对所有令牌。失败开放(fail open)意味着在为一个已过期授权列表服务,这无法证明此后的任何吊销。
- 策略签发于未来、或在到达时因时钟与签名者不一致而过期 → 仍然 503,但消息点名NTP而非暗示控制平面故障。
- 失败的刷新会保留上一份文档。一次坏的拉取不是故障。
- 为不同组织签发的策略即使验证通过也会被拒绝:签名密钥跨租户共享,所以有效签名只能证明 Screenpipe 签发了该信封。载荷的
license_id才是全部租户绑定——因此第三节强调查询按SCREENPIPE_GATEWAY_LICENSE_ID划定范围。
main.rs 的认证装配清晰可见:设置policy_pubkey_b64时构造PolicyStore::new(&cfg.license_id)(绑定租户的存储),随后ControlPlaneTask::boot完成注册→播种策略→武装刷新与心跳循环;无控制平面时回退到文件姿态或大声报错。
验证者摘要列表(verifier digest list)
网关持有的签名策略包含你组织中每个活跃sk_ent_令牌的 SHA-256 摘要,因此验证完全可以离线——无需对 Screenpipe 做每次查询的调用,这正是整个设计的要点。这允许与不允许什么(非加盐摘要、高熵令牌、轮换、以及未决的安全评审问题)写在信任模型文档的 "verifier digest" 一节。信封格式在 policy.rs 中有完整 JSON 示例:version、alg: ed25519、key_id、payload_b64、signature_b64,签名覆盖解码后的原始载荷字节(与 JWS 相同的构造,完全绕开 JSON 规范化问题);载荷为license_id、issued_at、valid_until、token_grants[](每个 grant 含digest、scopes、可选expires_at)。
认证中间件 auth.rs 实现了细节:令牌形状合法性(长度 16..=4096)、未知令牌 → 401invalid token、过期授权 → 401token expired、缺作用域 → 403 并列出已拥有作用域;路由分类默认拒绝(deny by default)——只有PUBLIC_ROUTES(/health、/version、/access-log)允许免认证,未分类的新路由会被 403 拒绝(SCR-353 的回归防护)。
十、验证是否工作——以及访问日志
健康与版本端点免认证(/health、/version)。然后:
GW=http://127.0.0.1:3040 curl -sf "$GW/health" # 首次上传后的一个轮询周期内应出现设备 curl -sf "$GW/api/enterprise/v1/devices" -H "authorization: Bearer $SK" | jq curl -sf "$GW/api/enterprise/v1/search?q=roadmap" -H "authorization: Bearer $SK" | jq每个 v1 请求都会在容器 stdout 产生一行访问日志,在RUST_LOG=info下:
2026-07-24T09:14:02.117Z INFO screenpipe_gateway::access_log: v1 query \ path=/api/enterprise/v1/search scope="read:search" status=200 served=true \ token_digest_prefix="9f2c1ab0" elapsed_ms=7每请求一行(上面为可读性折行)。字符串字段带引号,所以用grep 9f2c1ab0搜裸值,而不是grep token_digest_prefix=9f2c1ab0。颜色码只在 stdout 是终端时输出——日志文件或容器日志驱动会得到干净可 grep、可解析的纯文本。access_log.rs 中有专门测试no_binary_configures_tracing_by_hand守护这一点,防止任何二进制绕过统一的init_tracing而把 ANSI 转义码带进日志。
要点:
- 查询串刻意缺席——
?q=…是搜索者真正的搜索文本,访问日志不是放它的地方。 token_digest_prefix是sha256(token)的前 8 个十六进制字符,与策略授权列表使用同一摘要方案。要把一行归属到某个令牌,就用策略信封中的摘要对它做前缀匹配。日志永不持有凭据。- 把这些行送到你的日志汇(log sink),按自己的节奏保留。这就是"谁读了归档"的持久审计记录——Screenpipe 侧按构造没有等价物。
- 两个
scope值不是作用域。<unmapped>是没有匹配到作用域、因此在读令牌之前就被拒绝的路由;<not-served>是托管专属表面(/pipes、/workflows/generated)以类型化 501 应答。两者都会被记录,让探测留下痕迹,并与read:*分开计数——二者永远不可能是归档读取,合并计数会夸大你的归档被查询的量。
机器可读摘要位于/access-log:
curl -sf "$GW/access-log" | jq { "process_started_at": "…", "queries_served": 412, "queries_denied": 3, "last_query_served_at": "…", "by_scope": { "read:search": { "served": 380, "denied": 2 }, … }, "reported_to_screenpipe": false }计数器是进程生命周期的,重启即重置——日志行才是持久记录。该端点刻意免认证:它正是你在认证不工作时(策略过期、控制平面宕机、令牌被吊销)需要的东西,而恰恰在这些时候,认证门后的计数器会读不到。它只携带聚合计数——无查询文本、无设备 id、无对象键、无令牌材料——但确实会向任何能触达端口的东西暴露网关有多忙,这正是第一、七节要求你限制端口的原因。
查询量永远不会发给 Screenpipe。心跳只携带摄入计数器(看到/摄入/失败的对象、插入/去重的记录、不可解析的行)与摄入游标——与查询无关。reported_to_screenpipe在该载荷中字面为false,让评审者可以直接核查该声明而非相信它。access_log.rs 的模块注释说明了为什么审计日志与计数器是两个刻意分离的产物:日志是持久记录,计数器是进程内快照;并解释了为何/access-log必须免认证(故障时可用)以及为何按作用域而非路径计数(防止/files/*key这类调用者可控段导致内存无界增长的 DoS)。
十一、故障排查
仪表盘的网关面板显示最近一次心跳的错误码。对照此表:
| 码 | 含义 | 首先检查什么 |
|---|---|---|
E_S3_ACCESS_DENIED | 网关的凭据/角色读不了桶。 | 角色在enterprise-telemetry/{license_id}/*上的s3:GetObject+s3:ListBucket(第五节)。 |
E_S3_LIST/E_S3_GET | 存储可达但调用失败。 | endpoint、region、path-style、网络出口。 |
E_BATCH_PARSE | 对象不是合法线上格式。 | 桌面应用版本偏差;遗留加密对象会被跳过而非失败。 |
E_DB_WRITE/E_DB_READ/E_SNAPSHOT_STORE | 本地磁盘。 | 卷满,或$DATA_DIR对screenpipe用户不可写。 |
E_POLICY_FETCH | 策略拉取失败(不可达、5xx、或控制平面签名密钥未配置)。 | 每个受作用域路由都在 503。每次心跳刻意重申。 |
E_POLICY_REJECTED | 信封到达但验证失败,或它为另一组织签名。 | POLICY_PUBKEY_B64与/api/enterprise/gateway/policy-key一致;LICENSE_ID与策略一致。 |
E_POLICY_STALE | 缓存策略老化超时。所有受作用域内容都在 503。 | 控制平面可达性,然后是时钟。 |
E_POLICY_CLOCK_SKEW | 本机时钟与签名issued_at不一致。 | 用date -u对照控制平面。运行 NTP。 |
按症状排查:
| 症状 | 原因 |
|---|---|
| 容器启动即退出 | 配置错误。读最后一行日志——每一行都会点名对应变量。 |
| 每个查询都 503 | 尚未安装策略,或策略过期/未来日期。/health仍应答;查启动日志与心跳码。 |
每个查询都 401invalid token | 令牌不在当前授权列表中——被吊销,或在上次刷新之后铸造。等一个刷新周期。 |
403token lacks required scope | 看仪表盘 API-tokens 页里令牌的作用域。消息会列出它实际拥有的作用域。 |
403route has no scope mapping | 你到达了本构建未分类的路径。不是配置问题——请上报。 |
上传后/devices返回 0 | 摄入尚未跟上(一个轮询周期),或桶/前缀/license id 与设备上传目标不匹配。 |
状态卡在registered,从不active | 激活需要心跳和通过拒绝金丝雀。从仪表盘运行金丝雀。 |
十二、容量规划
诚实声明:我们未发布单设备-日(per-device-day)数字,因为我们没有在真实设备群上测量过。两次合成设备本地运行得出的数字对真实部署会错上几个数量级,而错误指导比没有更糟。能告诉你的只有形态,以及如何测你自己的。
- CPU由摄入主导(JSON 解析 + SQLite 插入 + FTS 分词),在轮询间隔上是突发性的而非平稳的。搜索是本地文件上的 SQLite FTS5。单个小实例(2 vCPU)是合理的起点。
- 内存由 SQLite 的页缓存和正在解析的批次大小主导。没有归档的内存索引。
- 磁盘是关键的轴,在你清除它之前无界增长(第七节)。两个贡献者,规模差异很大:记录文本(小、可压缩、大致与你设备上传的 OCR/转写量成正比)和
snapshots/(帧图——如果你的设备群上传快照,它就是主导项)。 - 来自桶的网络出口在首次摄入时等于归档大小,之后每次轮询是增量。在 AWS 上,让网关与桶同区域。
在真实流量跑一周后测你自己的:
# 索引与快照分开测——比值就是全部故事 docker compose exec gateway sh -c 'du -sh /data/gateway.db /data/snapshots' # 这代表多少条记录:看心跳计数器,在仪表盘面板或直接从线上抓除以records_inserted和设备-日数,你就得到你自己的设备群内容配比数字。据此设置卷,并在它填满前规划清除或快照生命周期——E_DB_WRITE就是卷满的样子。
十三、重启与升级
网关可随时安全重启,也可从全新镜像运行:
- 摄入对每个对象和每条记录都是幂等的,与记账表原子提交,因此批次中途崩溃会干净重放,重复上传会合并。
- 升级时保留
$DATA_DIR。凭据在里头(清除 = 重新注册),索引也在里头(清除 = 重读整个桶)。 - 不要对同一个
DATA_DIR跑两个网关。它们会争夺 SQLite 文件,而且每次/register都会吊销上一个网关行——它们会互相作废凭据。 - 向前滚动升级,不要对同一卷跑混版。
十四、Screenpipe 能看到什么
为完整性说明——这也是上面所有设计的原因。从你的网关,我们只收到心跳:版本、摄入游标、摄入计数器、错误码。没有查询、没有查询量、没有结果、没有内容。令牌生命周期(铸造/吊销)发生在仪表盘,策略拉取按节奏而非按查询——所以我们的访问日志不携带你组织的任何按查询认证流量。你确实查询过的证据在你的侧:第十节。
完整的账目,包括托管部分与托管审计表里的排序怪癖,在信任模型文档中。而网关侧这条"查询发生在这里而非 Screenpipe"的正面证据链,正是 access_log.rs 模块注释所说的"positive control":让"Screenpipe 托管侧显示零内容读取"这个声明变得可证伪、可验证——接受运行(acceptance run)需要客户侧的正向证据,证明查询确实发生了而 Screenpipe 侧零感知。
总结
screenpipe-gateway 是这套写只读企业归档体系中唯一读取主体:它以纯容器形态运行在客户网络内,通过环境变量完成全部配置,从 S3 兼容桶摄入明文批次到本地 SQLite+FTS 索引,以离线验证的签名策略承载sk_ent_令牌认证,并以一请求一行的访问日志把"谁读了归档"的审计记录完整留在客户侧。部署时记住四条红线——桶不公开、端口不公开、明文索引自管、时钟走 NTP——再按三种认证姿态选择适合自己的路径,即可在生产环境中安全落地。
深入阅读:完整的代码与配置可从 crates/screenpipe-gateway/README.md、Dockerfile、e2e/docker-compose.yml 及 src/config.rs、src/main.rs、src/auth.rs、src/policy.rs、src/access_log.rs 入手;端到端行为测试可参考 tests/binary_talks_to_the_control_plane.rs 与 e2e 一致性测试目录 e2e/conformance。
【免费下载链接】screenpipeYC (S26) | Open Computer History | Record your screen continuously locally and provide context to your agents (Claude, Codex, Openclaw, Hermes, Runner...)项目地址: https://gitcode.com/GitHub_Trending/sc/screenpipe
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考