CentOS 7: Run Mastodon instance

 

This article will describe running Mastodon instance directly on CentOS 7 without Docker and Vargrant.

1 Limitation

  • This article reffers Production-guide.md and Alternatives.md in Mastodon documentation.
  • This Mastodon instance is for checking Mastodon usage and API. This is not production level.
  • The Mastodon, Redis, PostgreSQL, Apache and Postfix will be installed in the same machine.
  • Only <user>@localhost can be used for account (This Postfix setting only sends to localhost). If you need multiple account, you need to create multiple local user in machine for creating multiple mail address.
  • You need to login to machine for checking confirmation mail.
  • The Apache setting does not use RewriteRule and subdomain. This will prevent other web service which uses Apache.

2 Before running Mastodon instance

You need to install FFmpeg and Ruby 2.3 before running Mastodon instance.

2.1 Install FFmpeg

Install FFmpeg with this script.

2.2 Install Ruby 2.3

Install Ruby 2.3 with this script.

3 Run Mastodon instance

The following script will run Mastodon instance. The LOCAL_DOMAIN variable can be used as IP address and FQDN. This will be used in confirmation mail.

$ LOCAL_DOMAIN=192.168.11.86 ./run-this-script.sh
#!/bin/sh

set -e

[ -z "${LOCAL_DOMAIN}" ] && \
  LOCAL_DOMAIN=centos-7-mastodon.hiroom2.com
[ -z "${MASTODON_DIR}" ] && \
  MASTODON_DIR=/var/lib/mastodon
MASTODON_TAG=v1.3.3

mastodon_install_depend()
{
  sudo yum install -y epel-release
  sudo yum install -y ImageMagick postgresql-devel libxml2-devel \
       libxslt-devel file git curl nodejs npm
  sudo gem install bundler rake
  sudo npm install -g yarn
}

mastodon_install_redis()
{
  sudo yum install -y redis
  sudo systemctl enable redis
  sudo systemctl start redis
}

mastodon_install_postgres()
{
  sudo yum install -y postgresql-server
  sudo postgresql-setup initdb
  sudo sed -e 's/^host\(.*\)ident/host\1trust/g' \
       -i /var/lib/pgsql/data/pg_hba.conf
  sudo systemctl enable postgresql
  sudo systemctl start postgresql
  cat <<EOF | sudo -u postgres psql
CREATE USER mastodon CREATEDB;
\q
EOF
}

mastodon_install_mastodon()
{
  # Not use -m for disable creating skel like .bashrc.
  sudo useradd mastodon -M -d ${MASTODON_DIR}
  git clone https://github.com/tootsuite/mastodon.git
  cd mastodon
  git checkout ${MASTODON_TAG} -b ${MASTODON_TAG}
  cd ..
  sudo mkdir -p "$(dirname ${MASTODON_DIR})"
  sudo mv mastodon ${MASTODON_DIR}
  sudo chown -R mastodon:mastodon ${MASTODON_DIR}

  sudo su - mastodon -c "
set -e
cd ${MASTODON_DIR}
# The ruby version checker may not work correctly.
sed -e \"s/^ruby/#ruby/g\" -i Gemfile
bundle install --deployment --without development test
yarn install --pure-lockfile

PAPERCLIP_SECRET=\$(rake secret)
SECRET_KEY_BASE=\$(rake secret)
OTP_SECRET=\$(rake secret)

sed -e \"s/^REDIS_HOST=.*/REDIS_HOST=localhost/g\" \
    -e \"s/^DB_HOST=.*/DB_HOST=localhost/g\" \
    -e \"s/^DB_USER=.*/DB_USER=mastodon/g\" \
    -e \"s/^DB_NAME=.*/DB_NAME=mastodon/g\" \
    -e \"s/^LOCAL_DOMAIN=.*/LOCAL_DOMAIN=${LOCAL_DOMAIN}/g\" \
    -e \"s/^LOCAL_HTTPS=.*/LOCAL_HTTPS=true/g\" \
    -e \"s/^PAPERCLIP_SECRET=.*/PAPERCLIP_SECRET=\${PAPERCLIP_SECRET}/g\" \
    -e \"s/^SECRET_KEY_BASE=.*/SECRET_KEY_BASE=\${SECRET_KEY_BASE}/g\" \
    -e \"s/^OTP_SECRET=.*/OTP_SECRET=\${OTP_SECRET}/g\" \
    -e \"s/^SMTP_SERVER=.*/SMTP_SERVER=localhost/g\" \
    -e \"s/^SMTP_PORT=.*/SMTP_PORT=25/g\" \
    -e \"s/^SMTP_LOGIN=/#SMTP_LOGIN=/g\" \
    -e \"s/^SMTP_PASSWORD=/#SMTP_PASSWORD=/g\" \
    -e \"s/^SMTP_FROM_ADDRESS=.*/SMTP_FROM_ADDRESS=noreply@localhost/g\" \
    -e \"s/^#SMTP_AUTH_METHOD=.*/SMTP_AUTH_METHOD=none/g\" \
    -e \"s/^# DEFAULT_LOCALE=.*/DEFAULT_LOCALE=en/g\" \
    .env.production.sample > .env.production

RAILS_ENV=production bundle exec rails db:setup
RAILS_ENV=production bundle exec rails assets:precompile
"

  cat <<EOF | sudo tee /lib/systemd/system/mastodon-web.service
[Unit]
Description=mastodon-web
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=${MASTODON_DIR}
Environment="RAILS_ENV=production"
Environment="PORT=3000"
ExecStart=/usr/local/bin/bundle exec puma -C config/puma.rb
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
EOF

  cat <<EOF | sudo tee /lib/systemd/system/mastodon-sidekiq.service
[Unit]
Description=mastodon-sidekiq
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=${MASTODON_DIR}
Environment="RAILS_ENV=production"
Environment="DB_POOL=5"
ExecStart=/usr/local/bin/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
EOF

  cat <<EOF | sudo tee /lib/systemd/system/mastodon-streaming.service
[Unit]
Description=mastodon-streaming
After=network.target

[Service]
Type=simple
User=mastodon
WorkingDirectory=${MASTODON_DIR}
Environment="NODE_ENV=production"
Environment="PORT=4000"
ExecStart=/usr/bin/npm run start
TimeoutSec=15
Restart=always

[Install]
WantedBy=multi-user.target
EOF

  sudo systemctl enable mastodon-web mastodon-sidekiq mastodon-streaming
  sudo systemctl start mastodon-web mastodon-sidekiq mastodon-streaming
}

