this repo has no description

Remove alpine & openbsd instructions

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

lewis 86e7bd3b 8b61506c

-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 - ```