← 返回日报
精读 预计 4 分钟

Make the PDS Your Own: Customization and Metrics

摘要

这是 AT Protocol 官方博客发布的一篇关于参考 PDS(Personal Data Server)更新的文章。本次发布包含四项内容:一是账户管理界面与 OAuth 登录页的品牌定制,将原先零散的开关整理成一组更小、更清晰且有文档的变量(名称、Logo、颜色、页脚链接),并新增认证页背景图功能,文字颜色会自动根据主色选择黑或白以保证可读性;二是为运维人员提供 OpenTelemetry 支持,可输出追踪、指标和日志,默认关闭,开启后可自动采集 HTTP、SQLite、S3 存储及 Node 运行时指标,并新增 account.created、session.created、oauth.authorization 等计数器,同时发布配套的 Prometheus/Grafana/node exporter 监控栈与 PDS Overview 仪表盘,整个栈内存占用低于 1GB,默认绑定 localhost 可通过 SSH 隧道访问;三是将默认最大 blob 大小提升至 300M,以支持更长的视频上传,现有安装需手动修改 pds.env 并重启,PDS 还新增通过 describeServer 通告最大 blob 大小的能力;四是修复了账户管理页连接应用列表中部分会话因长时间未刷新而缺失的 bug,现在列表能准确显示所有已授权应用。文章面向自托管 PDS 的运维者,提供了具体的环境变量示例和配置方法。

荐读理由

照文中给的 pds.env 变量就能给自建 PDS 换品牌和接 OpenTelemetry 监控,Prometheus 直收 OTLP 的整套仪表盘配置可直接抄走

原文

When we shipped the account management page back in June, we closed that post with a promise: more reference PDS updates over the summer, including observability tooling. Today’s release makes good on that and then some.

There are four things in this release: customization for the account management interface, OpenTelemetry support, bigger default blob sizes, and a fix for a bug in the connected apps list.

Making it yours

The account management page and the OAuth sign-in screens are the parts of your PDS that your users actually look at. You’ve already been able to put your own name, logo, colors and links on them, but they were one-off toggles and not documented consistently.

This release cleans that up: a smaller, clearer set of variables, all of it properly documented, plus one fully new piece: a background image for the auth screens.

If you’re running the reference PDS with the standard Docker deployment, you can start experimenting in your pds.env and restart. Start with a name and logo:

PDS_SERVICE_NAME="Example Social"
PDS_LOGO_URL="https://example.com/logo.svg"

PDS_SERVICE_NAME defaults to your hostname followed by “PDS”, so setting it is the single highest-impact change you can make. Both of these also flow through to the transactional emails your PDS sends, so password reset messages get your branding too.

Colors are set the same way. The one you’ll want first is the primary color, which drives buttons, links, and accents:

PDS_PRIMARY_COLOR="#7c3aed"

There are four more for the semantic states: PDS_ERROR_COLOR, PDS_WARNING_COLOR, PDS_INFO_COLOR, and PDS_SUCCESS_COLOR.

All of them are optional. The color of the text drawn on top of your primary color is derived for you, picking whichever of black or white reads better against it, so the accessible choice is the default rather than something you have to configure.

Finally, you can add your own links to the footer:

PDS_HOME_URL="https://example.com"
PDS_TERMS_OF_SERVICE_URL="https://example.com/tos"
PDS_PRIVACY_POLICY_URL="https://example.com/privacy"
PDS_SUPPORT_URL="https://example.com/support"

Here’s the sign-in step on a deployment with branding configured — in this case Bluesky’s own, applied through exactly the variables above:

A PDS that configures none of this does not look like Bluesky. The defaults are neutral, and the branding above is the result of setting those variables, not something you inherit.

To set a background image(!) for the auth screens, which sits behind the sign-in card:

PDS_BACKGROUND_LIGHT_URL="https://example.com/bg-light.png"
PDS_BACKGROUND_DARK_URL="https://example.com/bg-dark.png"

