#!/bin/bash
# Mastodon v4.5.4 Bare-Metal Install Script for Rocky Linux 10
# Usage: curl -sSL https://git.vish.gg/Vish/pihole-baremetal/raw/branch/main/mastodon/install-mastodon.sh | bash
# Run as root on a fresh Rocky Linux 10 VM

set -e

# Configuration - Edit these before running
DOMAIN="${DOMAIN:-mastodon.example.com}"
ADMIN_USER="${ADMIN_USER:-admin}"
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@example.com}"
SMTP_SERVER="${SMTP_SERVER:-smtp.gmail.com}"
SMTP_PORT="${SMTP_PORT:-587}"
SMTP_USER="${SMTP_USER:-}"
SMTP_PASS="REDACTED_PASSWORD"
SMTP_FROM="${SMTP_FROM:-notifications@example.com}"

echo "=========================================="
echo "Mastodon v4.5.4 Installation Script"
echo "Target Domain: $DOMAIN"
echo "=========================================="

# Check if running as root
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root"
   exit 1
fi

# Install system dependencies
echo "[1/12] Installing system dependencies..."
dnf install -y epel-release
dnf install -y git curl wget gcc make autoconf bison openssl-devel \
    libyaml-devel libffi-devel readline-devel zlib-devel gdbm-devel ncurses-devel \
    libxml2-devel libxslt-devel libicu-devel libidn-devel jemalloc-devel \
    ImageMagick ImageMagick-devel nginx postgresql-server postgresql-contrib \
    valkey certbot python3-certbot-nginx meson ninja-build \
    libpng-devel libjpeg-turbo-devel libwebp-devel libtiff-devel \
    expat-devel gobject-introspection-devel glib2-devel

# Install Node.js 20
echo "[2/12] Installing Node.js 20..."
curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
dnf install -y nodejs

# Enable corepack for Yarn
corepack enable

# Build libvips from source (not in Rocky 10 repos)
echo "[3/12] Building libvips from source..."
cd /tmp
wget https://github.com/libvips/libvips/releases/download/v8.16.1/vips-8.16.1.tar.xz
tar xf vips-8.16.1.tar.xz
cd vips-8.16.1
meson setup build --prefix=/usr --buildtype=release
cd build && ninja && ninja install
ldconfig
cd /tmp && rm -rf vips-8.16.1*

# Initialize PostgreSQL
echo "[4/12] Setting up PostgreSQL..."
postgresql-setup --initdb
systemctl enable --now postgresql

# Create mastodon database user and database
sudo -u postgres psql -c "CREATE USER mastodon CREATEDB;"
sudo -u postgres psql -c "CREATE DATABASE mastodon_production OWNER mastodon;"

# Start Valkey (Redis)
echo "[5/12] Starting Valkey..."
systemctl enable --now valkey

# Create mastodon user
echo "[6/12] Creating mastodon user..."
useradd -m -s /bin/bash mastodon || true

# Install Ruby via rbenv
echo "[7/12] Installing Ruby 3.4.7..."
sudo -u mastodon bash << 'RUBY_INSTALL'
cd ~
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"

git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
RUBY_CONFIGURE_OPTS="--with-jemalloc" rbenv install 3.4.7
rbenv global 3.4.7
gem install bundler
RUBY_INSTALL

# Clone Mastodon
echo "[8/12] Cloning Mastodon v4.5.4..."
sudo -u mastodon bash << 'CLONE'
cd ~
git clone https://github.com/mastodon/mastodon.git live
cd live
git checkout v4.5.4
CLONE

# Install dependencies
echo "[9/12] Installing Ruby and Node dependencies..."
sudo -u mastodon bash << 'DEPS'
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
cd ~/live
bundle config deployment 'true'
bundle config without 'development test'
bundle install -j$(nproc)
yarn install --immutable
DEPS

# Generate secrets and create .env.production
echo "[10/12] Generating secrets and configuration..."
SECRET_KEY=$(openssl rand -hex 64)
OTP_SECRET=$(openssl rand -hex 64)
VAPID_KEYS=$(sudo -u mastodon bash -c 'cd ~/live && export PATH="$HOME/.rbenv/bin:$PATH" && eval "$(rbenv init -)" && RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key 2>/dev/null')
VAPID_PRIVATE=$(echo "$VAPID_KEYS" | grep VAPID_PRIVATE_KEY | cut -d= -f2)
VAPID_PUBLIC=$(echo "$VAPID_KEYS" | grep VAPID_PUBLIC_KEY | cut -d= -f2)

AR_KEY=$(openssl rand -hex 32)
AR_DETERMINISTIC=$(openssl rand -hex 32)
AR_SALT=$(openssl rand -hex 32)

cat > /home/mastodon/live/.env.production << ENVFILE
LOCAL_DOMAIN=$DOMAIN
SINGLE_USER_MODE=false
SECRET_KEY_BASE=$SECRET_KEY
OTP_SECRET=$OTP_SECRET
VAPID_PRIVATE_KEY=$VAPID_PRIVATE
VAPID_PUBLIC_KEY=$VAPID_PUBLIC
DB_HOST=/var/run/postgresql
DB_USER=mastodon
DB_NAME=mastodon_production
DB_PASS=
"REDACTED_PASSWORD"
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
SMTP_SERVER=$SMTP_SERVER
SMTP_PORT=$SMTP_PORT
SMTP_LOGIN=$SMTP_USER
SMTP_PASSWORD="REDACTED_PASSWORD"
SMTP_FROM_ADDRESS=$SMTP_FROM
SMTP_AUTH_METHOD=plain
SMTP_OPENSSL_VERIFY_MODE=none
SMTP_ENABLE_STARTTLS=auto
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=$AR_KEY
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=$AR_DETERMINISTIC
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=$AR_SALT
TRUSTED_PROXY_IP=127.0.0.1,::1,192.168.0.0/16
ENVFILE

