Our Personal Data Server from scratch!
0
fork

Configure Feed

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

at main 369 lines 9.6 kB view raw view rendered
1# Tranquil PDS production installation on debian 2 3This guide covers installing Tranquil PDS on Debian. 4 5It is a "compile the thing on the server itself" -style guide. 6This cop-out is because Tranquil isn't built and released via CI as of yet. 7 8## Prerequisites 9 10- A server :p 11- Disk space enough for blobs (depends on usage; plan for ~1GB per active user as a baseline) 12- A domain name pointing to your server's IP 13- A wildcard TLS certificate for `*.pds.example.com` (user handles are served as subdomains) 14- Root/sudo/doas access 15 16## System setup 17 18```bash 19apt update && apt upgrade -y 20apt install -y curl git build-essential pkg-config libssl-dev 21``` 22 23## Install rust 24 25```bash 26curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 27source ~/.cargo/env 28rustup default stable 29``` 30 31This installs the latest stable Rust. 32 33## Install postgres 34 35```bash 36apt install -y postgresql postgresql-contrib 37systemctl enable postgresql 38systemctl start postgresql 39sudo -u postgres psql -c "CREATE USER tranquil_pds WITH PASSWORD 'your-secure-password';" 40sudo -u postgres psql -c "CREATE DATABASE pds OWNER tranquil_pds;" 41sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE pds TO tranquil_pds;" 42``` 43 44## Create blob storage directories 45 46```bash 47mkdir -p /var/lib/tranquil/blobs 48``` 49 50We'll set ownership after creating the service user. 51 52## Install deno (for frontend build) 53 54```bash 55curl -fsSL https://deno.land/install.sh | sh 56export PATH="$HOME/.deno/bin:$PATH" 57echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.bashrc 58``` 59 60## Clone and build Tranquil PDS 61 62```bash 63cd /opt 64git clone https://tangled.org/tranquil.farm/tranquil-pds tranquil-pds 65cd tranquil-pds 66cd frontend 67deno task build 68cd .. 69cargo build --release 70``` 71 72## Configure Tranquil PDS 73 74```bash 75mkdir -p /etc/tranquil-pds 76cp /opt/tranquil-pds/example.toml /etc/tranquil-pds/config.toml 77chmod 600 /etc/tranquil-pds/config.toml 78``` 79 80Edit `/etc/tranquil-pds/config.toml` and fill in your values. Generate secrets with: 81```bash 82openssl rand -base64 48 83``` 84 85> **Note:** Every config option can also be set via environment variables 86> (see comments in `example.toml`). Environment variables always take 87> precedence over the config file. You can also pass the config file path 88> via the `TRANQUIL_PDS_CONFIG` env var instead of `--config`. 89 90You can validate your configuration before starting the service: 91```bash 92/usr/local/bin/tranquil-pds --config /etc/tranquil-pds/config.toml validate 93``` 94 95## Install frontend files 96 97```bash 98mkdir -p /var/www/tranquil-pds 99cp -r /opt/tranquil-pds/frontend/dist/* /var/www/tranquil-pds/ 100chown -R www-data:www-data /var/www/tranquil-pds 101``` 102 103## Create systemd service 104 105```bash 106useradd -r -s /sbin/nologin tranquil-pds 107chown -R tranquil-pds:tranquil-pds /var/lib/tranquil 108cp /opt/tranquil-pds/target/release/tranquil-pds /usr/local/bin/ 109 110cat > /etc/systemd/system/tranquil-pds.service << 'EOF' 111[Unit] 112Description=Tranquil PDS - AT Protocol PDS 113After=network.target postgresql.service 114[Service] 115Type=simple 116User=tranquil-pds 117Group=tranquil-pds 118ExecStart=/usr/local/bin/tranquil-pds --config /etc/tranquil-pds/config.toml 119Restart=always 120RestartSec=5 121ProtectSystem=strict 122ProtectHome=true 123PrivateTmp=true 124ReadWritePaths=/var/lib/tranquil 125[Install] 126WantedBy=multi-user.target 127EOF 128 129systemctl daemon-reload 130systemctl enable tranquil-pds 131systemctl start tranquil-pds 132``` 133 134## Install and configure nginx 135 136```bash 137apt install -y nginx certbot python3-certbot-nginx 138 139cat > /etc/nginx/sites-available/tranquil-pds << 'EOF' 140server { 141 listen 80; 142 listen [::]:80; 143 server_name pds.example.com *.pds.example.com; 144 145 location /.well-known/acme-challenge/ { 146 root /var/www/acme; 147 } 148 149 location / { 150 return 301 https://$host$request_uri; 151 } 152} 153 154server { 155 listen 443 ssl; 156 listen [::]:443 ssl; 157 http2 on; 158 server_name pds.example.com *.pds.example.com; 159 160 ssl_certificate /etc/letsencrypt/live/pds.example.com/fullchain.pem; 161 ssl_certificate_key /etc/letsencrypt/live/pds.example.com/privkey.pem; 162 163 client_max_body_size 10G; 164 165 root /var/www/tranquil-pds; 166 167 location /xrpc/ { 168 proxy_pass http://127.0.0.1:3000; 169 proxy_http_version 1.1; 170 proxy_set_header Upgrade $http_upgrade; 171 proxy_set_header Connection "upgrade"; 172 proxy_set_header Host $host; 173 proxy_set_header X-Real-IP $remote_addr; 174 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 175 proxy_set_header X-Forwarded-Proto $scheme; 176 proxy_read_timeout 86400; 177 proxy_send_timeout 86400; 178 proxy_buffering off; 179 proxy_request_buffering off; 180 } 181 182 location = /oauth-client-metadata.json { 183 root /var/www/tranquil-pds; 184 default_type application/json; 185 sub_filter_once off; 186 sub_filter_types application/json; 187 sub_filter '__PDS_HOSTNAME__' $host; 188 } 189 190 location /oauth/ { 191 proxy_pass http://127.0.0.1:3000; 192 proxy_http_version 1.1; 193 proxy_set_header Host $host; 194 proxy_set_header X-Real-IP $remote_addr; 195 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 196 proxy_set_header X-Forwarded-Proto $scheme; 197 proxy_read_timeout 300; 198 proxy_send_timeout 300; 199 } 200 201 location /.well-known/ { 202 proxy_pass http://127.0.0.1:3000; 203 proxy_http_version 1.1; 204 proxy_set_header Host $host; 205 proxy_set_header X-Real-IP $remote_addr; 206 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 207 proxy_set_header X-Forwarded-Proto $scheme; 208 } 209 210 location /webhook/ { 211 proxy_pass http://127.0.0.1:3000; 212 proxy_http_version 1.1; 213 proxy_set_header Host $host; 214 proxy_set_header X-Real-IP $remote_addr; 215 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 216 proxy_set_header X-Forwarded-Proto $scheme; 217 } 218 219 location = /metrics { 220 proxy_pass http://127.0.0.1:3000; 221 proxy_http_version 1.1; 222 proxy_set_header Host $host; 223 } 224 225 location = /health { 226 proxy_pass http://127.0.0.1:3000; 227 proxy_http_version 1.1; 228 proxy_set_header Host $host; 229 } 230 231 location = /robots.txt { 232 proxy_pass http://127.0.0.1:3000; 233 proxy_http_version 1.1; 234 proxy_set_header Host $host; 235 } 236 237 location = /logo { 238 proxy_pass http://127.0.0.1:3000; 239 proxy_http_version 1.1; 240 proxy_set_header Host $host; 241 } 242 243 location ~ ^/u/[^/]+/did\.json$ { 244 proxy_pass http://127.0.0.1:3000; 245 proxy_http_version 1.1; 246 proxy_set_header Host $host; 247 proxy_set_header X-Real-IP $remote_addr; 248 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 249 proxy_set_header X-Forwarded-Proto $scheme; 250 } 251 252 location /assets/ { 253 expires 1y; 254 add_header Cache-Control "public, immutable"; 255 try_files $uri =404; 256 } 257 258 location /app/ { 259 try_files $uri $uri/ /index.html; 260 } 261 262 location = / { 263 try_files /homepage.html /index.html; 264 } 265 266 location / { 267 try_files $uri $uri/ /index.html; 268 } 269} 270EOF 271 272ln -sf /etc/nginx/sites-available/tranquil-pds /etc/nginx/sites-enabled/ 273rm -f /etc/nginx/sites-enabled/default 274mkdir -p /var/www/acme 275nginx -t 276systemctl reload nginx 277``` 278 279## Obtain a wildcard SSL cert 280 281User handles are served as subdomains (eg., `alice.pds.example.com`), so you need a wildcard certificate. 282 283Wildcard certs require DNS-01 validation. If your DNS provider has a certbot plugin: 284```bash 285apt install -y python3-certbot-dns-cloudflare 286certbot certonly --dns-cloudflare \ 287 --dns-cloudflare-credentials /etc/cloudflare.ini \ 288 -d pds.example.com -d '*.pds.example.com' 289``` 290 291For manual DNS validation (works with any provider): 292```bash 293certbot certonly --manual --preferred-challenges dns \ 294 -d pds.example.com -d '*.pds.example.com' 295``` 296 297Follow the prompts to add TXT records to your DNS. Note: manual mode doesn't auto-renew. 298 299After obtaining the cert, reload nginx: 300```bash 301systemctl reload nginx 302``` 303 304## Configure firewall if you're into that sort of thing 305 306```bash 307apt install -y ufw 308ufw allow ssh 309ufw allow 80/tcp 310ufw allow 443/tcp 311ufw enable 312``` 313 314## Verify installation 315 316```bash 317systemctl status tranquil-pds 318curl -s https://pds.example.com/xrpc/_health | jq 319curl -s https://pds.example.com/.well-known/atproto-did 320``` 321 322## Maintenance 323 324View logs: 325```bash 326journalctl -u tranquil-pds -f 327``` 328 329Update Tranquil PDS: 330```bash 331cd /opt/tranquil-pds 332git pull 333cd frontend && deno task build && cd .. 334cargo build --release 335systemctl stop tranquil-pds 336cp target/release/tranquil-pds /usr/local/bin/ 337cp -r frontend/dist/* /var/www/tranquil-pds/ 338systemctl start tranquil-pds 339``` 340 341Tranquil should auto-migrate if there are any new migrations to be applied to the db, so you don't need to worry. 342 343Backup database: 344```bash 345sudo -u postgres pg_dump pds > /var/backups/pds-$(date +%Y%m%d).sql 346``` 347 348## Custom homepage 349 350Drop 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. 351 352```bash 353cat > /var/www/tranquil-pds/homepage.html << 'EOF' 354<!DOCTYPE html> 355<html> 356<head> 357 <title>Welcome to my PDS</title> 358 <style> 359 body { font-family: system-ui; max-width: 600px; margin: 100px auto; padding: 20px; } 360 </style> 361</head> 362<body> 363 <h1>Welcome to my secret PDS</h1> 364 <p>This is a <a href="https://atproto.com">AT Protocol</a> Personal Data Server.</p> 365 <p><a href="/app/">Sign in</a> or learn more at <a href="https://bsky.social">Bluesky</a>.</p> 366</body> 367</html> 368EOF 369```