mastodon_install_apache()
{
  sudo yum install -y httpd mod_ssl
  cat <<EOF | sudo tee /etc/httpd/conf.d/mastodon.conf
<VirtualHost _default_:443>
  SSLEngine on
  SSLCertificateFile /etc/pki/tls/certs/localhost.crt
  SSLCertificateKeyFile /etc/pki/tls/private/localhost.key

  <Location /assets>
    Header always set Cache-Control "public, max-age=31536000, immutable"
  </Location>

  ProxyPreserveHost On
  RequestHeader set X-Forwarded-Proto "https"
  ProxyPass /500.html !
  ProxyPass /oops.png !
  ProxyPass /api/v1/streaming/ ws://localhost:4000/
  ProxyPassReverse /api/v1/streaming/ ws://localhost:4000/
  ProxyPass / http://localhost:3000/
  ProxyPassReverse / http://localhost:3000/
</VirtualHost>
EOF

  sudo setsebool -P httpd_can_network_connect 1
  sudo setsebool -P httpd_can_sendmail 1
  sudo systemctl enable httpd
  sudo systemctl restart httpd
  sudo firewall-cmd --add-service=https --permanent
  sudo firewall-cmd --reload
}

mastodon_install_postfix()
{
  sudo yum install -y postfix
  cat <<EOF | sudo tee /etc/postfix/main.cf
myhostname = localhost
mydomain = localdomain
myorigin = \$myhostname.\$mydomain
mydestination = localhost, localhost.\$mydomain, \$myhostname, \$mydomain, \$myorigin
compatibility_level = 2
queue_directory = /var/spool/postfix
command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
data_directory = /var/lib/postfix
mail_owner = postfix
inet_interfaces = all
local_recipient_maps = unix:passwd.byname \$alias_maps
unknown_local_recipient_reject_code = 550
mynetworks_style = subnet
mynetworks = 127.0.0.0/8
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
smtpd_banner = \$myhostname ESMTP  (\$mail_version)
debug_peer_level = 2
debugger_command =
         PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
         ddd \$daemon_directory/\$process_name \$process_id & sleep 5
sendmail_path = /usr/sbin/sendmail.postfix
newaliases_path = /usr/bin/newaliases.postfix
mailq_path = /usr/bin/mailq.postfix
setgid_group = postdrop
inet_protocols = ipv4
EOF

  sudo newaliases
  sudo systemctl restart postfix
  sudo firewall-cmd --add-service=smtp --permanent
  sudo firewall-cmd --reload
  sudo yum install -y mutt
}

mastodon_main()
{
  mastodon_install_depend
  mastodon_install_redis
  mastodon_install_postgres
  mastodon_install_mastodon
  mastodon_install_apache
  mastodon_install_postfix
}

mastodon_main "$@"

4 Access to Mastodon instance

This is the same with Ubuntu 16.04.