- Install to Debian Buster
- All of services needed to run Mastodon instance (tor, postgresql, redis, nginx) will be installed to the same server.
# apt install postgresql redis nodejs npm ruby tor ffmpeg imagemagick git \
nginx wget bundler protobuf-compiler iptables-persistent ncurses-term vim \
gcc g++ make patch ruby-dev libprotobuf-dev libidn11-dev libpq-dev libicu-dev libxml2-dev libxslt1-dev
# adduser mastodon
# adduser mastodon www-data
Create mastodon
as superuser.
# su -c 'createuser -s mastodon' postgres
Edit following directives in /etc/redis/redis.conf
.
port 0
unixsocket /run/redis/redis-server.sock
unixsocketperm 666
# systemctl restart redis-server
# npm install -g --prefix /opt/yarn yarn
# echo 'export PATH=$PATH:/opt/yarn/bin' >/etc/profile.d/yarn.sh
Append following to /etc/tor/torrc
.
TransPort 127.0.0.1:9040
DNSPort 127.0.0.1:5353
VirtualAddrNetwork 127.192.0.0/10
TransPort [::1]:9040
DNSPort [::1]:5353
VirtualAddrNetworkIPv6 [fc00:70a::]/32
AutomapHostsOnResolve 1
HiddenServiceDir /var/lib/tor/mastodon
HiddenServiceVersion 3
HiddenServicePort 80 [::1]:80
# systemctl restart tor
The onion address will be generated at /var/lib/tor/mastodon/hostname
.
Make transparent proxy by iptables.
Create a chain for "torify."
# iptables -N TORIFY
# iptables -A TORIFY -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -A TORIFY -j REJECT --reject-with icmp-net-prohibited
# iptables -t nat -N TORIFY
# iptables -t nat -A TORIFY -p udp --dport 53 -j REDIRECT --to-ports 5353
# iptables -t nat -A TORIFY -p tcp -j REDIRECT --to-ports 9040
Create a chain for accessing to mastodon backends. If you choose to access backend services on remote, You need to prepend the rules (-I) to this chain.
# iptables -N MASTODON-BE
# iptables -A MASTODON-BE -j TORIFY
# iptables -t nat -N MASTODON-BE
# iptables -t nat -A MASTODON-BE -j TORIFY
Apply these rules for mastodon
user.
# iptables -A OUTPUT -m owner --uid-owner mastodon -d 127.0.0.0/8 -j ACCEPT
# iptables -A OUTPUT -m owner --uid-owner mastodon -j MASTODON-BE
# iptables -t nat -A OUTPUT -d 127.0.0.0/8 -j ACCEPT
# iptables -t nat -A OUTPUT -m owner --uid-owner mastodon -j MASTODON-BE
Repeat to IPv6.
# ip6tables -N TORIFY
# ip6tables -A TORIFY -m state --state RELATED,ESTABLISHED -j ACCEPT
# ip6tables -A TORIFY -j REJECT --reject-with icmp6-adm-prohibited
# ip6tables -t nat -N TORIFY
# ip6tables -t nat -A TORIFY -p udp --dport 53 -j REDIRECT --to-ports 5353
# ip6tables -t nat -A TORIFY -p tcp -j REDIRECT --to-ports 9040
# ip6tables -N MASTODON-BE
# ip6tables -A MASTODON-BE -j TORIFY
# ip6tables -t nat -N MASTODON-BE
# ip6tables -t nat -A MASTODON-BE -j TORIFY
# ip6tables -A OUTPUT -m owner --uid-owner mastodon -d ::1 -j ACCEPT
# ip6tables -A OUTPUT -m owner --uid-owner mastodon -j MASTODON-BE
# ip6tables -t nat -A OUTPUT -d ::1 -j ACCEPT
# ip6tables -t nat -A OUTPUT -m owner --uid-owner mastodon -j MASTODON-BE
Persistent the rules.
# iptables-save >/etc/iptables/rules.v4
# ip6tables-save >/etc/iptables/rules.v6
Check connectivity
# su -c 'wget -O- --quiet https://check.torproject.org |sed -n "/<h1/,/<\\/h1/p"' mastodon
<h1 class="not">
Congratulations. This browser is configured to use Tor.
</h1>
# su -c 'wget -O/dev/null https://www.facebookcorewwwi.onion' mastodon
Save following as /etc/nginx/sites-available/mastodon
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen [::1]:80;
server_name %%%.onion;
keepalive_timeout 70;
sendfile on;
client_max_body_size 8m;
root /home/mastodon/live/public;
add_header Referrer-Policy "same-origin";
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 8;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location / {
try_files $uri @proxy;
}
location ~ ^/(emoji|packs) {
add_header Cache-Control "public, max-age=31536000, immutable";
gzip_static on;
try_files $uri @proxy;
}
location /system {
add_header Cache-Control "public, max-age=31536000, immutable";
gzip off;
try_files $uri @proxy;
}
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 Proxy "";
proxy_pass_header Server;
proxy_pass http://unix:/home/mastodon/live/tmp/web.sock:;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
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 Proxy "";
proxy_pass http://unix:/home/mastodon/live/tmp/streaming.sock:;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
error_page 500 501 502 503 504 /500.html;
}
# ln -s ../sites-available/mastodon /etc/nginx/sites-enabled/
# systemctl restart nginx
Login as mastodon
$ git clone https://github.com/tootsuite/mastodon live
$ cd live
$ git checkout -b run v2.4.5
Save following as ~/disable-https.patch
.
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 29ba6cad6..df22cf32e 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -33,7 +33,7 @@ class ApplicationController < ActionController::Base
private
def https_enabled?
- Rails.env.production?
+ false
end
def store_current_location
diff --git a/config/initializers/ostatus.rb b/config/initializers/ostatus.rb
index 5773b7290..93961fd19 100644
--- a/config/initializers/ostatus.rb
+++ b/config/initializers/ostatus.rb
@@ -7,7 +7,7 @@ web_host = ENV.fetch('WEB_DOMAIN') { host }
alternate_domains = ENV.fetch('ALTERNATE_DOMAINS') { '' }
Rails.application.configure do
- https = Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true'
+ https = false
config.x.local_domain = host
config.x.web_domain = web_host
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index 3dc0edd6f..85983d259 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -1,3 +1,3 @@
# Be sure to restart your server when you modify this file.
-Rails.application.config.session_store :cookie_store, key: '_mastodon_session', secure: (Rails.env.production? || ENV['LOCAL_HTTPS'] == 'true')
+Rails.application.config.session_store :cookie_store, key: '_mastodon_session'
$ cd live
$ patch -p1 <~/disable-https.patch
patching file app/controllers/application_controller.rb
patching file config/initializers/ostatus.rb
patching file config/initializers/session_store.rb
$ bundle config --local build.nokogiri --use-system-libraries
You are replacing the current local value of build.nokogiri, which is currently nil
$ bundle install --deployment --jobs 3 --without development:test
$ yarn install --pure-lockfile --prod
~/live/.env.production
LOCAL_DOMAIN=%%%.onion
SINGLE_USER_MODE=true|false
DB_HOST=/run/postgresql
DB_NAME=mastodon_production
DB_USER=mastodon
REDIS_URL=unix:///run/redis/redis-server.sock
SMTP_FROM_ADDRESS=notifications@%%%.onion
SMTP_DELIVERY_METHOD=smtp|sendmail
SMTP_SERVER=***.onion
SMTP_PORT=25
#SMTP_LOGIN=
#SMTP_PASSWORD=
SMTP_AUTH_METHOD=none|plain|cram_md5
SMTP_OPENSSL_VERIFY_MODE=none|...
ALLOW_ACCESS_TO_HIDDEN_SERVICE=true
Generate some keys and append them
$ echo SECRET_KEY_BASE=$(openssl rand -hex 64) >>.env.production
$ echo OTP_SECRET=$(openssl rand -hex 64) >>.env.production
$ RAILS_ENV=production bundle exec rails mastodon:webpush:generate_vapid_key >>.env.production
$ RAILS_ENV=production bundle exec rails db:setup SAFETY_ASSURED=1
$ RAILS_ENV=production bundle exec rails assets:precompile
# su -c 'psql -c "alter role mastodon nosuperuser nocreaterole nocreatedb;"' postgres
ALTER ROLE
/etc/systemd/system/mastodon-web.service
[Unit]
Description=mastodon-web
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
ExecStartPre=/bin/sh -c '/bin/rm tmp/web.sock 2>/dev/null || :'
ExecStart=/usr/bin/bundle exec puma -C config/puma.rb -e production -b unix:///home/mastodon/live/tmp/web.sock
TimeoutSec=15
Restart=always
[Install]
WantedBy=multi-user.target
/etc/systemd/system/mastodon-sidekiq.service
[Unit]
Description=mastodon-sidekiq
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment=RAILS_ENV=production
Environment=DB_POOL=5
ExecStart=/usr/bin/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
TimeoutSec=15
Restart=always
[Install]
WantedBy=multi-user.target
/etc/systemd/system/mastodon-streaming.service
[Unit]
Description=mastodon-streaming
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment=NODE_ENV=production
Environment=PORT=/home/mastodon/live/tmp/streaming.sock
ExecStartPre=/bin/sh -c '/bin/rm $PORT 2>/dev/null || :'
ExecStart=/opt/npm/bin/npm run start
ExecStartPost=/bin/sh -c 'retry=30; while [ $retry -gt 0 ]; do if [ -e $PORT ]; then chmod 660 $PORT; chown :www-data $PORT; exit; else sleep 1; retry=$((retry-1)); fi; done; kill $MAINPID; exit 1'
TimeoutSec=15
Restart=always
[Install]
WantedBy=multi-user.target
# systemctl daemon-reload
# systemctl start mastodon-{web,sidekiq,streaming}
# systemctl enable mastodon-{web,sidekiq,streaming}
Created symlink /etc/systemd/system/multi-user.target.wants/mastodon-web.service → /etc/systemd/system/mastodon-web.service.
Created symlink /etc/systemd/system/multi-user.target.wants/mastodon-sidekiq.service → /etc/systemd/system/mastodon-sidekiq.service.
Created symlink /etc/systemd/system/multi-user.target.wants/mastodon-streaming.service → /etc/systemd/system/mastodon-streaming.service.
Hello, I have used this gist to setup a mastodon hidden service. Everything other than email confirmation (which I do not want anyway) and logging in works. When attempting to log in, the login prompt in the web UI redisplays and states "You need to sign in or sign up before continuing." even though the user is signed up and (manually) confirmed.