A user in dark mode gets the dark layout implicitly, without a toggle. The image is drawn cover and centered over your neutral base color, and the card keeps its own opaque surface, so your copy stays legible no matter how busy the image is.

Knowing what your PDS is doing

The other half of this release is for operators rather than users. The PDS now supports OpenTelemetry for traces, metrics, and logs.

Telemetry is off by default, and once again, you can opt in by setting environment variables on the reference PDS:

NODE_OPTIONS="--import=@atproto/pds/telemetry"
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
OTEL_SERVICE_NAME="pds"

Once it’s on, you get automatic instrumentation for PDS metrics: inbound and outbound HTTP, the SQLite layer, S3-compatible blob storage, and Node runtime metrics like event loop lag and garbage collection.

XRPC requests are normalized by method, so a span comes through as GET /xrpc/com.atproto.repo.getRecord rather than being flattened into a single / route, and the NSID is attached as an attribute.

On top of the automatic instrumentation, the PDS emits counters for the events an operator cares about:

  • account.created — new accounts, dimensioned by whether signup came through OAuth or the XRPC endpoint

  • session.created — sign-ins, dimensioned by source

  • oauth.authorization — OAuth grants issued to apps

We’re also publishing a dashboard to go with all of this. The monitoring/ directory in the reference PDS repo has a self-contained Prometheus, Grafana and node_exporter stack plus a ready-made PDS Overview dashboard, covering host health alongside PDS activity:

There’s no OpenTelemetry Collector in that stack. Prometheus v3 can receive OTLP directly, so the PDS pushes metrics straight to it. Our sample dashboard stack can run alongside a PDS in under 1GB of memory.

Everything binds to localhost by default, so you can reach Grafana over an SSH tunnel. If you already run Prometheus and Grafana, you don’t need the compose file at all; you can point the PDS at your own OTLP endpoint and import the dashboard JSON. Either way, monitoring/README.md has the walkthrough, including which OTEL_* variables the dashboard’s panels depend on.

Bigger blobs by default

We’ve decided to raise the default maximum blob size to 300M. This is primarily to allow longer videos on Bluesky, which I posted about last week:

hey self-hosters! we’re planning to raise default PDS blob size limits to 300M soon to allow users to upload longer videos (up to ~10 minutes at 3mbit) by default. any thoughts?

Alex (@alex.bsky.team) 2026-07-28T21:04:22.466Z

The response was positive, so we went ahead and made the change.

If you’re already running a PDS: this is a change to what the installer writes into pds.env, so new installs pick it up but existing ones don’t. To raise the limit on a PDS you’ve already got running, set it yourself and restart:

PDS_BLOB_UPLOAD_LIMIT=314572800

We’ve also enabled the PDS to advertise its maximum blob size via describeServer, so clients can split or reject uploads if desired:

curl -s https://maitake.us-west.host.bsky.network/xrpc/com.atproto.server.describeServer | jq
{
  "did": "did:web:maitake.us-west.host.bsky.network",
  "availableUserDomains": [
    ".bsky.social"
  ],
  "inviteCodeRequired": true,
  "blobUploadLimit": 314572800,
  "links": {
    "privacyPolicy": "https://bsky.social/about/support/privacy-policy",
    "termsOfService": "https://bsky.social/about/support/tos"
  },
  "contact": {}
}

Sessions that actually show up

This release also fixes a bug in the connected apps list on the Account Management page.

Previously, the list only reliably surfaced sessions that had been refreshed recently. If you’d authorized an app and then not opened it in a while, it could be missing from the list.

The list is now accurate regardless of when a session was last refreshed. If you’ve been using the account management page to audit your connected apps, you may see entries that were previously hidden.

Getting the update

All in all, this is a big release for the reference PDS, and knocks out all the remaining items on our summer PDS to-do list. If you’re running the reference PDS with the standard Docker deployment, it’ll automatically update to the newest release. Try it out and let us know what you think!

Lobsters · 1 赞 · 0 评 讨论 → 阅读原文 →

这条对你有帮助吗?