Mastodon Installation Guide

Mastodon is a free and open-source decentralized social media platform that serves as an alternative to proprietary platforms like Twitter/X. It's part of the fediverse, uses the ActivityPub protocol for federation, and allows users to run their own social media instances with full control over their data and community.

Communication🔴 advanced31 min⏱️ 1-2 hours

Mastodon is a free, open-source federated social network server that provides a decentralized alternative to proprietary platforms like Twitter/X. Built on Ruby on Rails and using ActivityPub protocol, Mastodon allows users to run their own social media instance while connecting to the broader fediverse.

FOSS Alternatives

Mastodon is part of the broader fediverse ecosystem. Consider these FOSS alternatives for decentralized social networking:

  • Pleroma - Lightweight ActivityPub server with lower resource requirements
  • Misskey - Feature-rich microblogging platform with advanced customization
  • GoToSocial - Lightweight, security-focused ActivityPub server written in Go
  • PixelFed - Photo-sharing platform (Instagram alternative) that federates with Mastodon
  • Friendica - Full-featured social network with multiple protocol support
  • Akkoma - Pleroma fork with enhanced features and modern development
  • Calckey - Misskey fork with improved user experience
  • Hometown - Mastodon fork with local-only posting features
  • 1. Prerequisites

    Hardware Requirements

  • CPU: 2+ cores (4+ cores recommended for production)
  • RAM: 4GB minimum (8GB+ recommended for production)
  • Storage: 20GB minimum (SSD recommended, scale based on media storage needs)
  • Network: Reliable internet connection with public IP (for federation)
  • Software Dependencies

  • Operating System: Linux (RHEL-based, Debian-based, Arch Linux, Alpine Linux)
  • Database: PostgreSQL 12+ (PostgreSQL 15+ recommended)
  • Cache/Queue: Redis 6.0+
  • Runtime: Ruby 3.0+ (Ruby 3.2+ recommended)
  • Web Server: nginx or Apache (for reverse proxy)
  • SSL Certificate: Let's Encrypt or commercial certificate
  • Node.js: 16+ (for asset compilation)
  • Yarn: Package manager for Node.js dependencies
  • Network Requirements

  • Ports:
  • 80/443 (HTTP/HTTPS)
  • 25/587 (SMTP - for email delivery)
  • 3000 (Mastodon web interface)
  • 4000 (Mastodon streaming API)
  • Domain: Registered domain name with DNS control
  • Email: SMTP server for notifications and user registration
  • System Access

  • Root or sudo access required for installation
  • Dedicated user account for Mastodon service
  • Firewall configuration access
  • Supported Operating Systems

    This guide supports installation on:

  • RHEL-based: RHEL 8/9, CentOS Stream 8/9, Rocky Linux 8/9, AlmaLinux 8/9, Fedora 37+
  • Debian-based: Debian 11/12, Ubuntu 20.04/22.04/24.04 LTS
  • Arch Linux: Arch Linux (rolling), Manjaro
  • Alpine Linux: 3.18+ (containerized deployments)
  • macOS: 12+ (development only)
  • FreeBSD: 13.0+ (experimental)
  • 2. Installation

    RHEL/CentOS/Rocky Linux/AlmaLinux

    bash
    # Install EPEL and PowerTools repositories
    sudo dnf install -y epel-release
    sudo dnf config-manager --set-enabled powertools  # CentOS Stream 8
    sudo dnf config-manager --set-enabled crb         # CentOS Stream 9, Rocky, AlmaLinux
    
    # Install Node.js repository
    curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
    
    # Install Yarn repository
    curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
    
    # Install PostgreSQL repository (for latest version)
    sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm
    
    # Install required packages
    sudo dnf install -y \
        git curl wget gnupg2 \
        gcc gcc-c++ make automake autoconf libtool \
        postgresql15-server postgresql15-devel \
        redis \
        nodejs yarn \
        nginx \
        ImageMagick ImageMagick-devel \
        ffmpeg \
        libxml2-devel libxslt-devel \
        libidn-devel \
        openssl-devel \
        readline-devel \
        zlib-devel \
        libyaml-devel \
        gdbm-devel \
        ncurses-devel \
        libffi-devel
    
    # Initialize PostgreSQL
    sudo postgresql-15-setup initdb
    sudo systemctl enable --now postgresql-15 redis
    
    # Configure PostgreSQL
    sudo -u postgres createuser mastodon --createdb
    sudo -u postgres psql -c "ALTER USER mastodon WITH ENCRYPTED PASSWORD 'secure_random_password_here';"
    
    # Create mastodon user
    sudo useradd -m -s /bin/bash mastodon
    sudo usermod -a -G mastodon nginx
    
    # Install Ruby (using rbenv for version management)
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon
    git clone https://github.com/rbenv/rbenv.git ~/.rbenv
    echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
    echo 'eval "$(rbenv init -)"' >> ~/.bashrc
    git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    rbenv install 3.2.2
    rbenv global 3.2.2
    gem install bundler
    EOF
    
    # Clone Mastodon
    sudo -u mastodon git clone https://github.com/mastodon/mastodon.git /home/mastodon/live
    cd /home/mastodon/live
    sudo -u mastodon git checkout $(git tag -l | grep -v 'rc' | sort -V | tail -n 1)
    
    # Install Ruby dependencies
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    bundle config deployment 'true'
    bundle config without 'development test'
    bundle install
    EOF
    
    # Install Node.js dependencies
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    yarn install --pure-lockfile
    EOF

    Debian/Ubuntu

    bash
    # Update package list
    sudo apt update
    
    # Install curl and gnupg (if not already installed)
    sudo apt install -y curl gnupg
    
    # Add Node.js repository
    curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
    
    # Add Yarn repository
    curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
    echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
    
    # Add PostgreSQL repository (for latest version)
    wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
    echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
    
    # Update package list
    sudo apt update
    
    # Install required packages
    sudo apt install -y \
        git curl wget gnupg \
        build-essential \
        postgresql-15 postgresql-contrib-15 postgresql-server-dev-15 \
        redis-server \
        nodejs yarn \
        nginx \
        imagemagick ffmpeg \
        libxml2-dev libxslt1-dev \
        libidn11-dev \
        libssl-dev \
        libreadline-dev \
        zlib1g-dev \
        libyaml-dev \
        libgdbm-dev \
        libncurses5-dev \
        libffi-dev \
        libpq-dev
    
    # Start and enable services
    sudo systemctl enable --now postgresql redis-server
    
    # Configure PostgreSQL
    sudo -u postgres createuser mastodon --createdb
    sudo -u postgres psql -c "ALTER USER mastodon WITH ENCRYPTED PASSWORD 'secure_random_password_here';"
    
    # Create mastodon user
    sudo useradd -m -s /bin/bash mastodon
    sudo usermod -a -G mastodon www-data
    
    # Install Ruby (using rbenv)
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon
    git clone https://github.com/rbenv/rbenv.git ~/.rbenv
    echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
    echo 'eval "$(rbenv init -)"' >> ~/.bashrc
    git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    rbenv install 3.2.2
    rbenv global 3.2.2
    gem install bundler
    EOF
    
    # Clone Mastodon
    sudo -u mastodon git clone https://github.com/mastodon/mastodon.git /home/mastodon/live
    cd /home/mastodon/live
    sudo -u mastodon git checkout $(git tag -l | grep -v 'rc' | sort -V | tail -n 1)
    
    # Install dependencies
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    bundle config deployment 'true'
    bundle config without 'development test'
    bundle install
    yarn install --pure-lockfile
    EOF

    Arch Linux

    bash
    # Update system
    sudo pacman -Syu
    
    # Install required packages
    sudo pacman -S --needed \
        git curl wget gnupg \
        base-devel \
        postgresql redis \
        nodejs npm yarn \
        nginx \
        imagemagick ffmpeg \
        libxml2 libxslt \
        libidn \
        openssl \
        readline \
        zlib \
        libyaml \
        gdbm \
        ncurses \
        libffi
    
    # Initialize PostgreSQL
    sudo -u postgres initdb -D /var/lib/postgres/data
    sudo systemctl enable --now postgresql redis
    
    # Configure PostgreSQL
    sudo -u postgres createuser mastodon --createdb
    sudo -u postgres psql -c "ALTER USER mastodon WITH ENCRYPTED PASSWORD 'secure_random_password_here';"
    
    # Create mastodon user
    sudo useradd -m -s /bin/bash mastodon
    sudo usermod -a -G mastodon http
    
    # Install Ruby using rbenv
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon
    git clone https://github.com/rbenv/rbenv.git ~/.rbenv
    echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
    echo 'eval "$(rbenv init -)"' >> ~/.bashrc
    git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    rbenv install 3.2.2
    rbenv global 3.2.2
    gem install bundler
    EOF
    
    # Clone and setup Mastodon
    sudo -u mastodon git clone https://github.com/mastodon/mastodon.git /home/mastodon/live
    cd /home/mastodon/live
    sudo -u mastodon git checkout $(git tag -l | grep -v 'rc' | sort -V | tail -n 1)
    
    # Install dependencies
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    bundle config deployment 'true'
    bundle config without 'development test'
    bundle install
    yarn install --pure-lockfile
    EOF

    Alpine Linux

    bash
    # Update package index
    apk update
    
    # Install required packages
    apk add --no-cache \
        git curl wget gnupg \
        build-base \
        postgresql15 postgresql15-dev postgresql15-contrib \
        redis \
        nodejs npm yarn \
        nginx \
        imagemagick imagemagick-dev ffmpeg \
        libxml2-dev libxslt-dev \
        libidn-dev \
        openssl-dev \
        readline-dev \
        zlib-dev \
        yaml-dev \
        gdbm-dev \
        ncurses-dev \
        libffi-dev
    
    # Initialize and start services
    rc-service postgresql setup
    rc-service postgresql start
    rc-service redis start
    rc-update add postgresql
    rc-update add redis
    
    # Configure PostgreSQL
    sudo -u postgres createuser mastodon --createdb
    sudo -u postgres psql -c "ALTER USER mastodon WITH ENCRYPTED PASSWORD 'secure_random_password_here';"
    
    # Create mastodon user
    adduser -D -s /bin/ash mastodon
    addgroup mastodon nginx
    
    # Install Ruby using rbenv
    sudo -u mastodon ash << 'EOF'
    cd /home/mastodon
    git clone https://github.com/rbenv/rbenv.git ~/.rbenv
    echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.profile
    echo 'eval "$(rbenv init -)"' >> ~/.profile
    git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    rbenv install 3.2.2
    rbenv global 3.2.2
    gem install bundler
    EOF
    
    # Clone and setup Mastodon
    sudo -u mastodon git clone https://github.com/mastodon/mastodon.git /home/mastodon/live
    cd /home/mastodon/live
    sudo -u mastodon git checkout $(git tag -l | grep -v 'rc' | sort -V | tail -n 1)
    
    # Install dependencies
    sudo -u mastodon ash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    bundle config deployment 'true'
    bundle config without 'development test'
    bundle install
    yarn install --pure-lockfile
    EOF

    3. Configuration

    Production Environment Configuration

    #### Complete Production Configuration

    bash
    # Generate secrets first
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    
    # Generate secrets
    SECRET_KEY_BASE=$(bundle exec rake secret)
    OTP_SECRET=$(bundle exec rake secret)
    
    # Generate VAPID keys
    VAPID_KEYS=$(bundle exec rake mastodon:webpush:generate_vapid_key)
    VAPID_PRIVATE_KEY=$(echo "$VAPID_KEYS" | grep 'VAPID_PRIVATE_KEY=' | cut -d '=' -f2)
    VAPID_PUBLIC_KEY=$(echo "$VAPID_KEYS" | grep 'VAPID_PUBLIC_KEY=' | cut -d '=' -f2)
    
    # Save to temp file for reference
    cat > /tmp/mastodon_secrets.txt << SECRETS
    SECRET_KEY_BASE=$SECRET_KEY_BASE
    OTP_SECRET=$OTP_SECRET
    VAPID_PRIVATE_KEY=$VAPID_PRIVATE_KEY
    VAPID_PUBLIC_KEY=$VAPID_PUBLIC_KEY
    SECRETS
    
    echo "Secrets generated and saved to /tmp/mastodon_secrets.txt"
    EOF
    
    # Create comprehensive production configuration
    sudo -u mastodon tee /home/mastodon/live/.env.production << 'EOF'
    # Mastodon Production Configuration
    # Generated: $(date)
    
    # ==============================================================================
    # FEDERATION SETTINGS
    # ==============================================================================
    
    # Primary domain
    LOCAL_DOMAIN=mastodon.example.com
    
    # Web domain (if different from LOCAL_DOMAIN for CDN/proxy)
    WEB_DOMAIN=mastodon.example.com
    
    # Alternative domains (comma-separated)
    # ALTERNATE_DOMAINS=alt1.example.com,alt2.example.com
    
    # Use HTTPS (highly recommended)
    LOCAL_HTTPS=true
    
    # ==============================================================================
    # DATABASE CONFIGURATION
    # ==============================================================================
    
    # PostgreSQL
    DB_HOST=127.0.0.1
    DB_USER=mastodon
    DB_NAME=mastodon_production
    DB_PASS=Mast0d0n_DB_P@ss_2024!
    DB_PORT=5432
    
    # Database pool settings
    DB_POOL=25
    PREPARED_STATEMENTS=false
    
    # ==============================================================================
    # REDIS CONFIGURATION
    # ==============================================================================
    
    # Redis for cache
    REDIS_HOST=127.0.0.1
    REDIS_PORT=6379
    REDIS_NAMESPACE=mastodon
    
    # Separate Redis databases for different functions
    CACHE_REDIS_HOST=127.0.0.1
    CACHE_REDIS_PORT=6379
    CACHE_REDIS_DB=0
    CACHE_REDIS_NAMESPACE=mastodon:cache
    
    SIDEKIQ_REDIS_HOST=127.0.0.1
    SIDEKIQ_REDIS_PORT=6379
    SIDEKIQ_REDIS_DB=1
    SIDEKIQ_REDIS_NAMESPACE=mastodon:sidekiq
    
    # Redis password (if configured)
    # REDIS_PASSWORD=redis_password_here
    
    # ==============================================================================
    # ELASTICSEARCH (Full-text search)
    # ==============================================================================
    
    ES_ENABLED=true
    ES_HOST=localhost
    ES_PORT=9200
    ES_USER=elastic
    ES_PASS=Elast1c_P@ss_2024!
    ES_PREFIX=mastodon
    
    # ==============================================================================
    # SECRET KEYS (Replace with generated values)
    # ==============================================================================
    
    # Generate with: bundle exec rake secret
    SECRET_KEY_BASE=<INSERT_SECRET_KEY_BASE_HERE>
    OTP_SECRET=<INSERT_OTP_SECRET_HERE>
    
    # Generate with: bundle exec rake mastodon:webpush:generate_vapid_key
    VAPID_PRIVATE_KEY=<INSERT_VAPID_PRIVATE_KEY_HERE>
    VAPID_PUBLIC_KEY=<INSERT_VAPID_PUBLIC_KEY_HERE>
    
    # ==============================================================================
    # EMAIL CONFIGURATION
    # ==============================================================================
    
    SMTP_SERVER=smtp.mailgun.org
    SMTP_PORT=587
    SMTP_LOGIN=postmaster@mg.example.com
    SMTP_PASSWORD=SMTP_P@ssw0rd_2024!
    SMTP_FROM_ADDRESS=Mastodon <notifications@mastodon.example.com>
    SMTP_DOMAIN=mastodon.example.com
    SMTP_DELIVERY_METHOD=smtp
    SMTP_AUTH_METHOD=plain
    SMTP_CA_FILE=/etc/ssl/certs/ca-certificates.crt
    SMTP_OPENSSL_VERIFY_MODE=peer
    SMTP_ENABLE_STARTTLS=auto
    SMTP_TLS=false
    
    # ==============================================================================
    # FILE STORAGE
    # ==============================================================================
    
    # Local storage
    PAPERCLIP_ROOT_PATH=/home/mastodon/live/public/system
    PAPERCLIP_ROOT_URL=/system
    
    # S3-compatible storage (uncomment to enable)
    # S3_ENABLED=true
    # S3_BUCKET=mastodon-media
    # AWS_ACCESS_KEY_ID=your_access_key
    # AWS_SECRET_ACCESS_KEY=your_secret_key
    # S3_REGION=us-east-1
    # S3_PROTOCOL=https
    # S3_HOSTNAME=s3.amazonaws.com
    # S3_ENDPOINT=https://s3.amazonaws.com
    # S3_SIGNATURE_VERSION=v4
    # S3_MULTIPART_THRESHOLD=15728640
    
    # Cloudflare R2 (S3-compatible)
    # S3_ENABLED=true
    # S3_BUCKET=mastodon
    # AWS_ACCESS_KEY_ID=your_r2_access_key
    # AWS_SECRET_ACCESS_KEY=your_r2_secret_key
    # S3_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
    # S3_REGION=auto
    # S3_HOSTNAME=your-bucket.your-account-id.r2.cloudflarestorage.com
    # S3_PROTOCOL=https
    
    # ==============================================================================
    # CDN CONFIGURATION
    # ==============================================================================
    
    # CDN for assets
    # CDN_HOST=https://cdn.example.com
    
    # CDN for media files
    # S3_ALIAS_HOST=media.example.com
    
    # ==============================================================================
    # STREAMING API
    # ==============================================================================
    
    STREAMING_API_BASE_URL=wss://mastodon.example.com
    STREAMING_CLUSTER_NUM=1
    
    # Node.js streaming
    NODE_ENV=production
    PORT=4000
    BIND=127.0.0.1
    
    # ==============================================================================
    # SECURITY SETTINGS
    # ==============================================================================
    
    # Authorized fetch (require authentication for ActivityPub)
    AUTHORIZED_FETCH=false
    
    # Limited federation (allowlist mode)
    LIMITED_FEDERATION_MODE=false
    
    # IP retention period (days)
    IP_RETENTION_PERIOD=365
    
    # Session retention period (days)
    SESSION_RETENTION_PERIOD=365
    
    # Content retention (days, 0 = disabled)
    CONTENT_CACHE_RETENTION_PERIOD=7
    BACKUPS_RETENTION_PERIOD=7
    
    # Security headers
    FORCE_SSL=true
    SEND_HSTS_PRELOAD=true
    
    # CSRF protection
    CSRF_PROTECTION=true
    
    # ==============================================================================
    # FEATURE FLAGS
    # ==============================================================================
    
    # Registration
    SINGLE_USER_MODE=false
    REGISTRATIONS_MODE=open  # open, approved, closed
    REQUIRE_INVITE_TEXT=false
    
    # Captcha (hCaptcha)
    # HCAPTCHA_SITE_KEY=your_site_key
    # HCAPTCHA_SECRET_KEY=your_secret_key
    
    # Trends
    TRENDS=true
    TRENDS_AS_LANDING_PAGE=true
    
    # Translation
    DEEPL_API_KEY=
    DEEPL_PLAN=free  # free or pro
    
    # ==============================================================================
    # LIMITS AND QUOTAS
    # ==============================================================================
    
    # Character limits
    MAX_TOOT_CHARS=500
    MAX_DISPLAY_NAME_CHARS=30
    MAX_BIO_CHARS=500
    MAX_PROFILE_FIELDS=4
    
    # Poll limits
    MAX_POLL_OPTIONS=4
    MAX_POLL_OPTION_CHARS=100
    
    # Media limits
    MAX_IMAGE_SIZE=10485760      # 10MB
    MAX_VIDEO_SIZE=41943040       # 40MB
    MAX_EMOJI_SIZE=256000         # 250KB
    
    # API rate limits
    DEFAULT_THROTTLE_MULTIPLIER=1
    API_RATE_LIMIT_MULTIPLIER=1
    
    # ==============================================================================
    # ADMIN SETTINGS
    # ==============================================================================
    
    # Admin email for reports
    ADMIN_EMAIL=admin@example.com
    
    # Instance information
    INSTANCE_TITLE="Example Mastodon Instance"
    INSTANCE_SHORT_DESCRIPTION="A federated social network instance"
    INSTANCE_DESCRIPTION="Welcome to our Mastodon instance!"
    INSTANCE_EXTENDED_DESCRIPTION="This is a longer description of the instance."
    INSTANCE_CONTACT_EMAIL=contact@example.com
    INSTANCE_CONTACT_USERNAME=admin
    
    # Terms and Privacy Policy URLs
    # TERMS_URL=https://example.com/terms
    # PRIVACY_POLICY_URL=https://example.com/privacy
    
    # ==============================================================================
    # MONITORING AND LOGGING
    # ==============================================================================
    
    # Log level
    LOG_LEVEL=info
    
    # Lograge for structured logging
    ENABLE_LOGRAGE=true
    
    # StatsD metrics
    # STATSD_ADDR=localhost:8125
    # STATSD_NAMESPACE=mastodon
    
    # OpenTelemetry
    # OPENTELEMETRY_ENABLED=true
    # OPENTELEMETRY_ENDPOINT=http://localhost:4318
    
    # Sentry error tracking
    # SENTRY_DSN=https://your-key@sentry.io/project-id
    # SENTRY_ENVIRONMENT=production
    
    # ==============================================================================
    # DEVELOPMENT/DEBUG (Disable in production)
    # ==============================================================================
    
    RAILS_ENV=production
    RAILS_SERVE_STATIC_FILES=false
    RAILS_LOG_TO_STDOUT=false
    TRUSTED_PROXY_IP=127.0.0.1
    
    # ==============================================================================
    # SCHEDULED MAINTENANCE
    # ==============================================================================
    
    # Maintenance mode message
    # MAINTENANCE_MODE=true
    # MAINTENANCE_MESSAGE="We are currently performing maintenance."
    
    # ==============================================================================
    # LDAP AUTHENTICATION (Optional)
    # ==============================================================================
    
    # LDAP_ENABLED=true
    # LDAP_HOST=ldap.example.com
    # LDAP_PORT=636
    # LDAP_METHOD=simple_tls
    # LDAP_BASE=dc=example,dc=com
    # LDAP_BIND_DN=cn=admin,dc=example,dc=com
    # LDAP_PASSWORD=ldap_password
    # LDAP_UID=uid
    # LDAP_SEARCH_FILTER=(|(uid=%u)(mail=%u))
    
    # ==============================================================================
    # SAML AUTHENTICATION (Optional)
    # ==============================================================================
    
    # SAML_ENABLED=true
    # SAML_ACS_URL=https://mastodon.example.com/auth/saml/callback
    # SAML_ISSUER=mastodon
    # SAML_IDP_SSO_TARGET_URL=https://idp.example.com/sso
    # SAML_IDP_CERT=base64_encoded_cert
    # SAML_IDP_CERT_FINGERPRINT=fingerprint
    
    # ==============================================================================
    # OIDC AUTHENTICATION (Optional)
    # ==============================================================================
    
    # OIDC_ENABLED=true
    # OIDC_DISPLAY_NAME=SSO
    # OIDC_ISSUER=https://auth.example.com
    # OIDC_DISCOVERY=true
    # OIDC_CLIENT_ID=mastodon
    # OIDC_CLIENT_SECRET=client_secret
    # OIDC_REDIRECT_URI=https://mastodon.example.com/auth/openid_connect/callback
    # OIDC_SCOPES=openid profile email
    
    # ==============================================================================
    # CAS AUTHENTICATION (Optional)
    # ==============================================================================
    
    # CAS_ENABLED=true
    # CAS_URL=https://cas.example.com
    # CAS_HOST=cas.example.com
    # CAS_PORT=443
    # CAS_SSL=true
    # CAS_VALIDATE_URL=https://cas.example.com/validate
    # CAS_CALLBACK_URL=https://mastodon.example.com/auth/cas/callback
    EOF
    
    # Set proper permissions
    sudo chmod 600 /home/mastodon/live/.env.production
    sudo chown mastodon:mastodon /home/mastodon/live/.env.production

    #### Database Setup with Optimization

    bash
    # Create and configure PostgreSQL database
    sudo -u postgres psql << 'EOF'
    -- Create user and database
    CREATE USER mastodon WITH PASSWORD 'Mast0d0n_DB_P@ss_2024!' CREATEDB;
    CREATE DATABASE mastodon_production OWNER mastodon;
    
    -- Grant privileges
    GRANT ALL PRIVILEGES ON DATABASE mastodon_production TO mastodon;
    
    -- Connect to the database
    \c mastodon_production
    
    -- Enable required extensions
    CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
    CREATE EXTENSION IF NOT EXISTS pg_trgm;
    CREATE EXTENSION IF NOT EXISTS btree_gin;
    CREATE EXTENSION IF NOT EXISTS btree_gist;
    
    -- Set optimal parameters for Mastodon
    ALTER DATABASE mastodon_production SET shared_preload_libraries = 'pg_stat_statements';
    ALTER DATABASE mastodon_production SET pg_stat_statements.track = 'all';
    ALTER DATABASE mastodon_production SET random_page_cost = 1.1;
    ALTER DATABASE mastodon_production SET effective_cache_size = '4GB';
    ALTER DATABASE mastodon_production SET shared_buffers = '1GB';
    ALTER DATABASE mastodon_production SET work_mem = '16MB';
    ALTER DATABASE mastodon_production SET maintenance_work_mem = '256MB';
    ALTER DATABASE mastodon_production SET max_connections = 200;
    EOF
    
    # Initialize database schema
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    
    # Run database setup
    RAILS_ENV=production bundle exec rails db:setup
    
    # Run migrations
    RAILS_ENV=production bundle exec rails db:migrate
    
    # Precompile assets
    RAILS_ENV=production bundle exec rails assets:precompile
    
    # Create admin user
    RAILS_ENV=production bundle exec tootctl accounts create admin --email admin@example.com --confirmed --role Admin
    EOF

    #### Redis Configuration

    bash
    # Configure Redis for Mastodon
    sudo tee /etc/redis/redis.conf << 'EOF'
    # Redis Production Configuration for Mastodon
    
    # Network
    bind 127.0.0.1 ::1
    protected-mode yes
    port 6379
    tcp-backlog 511
    tcp-keepalive 300
    timeout 0
    
    # General
    daemonize yes
    supervised systemd
    pidfile /var/run/redis/redis-server.pid
    loglevel notice
    logfile /var/log/redis/redis-server.log
    syslog-enabled yes
    databases 16
    
    # Snapshotting
    save 900 1
    save 300 10
    save 60 10000
    stop-writes-on-bgsave-error yes
    rdbcompression yes
    rdbchecksum yes
    dbfilename dump.rdb
    dir /var/lib/redis
    
    # Replication
    replica-read-only yes
    repl-diskless-sync no
    repl-diskless-sync-delay 5
    
    # Security
    requirepass Redis_P@ss_2024!
    masterauth Redis_P@ss_2024!
    
    # Limits
    maxclients 10000
    maxmemory 2gb
    maxmemory-policy allkeys-lru
    
    # Append only mode
    appendonly yes
    appendfilename "appendonly.aof"
    appendfsync everysec
    no-appendfsync-on-rewrite no
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    
    # Lua scripting
    lua-time-limit 5000
    
    # Cluster
    cluster-enabled no
    
    # Slow log
    slowlog-log-slower-than 10000
    slowlog-max-len 128
    
    # Latency monitor
    latency-monitor-threshold 0
    
    # Advanced config
    hash-max-ziplist-entries 512
    hash-max-ziplist-value 64
    list-max-ziplist-size -2
    list-compress-depth 0
    set-max-intset-entries 512
    zset-max-ziplist-entries 128
    zset-max-ziplist-value 64
    hll-sparse-max-bytes 3000
    stream-node-max-bytes 4096
    stream-node-max-entries 100
    activerehashing yes
    client-output-buffer-limit normal 0 0 0
    client-output-buffer-limit replica 256mb 64mb 60
    client-output-buffer-limit pubsub 32mb 8mb 60
    hz 10
    dynamic-hz yes
    aof-rewrite-incremental-fsync yes
    rdb-save-incremental-fsync yes
    EOF
    
    sudo systemctl restart redis

    #### Nginx Configuration

    bash
    # Create comprehensive Nginx configuration
    sudo tee /etc/nginx/sites-available/mastodon << 'EOF'
    upstream backend {
        server 127.0.0.1:3000 fail_timeout=0;
    }
    
    upstream streaming {
        server 127.0.0.1:4000 fail_timeout=0;
    }
    
    proxy_cache_path /var/cache/nginx/mastodon levels=1:2 keys_zone=CACHE:10m max_size=1g inactive=7d use_temp_path=off;
    
    server {
        listen 80;
        listen [::]:80;
        server_name mastodon.example.com;
        root /home/mastodon/live/public;
        location /.well-known/acme-challenge/ { allow all; }
        location / { return 301 https://$host$request_uri; }
    }
    
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name mastodon.example.com;
    
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers off;
    
        ssl_certificate /etc/letsencrypt/live/mastodon.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/mastodon.example.com/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/mastodon.example.com/chain.pem;
    
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;
    
        ssl_stapling on;
        ssl_stapling_verify on;
        resolver 8.8.8.8 8.8.4.4 valid=300s;
        resolver_timeout 5s;
    
        # Security headers
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;
        add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss://mastodon.example.com; media-src 'self' https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always;
    
        keepalive_timeout 70;
        sendfile on;
        client_max_body_size 80m;
    
        root /home/mastodon/live/public;
    
        gzip on;
        gzip_disable "msie6";
        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/x-icon;
    
        location / {
            try_files $uri @proxy;
        }
    
        location ~ ^/(system|avatars|headers|emoji|packs|media_attachments) {
            add_header Cache-Control "public, max-age=31536000, immutable";
            add_header X-Content-Type-Options nosniff;
            try_files $uri =404;
        }
    
        location /sw.js {
            add_header Cache-Control "public, max-age=0";
            try_files $uri =404;
        }
    
        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 $scheme;
            proxy_set_header Proxy "";
            proxy_pass_header Server;
    
            proxy_pass http://backend;
            proxy_buffering on;
            proxy_cache CACHE;
            proxy_cache_valid 200 7d;
            proxy_cache_valid 410 24h;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
            add_header X-Cached $upstream_cache_status;
            tcp_nodelay on;
        }
    
        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 $scheme;
            proxy_set_header Proxy "";
    
            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;
        }
    
        error_page 500 501 502 503 504 /500.html;
    }
    EOF
    
    sudo ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/
    sudo nginx -t && sudo systemctl reload nginx

    4. Service Management

    Systemd Service Files (RHEL/Debian/Arch/SUSE)

    Create the web service (/etc/systemd/system/mastodon-web.service):

    ini
    [Unit]
    Description=mastodon-web
    After=network.target
    
    [Service]
    Type=simple
    User=mastodon
    WorkingDirectory=/home/mastodon/live
    Environment="RAILS_ENV=production"
    Environment="PORT=3000"
    ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
    ExecReload=/bin/kill -SIGUSR1 $MAINPID
    TimeoutSec=15
    Restart=always
    RestartSec=10
    SyslogIdentifier=mastodon-web
    
    [Install]
    WantedBy=multi-user.target

    Create the background jobs service (/etc/systemd/system/mastodon-sidekiq.service):

    ini
    [Unit]
    Description=mastodon-sidekiq
    After=network.target
    
    [Service]
    Type=simple
    User=mastodon
    WorkingDirectory=/home/mastodon/live
    Environment="RAILS_ENV=production"
    Environment="DB_POOL=25"
    ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25
    TimeoutSec=15
    Restart=always
    RestartSec=10
    SyslogIdentifier=mastodon-sidekiq
    
    [Install]
    WantedBy=multi-user.target

    Create the streaming service (/etc/systemd/system/mastodon-streaming.service):

    ini
    [Unit]
    Description=mastodon-streaming
    After=network.target
    
    [Service]
    Type=simple
    User=mastodon
    WorkingDirectory=/home/mastodon/live
    Environment="NODE_ENV=production"
    Environment="PORT=4000"
    ExecStart=/usr/bin/node streaming
    TimeoutSec=15
    Restart=always
    RestartSec=10
    SyslogIdentifier=mastodon-streaming
    
    [Install]
    WantedBy=multi-user.target

    Enable and Start Services

    bash
    # Reload systemd and enable services
    sudo systemctl daemon-reload
    sudo systemctl enable mastodon-web mastodon-sidekiq mastodon-streaming
    sudo systemctl start mastodon-web mastodon-sidekiq mastodon-streaming
    
    # Check status
    sudo systemctl status mastodon-web mastodon-sidekiq mastodon-streaming

    OpenRC Services (Alpine Linux)

    Create /etc/init.d/mastodon-web:

    bash
    #!/sbin/openrc-run
    
    name="mastodon-web"
    description="Mastodon web service"
    
    user="mastodon"
    group="mastodon"
    directory="/home/mastodon/live"
    
    command="/home/mastodon/.rbenv/shims/bundle"
    command_args="exec puma -C config/puma.rb"
    command_background="yes"
    
    pidfile="/run/${name}.pid"
    output_log="/var/log/${name}.log"
    error_log="/var/log/${name}.error.log"
    
    depend() {
        need net postgresql redis
    }
    
    start_pre() {
        export RAILS_ENV=production
        export PORT=3000
    }

    Create similar files for mastodon-sidekiq and mastodon-streaming, then:

    bash
    # Make executable
    sudo chmod +x /etc/init.d/mastodon-*
    
    # Enable and start
    sudo rc-update add mastodon-web
    sudo rc-update add mastodon-sidekiq
    sudo rc-update add mastodon-streaming
    sudo rc-service mastodon-web start
    sudo rc-service mastodon-sidekiq start
    sudo rc-service mastodon-streaming start

    5. Troubleshooting

    Common Issues

    Ruby/Bundle Issues:

    bash
    # Ensure proper rbenv setup
    sudo -u mastodon bash << 'EOF'
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    which ruby
    ruby --version
    EOF
    
    # Reinstall gems if needed
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    bundle install --deployment --without development test
    EOF

    Database Connection Issues:

    bash
    # Test PostgreSQL connection
    sudo -u mastodon psql -h localhost -U mastodon mastodon_production
    
    # Check PostgreSQL logs
    sudo journalctl -u postgresql-15 -f
    
    # Verify database configuration
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    RAILS_ENV=production bundle exec rails console
    # In console: ActiveRecord::Base.connection
    EOF

    Asset Compilation Issues:

    bash
    # Clear and recompile assets
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    RAILS_ENV=production bundle exec rails assets:clobber
    RAILS_ENV=production bundle exec rails assets:precompile
    EOF

    Service Startup Issues:

    bash
    # Check service logs
    sudo journalctl -u mastodon-web -f
    sudo journalctl -u mastodon-sidekiq -f
    sudo journalctl -u mastodon-streaming -f
    
    # Check for port conflicts
    sudo netstat -tlnp | grep :3000
    sudo netstat -tlnp | grep :4000
    
    # Verify file permissions
    sudo ls -la /home/mastodon/live/
    sudo -u mastodon test -r /home/mastodon/live/.env.production && echo "Can read env file"

    Federation Issues

    bash
    # Check federation status
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    RAILS_ENV=production bundle exec rails console
    # In console: Account.find_remote('username', 'instance.domain')
    EOF
    
    # Test ActivityPub endpoint
    curl -H "Accept: application/activity+json" https://your-domain.com/users/username
    
    # Check delivery worker
    sudo journalctl -u mastodon-sidekiq | grep DeliveryWorker

    Performance Issues

    bash
    # Monitor resource usage
    htop
    iostat -x 1
    free -h
    
    # Check database performance
    sudo -u postgres psql mastodon_production -c "SELECT * FROM pg_stat_activity;"
    
    # Redis monitoring
    redis-cli monitor
    redis-cli info memory

    6. Security Considerations

    Firewall Configuration

    firewalld (RHEL/CentOS/Fedora):

    bash
    # Open required ports
    sudo firewall-cmd --permanent --add-service=http
    sudo firewall-cmd --permanent --add-service=https
    sudo firewall-cmd --permanent --add-port=3000/tcp
    sudo firewall-cmd --permanent --add-port=4000/tcp
    sudo firewall-cmd --reload

    ufw (Ubuntu/Debian):

    bash
    # Configure firewall
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw allow 3000/tcp
    sudo ufw allow 4000/tcp
    sudo ufw enable

    iptables (Generic):

    bash
    # Basic firewall rules
    sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
    sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
    sudo iptables -A INPUT -p tcp --dport 3000 -j ACCEPT
    sudo iptables -A INPUT -p tcp --dport 4000 -j ACCEPT

    SSL/TLS Configuration with nginx

    Create /etc/nginx/sites-available/mastodon (Debian/Ubuntu) or /etc/nginx/conf.d/mastodon.conf (RHEL):

    nginx
    map $http_upgrade $connection_upgrade {
      default upgrade;
      ''      close;
    }
    
    upstream backend {
        server 127.0.0.1:3000 fail_timeout=0;
    }
    
    upstream streaming {
        server 127.0.0.1:4000 fail_timeout=0;
    }
    
    proxy_cache_path /var/cache/nginx/mastodon keys_zone=CACHE:10m levels=1:2 inactive=7d max_size=1g;
    
    server {
        listen 80;
        listen [::]:80;
        server_name mastodon.example.com;
        root /home/mastodon/live/public;
        location /.well-known/acme-challenge/ { allow all; }
        location / { return 301 https://$host$request_uri; }
    }
    
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
        server_name mastodon.example.com;
    
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers off;
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;
    
        ssl_certificate     /etc/letsencrypt/live/mastodon.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/mastodon.example.com/privkey.pem;
    
        keepalive_timeout    70;
        sendfile             on;
        client_max_body_size 80m;
    
        root /home/mastodon/live/public;
    
        gzip on;
        gzip_disable "msie6";
        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_types
            text/plain
            text/css
            text/xml
            text/javascript
            application/json
            application/javascript
            application/xml+rss
            application/atom+xml
            image/svg+xml;
    
        add_header Strict-Transport-Security "max-age=31536000" always;
    
        location / {
            try_files $uri @proxy;
        }
    
        location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {
            add_header Cache-Control "public, max-age=31536000, immutable";
            add_header Strict-Transport-Security "max-age=31536000" always;
            try_files $uri @proxy;
        }
    
        location /sw.js {
            add_header Cache-Control "public, max-age=604800, must-revalidate";
            add_header Strict-Transport-Security "max-age=31536000" always;
            try_files $uri @proxy;
        }
    
        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 $scheme;
            proxy_set_header Proxy "";
            proxy_pass_header Server;
    
            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;
    
            proxy_cache CACHE;
            proxy_cache_valid 200 7d;
            proxy_cache_valid 410 24h;
            proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
            proxy_cache_lock on;
    
            tcp_nodelay on;
        }
    
        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 $scheme;
            proxy_set_header Proxy "";
    
            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;
        }
    
        error_page 500 501 502 503 504 /500.html;
    }

    SSL Certificate Setup

    bash
    # Install Certbot
    # RHEL/CentOS/Fedora
    sudo dnf install -y certbot python3-certbot-nginx
    
    # Debian/Ubuntu
    sudo apt install -y certbot python3-certbot-nginx
    
    # Arch Linux
    sudo pacman -S certbot certbot-nginx
    
    # Obtain certificate
    sudo certbot --nginx -d mastodon.example.com
    
    # Auto-renewal
    echo "0 12 * * * /usr/bin/certbot renew --quiet" | sudo crontab -

    SELinux Configuration (RHEL-based systems)

    bash
    # Allow nginx to connect to Mastodon services
    sudo setsebool -P httpd_can_network_connect 1
    
    # Set SELinux contexts for Mastodon files
    sudo semanage fcontext -a -t httpd_exec_t "/home/mastodon/live/public(/.*)?"
    sudo restorecon -R /home/mastodon/live/public/
    
    # Allow Mastodon to bind to required ports
    sudo semanage port -a -t http_port_t -p tcp 3000
    sudo semanage port -a -t http_port_t -p tcp 4000

    Security Hardening

    bash
    # Disable password authentication for mastodon user
    sudo passwd -l mastodon
    
    # Set proper file permissions
    sudo chmod 750 /home/mastodon
    sudo chmod 755 /home/mastodon/live
    sudo chmod 600 /home/mastodon/live/.env.production
    
    # Configure fail2ban for nginx
    sudo tee /etc/fail2ban/jail.d/nginx.conf << 'EOF'
    [nginx-http-auth]
    enabled = true
    port = http,https
    logpath = /var/log/nginx/error.log
    
    [nginx-limit-req]
    enabled = true
    port = http,https
    logpath = /var/log/nginx/error.log
    EOF
    
    sudo systemctl restart fail2ban

    7. Performance Tuning

    PostgreSQL Optimization

    Edit /var/lib/pgsql/15/data/postgresql.conf:

    ini
    # Memory settings (adjust based on available RAM)
    shared_buffers = 256MB                 # 1/4 of RAM
    effective_cache_size = 1GB            # 3/4 of RAM
    work_mem = 4MB                        # RAM/max_connections/4
    maintenance_work_mem = 64MB           # RAM/16
    
    # Connection settings
    max_connections = 100
    superuser_reserved_connections = 3
    
    # WAL settings for better performance
    wal_buffers = 16MB
    checkpoint_completion_target = 0.7
    checkpoint_timeout = 5min
    max_wal_size = 1GB
    min_wal_size = 80MB
    
    # Query optimization
    random_page_cost = 1.1                # For SSD storage
    effective_io_concurrency = 200        # For SSD storage

    Redis Optimization

    Edit /etc/redis/redis.conf or /etc/redis.conf:

    ini
    # Memory optimization
    maxmemory 256mb
    maxmemory-policy allkeys-lru
    
    # Persistence (adjust based on needs)
    save 900 1
    save 300 10
    save 60 10000
    
    # Network optimization
    tcp-keepalive 300
    timeout 0

    Ruby/Rails Optimization

    Edit /home/mastodon/live/.env.production:

    bash
    # Database connection pooling
    DB_POOL=25
    
    # Sidekiq concurrency
    SIDEKIQ_CONCURRENCY=25
    
    # Puma workers (number of CPU cores)
    WEB_CONCURRENCY=4
    MAX_THREADS=5
    
    # Streaming cluster
    STREAMING_CLUSTER_NUM=4

    System-level Optimization

    bash
    # Increase file descriptors limit
    echo "mastodon soft nofile 65536" | sudo tee -a /etc/security/limits.conf
    echo "mastodon hard nofile 65536" | sudo tee -a /etc/security/limits.conf
    
    # Optimize kernel parameters
    sudo tee -a /etc/sysctl.conf << 'EOF'
    # Network optimization
    net.core.somaxconn = 1024
    net.core.netdev_max_backlog = 5000
    net.ipv4.tcp_max_syn_backlog = 1024
    net.ipv4.tcp_keepalive_time = 120
    net.ipv4.tcp_keepalive_intvl = 30
    net.ipv4.tcp_keepalive_probes = 3
    
    # Memory optimization
    vm.swappiness = 10
    vm.dirty_ratio = 15
    vm.dirty_background_ratio = 5
    EOF
    
    sudo sysctl -p

    Elasticsearch Integration (Optional)

    bash
    # Install Elasticsearch (RHEL/CentOS)
    sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
    sudo tee /etc/yum.repos.d/elasticsearch.repo << 'EOF'
    [elasticsearch]
    name=Elasticsearch repository for 8.x packages
    baseurl=https://artifacts.elastic.co/packages/8.x/yum
    gpgcheck=1
    gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
    enabled=1
    autorefresh=1
    type=rpm-md
    EOF
    
    sudo dnf install -y elasticsearch
    sudo systemctl enable --now elasticsearch
    
    # Configure for Mastodon
    sudo tee -a /home/mastodon/live/.env.production << 'EOF'
    ES_ENABLED=true
    ES_HOST=localhost
    ES_PORT=9200
    EOF
    
    # Create search index
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    RAILS_ENV=production bundle exec rake chewy:upgrade
    EOF

    8. Backup and Restore

    Database Backup

    bash
    # Create backup script
    sudo tee /usr/local/bin/mastodon-backup.sh << 'EOF'
    #!/bin/bash
    
    BACKUP_DIR="/backup/mastodon"
    DATE=$(date +%Y%m%d_%H%M%S)
    DB_NAME="mastodon_production"
    MEDIA_DIR="/home/mastodon/live/public/system"
    
    # Create backup directory
    mkdir -p "$BACKUP_DIR"
    
    # Database backup
    sudo -u postgres pg_dump "$DB_NAME" | gzip > "$BACKUP_DIR/db_${DATE}.sql.gz"
    
    # Media backup (if stored locally)
    if [ -d "$MEDIA_DIR" ]; then
        tar -czf "$BACKUP_DIR/media_${DATE}.tar.gz" -C "$(dirname "$MEDIA_DIR")" "$(basename "$MEDIA_DIR")"
    fi
    
    # Configuration backup
    tar -czf "$BACKUP_DIR/config_${DATE}.tar.gz" /home/mastodon/live/.env.production
    
    # Remove backups older than 30 days
    find "$BACKUP_DIR" -name "*.gz" -mtime +30 -delete
    
    echo "Backup completed: $DATE"
    EOF
    
    sudo chmod +x /usr/local/bin/mastodon-backup.sh

    Automated Backups

    bash
    # Add to crontab
    echo "0 2 * * * /usr/local/bin/mastodon-backup.sh" | sudo crontab -
    
    # Verify crontab
    sudo crontab -l

    S3 Backup Integration

    bash
    # Install AWS CLI
    sudo dnf install -y awscli  # RHEL/CentOS
    sudo apt install -y awscli  # Debian/Ubuntu
    
    # Configure AWS credentials
    aws configure
    
    # Enhanced backup script with S3
    sudo tee /usr/local/bin/mastodon-s3-backup.sh << 'EOF'
    #!/bin/bash
    
    BACKUP_DIR="/tmp/mastodon-backup"
    DATE=$(date +%Y%m%d_%H%M%S)
    S3_BUCKET="your-backup-bucket"
    DB_NAME="mastodon_production"
    
    mkdir -p "$BACKUP_DIR"
    
    # Database backup
    sudo -u postgres pg_dump "$DB_NAME" | gzip > "$BACKUP_DIR/db_${DATE}.sql.gz"
    
    # Upload to S3
    aws s3 cp "$BACKUP_DIR/db_${DATE}.sql.gz" "s3://$S3_BUCKET/mastodon/db/"
    
    # Clean up local backup
    rm -f "$BACKUP_DIR/db_${DATE}.sql.gz"
    
    echo "S3 backup completed: $DATE"
    EOF
    
    sudo chmod +x /usr/local/bin/mastodon-s3-backup.sh

    Restore Procedure

    bash
    # Stop Mastodon services
    sudo systemctl stop mastodon-web mastodon-sidekiq mastodon-streaming
    
    # Restore database
    sudo -u postgres dropdb mastodon_production
    sudo -u postgres createdb mastodon_production
    sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE mastodon_production TO mastodon;"
    gunzip -c /backup/mastodon/db_YYYYMMDD_HHMMSS.sql.gz | sudo -u postgres psql mastodon_production
    
    # Restore media files (if needed)
    sudo rm -rf /home/mastodon/live/public/system
    sudo tar -xzf /backup/mastodon/media_YYYYMMDD_HHMMSS.tar.gz -C /home/mastodon/live/public/
    sudo chown -R mastodon:mastodon /home/mastodon/live/public/system
    
    # Restore configuration
    sudo tar -xzf /backup/mastodon/config_YYYYMMDD_HHMMSS.tar.gz -C /
    
    # Start services
    sudo systemctl start mastodon-web mastodon-sidekiq mastodon-streaming

    Database Migration and Upgrades

    bash
    # Before upgrading Mastodon
    sudo systemctl stop mastodon-web mastodon-sidekiq mastodon-streaming
    
    # Backup current version
    sudo -u postgres pg_dump mastodon_production | gzip > /backup/pre-upgrade-$(date +%Y%m%d).sql.gz
    
    # Update Mastodon code
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    git fetch
    git checkout $(git tag -l | grep -v 'rc' | sort -V | tail -n 1)
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    bundle install --deployment --without development test
    yarn install --pure-lockfile
    RAILS_ENV=production bundle exec rails db:migrate
    RAILS_ENV=production bundle exec rails assets:precompile
    EOF
    
    # Start services
    sudo systemctl start mastodon-web mastodon-sidekiq mastodon-streaming

    9. System Requirements

    Minimum Requirements

  • CPU: 2 cores, 2.0 GHz
  • RAM: 4GB
  • Storage: 20GB SSD
  • Network: 100 Mbps
  • OS: Linux (64-bit)
  • CPU: 4+ cores, 2.5+ GHz
  • RAM: 8GB+ (16GB for large instances)
  • Storage: 100GB+ SSD with good IOPS
  • Network: 1 Gbps with low latency
  • OS: Recent Linux distribution with long-term support
  • Scaling Considerations

  • Small Instance: <1,000 users - 2 cores, 4GB RAM, 50GB storage
  • Medium Instance: 1,000-10,000 users - 4 cores, 8GB RAM, 200GB storage
  • Large Instance: 10,000+ users - 8+ cores, 16GB+ RAM, 500GB+ storage
  • Storage Requirements

  • Database: 1-10GB for small instances, scales with user activity
  • Media Storage: Highly variable, 10GB-1TB+ depending on media uploads
  • Logs: 1-5GB for standard retention periods
  • Elasticsearch: 2-3x database size if enabled
  • Network Requirements

  • Bandwidth: 1Mbps per 100 concurrent users (minimum)
  • Latency: <100ms for good federation performance
  • IPv6: Recommended for better federation connectivity
  • Domain: Must have valid SSL certificate
  • 10. Support

    Official Resources

  • Official Website: https://joinmastodon.org
  • Documentation: https://docs.joinmastodon.org
  • GitHub Repository: https://github.com/mastodon/mastodon
  • Admin Documentation: https://docs.joinmastodon.org/admin/
  • Community Support

  • Mastodon Discord: https://discord.gg/mastodon
  • GitHub Issues: https://github.com/mastodon/mastodon/issues
  • Mastodon Community: Follow @Mastodon@mastodon.social
  • Admin Forums: Various Mastodon admin communities on the fediverse
  • Commercial Support

  • Available from various consulting companies
  • Managed hosting providers offer Mastodon services
  • Professional services for large deployments
  • Troubleshooting Resources

  • Server Status: Check instance health and federation status
  • Log Analysis: Use journalctl and application logs for debugging
  • Performance Monitoring: Implement monitoring for proactive support
  • Security Updates: Subscribe to security announcements
  • 11. Contributing

    How to Contribute

    1. Report Bugs: Submit issues to GitHub

    2. Translate: Help with internationalization at Crowdin

    3. Code Contributions: Submit pull requests for bug fixes and features

    4. Documentation: Improve documentation and guides

    5. Testing: Test release candidates and provide feedback

    Development Setup

    bash
    # Clone repository
    git clone https://github.com/mastodon/mastodon.git
    cd mastodon
    
    # Install dependencies
    bundle install
    yarn install
    
    # Setup development database
    rails db:setup
    
    # Run development server
    foreman start

    Contribution Guidelines

  • Follow Ruby and JavaScript style guides
  • Include tests for new features
  • Update documentation for changes
  • Use conventional commit messages
  • Sign commits with GPG key
  • Code of Conduct

  • Be respectful and inclusive
  • Follow the project's code of conduct
  • Report harassment or inappropriate behavior
  • Maintain professional communication
  • Pull Request Process

    1. Fork the repository

    2. Create a feature branch

    3. Make your changes with tests

    4. Update documentation

    5. Submit pull request with clear description

    12. License

    Mastodon is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).

    Key License Points

  • Free to Use: Can be used for any purpose
  • Source Available: Source code must be provided to users
  • Copyleft: Derivative works must use same license
  • Network Use: AGPL applies to network/web services
  • No Warranty: Software provided "as is"
  • License Compliance

  • Keep license notices intact
  • Provide source code to users
  • Document any modifications
  • Use same license for derivatives
  • Consider legal requirements for your jurisdiction
  • Commercial Use

  • Commercial use is permitted under AGPL-3.0
  • Must provide source code to users
  • Cannot be relicensed as proprietary
  • Consider consulting legal counsel for commercial deployments
  • Full license text: https://github.com/mastodon/mastodon/blob/main/LICENSE

    13. Acknowledgments

    Core Team

  • Eugen Rochko - Creator and lead developer
  • Claire - Core maintainer
  • Renaud Chaput - Core maintainer
  • ThibG - Significant contributor
  • And many other contributors
  • Technologies Used

  • Ruby on Rails - Web application framework
  • PostgreSQL - Primary database
  • Redis - Caching and job queue
  • React.js - Frontend user interface
  • ActivityPub - Federation protocol
  • Sidekiq - Background job processing
  • Community

  • Translators - Making Mastodon available in many languages
  • Instance Administrators - Running the fediverse
  • Users - Creating the vibrant community
  • Contributors - Improving the software
  • Special Thanks

  • W3C - For the ActivityPub standard
  • FOSS Community - For the foundational technologies
  • Security Researchers - For responsible disclosure
  • Hosting Providers - Supporting the decentralized network
  • 14. Version History

    Major Releases

  • v4.2 (September 2023) - Enhanced moderation tools, quote posts
  • v4.1 (February 2023) - Improved federation, performance optimizations
  • v4.0 (October 2022) - Major UI overhaul, new features
  • v3.5 (May 2022) - Content warnings improvements, admin features
  • v3.4 (October 2021) - Server rules, report improvements
  • v3.3 (February 2021) - Profile directory, admin announcements
  • v3.2 (July 2020) - Audio uploads, admin interface improvements
  • v3.1 (February 2020) - Polls, improved federation
  • v3.0 (October 2019) - Single column mode, admin dashboard
  • Current Stable Version

  • v4.2.x - Latest stable release
  • Check GitHub releases for current version
  • Upgrade Path

  • Always backup before upgrading
  • Follow official upgrade guides
  • Test in staging environment first
  • Monitor for federation issues after upgrade
  • Release Cycle

  • Major releases every 6-12 months
  • Minor releases for features and improvements
  • Patch releases for security and critical fixes
  • LTS releases for enterprise deployments
  • Breaking Changes

  • Review changelog for breaking changes
  • Update configuration as needed
  • Test federation compatibility
  • Update dependent services
  • 15. Appendices

    Appendix A: Port Reference

    | Port | Service | Protocol | Description |

    |------|---------|----------|-------------|

    | 80 | HTTP | TCP | Web traffic (redirects to HTTPS) |

    | 443 | HTTPS | TCP | Secure web traffic |

    | 3000 | Mastodon Web | TCP | Internal web service |

    | 4000 | Mastodon Streaming | TCP | Real-time updates |

    | 5432 | PostgreSQL | TCP | Database (internal) |

    | 6379 | Redis | TCP | Cache and queues (internal) |

    | 25/587 | SMTP | TCP | Email delivery (outbound) |

    Appendix B: File Locations

    | Path | Description |

    |------|-------------|

    | /home/mastodon/live/ | Mastodon application directory |

    | /home/mastodon/live/.env.production | Main configuration file |

    | /home/mastodon/live/public/system/ | Media files storage |

    | /etc/systemd/system/mastodon-*.service | Service definitions |

    | /etc/nginx/sites-available/mastodon | nginx configuration |

    | /var/lib/postgresql/*/data/ | PostgreSQL data directory |

    | /etc/redis/redis.conf | Redis configuration |

    | /var/log/nginx/ | nginx logs |

    Appendix C: Common Commands

    bash
    # Service management
    sudo systemctl status mastodon-web mastodon-sidekiq mastodon-streaming
    sudo systemctl restart mastodon-web mastodon-sidekiq mastodon-streaming
    
    # Mastodon maintenance
    sudo -u mastodon bash -c 'cd /home/mastodon/live && RAILS_ENV=production bundle exec rails mastodon:maintenance'
    
    # Database management
    sudo -u postgres psql mastodon_production
    
    # Log monitoring
    sudo journalctl -u mastodon-web -f
    sudo tail -f /var/log/nginx/access.log

    Appendix D: Environment Variables Reference

    | Variable | Description | Required |

    |----------|-------------|----------|

    | LOCAL_DOMAIN | Your Mastodon domain | Yes |

    | SECRET_KEY_BASE | Rails secret key | Yes |

    | OTP_SECRET | Two-factor authentication secret | Yes |

    | VAPID_PRIVATE_KEY | Push notification private key | Yes |

    | VAPID_PUBLIC_KEY | Push notification public key | Yes |

    | DB_HOST | Database hostname | Yes |

    | DB_USER | Database username | Yes |

    | DB_PASS | Database password | Yes |

    | DB_NAME | Database name | Yes |

    | REDIS_HOST | Redis hostname | Yes |

    | SMTP_SERVER | SMTP server hostname | Recommended |

    | SMTP_FROM_ADDRESS | From email address | Recommended |

    | S3_ENABLED | Enable S3 storage | No |

    | CDN_HOST | CDN hostname for assets | No |

    Appendix E: Federation Debugging

    bash
    # Test federation endpoints
    curl -H "Accept: application/activity+json" https://your-domain.com/.well-known/webfinger?resource=acct:username@your-domain.com
    curl -H "Accept: application/activity+json" https://your-domain.com/users/username
    
    # Check instance reachability
    sudo -u mastodon bash << 'EOF'
    cd /home/mastodon/live
    export PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init -)"
    RAILS_ENV=production bundle exec rails console
    # Instance.find_by(domain: 'example.com')&.ping
    EOF
    
    # Monitor federation jobs
    sudo journalctl -u mastodon-sidekiq | grep -E "(DeliveryWorker|ActivityPub)"

    Appendix F: Monitoring and Alerting

    bash
    # Basic monitoring script
    sudo tee /usr/local/bin/mastodon-monitor.sh << 'EOF'
    #!/bin/bash
    
    # Check services
    systemctl is-active --quiet mastodon-web || echo "ALERT: Mastodon web service down"
    systemctl is-active --quiet mastodon-sidekiq || echo "ALERT: Mastodon sidekiq down"
    systemctl is-active --quiet mastodon-streaming || echo "ALERT: Mastodon streaming down"
    
    # Check disk space
    DISK_USAGE=$(df /home/mastodon | tail -1 | awk '{print $5}' | sed 's/%//')
    if [ "$DISK_USAGE" -gt 80 ]; then
        echo "ALERT: Disk usage high: ${DISK_USAGE}%"
    fi
    
    # Check database connections
    DB_CONNECTIONS=$(sudo -u postgres psql -t -c "SELECT count(*) FROM pg_stat_activity WHERE datname='mastodon_production';" | tr -d ' ')
    if [ "$DB_CONNECTIONS" -gt 80 ]; then
        echo "ALERT: High database connections: $DB_CONNECTIONS"
    fi
    EOF
    
    sudo chmod +x /usr/local/bin/mastodon-monitor.sh

    ---

    Note: This guide is part of the HowToMgr collection. Always refer to official Mastodon documentation for the most up-to-date information.