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