this repo has no description
1#!/bin/bash 2set -euo pipefail 3 4RED='\033[0;31m' 5GREEN='\033[0;32m' 6YELLOW='\033[1;33m' 7BLUE='\033[0;34m' 8NC='\033[0m' 9 10log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } 11log_success() { echo -e "${GREEN}[OK]${NC} $1"; } 12log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } 13log_error() { echo -e "${RED}[ERROR]${NC} $1"; } 14 15if [[ $EUID -ne 0 ]]; then 16 log_error "This script must be run as root" 17 exit 1 18fi 19 20if ! grep -qi "debian" /etc/os-release 2>/dev/null; then 21 log_warn "This script is designed for Debian. Proceed with caution on other distros." 22fi 23 24nuke_installation() { 25 log_warn "NUKING EXISTING INSTALLATION" 26 log_info "Stopping services..." 27 systemctl stop tranquil-pds 2>/dev/null || true 28 systemctl disable tranquil-pds 2>/dev/null || true 29 30 log_info "Removing Tranquil PDS files..." 31 rm -rf /opt/tranquil-pds 32 rm -rf /var/lib/tranquil-pds 33 rm -f /usr/local/bin/tranquil-pds 34 rm -f /usr/local/bin/tranquil-pds-sendmail 35 rm -f /usr/local/bin/tranquil-pds-mailq 36 rm -rf /var/spool/tranquil-pds-mail 37 rm -f /etc/systemd/system/tranquil-pds.service 38 systemctl daemon-reload 39 40 log_info "Removing Tranquil PDS configuration..." 41 rm -rf /etc/tranquil-pds 42 43 log_info "Dropping postgres database and user..." 44 sudo -u postgres psql -c "DROP DATABASE IF EXISTS pds;" 2>/dev/null || true 45 sudo -u postgres psql -c "DROP USER IF EXISTS tranquil_pds;" 2>/dev/null || true 46 47 log_info "Removing minio buckets..." 48 if command -v mc &>/dev/null; then 49 mc rb local/pds-blobs --force 2>/dev/null || true 50 mc rb local/pds-backups --force 2>/dev/null || true 51 mc alias remove local 2>/dev/null || true 52 fi 53 systemctl stop minio 2>/dev/null || true 54 rm -rf /var/lib/minio/data/.minio.sys 2>/dev/null || true 55 rm -f /etc/default/minio 2>/dev/null || true 56 57 log_info "Removing nginx config..." 58 rm -f /etc/nginx/sites-enabled/tranquil-pds 59 rm -f /etc/nginx/sites-available/tranquil-pds 60 systemctl reload nginx 2>/dev/null || true 61 62 log_success "Previous installation nuked" 63} 64 65if [[ -f /etc/tranquil-pds/tranquil-pds.env ]] || [[ -d /opt/tranquil-pds ]] || [[ -f /usr/local/bin/tranquil-pds ]]; then 66 log_warn "Existing installation detected" 67 echo "" 68 echo "Options:" 69 echo " 1) Nuke everything and start fresh (destroys database!)" 70 echo " 2) Continue with existing installation (idempotent update)" 71 echo " 3) Exit" 72 echo "" 73 read -p "Choose an option [1/2/3]: " INSTALL_CHOICE 74 75 case "$INSTALL_CHOICE" in 76 1) 77 echo "" 78 log_warn "This will DELETE:" 79 echo " - PostgreSQL database 'pds' and all data" 80 echo " - All Tranquil PDS configuration and credentials" 81 echo " - All source code in /opt/tranquil-pds" 82 echo " - MinIO buckets 'pds-blobs' and 'pds-backups' and all data" 83 echo "" 84 read -p "Type 'NUKE' to confirm: " CONFIRM_NUKE 85 if [[ "$CONFIRM_NUKE" == "NUKE" ]]; then 86 nuke_installation 87 else 88 log_error "Nuke cancelled" 89 exit 1 90 fi 91 ;; 92 2) 93 log_info "Continuing with existing installation..." 94 ;; 95 3) 96 exit 0 97 ;; 98 *) 99 log_error "Invalid option" 100 exit 1 101 ;; 102 esac 103fi 104 105echo "" 106log_info "Tranquil PDS Installation Script for Debian" 107echo "" 108 109get_public_ips() { 110 IPV4=$(curl -4 -s --max-time 5 ifconfig.me 2>/dev/null || curl -4 -s --max-time 5 icanhazip.com 2>/dev/null || echo "Could not detect") 111 IPV6=$(curl -6 -s --max-time 5 ifconfig.me 2>/dev/null || curl -6 -s --max-time 5 icanhazip.com 2>/dev/null || echo "") 112} 113 114log_info "Detecting public IP addresses..." 115get_public_ips 116echo " IPv4: ${IPV4}" 117[[ -n "$IPV6" ]] && echo " IPv6: ${IPV6}" 118echo "" 119 120read -p "Enter your PDS domain (e.g., pds.example.com): " PDS_DOMAIN 121if [[ -z "$PDS_DOMAIN" ]]; then 122 log_error "Domain cannot be empty" 123 exit 1 124fi 125 126read -p "Enter your email for Let's Encrypt: " CERTBOT_EMAIL 127if [[ -z "$CERTBOT_EMAIL" ]]; then 128 log_error "Email cannot be empty" 129 exit 1 130fi 131 132echo "" 133log_info "DNS records required (create these now if you haven't):" 134echo "" 135echo " ${PDS_DOMAIN} A ${IPV4}" 136[[ -n "$IPV6" ]] && echo " ${PDS_DOMAIN} AAAA ${IPV6}" 137echo " *.${PDS_DOMAIN} A ${IPV4} (for user handles)" 138[[ -n "$IPV6" ]] && echo " *.${PDS_DOMAIN} AAAA ${IPV6} (for user handles)" 139echo "" 140read -p "Have you created these DNS records? (y/N): " DNS_CONFIRMED 141if [[ ! "$DNS_CONFIRMED" =~ ^[Yy]$ ]]; then 142 log_warn "Please create the DNS records and run this script again." 143 exit 0 144fi 145 146CREDENTIALS_FILE="/etc/tranquil-pds/.credentials" 147if [[ -f "$CREDENTIALS_FILE" ]]; then 148 log_info "Loading existing credentials..." 149 source "$CREDENTIALS_FILE" 150else 151 log_info "Generating secrets..." 152 JWT_SECRET=$(openssl rand -base64 48) 153 DPOP_SECRET=$(openssl rand -base64 48) 154 MASTER_KEY=$(openssl rand -base64 48) 155 DB_PASSWORD=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32) 156 MINIO_PASSWORD=$(openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32) 157 158 mkdir -p /etc/tranquil-pds 159 cat > "$CREDENTIALS_FILE" << EOF 160JWT_SECRET="$JWT_SECRET" 161DPOP_SECRET="$DPOP_SECRET" 162MASTER_KEY="$MASTER_KEY" 163DB_PASSWORD="$DB_PASSWORD" 164MINIO_PASSWORD="$MINIO_PASSWORD" 165EOF 166 chmod 600 "$CREDENTIALS_FILE" 167 log_success "Secrets generated" 168fi 169 170log_info "Checking swap space..." 171TOTAL_MEM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}') 172TOTAL_SWAP_KB=$(grep SwapTotal /proc/meminfo | awk '{print $2}') 173 174if [[ $TOTAL_SWAP_KB -lt 2000000 ]]; then 175 if [[ ! -f /swapfile ]]; then 176 log_info "Adding swap space for compilation..." 177 SWAP_SIZE="4G" 178 [[ $TOTAL_MEM_KB -ge 4000000 ]] && SWAP_SIZE="2G" 179 fallocate -l $SWAP_SIZE /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=4096 180 chmod 600 /swapfile 181 mkswap /swapfile 182 swapon /swapfile 183 grep -q '/swapfile' /etc/fstab || echo '/swapfile none swap sw 0 0' >> /etc/fstab 184 log_success "Swap added ($SWAP_SIZE)" 185 else 186 swapon /swapfile 2>/dev/null || true 187 fi 188fi 189 190log_info "Updating system packages..." 191apt update && apt upgrade -y 192 193log_info "Installing build dependencies..." 194apt install -y curl git build-essential pkg-config libssl-dev ca-certificates gnupg lsb-release unzip xxd 195 196log_info "Installing postgres..." 197apt install -y postgresql postgresql-contrib 198systemctl enable postgresql 199systemctl start postgresql 200sudo -u postgres psql -c "CREATE USER tranquil_pds WITH PASSWORD '${DB_PASSWORD}';" 2>/dev/null || \ 201 sudo -u postgres psql -c "ALTER USER tranquil_pds WITH PASSWORD '${DB_PASSWORD}';" 202sudo -u postgres psql -c "CREATE DATABASE pds OWNER tranquil_pds;" 2>/dev/null || true 203sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE pds TO tranquil_pds;" 204log_success "postgres configured" 205 206log_info "Installing valkey..." 207apt install -y valkey 2>/dev/null || { 208 log_warn "valkey not in repos, installing redis..." 209 apt install -y redis-server 210 systemctl enable redis-server 211 systemctl start redis-server 212} 213systemctl enable valkey-server 2>/dev/null || true 214systemctl start valkey-server 2>/dev/null || true 215 216log_info "Installing minio..." 217if [[ ! -f /usr/local/bin/minio ]]; then 218 ARCH=$(dpkg --print-architecture) 219 case "$ARCH" in 220 amd64) curl -fsSL -o /tmp/minio https://dl.min.io/server/minio/release/linux-amd64/minio ;; 221 arm64) curl -fsSL -o /tmp/minio https://dl.min.io/server/minio/release/linux-arm64/minio ;; 222 *) log_error "Unsupported architecture: $ARCH"; exit 1 ;; 223 esac 224 chmod +x /tmp/minio 225 mv /tmp/minio /usr/local/bin/ 226fi 227 228mkdir -p /var/lib/minio/data 229id -u minio-user &>/dev/null || useradd -r -s /sbin/nologin minio-user 230chown -R minio-user:minio-user /var/lib/minio 231 232cat > /etc/default/minio << EOF 233MINIO_ROOT_USER=minioadmin 234MINIO_ROOT_PASSWORD=${MINIO_PASSWORD} 235MINIO_VOLUMES="/var/lib/minio/data" 236MINIO_OPTS="--console-address :9001" 237EOF 238chmod 600 /etc/default/minio 239 240cat > /etc/systemd/system/minio.service << 'EOF' 241[Unit] 242Description=MinIO Object Storage 243After=network.target 244 245[Service] 246User=minio-user 247Group=minio-user 248EnvironmentFile=/etc/default/minio 249ExecStart=/usr/local/bin/minio server $MINIO_VOLUMES $MINIO_OPTS 250Restart=always 251LimitNOFILE=65536 252 253[Install] 254WantedBy=multi-user.target 255EOF 256 257systemctl daemon-reload 258systemctl enable minio 259systemctl start minio 260log_success "minio installed" 261 262log_info "Waiting for minio..." 263sleep 5 264 265if [[ ! -f /usr/local/bin/mc ]]; then 266 ARCH=$(dpkg --print-architecture) 267 case "$ARCH" in 268 amd64) curl -fsSL -o /tmp/mc https://dl.min.io/client/mc/release/linux-amd64/mc ;; 269 arm64) curl -fsSL -o /tmp/mc https://dl.min.io/client/mc/release/linux-arm64/mc ;; 270 esac 271 chmod +x /tmp/mc 272 mv /tmp/mc /usr/local/bin/ 273fi 274 275mc alias remove local 2>/dev/null || true 276mc alias set local http://localhost:9000 minioadmin "${MINIO_PASSWORD}" --api S3v4 277mc mb local/pds-blobs --ignore-existing 278mc mb local/pds-backups --ignore-existing 279log_success "minio buckets created" 280 281log_info "Installing rust..." 282if [[ -f "$HOME/.cargo/env" ]]; then 283 source "$HOME/.cargo/env" 284fi 285if ! command -v rustc &>/dev/null; then 286 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 287 source "$HOME/.cargo/env" 288fi 289 290log_info "Installing deno..." 291export PATH="$HOME/.deno/bin:$PATH" 292if ! command -v deno &>/dev/null && [[ ! -f "$HOME/.deno/bin/deno" ]]; then 293 curl -fsSL https://deno.land/install.sh | sh 294 grep -q 'deno/bin' ~/.bashrc 2>/dev/null || echo 'export PATH="$HOME/.deno/bin:$PATH"' >> ~/.bashrc 295fi 296 297log_info "Cloning Tranquil PDS..." 298if [[ ! -d /opt/tranquil-pds ]]; then 299 git clone https://tangled.org/lewis.moe/bspds-sandbox /opt/tranquil-pds 300else 301 cd /opt/tranquil-pds && git pull 302fi 303cd /opt/tranquil-pds 304 305log_info "Building frontend..." 306"$HOME/.deno/bin/deno" task build --filter=frontend 307log_success "Frontend built" 308 309log_info "Building Tranquil PDS (this takes a while)..." 310source "$HOME/.cargo/env" 311if [[ $TOTAL_MEM_KB -lt 4000000 ]]; then 312 log_info "Low memory - limiting parallel jobs" 313 CARGO_BUILD_JOBS=1 cargo build --release 314else 315 cargo build --release 316fi 317log_success "Tranquil PDS built" 318 319log_info "Running migrations..." 320cargo install sqlx-cli --no-default-features --features postgres 321export DATABASE_URL="postgres://tranquil_pds:${DB_PASSWORD}@localhost:5432/pds" 322"$HOME/.cargo/bin/sqlx" migrate run 323log_success "Migrations complete" 324 325log_info "Setting up mail trap..." 326mkdir -p /var/spool/tranquil-pds-mail 327chmod 1777 /var/spool/tranquil-pds-mail 328 329cat > /usr/local/bin/tranquil-pds-sendmail << 'SENDMAIL_EOF' 330#!/bin/bash 331MAIL_DIR="/var/spool/tranquil-pds-mail" 332TIMESTAMP=$(date +%Y%m%d-%H%M%S) 333RANDOM_ID=$(head -c 4 /dev/urandom | xxd -p) 334MAIL_FILE="${MAIL_DIR}/${TIMESTAMP}-${RANDOM_ID}.eml" 335mkdir -p "$MAIL_DIR" 336{ 337 echo "X-Tranquil-PDS-Received: $(date -Iseconds)" 338 echo "X-Tranquil-PDS-Args: $*" 339 echo "" 340 cat 341} > "$MAIL_FILE" 342chmod 644 "$MAIL_FILE" 343exit 0 344SENDMAIL_EOF 345chmod +x /usr/local/bin/tranquil-pds-sendmail 346 347cat > /usr/local/bin/tranquil-pds-mailq << 'MAILQ_EOF' 348#!/bin/bash 349MAIL_DIR="/var/spool/tranquil-pds-mail" 350case "${1:-list}" in 351 list) 352 ls -lt "$MAIL_DIR"/*.eml 2>/dev/null | head -20 || echo "No emails" 353 ;; 354 latest) 355 f=$(ls -t "$MAIL_DIR"/*.eml 2>/dev/null | head -1) 356 [[ -f "$f" ]] && cat "$f" || echo "No emails" 357 ;; 358 clear) 359 rm -f "$MAIL_DIR"/*.eml 360 echo "Cleared" 361 ;; 362 count) 363 ls -1 "$MAIL_DIR"/*.eml 2>/dev/null | wc -l 364 ;; 365 [0-9]*) 366 f=$(ls -t "$MAIL_DIR"/*.eml 2>/dev/null | sed -n "${1}p") 367 [[ -f "$f" ]] && cat "$f" || echo "Not found" 368 ;; 369 *) 370 [[ -f "$MAIL_DIR/$1" ]] && cat "$MAIL_DIR/$1" || echo "Usage: tranquil-pds-mailq [list|latest|clear|count|N]" 371 ;; 372esac 373MAILQ_EOF 374chmod +x /usr/local/bin/tranquil-pds-mailq 375 376log_info "Creating Tranquil PDS configuration..." 377cat > /etc/tranquil-pds/tranquil-pds.env << EOF 378SERVER_HOST=127.0.0.1 379SERVER_PORT=3000 380PDS_HOSTNAME=${PDS_DOMAIN} 381DATABASE_URL=postgres://tranquil_pds:${DB_PASSWORD}@localhost:5432/pds 382DATABASE_MAX_CONNECTIONS=100 383DATABASE_MIN_CONNECTIONS=10 384S3_ENDPOINT=http://localhost:9000 385AWS_REGION=us-east-1 386S3_BUCKET=pds-blobs 387BACKUP_S3_BUCKET=pds-backups 388AWS_ACCESS_KEY_ID=minioadmin 389AWS_SECRET_ACCESS_KEY=${MINIO_PASSWORD} 390VALKEY_URL=redis://localhost:6379 391JWT_SECRET=${JWT_SECRET} 392DPOP_SECRET=${DPOP_SECRET} 393MASTER_KEY=${MASTER_KEY} 394PLC_DIRECTORY_URL=https://plc.directory 395CRAWLERS=https://bsky.network 396AVAILABLE_USER_DOMAINS=${PDS_DOMAIN} 397MAIL_FROM_ADDRESS=noreply@${PDS_DOMAIN} 398MAIL_FROM_NAME=Tranquil PDS 399SENDMAIL_PATH=/usr/local/bin/tranquil-pds-sendmail 400EOF 401chmod 600 /etc/tranquil-pds/tranquil-pds.env 402 403log_info "Installing Tranquil PDS..." 404id -u tranquil-pds &>/dev/null || useradd -r -s /sbin/nologin tranquil-pds 405cp /opt/tranquil-pds/target/release/tranquil-pds /usr/local/bin/ 406mkdir -p /var/lib/tranquil-pds 407cp -r /opt/tranquil-pds/frontend/dist /var/lib/tranquil-pds/frontend 408chown -R tranquil-pds:tranquil-pds /var/lib/tranquil-pds 409 410cat > /etc/systemd/system/tranquil-pds.service << 'EOF' 411[Unit] 412Description=Tranquil PDS - AT Protocol PDS 413After=network.target postgresql.service minio.service 414 415[Service] 416Type=simple 417User=tranquil-pds 418Group=tranquil-pds 419EnvironmentFile=/etc/tranquil-pds/tranquil-pds.env 420Environment=FRONTEND_DIR=/var/lib/tranquil-pds/frontend 421ExecStart=/usr/local/bin/tranquil-pds 422Restart=always 423RestartSec=5 424 425[Install] 426WantedBy=multi-user.target 427EOF 428 429systemctl daemon-reload 430systemctl enable tranquil-pds 431systemctl start tranquil-pds 432log_success "Tranquil PDS service started" 433 434log_info "Installing nginx..." 435apt install -y nginx 436cat > /etc/nginx/sites-available/tranquil-pds << EOF 437server { 438 listen 80; 439 listen [::]:80; 440 server_name ${PDS_DOMAIN} *.${PDS_DOMAIN}; 441 442 location /.well-known/acme-challenge/ { 443 root /var/www/html; 444 } 445 446 location / { 447 proxy_pass http://127.0.0.1:3000; 448 proxy_http_version 1.1; 449 proxy_set_header Upgrade \$http_upgrade; 450 proxy_set_header Connection "upgrade"; 451 proxy_set_header Host \$host; 452 proxy_set_header X-Real-IP \$remote_addr; 453 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; 454 proxy_set_header X-Forwarded-Proto \$scheme; 455 proxy_read_timeout 86400; 456 proxy_send_timeout 86400; 457 client_max_body_size 100M; 458 } 459} 460EOF 461 462ln -sf /etc/nginx/sites-available/tranquil-pds /etc/nginx/sites-enabled/ 463rm -f /etc/nginx/sites-enabled/default 464nginx -t 465systemctl reload nginx 466log_success "nginx configured" 467 468log_info "Configuring firewall..." 469apt install -y ufw 470ufw --force reset 471ufw default deny incoming 472ufw default allow outgoing 473ufw allow ssh 474ufw allow 80/tcp 475ufw allow 443/tcp 476ufw --force enable 477log_success "Firewall configured" 478 479echo "" 480log_info "Obtaining wildcard SSL certificate..." 481echo "" 482echo "User handles are served as subdomains (e.g., alice.${PDS_DOMAIN})," 483echo "so you need a wildcard certificate. This requires DNS validation." 484echo "" 485echo "You'll need to add a TXT record to your DNS when prompted." 486echo "" 487read -p "Ready to proceed? (y/N): " CERT_READY 488 489if [[ "$CERT_READY" =~ ^[Yy]$ ]]; then 490 apt install -y certbot python3-certbot-nginx 491 492 log_info "Running certbot with DNS challenge..." 493 echo "" 494 echo "When prompted, add the TXT record to your DNS, wait a minute" 495 echo "for propagation, then press Enter to continue." 496 echo "" 497 498 if certbot certonly --manual --preferred-challenges dns \ 499 -d "${PDS_DOMAIN}" -d "*.${PDS_DOMAIN}" \ 500 --email "${CERTBOT_EMAIL}" --agree-tos; then 501 502 cat > /etc/nginx/sites-available/tranquil-pds << EOF 503server { 504 listen 80; 505 listen [::]:80; 506 server_name ${PDS_DOMAIN} *.${PDS_DOMAIN}; 507 508 location /.well-known/acme-challenge/ { 509 root /var/www/html; 510 } 511 512 location / { 513 return 301 https://\$host\$request_uri; 514 } 515} 516 517server { 518 listen 443 ssl http2; 519 listen [::]:443 ssl http2; 520 server_name ${PDS_DOMAIN} *.${PDS_DOMAIN}; 521 522 ssl_certificate /etc/letsencrypt/live/${PDS_DOMAIN}/fullchain.pem; 523 ssl_certificate_key /etc/letsencrypt/live/${PDS_DOMAIN}/privkey.pem; 524 ssl_protocols TLSv1.2 TLSv1.3; 525 ssl_ciphers HIGH:!aNULL:!MD5; 526 ssl_prefer_server_ciphers on; 527 ssl_session_cache shared:SSL:10m; 528 529 location / { 530 proxy_pass http://127.0.0.1:3000; 531 proxy_http_version 1.1; 532 proxy_set_header Upgrade \$http_upgrade; 533 proxy_set_header Connection "upgrade"; 534 proxy_set_header Host \$host; 535 proxy_set_header X-Real-IP \$remote_addr; 536 proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; 537 proxy_set_header X-Forwarded-Proto \$scheme; 538 proxy_read_timeout 86400; 539 proxy_send_timeout 86400; 540 client_max_body_size 100M; 541 } 542} 543EOF 544 nginx -t && systemctl reload nginx 545 log_success "Wildcard SSL certificate installed" 546 547 echo "" 548 log_warn "Certificate renewal note:" 549 echo "Manual DNS challenges don't auto-renew. Before expiry, run:" 550 echo " certbot renew --manual" 551 echo "" 552 echo "For auto-renewal, consider using a DNS provider plugin:" 553 echo " apt install python3-certbot-dns-cloudflare # or your provider" 554 echo "" 555 else 556 log_warn "Wildcard cert failed. You can retry later with:" 557 echo " certbot certonly --manual --preferred-challenges dns \\" 558 echo " -d ${PDS_DOMAIN} -d '*.${PDS_DOMAIN}'" 559 fi 560else 561 log_warn "Skipping SSL. Your PDS is running on HTTP only." 562 echo "To add SSL later, run:" 563 echo " certbot certonly --manual --preferred-challenges dns \\" 564 echo " -d ${PDS_DOMAIN} -d '*.${PDS_DOMAIN}'" 565fi 566 567log_info "Verifying installation..." 568sleep 3 569if curl -s "http://localhost:3000/xrpc/_health" | grep -q "version"; then 570 log_success "Tranquil PDS is responding" 571else 572 log_warn "Tranquil PDS may still be starting. Check: journalctl -u tranquil-pds -f" 573fi 574 575echo "" 576log_success "Installation complete" 577echo "" 578echo "PDS: https://${PDS_DOMAIN}" 579echo "" 580echo "Credentials (also in /etc/tranquil-pds/.credentials):" 581echo " DB password: ${DB_PASSWORD}" 582echo " MinIO password: ${MINIO_PASSWORD}" 583echo "" 584echo "Commands:" 585echo " journalctl -u tranquil-pds -f # logs" 586echo " systemctl restart tranquil-pds # restart" 587echo " tranquil-pds-mailq # view trapped emails" 588echo ""