diff --git a/README.md b/README.md index a5ab166..aee0bf9 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ fi **The following scripts are highly opinionated, catastrophically destructive, and very specific to me.** Check them out line-by-line instead of running them. -- [`install.sh`](scripts/install.sh): Assumes an absolutely clean install of Ubuntu 20.04 and installs Mastodon ***with all of the quirks from this repo.*** [Get the far less dangerous version of `install.sh` here instead.](https://github.com/jakejarvis/mastodon-installer/blob/main/install.sh) +- [`install.sh`](scripts/install.sh): Assumes an absolutely clean install of Ubuntu 20.04 and installs Mastodon ***with all of the quirks from this repo.*** Configure `MASTODON_ROOT` and other paths in [`init.sh`](init.sh) first if necessary. [Get the far less dangerous version of `install.sh` here instead.](https://github.com/jakejarvis/mastodon-installer/blob/main/install.sh) - [`upgrade.sh`](scripts/upgrade.sh): Upgrades Mastodon server (latest version if vanilla Mastodon, latest commit if `glitch-soc`) and ***re-applies every patch*** listed below. [Get the far less dangerous version of `upgrade.sh` here instead.](https://github.com/jakejarvis/mastodon-installer/blob/main/upgrade.sh) - [`apply_patches.sh`](scripts/apply_patches.sh): Apply every patch below on top of the currently installed version of Mastodon. diff --git a/etc/nginx/sites-available/mastodon.conf b/etc/nginx/sites-available/mastodon.conf index 763c638..e69628f 100644 --- a/etc/nginx/sites-available/mastodon.conf +++ b/etc/nginx/sites-available/mastodon.conf @@ -19,19 +19,19 @@ server { listen [::]:443 http2 ssl ipv6only=on; listen 443 http2 ssl; - server_name fediverse.jarv.is; + server_name mastodon.example.com; root /home/mastodon/live/public; - ssl_certificate /etc/letsencrypt/live/fediverse.jarv.is/fullchain.pem; # managed by Certbot - ssl_certificate_key /etc/letsencrypt/live/fediverse.jarv.is/privkey.pem; # managed by Certbot + ssl_certificate /etc/letsencrypt/live/mastodon.example.com/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/mastodon.example.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot # https://ssl-config.mozilla.org/#server=nginx&version=1.22.1&config=intermediate&openssl=1.1.1f&guideline=5.6 ssl_stapling on; ssl_stapling_verify on; - ssl_trusted_certificate /etc/letsencrypt/live/fediverse.jarv.is/chain.pem; + ssl_trusted_certificate /etc/letsencrypt/live/mastodon.example.com/chain.pem; keepalive_timeout 20; sendfile on; @@ -161,9 +161,9 @@ server { listen [::]:80; listen 80; - server_name fediverse.jarv.is; + server_name mastodon.example.com; - if ($host = fediverse.jarv.is) { + if ($host = mastodon.example.com) { return 301 https://$host$request_uri; } # managed by Certbot diff --git a/etc/systemd/system/mastodon-sidekiq.service b/etc/systemd/system/mastodon-sidekiq.service new file mode 100644 index 0000000..9203492 --- /dev/null +++ b/etc/systemd/system/mastodon-sidekiq.service @@ -0,0 +1,54 @@ +[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" +Environment="LD_PRELOAD=libjemalloc.so" +# note: this env is also set in .env.production, but this service is started before file is read: +Environment="DB_POOL=15" +ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 15 +TimeoutSec=15 +Restart=always +# Proc filesystem +# ProcSubset=pid +# ProtectProc=invisible +# Capabilities +CapabilityBoundingSet= +# Security +NoNewPrivileges=true +# Sandboxing +ProtectSystem=strict +PrivateTmp=true +PrivateDevices=true +PrivateUsers=true +ProtectHostname=true +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectControlGroups=true +RestrictAddressFamilies=AF_INET +RestrictAddressFamilies=AF_INET6 +RestrictAddressFamilies=AF_NETLINK +RestrictAddressFamilies=AF_UNIX +RestrictNamespaces=true +LockPersonality=true +RestrictRealtime=true +RestrictSUIDSGID=true +RemoveIPC=true +PrivateMounts=true +ProtectClock=true +# System Call Filtering +SystemCallArchitectures=native +SystemCallFilter=~@cpu-emulation @debug @keyring @ipc @mount @obsolete @privileged @setuid +SystemCallFilter=@chown +SystemCallFilter=pipe +SystemCallFilter=pipe2 +ReadWritePaths=/home/mastodon/live + +[Install] +WantedBy=multi-user.target diff --git a/etc/systemd/system/mastodon-streaming.service b/etc/systemd/system/mastodon-streaming.service new file mode 100644 index 0000000..a418d6a --- /dev/null +++ b/etc/systemd/system/mastodon-streaming.service @@ -0,0 +1,52 @@ +[Unit] +Description=mastodon-streaming +After=network.target + +[Service] +Type=simple +User=mastodon +WorkingDirectory=/home/mastodon/live +Environment="NODE_ENV=production" +Environment="PORT=4000" +# note: this env is also set in .env.production, but this service is started before file is read: +Environment="STREAMING_CLUSTER_NUM=1" +ExecStart=/home/mastodon/.nvm/nvm-exec node ./streaming +TimeoutSec=15 +Restart=always +# Proc filesystem +# ProcSubset=pid +# ProtectProc=invisible +# Capabilities +CapabilityBoundingSet= +# Security +NoNewPrivileges=true +# Sandboxing +ProtectSystem=strict +PrivateTmp=true +PrivateDevices=true +PrivateUsers=true +ProtectHostname=true +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectControlGroups=true +RestrictAddressFamilies=AF_INET +RestrictAddressFamilies=AF_INET6 +RestrictAddressFamilies=AF_NETLINK +RestrictAddressFamilies=AF_UNIX +RestrictNamespaces=true +LockPersonality=true +RestrictRealtime=true +RestrictSUIDSGID=true +RemoveIPC=true +PrivateMounts=true +ProtectClock=true +# System Call Filtering +SystemCallArchitectures=native +SystemCallFilter=~@cpu-emulation @debug @keyring @ipc @memlock @mount @obsolete @privileged @resources @setuid +SystemCallFilter=pipe +SystemCallFilter=pipe2 +ReadWritePaths=/home/mastodon/live + +[Install] +WantedBy=multi-user.target diff --git a/etc/systemd/system/mastodon-web.service b/etc/systemd/system/mastodon-web.service new file mode 100644 index 0000000..a8ccf6a --- /dev/null +++ b/etc/systemd/system/mastodon-web.service @@ -0,0 +1,56 @@ +[Unit] +Description=mastodon-web +After=network.target + +[Service] +Type=simple +User=mastodon +WorkingDirectory=/home/mastodon/live +Environment="RAILS_ENV=production" +Environment="PORT=3000" +Environment="LD_PRELOAD=libjemalloc.so" +# note: this env is also set in .env.production, but this service is started before file is read: +Environment="WEB_CONCURRENCY=3" +Environment="MAX_THREADS=10" +ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb +ExecReload=/bin/kill -SIGUSR1 $MAINPID +TimeoutSec=15 +Restart=always +# Proc filesystem +# ProcSubset=pid +# ProtectProc=invisible +# Capabilities +CapabilityBoundingSet= +# Security +NoNewPrivileges=true +# Sandboxing +ProtectSystem=strict +PrivateTmp=true +PrivateDevices=true +PrivateUsers=true +ProtectHostname=true +ProtectKernelLogs=true +ProtectKernelModules=true +ProtectKernelTunables=true +ProtectControlGroups=true +RestrictAddressFamilies=AF_INET +RestrictAddressFamilies=AF_INET6 +RestrictAddressFamilies=AF_NETLINK +RestrictAddressFamilies=AF_UNIX +RestrictNamespaces=true +LockPersonality=true +RestrictRealtime=true +RestrictSUIDSGID=true +RemoveIPC=true +PrivateMounts=true +ProtectClock=true +# System Call Filtering +SystemCallArchitectures=native +SystemCallFilter=~@cpu-emulation @debug @keyring @ipc @mount @obsolete @privileged @setuid +SystemCallFilter=@chown +SystemCallFilter=pipe +SystemCallFilter=pipe2 +ReadWritePaths=/home/mastodon/live + +[Install] +WantedBy=multi-user.target diff --git a/init.sh b/init.sh index 2877f52..cf67b0d 100755 --- a/init.sh +++ b/init.sh @@ -7,24 +7,32 @@ export APP_ROOT="$MASTODON_ROOT/live" # actual Mastodon files export BACKUPS_ROOT="$MASTODON_ROOT/backups" # backups destination export LOGS_ROOT="$MASTODON_ROOT/logs" # logs destintation export RBENV_ROOT="$MASTODON_ROOT/.rbenv" # rbenv (w/ ruby-build plugin) directory +export NVM_DIR="$MASTODON_ROOT/.nvm" # nvm directory # --- -# initialize rbenv manually -if [ -d "$RBENV_ROOT" ]; then +# initialize rbenv +if [ -s "$RBENV_ROOT/bin/rbenv" ]; then eval "$($RBENV_ROOT/bin/rbenv init -)" else - echo "⚠️ Didn't find rbenv at '$MASTODON_ROOT/.rbenv', double check the paths set in utils/init.sh..." + echo "⚠️ Couldn't find rbenv in '$RBENV_ROOT', double check the paths set in '$UTILS_ROOT/init.sh'..." +fi + +# initialize nvm +if [ -s "$NVM_DIR/nvm.sh" ]; then + . "$NVM_DIR/nvm.sh" +else + echo "⚠️ Couldn't find nvm.sh in '$NVM_DIR', double check the paths set in '$UTILS_ROOT/init.sh'..." fi # check for Mastodon in set location if [ ! -d "$APP_ROOT" ]; then - echo "⚠️ Didn't find Mastodon at '$APP_ROOT', double check the paths set in utils/init.sh..." + echo "⚠️ Couldn't find Mastodon at '$APP_ROOT', double check the paths set in '$UTILS_ROOT/init.sh'..." fi # clone this repo if it doesn't exist in the proper location # if [ ! -d "$UTILS_ROOT" ]; then -# echo "⚠️ Can't find mastodon-utils in '$UTILS_DIR', cloning it for you..." +# echo "⚠️ Couldn't find mastodon-utils at '$UTILS_ROOT', cloning it for you..." # sudo -u mastodon git clone https://github.com/jakejarvis/mastodon-utils.git "$UTILS_ROOT" # fi diff --git a/scripts/install.sh b/scripts/install.sh index 882b800..426aa90 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -52,10 +52,6 @@ sudo DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \ lsb-release \ ca-certificates -# add nodesource apt repository -curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/nodesource-archive-keyring.gpg -echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/nodesource-archive-keyring.gpg] https://deb.nodesource.com/node_16.x $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/nodesource.list >/dev/null - # 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] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/postgresql.list >/dev/null @@ -78,7 +74,6 @@ sudo DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \ libxml2-dev \ libxslt1-dev \ imagemagick \ - nodejs \ redis-server \ redis-tools \ postgresql \ @@ -107,32 +102,37 @@ sudo DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \ python3-venv \ libaugeas0 -# setup yarn -sudo npm install --global yarn -sudo corepack enable - # 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" eval "$("$RBENV_ROOT"/bin/rbenv init -)" +# install nvm +# https://github.com/nvm-sh/nvm#manual-install +as_mastodon git clone https://github.com/nvm-sh/nvm.git "$NVM_DIR" && cd "$NVM_DIR" +as_mastodon git checkout "$(as_mastodon git describe --abbrev=0 --tags --match "v[0-9]*" "$(as_mastodon git rev-list --tags --max-count=1)")" +. "$NVM_DIR/nvm.sh" + # clone vanilla Mastodon & checkout latest version: as_mastodon git clone https://github.com/mastodon/mastodon.git "$APP_ROOT" && cd "$APP_ROOT" -as_mastodon git checkout "$(as_mastodon git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)" +as_mastodon git checkout "$(as_mastodon git describe --abbrev=0 --tags --match "v[0-9]*" "$(as_mastodon git rev-list --tags --max-count=1)")" # clone glitch-soc & checkout latest commit: # as_mastodon git clone https://github.com/glitch-soc/mastodon.git "$APP_ROOT" && cd "$APP_ROOT" # install ruby -RUBY_VERSION="$(as_mastodon cat "$APP_ROOT"/.ruby-version)" -as_mastodon RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install --skip-existing "$RUBY_VERSION" -as_mastodon rbenv global "$RUBY_VERSION" +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 bash -c "\. "$NVM_DIR/nvm.sh"; nvm install; nvm use; 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 set version classic as_mastodon yarn install --pure-lockfile --network-timeout 100000 # set up database w/ random alphanumeric password @@ -224,25 +224,26 @@ sudo certbot certonly \ --email "$MASTODON_ADMIN_EMAIL" \ --standalone -# configure nginx: sets up symlinks from `/etc/nginx` to confs in this repo -sudo sed -i "$UTILS_ROOT/etc/nginx/sites-available/mastodon.conf" -e "s/fediverse.jarv.is/$MASTODON_DOMAIN/g" -sudo rm -rf /etc/nginx/sites-available -sudo rm -rf /etc/nginx/sites-enabled/* +# configure nginx: copies conf files from this repo to /etc/nginx sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak -sudo ln -sf "$UTILS_ROOT/etc/nginx/nginx.conf" /etc/nginx/nginx.conf -sudo ln -sf "$UTILS_ROOT/etc/nginx/modules" /usr/lib/nginx/modules -sudo ln -sf "$UTILS_ROOT/etc/nginx/sites-available" /etc/nginx/sites-available +sudo cp "$UTILS_ROOT"/etc/nginx/nginx.conf /etc/nginx/nginx.conf +sudo cp -f "$UTILS_ROOT"/etc/nginx/modules/* /usr/lib/nginx/modules/ +sudo cp -f "$UTILS_ROOT"/etc/nginx/sites-available/*.conf /etc/nginx/sites-available/ sudo ln -sf /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/default.conf sudo ln -sf /etc/nginx/sites-available/mastodon.conf /etc/nginx/sites-enabled/mastodon.conf +sudo sed -i /etc/nginx/sites-available/mastodon.conf -e "s|mastodon.example.com|$MASTODON_DOMAIN|g" sudo nginx -t -sudo systemctl start nginx # configure mastodon systemd services -sudo cp "$APP_ROOT"/dist/mastodon-*.service /etc/systemd/system/ +sudo cp "$UTILS_ROOT"/etc/systemd/system/mastodon-*.service /etc/systemd/system/ + +# fix hard-coded /home/mastodon in systemd files (this is the default from init.sh anyways, so it probably won't change) +sudo sed -i /etc/systemd/system/mastodon-*.service -e "s|/home/mastodon|$MASTODON_ROOT|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 diff --git a/scripts/upgrade.sh b/scripts/upgrade.sh index aacc7cb..e25c442 100755 --- a/scripts/upgrade.sh +++ b/scripts/upgrade.sh @@ -35,6 +35,9 @@ RUBY_VERSION="$(as_mastodon cat "$APP_ROOT"/.ruby-version)" as_mastodon RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install --skip-existing "$RUBY_VERSION" as_mastodon rbenv global "$RUBY_VERSION" +# set new node version +as_mastodon bash -c "\. "$NVM_DIR/nvm.sh"; nvm install; nvm use; npm install --global yarn" + # update dependencies as_mastodon bundle install --jobs "$(getconf _NPROCESSORS_ONLN)" as_mastodon yarn install --pure-lockfile --network-timeout 100000