chown mastodon:mastodon /home/mastodon/live/.env.production
chmod 600 /home/mastodon/live/.env.production

# Run migrations and seed
echo "[11/12] Running database migrations..."
sudo -u mastodon bash << 'MIGRATE'
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
cd ~/live
RAILS_ENV=production bundle exec rails db:migrate
RAILS_ENV=production bundle exec rails db:seed
RAILS_ENV=production bundle exec rails assets:precompile
MIGRATE

# Create systemd services
echo "[12/12] Creating systemd services..."
cat > /etc/systemd/system/mastodon-web.service << 'SERVICE'
[Unit]
Description=mastodon-web
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3001"
ExecStart=/bin/bash -lc 'cd /home/mastodon/live && exec bundle exec puma -C config/puma.rb'
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
SERVICE

cat > /etc/systemd/system/mastodon-sidekiq.service << 'SERVICE'
[Unit]
Description=mastodon-sidekiq
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="MALLOC_ARENA_MAX=2"
ExecStart=/bin/bash -lc 'cd /home/mastodon/live && exec bundle exec sidekiq -c 25'
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
SERVICE

cat > /etc/systemd/system/mastodon-streaming.service << 'SERVICE'
[Unit]
Description=mastodon-streaming
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="NODE_ENV=production"
Environment="PORT=4000"
Environment="STREAMING_CLUSTER_NUM=1"
ExecStart=/usr/bin/node ./streaming
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
SERVICE

# Nginx config
cat > /etc/nginx/conf.d/mastodon.conf << 'NGINX'
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

upstream backend {
    server 127.0.0.1:3001 fail_timeout=0;
}

upstream streaming {
    server 127.0.0.1:4000 fail_timeout=0;
}

server {
    listen 3000;
    listen [::]:3000;
    server_name _;

    keepalive_timeout    70;
    sendfile             on;
    client_max_body_size 99m;

    root /home/mastodon/live/public;

    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;

    location / {
        try_files $uri @proxy;
    }

    location ~ ^/(assets|avatars|emoji|headers|packs|shortcuts|sounds|system)/ {
        add_header Cache-Control "public, max-age=2419200, must-revalidate";
        try_files $uri =404;
    }

    location ^~ /api/v1/streaming {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_pass http://streaming;
        proxy_buffering off;
        proxy_redirect off;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        tcp_nodelay on;
    }

    location @proxy {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_pass http://backend;
        proxy_buffering on;
        proxy_redirect off;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        tcp_nodelay on;
    }

    error_page 404 500 501 502 503 504 /500.html;
}
NGINX

# SELinux and firewall
setsebool -P httpd_can_network_connect 1
setsebool -P httpd_read_user_content 1
chcon -R -t httpd_sys_content_t /home/mastodon/live/public
chmod 755 /home/mastodon /home/mastodon/live /home/mastodon/live/public
firewall-cmd --permanent --add-port=3000/tcp
firewall-cmd --reload

# Add localhost to Rails hosts
echo 'Rails.application.config.hosts << "localhost"' >> /home/mastodon/live/config/environments/production.rb
echo 'Rails.application.config.hosts << "127.0.0.1"' >> /home/mastodon/live/config/environments/production.rb
chown mastodon:mastodon /home/mastodon/live/config/environments/production.rb

# Enable and start services
systemctl daemon-reload
systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming nginx

# Create admin user
echo ""
echo "Creating admin user..."
ADMIN_PASS="REDACTED_PASSWORD" -u mastodon bash -c "cd ~/live && export PATH=\"\$HOME/.rbenv/bin:\$PATH\" && eval \"\$(rbenv init -)\" && RAILS_ENV=production bin/tootctl accounts create $ADMIN_USER --email=$ADMIN_EMAIL --confirmed 2>&1 | grep 'New password' | awk '{print \$3}'")
sudo -u mastodon bash -c "cd ~/live && export PATH=\"\$HOME/.rbenv/bin:\$PATH\" && eval \"\$(rbenv init -)\" && RAILS_ENV=production bin/tootctl accounts modify $ADMIN_USER --role Owner"
sudo -u mastodon bash -c "cd ~/live && export PATH=\"\$HOME/.rbenv/bin:\$PATH\" && eval \"\$(rbenv init -)\" && RAILS_ENV=production bin/tootctl accounts approve $ADMIN_USER"

echo ""
echo "=========================================="
echo "✅ Mastodon Installation Complete!"
echo "=========================================="
echo ""
echo "Domain: $DOMAIN"
echo "Admin User: $ADMIN_USER"
echo "Admin Email: $ADMIN_EMAIL"
echo "Admin Password: "REDACTED_PASSWORD"
echo ""
echo "Listening on port 3000 (HTTP)"
echo ""
echo "Next steps:"
echo "1. Configure your reverse proxy to forward HTTPS to port 3000"
echo "2. Login and change your password"
echo "3. Configure instance settings in Administration panel"
echo ""
