-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinstall.sh
executable file
·302 lines (255 loc) · 10.6 KB
/
install.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
#!/bin/bash
# exit when any step fails
set -euo pipefail
# initialize paths (and silence warnings about things not existing yet because that's why we're running the installer.)
# shellcheck disable=SC1091
. "$(dirname "${BASH_SOURCE[0]}")"/../init.sh >/dev/null
# 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
# 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
# shellcheck disable=SC1091
. "$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=$(
tr </dev/urandom -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-{purge,backup}.log
# set cleanup & backup tasks to run weekly
# https://docs.joinmastodon.org/admin/setup/#cleanup
(
sudo crontab -l
echo -e "\n$INSTALLER_WUZ_HERE
# purge old media weekly
@weekly bash -c \"$UTILS_ROOT/scripts/purge.sh >> $LOGS_ROOT/cron-purge.log 2>&1\"
# create & rotate backups daily
@daily bash -c \"$UTILS_ROOT/scripts/backup.sh >> $LOGS_ROOT/cron-backup.log 2>&1\"
# automatically renew Let's Encrypt certificates:
# https://certbot.eff.org/instructions?ws=other&os=pip
0 0,12 * * * /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"