1
mirror of https://github.com/jakejarvis/mastodon-utils.git synced 2025-04-26 02:15:22 -04:00
mastodon-utils/scripts/install.sh

297 lines
10 KiB
Bash
Executable File

#!/bin/bash
# exit when any step fails
set -euo pipefail
# :)
MY_NAME_IS_JAKE_JARVIS="false"
# can't say you weren't warned
if [ "$MY_NAME_IS_JAKE_JARVIS" != "pinky promise" ]; then
echo "🚨 LISTEN UP!!!! YOU PROBABLY WANT THIS SCRIPT INSTEAD:"
echo "https://github.com/jakejarvis/mastodon-installer/blob/main/install.sh"
exit 69
fi
# initialize paths (and silence warnings about things not existing yet because that's why we're running the installer.)
. "$(dirname "${BASH_SOURCE[0]}")"/../init.sh >/dev/null
# check for existing installation
if [ -d "$APP_ROOT" ]; then
echo "⚠️ $APP_ROOT already exists. Are you sure Mastodon isn't already installed?"
exit 255
fi
# ask for required info up-front
read -rp "Server FQDN? " MASTODON_DOMAIN
read -rp "Public domain? (the second part of usernames, usually the same as FQDN) " MASTODON_USERNAME_DOMAIN
read -rp "Admin username? " MASTODON_ADMIN_USERNAME
read -rp "Admin email? " MASTODON_ADMIN_EMAIL
# leave our mark
INSTALLER_WUZ_HERE="# Generated by mastodon-installer @ $(date)"
# set FQDN (especially necessary for sendmail)
echo -e "\n$INSTALLER_WUZ_HERE
127.0.0.1 localhost $MASTODON_DOMAIN
::1 localhost $MASTODON_DOMAIN" | sudo tee -a /etc/hosts >/dev/null
sudo hostnamectl set-hostname "$MASTODON_DOMAIN"
# create non-root user named MASTODON_USER (unless it already exists)
if ! id -u "$MASTODON_USER" >/dev/null 2>&1; then
sudo adduser --gecos "" --home "$MASTODON_ROOT" --disabled-login "$MASTODON_USER" || :
echo "[ -s \"$UTILS_ROOT/init.sh\" ] && \. \"$UTILS_ROOT/init.sh\" >/dev/null 2>&1" | sudo tee -a "$MASTODON_ROOT/.bashrc" >/dev/null
sudo chown -R "$MASTODON_USER":"$MASTODON_USER" "$MASTODON_ROOT"
fi
# install latest ubuntu updates & basic prerequisites
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
curl \
wget \
gnupg \
apt-transport-https \
lsb-release \
ca-certificates \
tzdata
# add official postgresql apt repository
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo gpg --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/postgresql-archive-keyring.gpg] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/postgresql.list >/dev/null
# add official redis apt repository
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list >/dev/null
# add official nginx apt repository
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://nginx.org/packages/ubuntu/ $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list >/dev/null
# install prerequisites:
# https://docs.joinmastodon.org/admin/install/#system-packages
sudo apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
autoconf \
bison \
build-essential \
ffmpeg \
file \
g++ \
gcc \
git \
imagemagick \
libaugeas-dev \
libffi-dev \
libgdbm-dev \
libicu-dev \
libidn11-dev \
libjemalloc-dev \
libncurses-dev \
libpq-dev \
libprotobuf-dev \
libreadline-dev \
libssl-dev \
libxml2-dev \
libxslt1-dev \
libyaml-dev \
nginx \
pkg-config \
postgresql \
postgresql-contrib \
protobuf-compiler \
python3 \
python3-psycopg2 \
python3-venv \
redis-server \
redis-tools \
shared-mime-info \
zlib1g-dev
# install rbenv & ruby-build
# https://github.com/rbenv/rbenv#basic-git-checkout
# https://github.com/rbenv/ruby-build#clone-as-rbenv-plugin-using-git
as_mastodon git clone https://github.com/rbenv/rbenv.git "$RBENV_ROOT"
as_mastodon git clone https://github.com/rbenv/ruby-build.git "$RBENV_ROOT/plugins/ruby-build"
# install nvm
# https://github.com/nvm-sh/nvm#manual-install
as_mastodon git clone https://github.com/nvm-sh/nvm.git "$NVM_DIR"
# clone vanilla Mastodon & checkout latest version:
as_mastodon git clone https://github.com/mastodon/mastodon.git "$APP_ROOT" && cd "$APP_ROOT"
as_mastodon git config --global --add safe.directory "$APP_ROOT"
as_mastodon git checkout "$(as_mastodon git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)"
# uncomment (and keep above lines) to install glitch-soc fork:
# as_mastodon git remote add glitch-soc https://github.com/glitch-soc/mastodon
# as_mastodon git fetch --all
# as_mastodon git checkout glitch-soc/main
# apply customizations
. "$UTILS_ROOT"/scripts/customize.sh
# install ruby
as_mastodon RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install --skip-existing
as_mastodon rbenv global "$(as_mastodon cat "$APP_ROOT"/.ruby-version)"
# install node & yarn
as_mastodon nvm install
as_mastodon nvm use
as_mastodon npm install --global yarn
# install npm and gem dependencies
as_mastodon gem install bundler --no-document
as_mastodon bundle config deployment "true"
as_mastodon bundle config without "development test"
as_mastodon bundle install --jobs "$(getconf _NPROCESSORS_ONLN)"
as_mastodon yarn install --pure-lockfile
# set up database w/ random alphanumeric password
DB_PASSWORD=$(< /dev/urandom tr -dc A-Za-z0-9 | head -c32; echo)
echo "CREATE USER $MASTODON_USER WITH PASSWORD '$DB_PASSWORD' CREATEDB" | sudo -u postgres psql -f -
# populate .env.production config
echo "$INSTALLER_WUZ_HERE
LOCAL_DOMAIN=$MASTODON_USERNAME_DOMAIN
WEB_DOMAIN=$MASTODON_DOMAIN
SINGLE_USER_MODE=false
WEB_CONCURRENCY=3
MAX_THREADS=10
STREAMING_CLUSTER_NUM=1
RAILS_LOG_LEVEL=warn
DB_HOST=localhost
DB_USER=$MASTODON_USER
DB_NAME=mastodon_production
DB_PASS=$DB_PASSWORD
# without pgbouncer:
DB_PORT=5432
# with pgbouncer: https://github.com/jakejarvis/mastodon-utils/wiki/Postgres-&-PgBouncer#pgbouncer
# DB_PORT=6432
# PREPARED_STATEMENTS=false
REDIS_HOST=localhost
REDIS_PORT=6379
# get SES credentials: https://us-east-1.console.aws.amazon.com/ses/home?region=us-east-1#/smtp
# ...or use SendGrid, MailGun, AWS SES, etc...
# SMTP_SERVER=email-smtp.us-east-1.amazonaws.com
# SMTP_PORT=587
# SMTP_FROM_ADDRESS=\"Mastodon <noreply@$MASTODON_DOMAIN>\"
# SMTP_LOGIN=XXXXXXXX
# SMTP_PASSWORD=XXXXXXXX
# uses linode, not brand name S3: https://cloud.linode.com/object-storage/buckets/create
# AWS_ACCESS_KEY_ID=XXXXXXXX
# AWS_SECRET_ACCESS_KEY=XXXXXXXX
# S3_ENABLED=true
# S3_BUCKET=my-bucket
# S3_PROTOCOL=https
# S3_HOSTNAME=us-east-1.linodeobjects.com
# S3_ENDPOINT=https://us-east-1.linodeobjects.com
# S3_ALIAS_HOST=my-bucket.us-east-1.linodeobjects.com
# https://github.com/jakejarvis/mastodon-utils/wiki/ElasticSearch
# ES_ENABLED=true
# ES_HOST=localhost
# ES_PORT=9200
# optional, not enabled by default:
# ES_USER=
# ES_PASS=
# https://github.com/jakejarvis/mastodon-utils/wiki/Prometheus-&-Grafana
# STATSD_ADDR=localhost:9125
IP_RETENTION_PERIOD=31556952
SESSION_RETENTION_PERIOD=31556952
SECRET_KEY_BASE=$(as_mastodon RAILS_ENV=production bundle exec rake secret)
OTP_SECRET=$(as_mastodon RAILS_ENV=production bundle exec rake secret)
$(as_mastodon RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key)" | as_mastodon tee "$APP_ROOT/.env.production" >/dev/null
# manually setup db
as_mastodon RAILS_ENV=production SAFETY_ASSURED=1 bundle exec rails db:setup
# precompile assets
as_mastodon RAILS_ENV=production bundle exec rails assets:precompile
# install latest certbot
# https://certbot.eff.org/instructions?ws=nginx&os=pip
sudo python3 -m venv /opt/certbot/
sudo /opt/certbot/bin/pip install --upgrade pip
sudo /opt/certbot/bin/pip install certbot certbot-nginx
sudo ln -s /opt/certbot/bin/certbot /usr/local/bin/certbot
# ensure nginx hasn't started itself
sudo systemctl stop nginx
# order an ssl certificate from LE
sudo certbot certonly \
--non-interactive \
--agree-tos \
--no-eff-email \
--domains "$MASTODON_DOMAIN" \
--email "$MASTODON_ADMIN_EMAIL" \
--standalone
# configure nginx: copies conf files from this repo to /etc/nginx
sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo cp "$UTILS_ROOT"/etc/nginx/nginx.conf /etc/nginx/nginx.conf
sudo sed -i /etc/nginx/nginx.conf -e "s|user nginx;|user $MASTODON_USER;|g"
sudo mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled /etc/nginx/snippets
sudo cp -f "$UTILS_ROOT"/etc/nginx/sites-available/*.conf /etc/nginx/sites-available/
sudo sed \
-i /etc/nginx/sites-available/mastodon.conf \
-e "s|mastodon.example.com|$MASTODON_DOMAIN|g" \
-e "s|/home/mastodon/live|$APP_ROOT|g"
sudo ln -sf /etc/nginx/sites-available/mastodon.conf /etc/nginx/sites-enabled/mastodon.conf
# sudo ln -sf /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/default.conf
sudo cp -f "$UTILS_ROOT"/etc/nginx/snippets/*.conf /etc/nginx/snippets/
sudo cp -f "$UTILS_ROOT"/etc/nginx/modules/*.so /usr/lib/nginx/modules/
sudo nginx -t
# configure mastodon systemd services
sudo cp "$UTILS_ROOT"/etc/systemd/system/mastodon-*.service /etc/systemd/system/
# fix hard-coded paths and usernames in systemd files
# (they already match the defaults from init.sh, so it's likely nothing will change)
sudo sed \
-i /etc/systemd/system/mastodon-*.service \
-e "s|/home/mastodon/live|$APP_ROOT|g" \
-e "s|/home/mastodon|$MASTODON_ROOT|g" \
-e "s|User=mastodon|User=$MASTODON_USER|g"
# start everything up!
sudo systemctl daemon-reload
sudo systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming
sudo systemctl start nginx
# wait a bit to be safe
sleep 5
# create admin account
tootctl accounts create \
"$MASTODON_ADMIN_USERNAME" \
--email "$MASTODON_ADMIN_EMAIL" \
--role Owner \
--confirmed
# create directory for cron logdrain
as_mastodon mkdir -p "$LOGS_ROOT"
as_mastodon touch "$LOGS_ROOT"/cron.log
# set cleanup & backup tasks to run weekly
# https://docs.joinmastodon.org/admin/setup/#cleanup
(sudo crontab -l; echo -e "\n$INSTALLER_WUZ_HERE
@weekly bash -c \"$UTILS_ROOT/scripts/weekly_cleanup.sh >> $LOGS_ROOT/cron.log 2>&1\"
@weekly bash -c \"$UTILS_ROOT/scripts/backup.sh >> $LOGS_ROOT/cron.log 2>&1\"
# automatically renew Let's Encrypt certificates
# https://certbot.eff.org/instructions?ws=nginx&os=pip
0 0,12 * * * root /opt/certbot/bin/python -c \"import random; import time; time.sleep(random.random() * 3600)\" && certbot renew -q
") | sudo crontab -
echo "🎉 done! don't forget to fill in .env.production with optional credentials"
echo "https://$MASTODON_DOMAIN/auth/sign_in"