# bluesky-pds-docker A self-contained Docker image for the [Bluesky PDS (Personal Data Server) ](https://github.com/bluesky-social/pds) for use with Traefik. This image is pinned to v0.4.74. 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. I use Cloudflare for this, see the screenshot below. Cloudflare's DNS Proxy Service will not work for this setup because of the email verification requirement. You must use the DNS only service. 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. ## Deployment Before changing images or upgrading, backup the files made in the volume. ### Reqirements I haven't verified these are the minimum requirements, but they are what I found to be necessary after starting this readme. I probably had some dependencies installed already. #### Manjaro/Arch ```bash sudo pacman -S jq ``` #### Debian/Ubunutu ```bash sudo apt install make xxd ``` ### Setup Generate secrets and add them to `.env` file. See [example.env](example.env) as an example. ```bash # 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) ``` ### Docker Compose Setup Full list of additional Environment Variables provided by bluesky upstream can be found in the [packages/pds/src/config/env.ts](https://github.com/bluesky-social/atproto/blob/main/packages/pds/src/config/env.ts) 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. The compose element `hostname` must be the same value as `PDS_HOSTNAME`. #### Traefik ```yaml # Traefik Proxy services: bluesky-pds: container_name: bluesky-pds hostname: example.com image: gravityfargo/bluesky-pds:0.4.74 networks: - proxy environment: # Define variables here or in a .env file PDS_JWT_SECRET: ... PDS_ADMIN_PASSWORD: ... PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX: ... PDS_HOSTNAME: example.com PDS_EMAIL_SMTP_URL: smtps://resend:@smtp.resend.com:465/ PDS_EMAIL_FROM_ADDRESS: admin@your.domain PUID: 1005 PGID: 1005 volumes: - ./bluesky-pds:/pds labels: traefik.enable: "true" traefik.http.routers.bluesky-pds-insecure.entrypoints: http traefik.http.routers.bluesky-pds-insecure.rule: HostRegexp(`^.+\.${URL_NAME}\.${URL_SUFFIX}$`) || Host(`${PDS_HOSTNAME}`) # 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(`^.+\.${URL_NAME}\.${URL_SUFFIX}$`) || Host(`${PDS_HOSTNAME}`) 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 ``` #### Standalone I do not run this, but it should be possible. ```yaml # Standalone, you'll need to add a proxy in front of this with SSL. services: bluesky-pds: container_name: bluesky-pds hostname: example.com image: gravityfargo/bluesky-pds:0.4.74 environment: # Define variables here or in a .env file 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: "" PUID: 1005 PGID: 1005 volumes: - ./bluesky-pds:/pds ``` #### Middleware I think file configs are cleaner than having a billion labels. This is not required, but it's nice to have. ```yaml # middleware.yaml http: middlewares: BlueskyHeaders: headers: accessControlAllowMethods: - GET - OPTIONS - PUT - POST - DELETE accessControlAllowHeaders: "*" accessControlAllowOriginList: "*" addVaryHeader: true stsSeconds: 63072000 ``` #### Optional Proxy Network ```bash docker network create --subnet=192.168.1.0/24 --ipv6 --attachable proxy # /etc/docker/daemon.json # { # "ipv6": true, # "fixed-cidr-v6": "2001:db8:1::/64" # } ``` #### Cloudflare DNS ![alt text](assets/image.png) #### Protonmail SMTP `PDS_EMAIL_SMTP_URL: smtp://user@example.com:TOKEN@smtp.protonmail.ch:587/` `PDS_EMAIL_FROM_ADDRESS: user@example.com` ## Development The development enviornment must be behind a proxy to generate SSL certificates. This will not work otherwise. In my case, I use Traefik installed on a VPS that's dedicated to development. I suggest buying a domain name for testing. I have one I use that's for a seperate project, but getting a throwaway domain is also an option. Millage may vary. ```bash make generate-env ``` Then set the variables - `PDS_HOSTNAME=example.com` - `URL_NAME=example` - `URL_SUFFIX=com` Build the base image. This will take a while. ```bash make build-base ``` Make edits as needed. Then build the dev image for testing. ```bash make build-tag TAG=dev ``` Run the dev image. ```bash make run # or docker-compose up ```