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