Bluesky PDS
A self-contained Docker image for the Bluesky PDS (Personal Data Server) for use with Traefik.
Custom Domain
You do not need to setup a PDS to have a custom domain in your username. Bluesky provides documentation for DNS setup.
| Official bluesky-pds project | GitHub - bluesky-social/pds |
| Image on Forgejo | Forgejo |
| Image on Dockerhub | Dockerhub |
| Image Source | Forgejo |
| Issue Tracker | GitHub - gravityfargo/bluesky-pds-docker |
A self-contained Docker image for the Bluesky PDS (Personal Data Server) for use with Traefik.
It is required to run the instance behind a proxy (like Traefik) to generate SSL certificates. This will not work otherwise. The standard pds install includes caddy to handle this. A wildcard DNS assignment along with a wildcard SSL certificate is required.
This is not intended for production, and I am not responsible for any data loss or security issues. This is a personal project, and I am not affiliated with Bluesky.
Setup¶
Generate secrets and add them to .env file.
See example.env as an example.
# Generate secret environment variables
echo PDS_ADMIN_PASSWORD: $(openssl rand --hex 16)
echo PDS_JWT_SECRET: $(openssl rand --hex 16)
echo PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX: $(openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32)
Compose File¶
By default, the image uses 1000:1000 as the UID:GID for the user. This can be changed by setting the PUID and PGID environment variables.
Traefik¶
# Traefik Proxy
services:
bluesky-pds:
image: code.modernleft.org/gravityfargo/bluesky-pds:latest
environment:
PDS_JWT_SECRET: ...
PDS_ADMIN_PASSWORD: ...
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX: ...
PDS_HOSTNAME: example.com
# PDS_EMAIL_SMTP_URL:
# PDS_EMAIL_FROM_ADDRESS:
EUID: 1000
EGID: 1000
volumes:
- ./bluesky-pds:/pds
labels:
traefik.enable: "true"
traefik.http.routers.bluesky-pds-insecure.entrypoints: http
traefik.http.routers.bluesky-pds-insecure.rule: HostRegexp(`^.+\.example\.com$`) || Host(`example.com`)
# traefik.http.routers.bluesky-pds-insecure.middlewares: BlueskyHeaders@file
traefik.http.routers.bluesky-pds-secure.entrypoints: https
traefik.http.routers.bluesky-pds-secure.rule: HostRegexp(`^.+\.example\.com$`) || Host(`example.com`)
traefik.http.routers.bluesky-pds-secure.tls: "true"
traefik.http.services.bluesky-pds.loadbalancer.server.scheme: http
traefik.http.services.bluesky-pds.loadbalancer.server.port: 3000
# traefik.http.routers.bluesky-pds-secure.middlewares: BlueskyHeaders@file
Optionally, you can use this file BlueskyHeaders.
I think file configs are cleaner than having a billion labels. This is not required, but it's nice to have.
Standalone¶
I do not run this, but it should be possible. You must setup SSL for it to connect to the Bluesky network. I have not tested this.
# Standalone, you'll need to add a proxy in front of this with SSL.
services:
bluesky-pds:
container_name: bluesky-pds
image: code.modernleft.org/gravityfargo/bluesky-pds:latest
environment:
PDS_JWT_SECRET: ...
PDS_ADMIN_PASSWORD: ...
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX: ...
PDS_HOSTNAME: example.com
# PDS_EMAIL_SMTP_URL:
# PDS_EMAIL_FROM_ADDRESS:
EUID: 1000
EGID: 1000
volumes:
- ./bluesky-pds:/pds
Environment Variables¶
Full list of additional Environment Variables provided by Bluesky upstream can be found in the packages/pds/src/config/env.ts
| Variable | Description | Default | Required |
|---|---|---|---|
PDS_JWT_SECRET |
JWT secret for the PDS server | "" |
* |
PDS_ADMIN_PASSWORD |
Password for the admin account | "" |
* |
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX |
64 char hex strings (256 bit) | "" |
* |
PDS_HOSTNAME |
Hostname for the PDS server | "" |
* |
PDS_EMAIL_SMTP_URL |
SMTP URL and authentication for email | "" |
|
PDS_EMAIL_FROM_ADDRESS |
Email address for email notifications | "" |
|
EUID |
User ID for the container | 1000 |
|
EGID |
Group ID for the container | 1000 |
|
LOG_ENABLED |
If the stdout will be shown in the console | true |
|
LOG_DESTINATION |
Where the logs will be sent | stdout |
|
LOG_LEVEL |
The level of logging | info |
Unraid¶
While I do not use Unraid, a user on Reddit has added this project to the Unraid App store. I won't be providing any meaningful support it.
Unraid does not include the xxd package. You'll need another Linux machine for that.
You can use a temporary alpine container for this.
Unraid does not come with the xxd command installed. There used to be a package called "NerdTools" that I used to use but it looks like it was removed. I do not recall if you can use docker run in Unraid, but these commands can be used. A quick google indicates windows users can use the docker cli.
Check your work¶
This is just a reiteration of Verifying that your PDS is online and accessible from the pds docs.
If you go to https://example.com/xrpc/_health you should be greeted with the JSON
To check that WebSockets are working use the go package wsdump or go to PieSoket's online websocket tester
Running Commands¶
The commands are the same as those for the upstream project. Such as
Updating
Don't use pdsadmin update. I have not tested this, and it may break things. Submit an
issue to my repository requesting an update, and I will release a new image version.
Networking¶
Container Hostname¶
If you set the container hostname to the domain of your pds server,
you will get the error curl: (7) Failed to connect to example.com port 443 after 0 ms: Couldn't connect to server. You have two options.
- Do not set the hostname.
- Add the
extra_hosts:section to your compose file to act as an entry to /etc/hosts that manually points the FQDN to your external IP. See the Cloudflare DNS section for an example.
Cloudflare DNS¶
I do not use their services after their many controversies. Theo - t3.gg has a good video on the topic. I wont be providing support for any issues that may arise. If you are a CF user and encounter issues, disable DNS proxy and restart the service.
This container does not work well with Cloudflare. I won't provide support. However, here are some notes. In the Cloudflare control panel, you need to enable WebSockets. You also need to set
services:
bluesky-pds:
image: forgejo.gravityfargo.dev/gravityfargo/bluesky-pds:v0.4.107
extra_hosts:
- "example.com:0.0.0.0" # must be the external IP to bypass cloudflare.
I stopped using Cloudflare around the same time I was messing with this. So I don't have any more information than this.
A user on reddit commented with a setup for using cloudflared if that helps.
FAQ¶
Why does command pdsadmin ... give me curl: (7) Failed to connect?¶
The pds server is unable to resolve itself. See the Networking section for more information.
I keep getting "/pds/pds.env: line N: $N: unbound variable"¶
You have not set all of the required environment variables.
Error: Resource URL must use the https scheme¶
PDS_HOSTNAME is not set.
"Invalid Handle"¶
Bluesky provided a fix. Here's a copy of their post.
One part of our upgraded infrastructure may affect your profile. If you see your handle now says “Invalid handle,” please reverify it by navigating to Settings > Change my handle > Type in your current handle > Verify DNS Record > Update. (Basically, update to the same handle.)