#!/bin/bash # ============================================================================= # Mastodon Health Check / Verification Script # ============================================================================= # Run as root echo "==========================================" echo "Mastodon Health Check" echo "==========================================" echo "" FAILED=0 WARN=0 # Load domain from .env if available if [ -f /home/mastodon/live/.env.production ]; then DOMAIN=$(grep "^LOCAL_DOMAIN=" /home/mastodon/live/.env.production | cut -d= -f2) echo "Domain: ${DOMAIN:-unknown}" fi echo "" echo "[Service Status]" services=("postgresql" "valkey" "nginx" "mastodon-web" "mastodon-sidekiq" "mastodon-streaming") for svc in "${services[@]}"; do STATUS=$(systemctl is-active $svc 2>/dev/null || echo "not-found") if [ "$STATUS" = "active" ]; then echo " ✓ $svc: running" elif [ "$STATUS" = "not-found" ]; then echo " - $svc: not installed" else echo " ✗ $svc: $STATUS" FAILED=1 fi done echo "" echo "[API Endpoints]" # Instance API INSTANCE=$(curl -sf http://127.0.0.1:3000/api/v1/instance 2>/dev/null) if [ -n "$INSTANCE" ]; then VERSION=$(echo "$INSTANCE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('version','unknown'))" 2>/dev/null) USERS=$(echo "$INSTANCE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('stats',{}).get('user_count',0))" 2>/dev/null) echo " ✓ Instance API: responding (v$VERSION, $USERS users)" else echo " ✗ Instance API: not responding" FAILED=1 fi # Streaming API STREAMING=$(curl -sf http://127.0.0.1:4000/api/v1/streaming/health 2>/dev/null) if [ -n "$STREAMING" ]; then echo " ✓ Streaming API: healthy" else echo " ✗ Streaming API: not responding" FAILED=1 fi # Nginx proxy NGINX_CHECK=$(curl -sf -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/ 2>/dev/null) if [ "$NGINX_CHECK" = "200" ] || [ "$NGINX_CHECK" = "302" ]; then echo " ✓ Nginx proxy: working (HTTP $NGINX_CHECK)" else echo " ✗ Nginx proxy: not working (HTTP $NGINX_CHECK)" FAILED=1 fi echo "" echo "[Database]" if systemctl is-active --quiet postgresql; then DB_SIZE=$(sudo -u postgres psql -t -c "SELECT pg_size_pretty(pg_database_size('mastodon_production'));" 2>/dev/null | xargs) ACCOUNTS=$(sudo -u postgres psql -t -d mastodon_production -c "SELECT COUNT(*) FROM accounts;" 2>/dev/null | xargs) STATUSES=$(sudo -u postgres psql -t -d mastodon_production -c "SELECT COUNT(*) FROM statuses;" 2>/dev/null | xargs) echo " ✓ PostgreSQL: running (DB: ${DB_SIZE:-unknown})" echo " Accounts: ${ACCOUNTS:-0}, Statuses: ${STATUSES:-0}" else echo " ✗ PostgreSQL: not running" FAILED=1 fi echo "" echo "[Cache]" if systemctl is-active --quiet valkey; then VALKEY_INFO=$(valkey-cli INFO server 2>/dev/null | grep valkey_version | cut -d: -f2 | tr -d '\r') echo " ✓ Valkey: running (v${VALKEY_INFO:-unknown})" elif systemctl is-active --quiet redis; then REDIS_INFO=$(redis-cli INFO server 2>/dev/null | grep redis_version | cut -d: -f2 | tr -d '\r') echo " ✓ Redis: running (v${REDIS_INFO:-unknown})" else echo " ✗ Valkey/Redis: not running" FAILED=1 fi echo "" echo "[Sidekiq Jobs]" # Check sidekiq process SIDEKIQ_PID=$(pgrep -f "sidekiq.*live" 2>/dev/null) if [ -n "$SIDEKIQ_PID" ]; then SIDEKIQ_MEM=$(ps -p $SIDEKIQ_PID -o rss= 2>/dev/null | awk '{printf "%.0fMB", $1/1024}') echo " ✓ Sidekiq: running (PID: $SIDEKIQ_PID, Mem: $SIDEKIQ_MEM)" else echo " ✗ Sidekiq: not running" FAILED=1 fi echo "" echo "[Federation]" # Check webfinger if [ -n "$DOMAIN" ]; then WF_CHECK=$(curl -sf -H "Accept: application/jrd+json" "http://127.0.0.1:3000/.well-known/webfinger?resource=acct:test@$DOMAIN" 2>/dev/null | head -c 50) if [ -n "$WF_CHECK" ]; then echo " ✓ Webfinger: responding" else echo " - Webfinger: no test account (may be normal)" fi # Check host-meta HOSTMETA=$(curl -sf "http://127.0.0.1:3000/.well-known/host-meta" 2>/dev/null | head -c 50) if [ -n "$HOSTMETA" ]; then echo " ✓ Host-meta: configured" else echo " ✗ Host-meta: not responding" WARN=1 fi # Check nodeinfo NODEINFO=$(curl -sf "http://127.0.0.1:3000/nodeinfo/2.0" 2>/dev/null) if [ -n "$NODEINFO" ]; then echo " ✓ NodeInfo: available" else echo " ✗ NodeInfo: not responding" WARN=1 fi fi echo "" echo "[Storage]" if [ -d /home/mastodon/live/public/system ]; then MEDIA_SIZE=$(du -sh /home/mastodon/live/public/system 2>/dev/null | cut -f1) echo " Media storage: ${MEDIA_SIZE:-empty}" else echo " Media storage: not yet created" fi DISK_USAGE=$(df -h /home 2>/dev/null | tail -1 | awk '{print $5}') echo " Disk usage (/home): ${DISK_USAGE:-unknown}" echo "" echo "[Configuration]" if [ -f /home/mastodon/live/.env.production ]; then echo " ✓ .env.production exists" # Check critical settings SECRET_KEY=$(grep "^SECRET_KEY_BASE=" /home/mastodon/live/.env.production | cut -d= -f2) if [ -n "$SECRET_KEY" ] && [ ${#SECRET_KEY} -gt 50 ]; then echo " ✓ SECRET_KEY_BASE: configured" else echo " ✗ SECRET_KEY_BASE: missing or invalid" FAILED=1 fi VAPID_KEY=$(grep "^VAPID_PRIVATE_KEY=" /home/mastodon/live/.env.production | cut -d= -f2) if [ -n "$VAPID_KEY" ]; then echo " ✓ VAPID keys: configured" else echo " ✗ VAPID keys: missing" WARN=1 fi else echo " ✗ .env.production: not found" FAILED=1 fi echo "" echo "==========================================" if [ $FAILED -eq 0 ] && [ $WARN -eq 0 ]; then echo "✅ All checks passed!" elif [ $FAILED -eq 0 ]; then echo "⚠️ Passed with warnings" else echo "❌ Some checks failed" fi echo "==========================================" exit $FAILED