Our Personal Data Server from scratch! tranquil.farm
pds rust database fun oauth atproto
237
fork

Configure Feed

Select the types of activity you want to include in your feed.

Remove alpine & openbsd instructions

Tested them both out and hated the experience.
Gonna double down on containers to make that the best
devex possible.

-544
-2
README.md
··· 53 53 | Guide | Best For | 54 54 |-------|----------| 55 55 | [Debian](docs/install-debian.md) | Debian 13+ with systemd | 56 - | [Alpine](docs/install-alpine.md) | Alpine 3.23+ with OpenRC | 57 - | [OpenBSD](docs/install-openbsd.md) | OpenBSD 7.8+ with rc.d | 58 56 | [Containers](docs/install-containers.md) | Podman with quadlets or OpenRC | 59 57 | [Kubernetes](docs/install-kubernetes.md) | You know what you're doing | 60 58
-265
docs/install-alpine.md
··· 1 - # Tranquil PDS Production Installation on Alpine Linux 2 - > **Warning**: These instructions are untested and theoretical, written from the top of Lewis' head. They may contain errors or omissions. This warning will be removed once the guide has been verified. 3 - 4 - This guide covers installing Tranquil PDS on Alpine Linux 3.23. 5 - 6 - ## Prerequisites 7 - - A VPS with at least 2GB RAM and 20GB disk 8 - - A domain name pointing to your server's IP 9 - - A **wildcard TLS certificate** for `*.pds.example.com` (user handles are served as subdomains) 10 - - Root access 11 - ## 1. System Setup 12 - ```sh 13 - apk update && apk upgrade 14 - apk add curl git build-base openssl-dev pkgconf 15 - ``` 16 - ## 2. Install Rust 17 - ```sh 18 - apk add rustup 19 - rustup-init -y 20 - source ~/.cargo/env 21 - rustup default stable 22 - ``` 23 - This installs the latest stable Rust. Alpine also ships Rust via `apk add rust cargo` if you prefer system packages. 24 - ## 3. Install postgres 25 - ```sh 26 - apk add postgresql postgresql-contrib 27 - rc-update add postgresql 28 - /etc/init.d/postgresql setup 29 - rc-service postgresql start 30 - psql -U postgres -c "CREATE USER tranquil_pds WITH PASSWORD 'your-secure-password';" 31 - psql -U postgres -c "CREATE DATABASE pds OWNER tranquil_pds;" 32 - psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE pds TO tranquil_pds;" 33 - ``` 34 - ## 4. Install minio 35 - ```sh 36 - curl -O https://dl.min.io/server/minio/release/linux-amd64/minio 37 - chmod +x minio 38 - mv minio /usr/local/bin/ 39 - mkdir -p /var/lib/minio/data 40 - adduser -D -H -s /sbin/nologin minio-user 41 - chown -R minio-user:minio-user /var/lib/minio 42 - cat > /etc/conf.d/minio << 'EOF' 43 - MINIO_ROOT_USER="minioadmin" 44 - MINIO_ROOT_PASSWORD="your-minio-password" 45 - MINIO_VOLUMES="/var/lib/minio/data" 46 - MINIO_OPTS="--console-address :9001" 47 - EOF 48 - cat > /etc/init.d/minio << 'EOF' 49 - #!/sbin/openrc-run 50 - name="minio" 51 - description="MinIO Object Storage" 52 - command="/usr/local/bin/minio" 53 - command_args="server ${MINIO_VOLUMES} ${MINIO_OPTS}" 54 - command_user="minio-user" 55 - command_background=true 56 - pidfile="/run/${RC_SVCNAME}.pid" 57 - output_log="/var/log/minio.log" 58 - error_log="/var/log/minio.log" 59 - depend() { 60 - need net 61 - } 62 - start_pre() { 63 - . /etc/conf.d/minio 64 - export MINIO_ROOT_USER MINIO_ROOT_PASSWORD 65 - } 66 - EOF 67 - chmod +x /etc/init.d/minio 68 - rc-update add minio 69 - rc-service minio start 70 - ``` 71 - Create the buckets (wait a few seconds for minio to start): 72 - ```sh 73 - curl -O https://dl.min.io/client/mc/release/linux-amd64/mc 74 - chmod +x mc 75 - mv mc /usr/local/bin/ 76 - mc alias set local http://localhost:9000 minioadmin your-minio-password 77 - mc mb local/pds-blobs 78 - mc mb local/pds-backups 79 - ``` 80 - ## 5. Install valkey 81 - ```sh 82 - apk add valkey 83 - rc-update add valkey 84 - rc-service valkey start 85 - ``` 86 - ## 6. Install deno (for frontend build) 87 - ```sh 88 - curl -fsSL https://deno.land/install.sh | sh 89 - export PATH="$HOME/.deno/bin:$PATH" 90 - echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.profile 91 - ``` 92 - ## 7. Clone and Build Tranquil PDS 93 - ```sh 94 - mkdir -p /opt && cd /opt 95 - git clone https://tangled.org/lewis.moe/bspds-sandbox tranquil-pds 96 - cd tranquil-pds 97 - cd frontend 98 - deno task build 99 - cd .. 100 - cargo build --release 101 - ``` 102 - ## 8. Install sqlx-cli and Run Migrations 103 - ```sh 104 - cargo install sqlx-cli --no-default-features --features postgres 105 - export DATABASE_URL="postgres://tranquil_pds:your-secure-password@localhost:5432/pds" 106 - sqlx migrate run 107 - ``` 108 - ## 9. Configure Tranquil PDS 109 - ```sh 110 - mkdir -p /etc/tranquil-pds 111 - cp /opt/tranquil-pds/.env.example /etc/tranquil-pds/tranquil-pds.env 112 - chmod 600 /etc/tranquil-pds/tranquil-pds.env 113 - ``` 114 - Edit `/etc/tranquil-pds/tranquil-pds.env` and fill in your values. Generate secrets with: 115 - ```sh 116 - openssl rand -base64 48 117 - ``` 118 - ## 10. Create OpenRC Service 119 - ```sh 120 - adduser -D -H -s /sbin/nologin tranquil-pds 121 - cp /opt/tranquil-pds/target/release/tranquil-pds /usr/local/bin/ 122 - mkdir -p /var/lib/tranquil-pds 123 - cp -r /opt/tranquil-pds/frontend/dist /var/lib/tranquil-pds/frontend 124 - chown -R tranquil-pds:tranquil-pds /var/lib/tranquil-pds 125 - cat > /etc/init.d/tranquil-pds << 'EOF' 126 - #!/sbin/openrc-run 127 - name="tranquil-pds" 128 - description="Tranquil PDS - AT Protocol PDS" 129 - command="/usr/local/bin/tranquil-pds" 130 - command_user="tranquil-pds" 131 - command_background=true 132 - pidfile="/run/${RC_SVCNAME}.pid" 133 - output_log="/var/log/tranquil-pds.log" 134 - error_log="/var/log/tranquil-pds.log" 135 - depend() { 136 - need net postgresql minio 137 - } 138 - start_pre() { 139 - export FRONTEND_DIR=/var/lib/tranquil-pds/frontend 140 - . /etc/tranquil-pds/tranquil-pds.env 141 - export SERVER_HOST SERVER_PORT PDS_HOSTNAME DATABASE_URL 142 - export S3_ENDPOINT AWS_REGION S3_BUCKET AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY 143 - export VALKEY_URL JWT_SECRET DPOP_SECRET MASTER_KEY CRAWLERS 144 - } 145 - EOF 146 - chmod +x /etc/init.d/tranquil-pds 147 - rc-update add tranquil-pds 148 - rc-service tranquil-pds start 149 - ``` 150 - ## 11. Install and Configure nginx 151 - ```sh 152 - apk add nginx certbot certbot-nginx 153 - cat > /etc/nginx/http.d/tranquil-pds.conf << 'EOF' 154 - server { 155 - listen 80; 156 - listen [::]:80; 157 - server_name pds.example.com; 158 - location / { 159 - proxy_pass http://127.0.0.1:3000; 160 - proxy_http_version 1.1; 161 - proxy_set_header Upgrade $http_upgrade; 162 - proxy_set_header Connection "upgrade"; 163 - proxy_set_header Host $host; 164 - proxy_set_header X-Real-IP $remote_addr; 165 - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 166 - proxy_set_header X-Forwarded-Proto $scheme; 167 - proxy_read_timeout 86400; 168 - } 169 - } 170 - EOF 171 - rc-update add nginx 172 - rc-service nginx start 173 - ``` 174 - ## 12. Obtain Wildcard SSL Certificate 175 - User handles are served as subdomains (e.g., `alice.pds.example.com`), so you need a wildcard certificate. 176 - 177 - Wildcard certs require DNS-01 validation. For manual DNS validation (works with any provider): 178 - ```sh 179 - certbot certonly --manual --preferred-challenges dns \ 180 - -d pds.example.com -d '*.pds.example.com' 181 - ``` 182 - Follow the prompts to add TXT records to your DNS. 183 - 184 - If your DNS provider has a certbot plugin, you can use that for auto-renewal: 185 - ```sh 186 - apk add certbot-dns-cloudflare 187 - certbot certonly --dns-cloudflare \ 188 - --dns-cloudflare-credentials /etc/cloudflare.ini \ 189 - -d pds.example.com -d '*.pds.example.com' 190 - ``` 191 - 192 - After obtaining the cert, update nginx to use it, then set up auto-renewal: 193 - ```sh 194 - echo "0 0 * * * certbot renew --quiet && rc-service nginx reload" | crontab - 195 - ``` 196 - ## 13. Configure Firewall 197 - ```sh 198 - apk add iptables ip6tables 199 - iptables -A INPUT -p tcp --dport 22 -j ACCEPT 200 - iptables -A INPUT -p tcp --dport 80 -j ACCEPT 201 - iptables -A INPUT -p tcp --dport 443 -j ACCEPT 202 - iptables -A INPUT -i lo -j ACCEPT 203 - iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 204 - iptables -P INPUT DROP 205 - ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT 206 - ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT 207 - ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT 208 - ip6tables -A INPUT -i lo -j ACCEPT 209 - ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 210 - ip6tables -P INPUT DROP 211 - rc-update add iptables 212 - rc-update add ip6tables 213 - /etc/init.d/iptables save 214 - /etc/init.d/ip6tables save 215 - ``` 216 - ## 14. Verify Installation 217 - ```sh 218 - rc-service tranquil-pds status 219 - curl -s https://pds.example.com/xrpc/_health 220 - curl -s https://pds.example.com/.well-known/atproto-did 221 - ``` 222 - ## Maintenance 223 - View logs: 224 - ```sh 225 - tail -f /var/log/tranquil-pds.log 226 - ``` 227 - Update Tranquil PDS: 228 - ```sh 229 - cd /opt/tranquil-pds 230 - git pull 231 - cd frontend && deno task build && cd .. 232 - cargo build --release 233 - rc-service tranquil-pds stop 234 - cp target/release/tranquil-pds /usr/local/bin/ 235 - cp -r frontend/dist /var/lib/tranquil-pds/frontend 236 - DATABASE_URL="postgres://tranquil_pds:your-secure-password@localhost:5432/pds" sqlx migrate run 237 - rc-service tranquil-pds start 238 - ``` 239 - Backup database: 240 - ```sh 241 - pg_dump -U postgres pds > /var/backups/pds-$(date +%Y%m%d).sql 242 - ``` 243 - 244 - ## Custom Homepage 245 - 246 - Drop a `homepage.html` in `/var/lib/tranquil-pds/frontend/` and it becomes your landing page. Go nuts with it. Account dashboard is at `/app/` so you won't break anything. 247 - 248 - ```sh 249 - cat > /var/lib/tranquil-pds/frontend/homepage.html << 'EOF' 250 - <!DOCTYPE html> 251 - <html> 252 - <head> 253 - <title>Welcome to my PDS</title> 254 - <style> 255 - body { font-family: system-ui; max-width: 600px; margin: 100px auto; padding: 20px; } 256 - </style> 257 - </head> 258 - <body> 259 - <h1>Welcome to my amazing zoo pen</h1> 260 - <p>This is a <a href="https://atproto.com">AT Protocol</a> Personal Data Server.</p> 261 - <p><a href="/app/">Sign in</a> or learn more at <a href="https://bsky.social">Bluesky</a>.</p> 262 - </body> 263 - </html> 264 - EOF 265 - ```
-277
docs/install-openbsd.md
··· 1 - # Tranquil PDS Production Installation on OpenBSD 2 - > **Warning**: These instructions are untested and theoretical, written from the top of Lewis' head. They may contain errors or omissions. This warning will be removed once the guide has been verified. 3 - This guide covers installing Tranquil PDS on OpenBSD 7.8. 4 - ## Prerequisites 5 - - A VPS with at least 2GB RAM and 20GB disk 6 - - A domain name pointing to your server's IP 7 - - A **wildcard TLS certificate** for `*.pds.example.com` (user handles are served as subdomains) 8 - - Root access (or doas configured) 9 - ## Why nginx over relayd? 10 - OpenBSD's native `relayd` supports WebSockets but does **not** support HTTP/2. For a modern PDS deployment, we recommend nginx which provides HTTP/2, WebSocket support, and automatic OCSP stapling. 11 - ## 1. System Setup 12 - ```sh 13 - pkg_add curl git 14 - ``` 15 - ## 2. Install Rust 16 - ```sh 17 - pkg_add rust 18 - ``` 19 - OpenBSD ships Rust in ports. For the latest stable, use rustup: 20 - ```sh 21 - pkg_add rustup 22 - rustup-init -y 23 - source ~/.cargo/env 24 - rustup default stable 25 - ``` 26 - ## 3. Install postgres 27 - ```sh 28 - pkg_add postgresql-server postgresql-client 29 - mkdir -p /var/postgresql/data 30 - chown _postgresql:_postgresql /var/postgresql/data 31 - su - _postgresql -c "initdb -D /var/postgresql/data -U postgres -A scram-sha-256" 32 - rcctl enable postgresql 33 - rcctl start postgresql 34 - psql -U postgres -c "CREATE USER tranquil_pds WITH PASSWORD 'your-secure-password';" 35 - psql -U postgres -c "CREATE DATABASE pds OWNER tranquil_pds;" 36 - psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE pds TO tranquil_pds;" 37 - ``` 38 - ## 4. Install minio 39 - OpenBSD doesn't have a minio package. Options: 40 - **Option A: Use an external S3-compatible service (recommended for production)** 41 - aws s3, backblaze b2, or upcloud managed object storage. Skip to step 5 and configure the S3 credentials in step 9. 42 - **Option B: Build minio from source** 43 - ```sh 44 - pkg_add go 45 - mkdir -p /tmp/minio-build && cd /tmp/minio-build 46 - ftp -o minio.tar.gz https://github.com/minio/minio/archive/refs/tags/RELEASE.2025-10-15T17-29-55Z.tar.gz 47 - tar xzf minio.tar.gz 48 - cd minio-* 49 - go build -o minio . 50 - cp minio /usr/local/bin/ 51 - mkdir -p /var/minio/data 52 - useradd -d /var/minio -s /sbin/nologin _minio 53 - chown -R _minio:_minio /var/minio 54 - cat > /etc/minio.conf << 'EOF' 55 - MINIO_ROOT_USER=minioadmin 56 - MINIO_ROOT_PASSWORD=your-minio-password 57 - EOF 58 - chmod 600 /etc/minio.conf 59 - cat > /etc/rc.d/minio << 'EOF' 60 - #!/bin/ksh 61 - daemon="/usr/local/bin/minio" 62 - daemon_user="_minio" 63 - daemon_flags="server /var/minio/data --console-address :9001" 64 - . /etc/rc.d/rc.subr 65 - rc_pre() { 66 - . /etc/minio.conf 67 - export MINIO_ROOT_USER MINIO_ROOT_PASSWORD 68 - } 69 - rc_cmd $1 70 - EOF 71 - chmod +x /etc/rc.d/minio 72 - rcctl enable minio 73 - rcctl start minio 74 - ``` 75 - Create the buckets: 76 - ```sh 77 - ftp -o /usr/local/bin/mc https://dl.min.io/client/mc/release/openbsd-amd64/mc 78 - chmod +x /usr/local/bin/mc 79 - mc alias set local http://localhost:9000 minioadmin your-minio-password 80 - mc mb local/pds-blobs 81 - mc mb local/pds-backups 82 - ``` 83 - ## 5. Install redis 84 - OpenBSD has redis in ports (valkey not available yet): 85 - ```sh 86 - pkg_add redis 87 - rcctl enable redis 88 - rcctl start redis 89 - ``` 90 - ## 6. Install deno (for frontend build) 91 - ```sh 92 - curl -fsSL https://deno.land/install.sh | sh 93 - export PATH="$HOME/.deno/bin:$PATH" 94 - echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.profile 95 - ``` 96 - ## 7. Clone and Build Tranquil PDS 97 - ```sh 98 - mkdir -p /opt && cd /opt 99 - git clone https://tangled.org/lewis.moe/bspds-sandbox tranquil-pds 100 - cd tranquil-pds 101 - cd frontend 102 - deno task build 103 - cd .. 104 - cargo build --release 105 - ``` 106 - ## 8. Install sqlx-cli and Run Migrations 107 - ```sh 108 - cargo install sqlx-cli --no-default-features --features postgres 109 - export DATABASE_URL="postgres://tranquil_pds:your-secure-password@localhost:5432/pds" 110 - sqlx migrate run 111 - ``` 112 - ## 9. Configure Tranquil PDS 113 - ```sh 114 - mkdir -p /etc/tranquil-pds 115 - cp /opt/tranquil-pds/.env.example /etc/tranquil-pds/tranquil-pds.conf 116 - chmod 600 /etc/tranquil-pds/tranquil-pds.conf 117 - ``` 118 - Edit `/etc/tranquil-pds/tranquil-pds.conf` and fill in your values. Generate secrets with: 119 - ```sh 120 - openssl rand -base64 48 121 - ``` 122 - ## 10. Create rc.d Service 123 - ```sh 124 - useradd -d /var/empty -s /sbin/nologin _tranquil_pds 125 - cp /opt/tranquil-pds/target/release/tranquil-pds /usr/local/bin/ 126 - mkdir -p /var/tranquil-pds 127 - cp -r /opt/tranquil-pds/frontend/dist /var/tranquil-pds/frontend 128 - chown -R _tranquil_pds:_tranquil_pds /var/tranquil-pds 129 - cat > /etc/rc.d/tranquil_pds << 'EOF' 130 - #!/bin/ksh 131 - daemon="/usr/local/bin/tranquil-pds" 132 - daemon_user="_tranquil_pds" 133 - daemon_logger="daemon.info" 134 - . /etc/rc.d/rc.subr 135 - rc_pre() { 136 - export FRONTEND_DIR=/var/tranquil-pds/frontend 137 - while IFS='=' read -r key value; do 138 - case "$key" in 139 - \#*|"") continue ;; 140 - esac 141 - export "$key=$value" 142 - done < /etc/tranquil-pds/tranquil-pds.conf 143 - } 144 - rc_cmd $1 145 - EOF 146 - chmod +x /etc/rc.d/tranquil_pds 147 - rcctl enable tranquil_pds 148 - rcctl start tranquil_pds 149 - ``` 150 - ## 11. Install and Configure nginx 151 - ```sh 152 - pkg_add nginx 153 - cat > /etc/nginx/nginx.conf << 'EOF' 154 - worker_processes 1; 155 - events { 156 - worker_connections 1024; 157 - } 158 - http { 159 - include mime.types; 160 - server { 161 - listen 80; 162 - listen [::]:80; 163 - server_name pds.example.com; 164 - location /.well-known/acme-challenge/ { 165 - root /var/www/acme; 166 - } 167 - location / { 168 - return 301 https://$host$request_uri; 169 - } 170 - } 171 - server { 172 - listen 443 ssl http2; 173 - listen [::]:443 ssl http2; 174 - server_name pds.example.com; 175 - ssl_certificate /etc/ssl/pds.example.com.fullchain.pem; 176 - ssl_certificate_key /etc/ssl/private/pds.example.com.key; 177 - ssl_protocols TLSv1.2 TLSv1.3; 178 - ssl_ciphers HIGH:!aNULL:!MD5; 179 - ssl_prefer_server_ciphers on; 180 - ssl_session_cache shared:SSL:10m; 181 - location / { 182 - proxy_pass http://127.0.0.1:3000; 183 - proxy_http_version 1.1; 184 - proxy_set_header Upgrade $http_upgrade; 185 - proxy_set_header Connection "upgrade"; 186 - proxy_set_header Host $host; 187 - proxy_set_header X-Real-IP $remote_addr; 188 - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 189 - proxy_set_header X-Forwarded-Proto $scheme; 190 - proxy_read_timeout 86400; 191 - } 192 - } 193 - } 194 - EOF 195 - mkdir -p /var/www/acme 196 - rcctl enable nginx 197 - ``` 198 - ## 12. Obtain Wildcard SSL Certificate 199 - User handles are served as subdomains (e.g., `alice.pds.example.com`), so you need a wildcard certificate. 200 - 201 - OpenBSD's native `acme-client` only supports HTTP-01 validation, which can't issue wildcard certs. You have a few options: 202 - 203 - **Option A: Use certbot with DNS validation (recommended)** 204 - ```sh 205 - pkg_add certbot 206 - certbot certonly --manual --preferred-challenges dns \ 207 - -d pds.example.com -d '*.pds.example.com' 208 - ``` 209 - Follow the prompts to add TXT records to your DNS. Then update nginx.conf to point to the certbot certs. 210 - 211 - **Option B: Use a managed DNS provider with API** 212 - If your DNS provider has a certbot plugin, you can automate renewal. 213 - 214 - **Option C: Use acme.sh** 215 - [acme.sh](https://github.com/acmesh-official/acme.sh) supports many DNS providers for automated wildcard cert renewal. 216 - 217 - After obtaining the cert, update nginx to use it and restart: 218 - ```sh 219 - rcctl restart nginx 220 - ``` 221 - ## 13. Configure Packet Filter (pf) 222 - ```sh 223 - cat >> /etc/pf.conf << 'EOF' 224 - pass in on egress proto tcp from any to any port { 22, 80, 443 } 225 - EOF 226 - pfctl -f /etc/pf.conf 227 - ``` 228 - ## 14. Verify Installation 229 - ```sh 230 - rcctl check tranquil_pds 231 - ftp -o - https://pds.example.com/xrpc/_health 232 - ftp -o - https://pds.example.com/.well-known/atproto-did 233 - ``` 234 - ## Maintenance 235 - View logs: 236 - ```sh 237 - tail -f /var/log/daemon 238 - ``` 239 - Update Tranquil PDS: 240 - ```sh 241 - cd /opt/tranquil-pds 242 - git pull 243 - cd frontend && deno task build && cd .. 244 - cargo build --release 245 - rcctl stop tranquil_pds 246 - cp target/release/tranquil-pds /usr/local/bin/ 247 - cp -r frontend/dist /var/tranquil-pds/frontend 248 - DATABASE_URL="postgres://tranquil_pds:your-secure-password@localhost:5432/pds" sqlx migrate run 249 - rcctl start tranquil_pds 250 - ``` 251 - Backup database: 252 - ```sh 253 - pg_dump -U postgres pds > /var/backups/pds-$(date +%Y%m%d).sql 254 - ``` 255 - 256 - ## Custom Homepage 257 - 258 - Drop a `homepage.html` in `/var/tranquil-pds/frontend/` and it becomes your landing page. Go nuts with it. Account dashboard is at `/app/` so you won't break anything. 259 - 260 - ```sh 261 - cat > /var/tranquil-pds/frontend/homepage.html << 'EOF' 262 - <!DOCTYPE html> 263 - <html> 264 - <head> 265 - <title>Welcome to my PDS</title> 266 - <style> 267 - body { font-family: system-ui; max-width: 600px; margin: 100px auto; padding: 20px; } 268 - </style> 269 - </head> 270 - <body> 271 - <h1>Welcome to my uma musume shipping site!</h1> 272 - <p>This is a <a href="https://atproto.com">AT Protocol</a> Personal Data Server.</p> 273 - <p><a href="/app/">Sign in</a> or learn more at <a href="https://bsky.social">Bluesky</a>.</p> 274 - </body> 275 - </html> 276 - EOF 277 - ```