341 lines
10 KiB
Bash
Executable File
341 lines
10 KiB
Bash
Executable File
#!/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 ""
|