···6677This particular PDS thrives under harsh conditions. It is a dandelion growing through the cracks in the sidewalk concrete.
8899-It has full compatibility with Bluesky's reference PDS: same endpoints, same behavior, same client compatibility. Everything works: repo operations, blob storage, firehose, OAuth, handle resolution, account migration, the lot.
1010-1111-Another excellent PDS is [Cocoon](https://tangled.org/hailey.at/cocoon), written in go.
99+It has full compatibility with Bluesky's reference PDS.
12101311## What's different about Tranquil PDS
14121515-It is a superset of the reference PDS, including: passkeys and 2FA (WebAuthn/FIDO2, TOTP, backup codes, trusted devices), SSO login and signup, did:web support (PDS-hosted subdomains or bring-your-own), multi-channel communication (email, discord, telegram, signal) for verification and alerts, granular OAuth scopes with a consent UI showing human-readable descriptions, app passwords with granular permissions (read-only, post-only, or custom scopes), account delegation (letting others manage an account with configurable permission levels), automatic backups (configurable retention and frequency, one-click restore), and a built-in web UI for account management, OAuth consent, repo browsing, and admin.
1313+It is a superset of the reference PDS, including: passkeys and 2FA (WebAuthn/FIDO2, TOTP, backup codes, trusted devices), SSO login and signup, did:web support (PDS-hosted subdomains or bring-your-own), multi-channel communication (email, discord, telegram, signal) for verification and alerts, granular OAuth scopes with a consent UI showing human-readable descriptions, app passwords with granular permissions (read-only, post-only, or custom scopes), account delegation (letting others manage an account with configurable permission levels), and a built-in web UI for account management, repo browsing, and admin.
16141717-The PDS itself is a single small binary with no node/npm runtime. It requires postgres. Blobs are stored on the local filesystem by default (S3 optional). Valkey is optional (supported as an alternative to the built-in cache).
1515+The PDS itself is a single binary with no nodeJS runtime. However, at time of writing, Tranquil requires postgres running separately. Blobs are stored on the local filesystem by default (S3 optional). Valkey is also optional (as an alternative to the built-in cache).
18161917## Quick Start
20182119```bash
2220cp .env.example .env
2323-podman compose up -d
2121+podman compose up db -d
2422just run
2523```
2624···41394240### Quick Deploy (Docker/Podman Compose)
43414444-Edit `.env.prod` with your values. Generate secrets with `openssl rand -base64 48`.
4242+Edit `.env` with your values. Generate secrets with `openssl rand -base64 48`.
45434644```bash
4747-cp .env.prod.example .env.prod
4545+cp .env.example .env
4846podman-compose -f docker-compose.prod.yaml up -d
4947```
50485149### Installation Guides
52505353-| Guide | Best For |
5454-|-------|----------|
5555-| [Debian](docs/install-debian.md) | Debian 13+ with systemd |
5656-| [Containers](docs/install-containers.md) | Podman with quadlets or OpenRC |
5757-| [Kubernetes](docs/install-kubernetes.md) | You know what you're doing |
5151+- [Debian](docs/install-debian.md)
5252+- [Containers](docs/install-containers.md)
5353+- [Kubernetes](docs/install-kubernetes.md)
58545955## Maintainers to ping
6056
+42-48
docs/install-containers.md
···11-# Tranquil PDS Containerized Production Deployment
11+# Tranquil PDS containerized production deployment
2233This guide covers deploying Tranquil PDS using containers with podman.
44···7788## Prerequisites
991010-- A VPS with at least 2GB RAM
1010+- A server :p
1111- Disk space for blobs (depends on usage; plan for ~1GB per active user as a baseline)
1212- A domain name pointing to your server's IP
1313- A **wildcard TLS certificate** for `*.pds.example.com` (user handles are served as subdomains)
1414-- Root or sudo access
1414+- Root/sudo/doas access
15151616-## Quick Start (Docker/Podman Compose)
1616+## Quickstart (docker/podman compose)
17171818If you just want to get running quickly:
1919···3838ln -sf live/pds.example.com/privkey.pem certs/privkey.pem
3939podman-compose -f docker-compose.prod.yaml restart nginx
4040```
4141+4242+The end!!!
4343+4444+Or wait, you want more? Perhaps a deployment that comes back on server restart?
41454246For production setups with proper service management, continue to either the Debian or Alpine section below.
43474444-## Standalone Containers (No Compose)
4848+## Standalone containers (no compose)
45494650If you already have postgres running on the host (eg. from the [Debian install guide](install-debian.md)), you can run just the app containers.
4751···91959296---
93979494-# Debian 13+ with Systemd Quadlets
9898+# Debian with systemd quadlets
95999696-Quadlets are the modern way to run podman containers under systemd.
100100+Quadlets are a nice way to run podman containers under systemd.
971019898-## Install Podman
102102+## Install podman
99103100104```bash
101105apt update
102106apt install -y podman
103107```
104108105105-## Create Directory Structure
109109+## Create the directory structure
106110107111```bash
108112mkdir -p /etc/containers/systemd
109113mkdir -p /srv/tranquil-pds/{postgres,blobs,backups,certs,acme,config}
110114```
111115112112-## Create Environment File
116116+## Create an environment file
113117114118```bash
115119cp /opt/tranquil-pds/.env.example /srv/tranquil-pds/config/tranquil-pds.env
···121125openssl rand -base64 48
122126```
123127124124-For quadlets, also add `DATABASE_URL` with the full connection string (systemd doesn't support variable expansion).
125125-126126-## Install Quadlet Definitions
128128+## Install quadlet definitions
127129128130Copy the quadlet files from the repository:
129131```bash
···136138137139Optional quadlets for valkey and minio are also available in `deploy/quadlets/` if you need them.
138140139139-Note: Systemd doesn't support shell-style variable expansion in `Environment=` lines. The quadlet files expect DATABASE_URL to be set in the environment file.
140140-141141-## Create nginx Configuration
141141+## Create nginx configuration
142142143143```bash
144144cp /opt/tranquil-pds/nginx.frontend.conf /srv/tranquil-pds/config/nginx.conf
145145```
146146147147-## Clone and Build Images
147147+## Clone and build images
148148149149```bash
150150cd /opt
···154154podman build -t tranquil-pds-frontend:latest ./frontend
155155```
156156157157-## Create Podman Secrets
157157+## Create podman secrets
158158159159```bash
160160source /srv/tranquil-pds/config/tranquil-pds.env
161161echo "$DB_PASSWORD" | podman secret create tranquil-pds-db-password -
162162```
163163164164-## Start Services and Initialize
164164+## Start services and initialize
165165166166```bash
167167systemctl daemon-reload
···169169sleep 10
170170```
171171172172-Run migrations:
173173-```bash
174174-cargo install sqlx-cli --no-default-features --features postgres
175175-DATABASE_URL="postgres://tranquil_pds:your-db-password@localhost:5432/pds" sqlx migrate run --source /opt/tranquil-pds/migrations
176176-```
177177-178178-## Obtain Wildcard SSL Certificate
172172+## Obtain a wildcard SSL cert
179173180174User handles are served as subdomains (eg. `alice.pds.example.com`), so you need a wildcard certificate. Wildcard certs require DNS-01 validation.
181175···209203systemctl restart tranquil-pds-nginx
210204```
211205212212-## Enable All Services
206206+## Enable all services
213207214208```bash
215209systemctl enable tranquil-pds-db tranquil-pds-app tranquil-pds-frontend tranquil-pds-nginx
216210```
217211218218-## Configure Firewall
212212+## Configure firewall if you're into that sort of thing
219213220214```bash
221215apt install -y ufw
···225219ufw enable
226220```
227221228228-## Certificate Renewal
222222+## Cert renewal
229223230224Add to root's crontab (`crontab -e`):
231225```
···234228235229---
236230237237-# Alpine 3.23+ with OpenRC
231231+# Alpine with OpenRC
238232239239-Alpine uses OpenRC, not systemd. We'll use podman-compose with an OpenRC service wrapper.
233233+Alpine uses OpenRC, not systemd. So instead of quadlets we'll use podman-compose with an OpenRC service wrapper.
240234241241-## Install Podman
235235+## Install podman
242236243237```sh
244238apk update
···253247rc-service podman start
254248```
255249256256-## Create Directory Structure
250250+## Create the directory structure
257251258252```sh
259253mkdir -p /srv/tranquil-pds/{data,config}
260254mkdir -p /srv/tranquil-pds/data/{postgres,blobs,backups,certs,acme}
261255```
262256263263-## Clone Repository and Build Images
257257+## Clone the repo and build images
264258265259```sh
266260cd /opt
···270264podman build -t tranquil-pds-frontend:latest ./frontend
271265```
272266273273-## Create Environment File
267267+## Create an environment file
274268275269```sh
276270cp /opt/tranquil-pds/.env.example /srv/tranquil-pds/config/tranquil-pds.env
···282276openssl rand -base64 48
283277```
284278285285-## Set Up Compose and nginx
279279+## Set up compose and nginx
286280287281Copy the production compose and nginx configs:
288282```sh
···297291Edit `/srv/tranquil-pds/config/nginx.conf` to update cert paths:
298292- Change `/etc/nginx/certs/live/${PDS_HOSTNAME}/` to `/etc/nginx/certs/`
299293300300-## Create OpenRC Service
294294+## Create OpenRC service
301295302296```sh
303297cat > /etc/init.d/tranquil-pds << 'EOF'
304298#!/sbin/openrc-run
305299name="tranquil-pds"
306306-description="Tranquil PDS AT Protocol PDS (containerized)"
300300+description="Tranquil PDS AT Protocol PDS"
307301command="/usr/bin/podman-compose"
308302command_args="-f /srv/tranquil-pds/docker-compose.yml up"
309303command_background=true
···331325chmod +x /etc/init.d/tranquil-pds
332326```
333327334334-## Initialize Services
328328+## Initialize services
335329336330Start services:
337331```sh
···349343DATABASE_URL="postgres://tranquil_pds:$DB_PASSWORD@$DB_IP:5432/pds" sqlx migrate run --source /opt/tranquil-pds/migrations
350344```
351345352352-## Obtain Wildcard SSL Certificate
346346+## Obtain wildcard SSL cert
353347354348User handles are served as subdomains (eg. `alice.pds.example.com`), so you need a wildcard certificate. Wildcard certs require DNS-01 validation.
355349···381375rc-service tranquil-pds restart
382376```
383377384384-## Enable Service at Boot
378378+## Enable service at boot time
385379386380```sh
387381rc-update add tranquil-pds
388382```
389383390390-## Configure Firewall
384384+## Configure firewall if you're into that sort of thing
391385392386```sh
393387apk add iptables ip6tables
···409403/etc/init.d/ip6tables save
410404```
411405412412-## Certificate Renewal
406406+## Cert renewal
413407414408Add to root's crontab (`crontab -e`):
415409```
···418412419413---
420414421421-# Verification and Maintenance
415415+# Verification and maintenance
422416423423-## Verify Installation
417417+## Verify installation
424418425419```sh
426420curl -s https://pds.example.com/xrpc/_health | jq
427421curl -s https://pds.example.com/.well-known/atproto-did
428422```
429423430430-## View Logs
424424+## View logs
431425432426**Debian:**
433427```bash
···462456rc-service tranquil-pds restart
463457```
464458465465-## Backup Database
459459+## Backup database
466460467461**Debian:**
468462```bash
···474468podman exec tranquil-pds-db-1 pg_dump -U tranquil_pds pds > /var/backups/pds-$(date +%Y%m%d).sql
475469```
476470477477-## Custom Homepage
471471+## Custom homepage
478472479473The frontend container serves `homepage.html` as the landing page. To customize it, either:
480474
+21-25
docs/install-debian.md
···11-# Tranquil PDS Production Installation on Debian
11+# Tranquil PDS production installation on debian
2233-This guide covers installing Tranquil PDS on Debian 13.
33+This guide covers installing Tranquil PDS on Debian.
44+55+It is a "compile the thing on the server itself" -style guide.
66+This cop-out is because Tranquil isn't built and released via CI as of yet.
4758## Prerequisites
6977-- A VPS with at least 2GB RAM
88-- Disk space for blobs (depends on usage; plan for ~1GB per active user as a baseline)
1010+- A server :p
1111+- Disk space enough for blobs (depends on usage; plan for ~1GB per active user as a baseline)
912- A domain name pointing to your server's IP
1013- A wildcard TLS certificate for `*.pds.example.com` (user handles are served as subdomains)
1111-- Root or sudo access
1414+- Root/sudo/doas access
12151313-## System Setup
1616+## System setup
14171518```bash
1619apt update && apt upgrade -y
1720apt install -y curl git build-essential pkg-config libssl-dev
1821```
19222020-## Install Rust
2323+## Install rust
21242225```bash
2326curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
···3841sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE pds TO tranquil_pds;"
3942```
40434141-## Create Blob Storage Directories
4444+## Create blob storage directories
42454346```bash
4447mkdir -p /var/lib/tranquil/blobs /var/lib/tranquil/backups
···5457echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.bashrc
5558```
56595757-## Clone and Build Tranquil PDS
6060+## Clone and build Tranquil PDS
58615962```bash
6063cd /opt
···6669cargo build --release
6770```
68716969-## Install sqlx-cli and Run Migrations
7070-7171-```bash
7272-cargo install sqlx-cli --no-default-features --features postgres
7373-export DATABASE_URL="postgres://tranquil_pds:your-secure-password@localhost:5432/pds"
7474-sqlx migrate run
7575-```
7676-7772## Configure Tranquil PDS
78737974```bash
···8782openssl rand -base64 48
8883```
89849090-## Install Frontend Files
8585+## Install frontend files
91869287```bash
9388mkdir -p /var/www/tranquil-pds
···9590chown -R www-data:www-data /var/www/tranquil-pds
9691```
97929898-## Create Systemd Service
9393+## Create systemd service
999410095```bash
10196useradd -r -s /sbin/nologin tranquil-pds
···127122systemctl start tranquil-pds
128123```
129124130130-## Install and Configure nginx
125125+## Install and configure nginx
131126132127```bash
133128apt install -y nginx certbot python3-certbot-nginx
···264259systemctl reload nginx
265260```
266261267267-## Obtain Wildcard SSL Certificate
262262+## Obtain a wildcard SSL cert
268263269264User handles are served as subdomains (eg., `alice.pds.example.com`), so you need a wildcard certificate.
270265···289284systemctl reload nginx
290285```
291286292292-## Configure Firewall
287287+## Configure firewall if you're into that sort of thing
293288294289```bash
295290apt install -y ufw
···299294ufw enable
300295```
301296302302-## Verify Installation
297297+## Verify installation
303298304299```bash
305300systemctl status tranquil-pds
···323318systemctl stop tranquil-pds
324319cp target/release/tranquil-pds /usr/local/bin/
325320cp -r frontend/dist/* /var/www/tranquil-pds/
326326-DATABASE_URL="postgres://tranquil_pds:your-secure-password@localhost:5432/pds" sqlx migrate run
327321systemctl start tranquil-pds
328322```
323323+324324+Tranquil should auto-migrate if there are any new migrations to be applied to the db, so you don't need to worry.
329325330326Backup database:
331327```bash
332328sudo -u postgres pg_dump pds > /var/backups/pds-$(date +%Y%m%d).sql
333329```
334330335335-## Custom Homepage
331331+## Custom homepage
336332337333Drop a `homepage.html` in `/var/www/tranquil-pds/` and it becomes your landing page. Account dashboard is at `/app/` so you won't break anything.
338334
+2-2
docs/install-kubernetes.md
···11-# Tranquil PDS on Kubernetes
11+# Tranquil PDS on kubernetes
2233If you're reaching for kubernetes for this app, you're experienced enough to know how to spin up:
44···19192020Health check: `GET /xrpc/_health`
21212222-## Custom Homepage
2222+## Custom homepage
23232424Mount a ConfigMap with your `homepage.html` into the container's frontend directory and it becomes your landing page. Go nuts with it. Account dashboard is at `/app/` so you won't break anything.
2525
+2-2
frontend/public/homepage.html
···420420 and alerts, granular OAuth scopes with human-readable descriptions,
421421 app passwords with configurable permissions (read-only, post-only,
422422 or custom scopes), account delegation with permission levels and
423423- audit logging, and a built-in web UI for account management, OAuth
424424- consent, repo browsing, and admin.
423423+ audit logging, and a built-in web UI for account management,
424424+ repo browsing, and admin.
425425 </p>
426426 </div>
427427 </section>