Categories
Uncategorized

Bluesky PDS Without Docker

Here’s how I got a self-hosted PDS (personal data server) running without docker.

This can be useful if you want to run the PDS on an existing machine or just don’t like docker. I came up with these steps by emulating what the installer script does.

My setup uses nginx and a wildcard TLS cert for my PDS domain.

Get the code

Clone the PDS repo

$ git clone https://github.com/bluesky-social/pds

Set up nginx

I use certbot to issue wildcard certs for my domains. See my wildcard cert script here. Note that you will need to set up credentials for your nameservers. I’m not aware of a way in nginx to issue certs on-demand like the example caddy config does.

Here’s my nginx config for the PDS.

server {
listen 80;
server_name hellthread.pro *.hellthread.pro;
return 302 https://$host$request_uri;
}

server {
listen 443 ssl http2;
server_name hellthread.pro *.hellthread.pro;
ssl_certificate /etc/letsencrypt/live/hellthread.pro/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hellthread.pro/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

location / {
include proxy_params;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://127.0.0.1:3002;
}
}

Configure your .env file

Adjust the top 4 options, filling in your domain and generating keys with the following commands:

Use this for the JWT_SECRET:

$ openssl rand --hex 16

Use this twice to generate the admin password and rotation key:

$ openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32
PDS_HOSTNAME="your domain here"
PDS_JWT_SECRET="generated secret"
PDS_ADMIN_PASSWORD="generated key"
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX="another generated key"

PDS_DATA_DIRECTORY=./data
PDS_BLOBSTORE_DISK_LOCATION=./data/blocks
PDS_DID_PLC_URL=https://plc.directory
PDS_BSKY_APP_VIEW_URL=https://api.bsky.app
PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app
PDS_REPORT_SERVICE_URL=https://mod.bsky.app
PDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndac
PDS_CRAWLERS=https://bsky.network
LOG_ENABLED=true
NODE_ENV=production
PDS_PORT=3002

Run the PDS

Be sure to install the dependencies:

$ cd service
$ pnpm install --production --frozen-lockfile
$ mkdir -p data/blocks

This is the systemd setup I use to run the PDS. Add your own user unit with the following steps:

$ mkdir -p ~/.config/systemd/user
$ $EDITOR ~/.config/systemd/user/pds.service
# copy in the example below and adjust as needed
$ systemctl --user daemon-reload
$ systemctl --user enable --now pds

pds.service:

[Unit]
Description=atproto personal data server

[Service]
WorkingDirectory=/home/ben/workspace/pds/service
ExecStart=/usr/bin/node --enable-source-maps index.js
Restart=on-failure
EnvironmentFile=/home/ben/workspace/pds/service/.env

[Install]
WantedBy=default.target

View the logs from journalctl like this:

$ journalctl --user --output=cat --follow --unit pds | jq

You can run the pdsadmin commands by setting the PDS_ENV_FILE variable like this:

ben@odin ~/w/p/pdsadmin (main)> PDS_ENV_FILE=../service/.env bash account.sh list
Handle Email DID
ben.hellthread.pro ben@hellthread.pro did:plc:g5isluhi3wkw557ucarjgtgy

Update

To update your PDS, use git pull in the directory you cloned it in. Then update dependencies in the service subdirectory and restart the unit:

$ cd pds
$ git pull
$ cd service
$ pnpm install --production --frozen-lockfile
$ systemctl --user restart pds
Categories
Uncategorized

tilde.team subdomains as bluesky handles

This is a quick tutorial on using your tilde.team subdomain as a handle on bluesky. Domain verification on bluesky can be done with a DNS challenge or by serving a text file from .well-known in your webroot.

Since adjusting the Content-Type for plaintext files with no extension isn’t possible without changing global nginx configs, the quickest way is to use a tiny php script.

<?php header("Content-Type: text/plain");
echo "did:plc:v7tbr6qxk6xanxzn6hjmbk7o";

Make sure that the following directory exists ~/public_html/.well-known/atproto-did and put the above script in there as index.php, replacing the did with your own.

Then go to Settings > Change Handle on bsky.app, pick “I have my own domain”, then pick the No DNS Panel tab. Enter your subdomain and hit Verify Text File.

You can use any of the domains that are hooked up to your ~/public_html. See the list on the tilde.team wiki.

Here’s the source for mine on tildegit.

Categories
Uncategorized

Bluesky Post Permalinks

I set up a handy way to permalink my bluesky posts with a quick nginx config change.

I use a custom domain as my handle on bluesky (https://bsky.app/profile/benharr.is), but have changed it before which has broken some links that I’ve shared elsewhere. See the DID tracker for my handle change history.

As an example, here’s some pics of Shaq Attaq that I posted the other day: https://benharr.is/post/3k655thdbzv2p. Note that bsky.app is not in the url.

I added this location block to the nginx config for benharr.is:

location ~ ^/post/ {
       return 302 https://bsky.app/profile/did:plc:v7tbr6qxk6xanxzn6hjmbk7o$request_uri;
}