Personal atproto services deployment handbook
atstack docs deploy.md
4.4 kB · 177 lines
Markdown
at main

First Deployment #

This runbook creates the first production PDS deployment. It assumes the repository has already been cloned locally and that production secrets are stored outside Git.

1. Local Preflight #

From this repository:

scripts/preflight.sh --local

Optional remote check:

ssh -i <ssh-key-path> <vm-user>@<vm-public-ip> 'bash -s' < scripts/preflight.sh

The remote preflight should warn about missing Docker before installation. Warnings are expected before provisioning.

2. Cloudflare DNS #

Create or confirm:

pds.3drx.top A <vm-public-ip> proxied

Keep _atproto.3drx.top unset until the account DID is known.

Ensure Cloudflare WebSockets are enabled for the zone.

3. Cloudflare Origin Certificate #

Create an Origin CA certificate for pds.3drx.top.

Store the certificate and private key outside Git. Suggested VM paths:

/pds/certs/cloudflare-origin.pem
/pds/certs/cloudflare-origin.key

Permissions:

sudo chown root:root /pds/certs/cloudflare-origin.*
sudo chmod 0644 /pds/certs/cloudflare-origin.pem
sudo chmod 0600 /pds/certs/cloudflare-origin.key

Set Cloudflare SSL/TLS mode to Full (strict) after the origin certificate is installed.

4. VM Preparation #

SSH to the VM:

ssh -i <ssh-key-path> <vm-user>@<vm-public-ip>

Create /pds on the root disk:

sudo mkdir -p /pds
sudo chown root:root /pds
sudo chmod 0755 /pds

Add swap because the VM has about 1 GB RAM:

sudo fallocate -l 2G /swapfile
sudo chmod 0600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Install Docker and the Docker Compose plugin using the official Docker Debian instructions. Do not commit package manager logs or generated configuration.

5. R2 Buckets and Credentials #

Create:

  • live blob bucket, for example <pds-blob-bucket>
  • backup bucket or prefix, for example <pds-backup-bucket>

Create scoped credentials:

  • live blob credentials: read/write to the live blob bucket
  • backup credentials: read/write to the backup bucket or prefix

Store real credentials only in ignored files on the VM or a password manager.

Validate live blob credentials from a safe shell after exporting the real values from an ignored env file or password manager:

scripts/verify-r2-blobstore.sh

6. Install PDS #

Use the official PDS installer as the base deployment path.

Deployment choices:

  • PDS_HOSTNAME=pds.3drx.top
  • invite required: enabled
  • public signup: disabled
  • initial account: one account only

After installation, update /pds/pds.env using config/pds.env.example as the reference. Add the R2 live blobstore settings and keep real secrets out of Git.

For this deployment, place the real shared R2 credential only in /etc/pds-r2.env and apply it with:

sudo /usr/local/sbin/apply-r2-config.sh

7. Configure Origin TLS in Caddy #

Use config/caddy-origin-ca.Caddyfile.example as a reference. Configure Caddy to serve pds.3drx.top with the Cloudflare Origin CA certificate and key.

Restart PDS/Caddy according to the installed service layout.

8. Configure Handle #

Get the created account DID from installer output, pdsadmin, or another atproto tool.

Add:

_atproto.3drx.top TXT did=did:plc:<your-did>

Then change the account handle to 3drx.top using the Bluesky app or an atproto CLI.

9. Install Backup Timer #

Copy templates and scripts to production paths:

sudo install -m 0755 scripts/backup-pds.sh /usr/local/sbin/backup-pds.sh
sudo install -m 0644 config/systemd/pds-backup.service.example /etc/systemd/system/pds-backup.service
sudo install -m 0644 config/systemd/pds-backup.timer.example /etc/systemd/system/pds-backup.timer

Create an ignored env file on the VM, for example /etc/pds-backup.env, based on config/pds-backup.env.example.

Enable the timer:

sudo systemctl daemon-reload
sudo systemctl enable --now pds-backup.timer

Run one manual backup:

sudo systemctl start pds-backup.service
sudo journalctl -u pds-backup.service -n 100 --no-pager

10. Acceptance Checks #

scripts/healthcheck.sh

Verify:

  • https://pds.3drx.top/xrpc/_health returns JSON
  • WebSocket connection opens
  • image uploads land in R2
  • account handle is @3drx.top
  • manual backup archive exists in R2