Add PDS bluesky docker setup write-up
This commit is contained in:
parent
184e120ef0
commit
69f47eff78
@ -1,7 +1,7 @@
|
||||
source: "."
|
||||
destination: _site
|
||||
site:
|
||||
title: QRouland DevBlog
|
||||
title: DevBlog
|
||||
description: QRouland DevBlog
|
||||
base_url: http://blog.qrouland.com
|
||||
posts:
|
||||
|
2
posts.md
2
posts.md
@ -5,5 +5,5 @@ permalink: /posts
|
||||
---
|
||||
|
||||
{% for post in collections.posts.pages %}
|
||||
### [{{ post.published_date | date: "%Y-%m-%d" }} - {{ post.title }}](/{{ post.permalink }})
|
||||
### [{% if post.published_date %}{{ post.published_date | date: "%Y-%m-%d" }} - {% endif %} {{ post.title }}](/{{ post.permalink }})
|
||||
{% endfor %}
|
||||
|
259
posts/2025-01-27-writeup-1-bluesky-pds.md
Normal file
259
posts/2025-01-27-writeup-1-bluesky-pds.md
Normal file
@ -0,0 +1,259 @@
|
||||
---
|
||||
permalink: /posts/writeup/1
|
||||
title: Hosting Bluesky PDS on my Server Using Docker
|
||||
categories:
|
||||
- Write Up
|
||||
tags:
|
||||
- write up
|
||||
- bluesky
|
||||
- docker
|
||||
published_date: 2025-01-27 10:37:07.201403915 +0000
|
||||
layout: default.liquid
|
||||
is_draft: false
|
||||
---
|
||||
## Self-hosting Bluesky PDS Using Docker
|
||||
|
||||
I'm not usually a big user of social networks, but with my new blog, I wanted a way to share updates on social media.
|
||||
I went with Bluesky for its decentralized nature, which aligns with my interest in the growing trend of decentralized social platforms.
|
||||
|
||||
In this write-up, I will document the steps I took to install [Bluesky’s PDS (Personal Data Server)](https://github.com/bluesky-social/pds) on my setup, an Ubuntu server running Docker.
|
||||
|
||||
Thanks to this [write-up](https://mattdyson.org/blog/2024/11/self-hosting-bluesky-pds), which was a huge help to do mine.
|
||||
While most of it was very useful, some parts differed since my Docker setup is different.
|
||||
Also, I encountered difficulties when trying to change my handle to the root domain, so I used a different method to achieve this.
|
||||
As a result, I hope this guide will provide additional value and be helpful to others.
|
||||
|
||||
|
||||
|
||||
### Installing the PDS Using Docker
|
||||
|
||||
The starting point is the official bluesky [compose.yaml](https://github.com/bluesky-social/pds/blob/main/compose.yaml). However, my environment already include other services, including an [NGINX proxy with ACME Companion](https://github.com/nginx-proxy/acme-companion) to automatically generate and renew TLS certificates for my http services (see [Basic usage](https://github.com/nginx-proxy/acme-companion/wiki/Basic-usage)).
|
||||
|
||||
Therefore, I modify this ```compose.yaml``` to reuse my proxy setup to provide a reverse proxy for the PDS container, eliminating the need for the reverse proxy (Caddy) provided in the initial file. I also remove Watchtower, as I use my own scripts to handle image updates.
|
||||
|
||||
|
||||
Finally, my ```compose.yaml``` is pretty simple file looks like this:
|
||||
|
||||
```yaml
|
||||
version: '3.9'
|
||||
services:
|
||||
pds:
|
||||
container_name: pds
|
||||
image: ghcr.io/bluesky-social/pds:0.4
|
||||
network_mode: host
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- type: bind
|
||||
source: <SOME PATH IN HOST>/pds # Change this for
|
||||
target: /pds
|
||||
env_file:
|
||||
- pds.env
|
||||
```
|
||||
|
||||
Most of the setup is to adapt with environment variables in the environment file ```pds.env```:
|
||||
|
||||
```ini
|
||||
# PDS_HOSTNAME: The domain name of your PDS service (e.g., domain.com)
|
||||
PDS_HOSTNAME=<YOUR DOMAIN>
|
||||
# PDS_SERVICE_HANDLE_DOMAINS: A suffix for the domain to be used with the service (e.g., .domain.com)
|
||||
PDS_SERVICE_HANDLE_DOMAINS=.<YOUR DOMAIN>
|
||||
# PDS_JWT_SECRET: A secret key for signing JWT tokens, needed for secure authentication
|
||||
PDS_JWT_SECRET=<SECRET HERE>
|
||||
# PDS_ADMIN_PASSWORD: The admin password for accessing the PDS service (use a strong password generated by a password manager)
|
||||
PDS_ADMIN_PASSWORD=<ADMIN PASSWORD>
|
||||
# PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX: A private key for cryptographic operations in hex format
|
||||
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=<KEY HEX HERE>
|
||||
# PDS_DATA_DIRECTORY: Directory where data will be stored (e.g., /pds)
|
||||
PDS_DATA_DIRECTORY=/pds
|
||||
# PDS_BLOBSTORE_DISK_LOCATION: Location for storing blob data (e.g., /pds/blocks)
|
||||
PDS_BLOBSTORE_DISK_LOCATION=/pds/blocks
|
||||
# PDS_BLOB_UPLOAD_LIMIT: The maximum upload size for blobs in bytes (e.g., 50 MB = 52428800 bytes)
|
||||
PDS_BLOB_UPLOAD_LIMIT=52428800
|
||||
# PDS_EMAIL_SMTP_URL: The URL for the SMTP server used to send emails (e.g., for email verification)
|
||||
PDS_EMAIL_SMTP_URL="smtp://<USERNAME>:<PASSWORD>@<SMTP HOSTNAME>"
|
||||
# PDS_EMAIL_FROM_ADDRESS: The email address used to send emails (e.g., noreply@domain.com)
|
||||
PDS_EMAIL_FROM_ADDRESS=<EMAIL FROM_ADDRESS>
|
||||
# LOG_ENABLED: Set to 'true' to enable logging
|
||||
LOG_ENABLED=true
|
||||
# PDS_DID_PLC_URL: URL for the DID (Decentralized Identifier) PLC service
|
||||
PDS_DID_PLC_URL=https://plc.directory
|
||||
# PDS_BSKY_APP_VIEW_URL: URL for the BlueSky app view service
|
||||
PDS_BSKY_APP_VIEW_URL=https://api.bsky.app
|
||||
# PDS_BSKY_APP_VIEW_DID: DID for the BlueSky app view service
|
||||
PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app
|
||||
# PDS_REPORT_SERVICE_URL: URL for the report service
|
||||
PDS_REPORT_SERVICE_URL=https://mod.bsky.app
|
||||
# PDS_REPORT_SERVICE_DID: DID for the report service
|
||||
PDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndac
|
||||
# PDS_CRAWLERS: URL for the crawlers to scrape data from (e.g., bsky.network)
|
||||
PDS_CRAWLERS=https://bsky.network
|
||||
# VIRTUAL_HOST: The virtual host for your PDS service (e.g., pds.domain.com)
|
||||
VIRTUAL_HOST=<PDS HOSTNAME>
|
||||
# VIRTUAL_PORT: The port number for the virtual host (e.g., 3000)
|
||||
VIRTUAL_PORT=3000
|
||||
# LETSENCRYPT_HOST: The host for generating a Let's Encrypt SSL certificate (e.g., pds.domain.com)
|
||||
LETSENCRYPT_HOST=<PDS HOSTNAME>
|
||||
# LETSENCRYPT_EMAIL: The email used for Let's Encrypt certificate registration (e.g., admin@domain.com)
|
||||
LETSENCRYPT_EMAIL=<LETSENCRYPT EMAIL>
|
||||
|
||||
```
|
||||
Most variable comments are self-explanatory, but here are some additional hints for a few of them.
|
||||
|
||||
To generate the ```PDS_JWT_SECRET``` , you can use the following command:
|
||||
```sh
|
||||
$ openssl rand --hex 16
|
||||
```
|
||||
|
||||
For ```PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX```, you can use
|
||||
```sh
|
||||
$ openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32
|
||||
```
|
||||
|
||||
Since I run my own mail server on my domain, I use my SMTP server by specifying the information in the format ```smtp://<USERNAME>:<PASSWORD>@<SMTP HOSTNAME>```. If you don't have your own mail server, as mentioned in the official documentation, you can use services like [resend](https://resend.com/) as an alternative.
|
||||
|
||||
|
||||
As I mention before, as I have already have the [NGINX proxy with ACME Companion set up](https://github.com/nginx-proxy/acme-companion), I only need to add the following lines to make the PDS container's port 3000 accessible on ```<PDS HOSTNAME>``` over HTTPS (e.g., https://pds.domain.com) through the reverse proxy:
|
||||
|
||||
```ini
|
||||
VIRTUAL_HOST=<PDS HOSTNAME>
|
||||
VIRTUAL_PORT=3000
|
||||
LETSENCRYPT_HOST=<PDS HOSTNAME>
|
||||
LETSENCRYPT_EMAIL=<LETSENCRYPT EMAIL>
|
||||
```
|
||||
|
||||
The container is now ready to run. To start everything, use the following command to verify is everything looks find:
|
||||
|
||||
```sh
|
||||
$ docker-compose up
|
||||
```
|
||||
|
||||
#### Ensuring Everything the PDS Running as Expected
|
||||
|
||||
As directed in the documentation [https://atproto.com/guides/self-hosting](https://atproto.com/guides/self-hosting), to check that everything is online and working, you can visit `https://<PDS HOSTNAME>>/xrpc/_health` in your browser. You should see a JSON response with the version, like:
|
||||
|
||||
```json
|
||||
{"version":"0.2.2-beta.2"}
|
||||
```
|
||||
|
||||
Additionally, you can use an online WebSocket tester (e.g. [piehost.com](https://piehost.com/websocket-tester))
|
||||
and entered the following URL: `wss://<PDS HOSTNAME>/xrpc/com.atproto.sync.subscribeRepos?cursor=0`
|
||||
If everything is configured correctly, the test should indicate that the connection has been successfully established.
|
||||
|
||||
|
||||
|
||||
### Get your Root Domain (e.g domain.com) as your Bluesky Handle
|
||||
|
||||
You cannot directly create a handle for the root domain (e.g., domain.com). Therefore, we need to create an account with a different handle (e.g., handle.domain.com) and then verify the root domain handle ownership using [Decentralised Identifier (DID)](https://atproto.com/specs/did) . We can verify using DNS or HTTP server verification. It seems you can use either, but I did both to be sure and can't confirm if only one is enough.
|
||||
|
||||
|
||||
#### Create account
|
||||
|
||||
Since the administrative tools are included in the Docker image, they do not need to be installed separately, as follows:
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/bluesky-social/pds/ bluesky-pds
|
||||
$ cd bluesky-pds/pds-admin
|
||||
```
|
||||
|
||||
Then, create an account using a temporary handle (e.g. myhandle.<DOMAIN>)
|
||||
|
||||
```sh
|
||||
$ PDS_ENV_FILE=/path/to/pds.env ./account.sh create <EMAIL ADDRESS> myhandle.<DOMAIN>
|
||||
Account created successfully!
|
||||
-----------------------------
|
||||
Handle : myhandle.<DOMAIN>
|
||||
DID : <DID>
|
||||
Password : <PASSWORD>
|
||||
-----------------------------
|
||||
```
|
||||
|
||||
Make sure to record the handle, DID, and password for future use.
|
||||
|
||||
|
||||
I should be able, at this step, to connect from the Bluesky client (e.g., [https://bsky.app/](https://bsky.app/)) using your custom domain and verify your email address.
|
||||
|
||||
Go to [https://bsky.app/](https://bsky.app/) > **Sign In** >In **Hosting Provider**, select **Custom** > enter your `<PDS HOSTNAME>` (e.g., pds.domain.com) and then use your credentials (email/password) to log in.
|
||||
|
||||
Then, you should be connected and able to verify your email address in the account settings by receiving a code, if your SMTP setup is correct.
|
||||
|
||||
|
||||
Now, to validate our root domain, we first need to set up a Domain Ownership Verification method to confirm that we own the domain for the handle we want (e.g., domain.com).
|
||||
|
||||
#### Domain Ownership Verification using DNS
|
||||
|
||||
To do the verification of the ownership of your domain using DNS add a DNS TXT record ```_atproto.<DOMAIN>``` with ```did=<DID>```.
|
||||
|
||||
#### Domain Ownership Verification using HTTP
|
||||
|
||||
To do the verification of the ownership of your domain using HTTP you need make accecible a file on http server at ```<DOMAIN>/.well-known/atproto-did``` (e.g. https://domain.com/.well-known/atproto-did) that contain your ```<DID>```.
|
||||
|
||||
As I already have an Nginx server running to serve your homepage, I simply added a file at the path ```/.well-known/atproto-did``` in the root directory of my site, containing my ```<DID>``` value running the following :
|
||||
|
||||
```sh
|
||||
$ mkdir <WEB DATA PATH IN HOST>/.well-known
|
||||
$ echo <DID> > <WEB DATA PATH IN HOST>/.well-known/atproto-did
|
||||
```
|
||||
|
||||
For reference, here’s a sample Docker configuration for serving my homepage:
|
||||
|
||||
```yaml
|
||||
version: '2'
|
||||
services:
|
||||
|
||||
web:
|
||||
image: nginx
|
||||
container_name: nginx
|
||||
restart: always
|
||||
expose:
|
||||
- 80
|
||||
volumes:
|
||||
- <WEB DATA PATH IN HOST>:/usr/share/nginx/html:ro
|
||||
environment:
|
||||
- VIRTUAL_HOST=<DOMAIN>
|
||||
- LETSENCRYPT_HOST=<DOMAIN>
|
||||
- LETSENCRYPT_EMAIL=<LETSENCRYPT EMAIL>
|
||||
```
|
||||
|
||||
|
||||
#### Validation
|
||||
|
||||
|
||||
To verify if the DNS or HTTP Domain Ownership Verification is set up correctly,
|
||||
you can check on [https://bsky-debug.app/handle](https://bsky-debug.app/handle) by entering your handle.
|
||||
|
||||
#### Update Handle
|
||||
|
||||
We can now update your handle to your root domain !
|
||||
|
||||
However, I encountered an issue when trying to verify my handle directly in the Bluesky app ([https://bsky.app/](https://bsky.app/)). After logging into my account, I was unable to update my handle to the root domain due to errors. In **Settings > Account > Change Handle > I have my own domain**, selecting **Verify DNS Record** or **Verify Text File** would return an error.
|
||||
|
||||
However, I was able to use the [Go AT protocol CLI tool (goat)](https://github.com/bluesky-social/indigo/tree/main/cmd/goat) to successfully update my handle as follow.
|
||||
|
||||
Installing ```goat``` (require the Go toolchain):
|
||||
```sh
|
||||
$ go install github.com/bluesky-social/indigo/cmd/goat@latest
|
||||
```
|
||||
|
||||
Then, update your handle using the following commands:
|
||||
|
||||
```sh
|
||||
$ goat account login -u <YOUR DID> -p <YOUR PASSWORD> --pds-host <PDS HOSTNAME>
|
||||
$ goat account update-handle <YOUR DOMAIN>
|
||||
```
|
||||
Once connected to your Bluesky account, your handle should now display as your root domain.
|
||||
|
||||
### Finally
|
||||
|
||||
Once the handle update is complete, you can restart the server in detached mode with the command below.
|
||||
|
||||
```sh
|
||||
$ docker-compose up -d
|
||||
```
|
||||
|
||||
### References
|
||||
|
||||
* [Bluesky PDS](https://github.com/bluesky-social/pds/)
|
||||
* [Atproto Self Hosting Documentation](https://atproto.com/guides/self-hosting)
|
||||
* [Matt Dysion Write Up](https://mattdyson.org/blog/2024/11/self-hosting-bluesky-pds)
|
||||
* [https://bsky-debug.app/handle](https://bsky-debug.app/handle)
|
||||
* [Go AT protocol CLI tool (goat)](https://github.com/bluesky-social/indigo/tree/main/cmd/goat)
|
Loading…
x
Reference in New Issue
Block a user