How to Install Mastodon Social Network with Docker on Ubuntu 22.04 LTS
Mastodon is free and open-source software for running self-hosted social networking services. It's a decentralized social network made up of independent servers organized around specific themes, topics, or interests.
Prerequisites
- A system with Ubuntu 22.04 and root access.
- Server requires a minimum of 2 CPU cores and 2GB of memory.
- Users receive email notifications from Mastodon. Using a third-party transactional mail service like Mailgun, Sendgrid, Amazon SES, or Sparkpost is something we strongly advise. Amazon SES will be used in the instructions in this wiki.
Update the System
Update the system to the latest with the following commands,
apt update
apt upgrade
Install some of the basic utility packages that would be used later in the installation,
apt install wget curl nano software-properties-common dirmngr apt-transport-https gnupg gnupg2 ca-certificates lsb-release ubuntu-keyring unzip -y
Configure Firewall
We will now enable Firewall and allow HTTP and HTTPS ports which are needed to allow public connection to the site.
ufw status
Output:
root@vps:~# ufw status
Status: inactive
Since the UFW
is inactive, we will enable the firewall. And at the same time, we would also need to allow port for OpenSSH so we don't loose our SSH connection to the server.
This can be done with the following command,
ufw allow OpenSSH
Allow both HTTP and HTTPS ports,
ufw allow http
ufw allow https
Enable the Firewall, press Y
key when prompted for confirmation,
ufw enable
Output:
root@vps:~# ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? Y
Firewall is active and enabled on system startup
Now, Check the status of the firewall again it should be active now
ufw status
Output:
root@vps:~# ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
80/tcp ALLOW Anywhere
443 ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443 (v6) ALLOW Anywhere (v6)
Install Docker and Docker Compose
Docker is shipped with an outdated version in Ubuntu 22.04. Import the Docker GPG key first before installing the most recent version.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
Create Docker repository file.
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Update the system repository list.
apt update
Install the latest version of Docker,
apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Preparing for Installation
For Elasticsearch, the mmap
counts have a relatively low default limit. Run the next command to verify the default setting,
sysctl vm.max_map_count
output:
root@vps:sysctl vm.max_map_count
vm.max_map_count = 65530
The following commands can be used to increase mmap
numbers,
echo "vm.max_map_count=262144" | sudo tee /etc/sysctl.d/90-max_map_count.conf
sysctl --load /etc/sysctl.d/90-max_map_count.conf
Install Mastodon
Make Directories and Configure Ownerships
Create directories for Mastodon and related services,
mkdir -p /opt/mastodon/database/{postgresql,pgbackups,redis,elasticsearch}
mkdir -p /opt/mastodon/web/{public,system}
mkdir -p /opt/mastodon/branding
access to the web, backup, and elasticsearch directories,
chown 991:991 /opt/mastodon/web/{public,system}
chown 1000 /opt/mastodon/database/elasticsearch
chown 70:70 /opt/mastodon/database/pgbackups
Now, Switch to the Mastodon directory,
cd /opt/mastodon
Create environment and docker compose files
Create an empty environment for the application and database,
touch application.env database.env
Create and open the Docker compose file for editing.
nano docker-compose.yml
Add the following content into Docker compose file docker-compose.yml
file and save it.
version: '3'
services:
postgresql:
image: postgres:15-alpine
env_file: database.env
restart: always
shm_size: 512mb
healthcheck:
test: ['CMD', 'pg_isready', '-U', 'postgres']
volumes:
- postgresql:/var/lib/postgresql/data
- pgbackups:/backups
networks:
- internal_network
redis:
image: redis:7-alpine
restart: always
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
volumes:
- redis:/data
networks:
- internal_network
redis-volatile:
image: redis:7-alpine
restart: always
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
networks:
- internal_network
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.7
restart: always
env_file: database.env
environment:
- cluster.name=elasticsearch-mastodon
- discovery.type=single-node
- bootstrap.memory_lock=true
- xpack.security.enabled=true
- ingest.geoip.downloader.enabled=false
- "ES_JAVA_OPTS=-Xms512m -Xmx512m -Des.enforce.bootstrap.checks=true"
- xpack.license.self_generated.type=basic
- xpack.watcher.enabled=false
- xpack.graph.enabled=false
- xpack.ml.enabled=false
- thread_pool.write.queue_size=1000
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
healthcheck:
test: ["CMD-SHELL", "nc -z elasticsearch 9200"]
volumes:
- elasticsearch:/usr/share/elasticsearch/data
networks:
- internal_network
ports:
- '127.0.0.1:9200:9200'
website:
image: tootsuite/mastodon:v4.1.2
env_file:
- application.env
- database.env
command: bash -c "bundle exec rails s -p 3000"
restart: always
depends_on:
- postgresql
- redis
- redis-volatile
- elasticsearch
ports:
- '127.0.0.1:3000:3000'
networks:
- internal_network
- external_network
healthcheck:
test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:3000/health || exit 1']
volumes:
- uploads:/mastodon/public/system
shell:
image: tootsuite/mastodon:v4.1.2
env_file:
- application.env
- database.env
command: /bin/bash
restart: "no"
networks:
- internal_network
- external_network
volumes:
- uploads:/mastodon/public/system
- static:/static
streaming:
image: tootsuite/mastodon:v4.1.2
env_file:
- application.env
- database.env
command: node ./streaming
restart: always
depends_on:
- postgresql
- redis
- redis-volatile
- elasticsearch
ports:
- '127.0.0.1:4000:4000'
networks:
- internal_network
- external_network
healthcheck:
test: ['CMD-SHELL', 'wget -q --spider --proxy=off localhost:4000/api/v1/streaming/health || exit 1']
sidekiq:
image: tootsuite/mastodon:v4.1.2
env_file:
- application.env
- database.env
command: bundle exec sidekiq
restart: always
depends_on:
- postgresql
- redis
- redis-volatile
- website
networks:
- internal_network
- external_network
healthcheck:
test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"]
volumes:
- uploads:/mastodon/public/system
networks:
external_network:
internal_network:
internal:true:
volumes:
postgresql:
driver_opts:
type: none
device: /opt/mastodon/database/postgresql
o: bind
pgbackups:
driver_opts:
type: none
device: /opt/mastodon/database/pgbackups
o: bind
redis:
driver_opts:
type: none
device: /opt/mastodon/database/redis
o: bind
elasticsearch:
driver_opts:
type: none
device: /opt/mastodon/database/elasticsearch
o: bind
uploads:
driver_opts:
type: none
device: /opt/mastodon/web/system
o: bind
static:
driver_opts:
type: none
device: /opt/mastodon/web/public
o: bind
Mastodon's most recent release as of the time the guide was written was v4.1.2.
Check the Mastodon GitHub Releases page and make the necessary adjustments to the version in the Docker compose file. https://github.com/mastodon/mastodon/releases
Redis and PostgreSQL are both running at the most recent versions. They can be modified to meet your needs.
Currently, we are utilising Elasticsearch 7.x. Elasticsearch does not have a major version that you can follow on the Docker Hub website, therefore you will need to constantly manually updating it for Java security patches.
Create Application Secrets
Generate SECRET_KEY_BASE and OTP_SECRET values by running the following command twice. The first time will take some time as it will pull the images,
docker compose run --rm shell bundle exec rake secret
Run this commands for SSL utility,
openssl rand -hex 64
Generate VAPID_PRIVATE_KEY and VAPID_PUBLIC_KEY values by using the following command,
docker compose run --rm shell bundle exec rake mastodon:webpush:generate_vapid_key
Output:
VAPID_PRIVATE_KEY=fxkMuPKbR1LR2WQEGhPV7_NiE3WqnAzoJ2VC8C-6BoA=
VAPID_PUBLIC_KEY=BF_LJDJJyF-Rhji9OvIqErui2S_EpaAG9bn_TyMD3Jmqzz8ce5KJE7apfxZ0Cm6cR-_kTBxdjC90LaqNJClKBAw=
The openssl utility to generate PostgreSQL and Elasticsearch passwords.
openssl rand -hex 15
Mastodon Environment Files
Edit the application.env
file,
nano application.env
Add the following lines of code into application.env
file and save it.
# environment
RAILS_ENV=production
NODE_ENV=production
# domain
LOCAL_DOMAIN=mastodon.example.com
# redirect to the first profile
SINGLE_USER_MODE=false
# do not serve static files
RAILS_SERVE_STATIC_FILES=false
# concurrency
WEB_CONCURRENCY=2
MAX_THREADS=5
# pgbouncer
#PREPARED_STATEMENTS=false
# locale
DEFAULT_LOCALE=en
# email, not used
SMTP_SERVER=email-smtp.us-west-2.amazonaws.com
SMTP_PORT=587
SMTP_LOGIN=AES_USER
SMTP_PASSWORD=AES_PWD
SMTP_FROM_ADDRESS=noreply@example.com
# secrets
SECRET_KEY_BASE=c09fa403575e0b431e54a2e228f20cd5a5fdfdbba0da80598959753b829a4e3c0266eedbac7e3cdf9f3345db36c56302c0e1bc5bfc8c5d516be59a2c41de7e37
OTP_SECRET=febb7dbb0d3308094083733fc923a430e52ccec767d48d7d2e0c577bfcb6863dbdfc920b1004b1f8c2967b9866bd7a0b4a15460f9fc7687aa4a42acf54e5a3d4
# Changing VAPID keys will break push notifications
VAPID_PRIVATE_KEY=13RgrfOY2tkwuUycylDPOkoHennkJ0ZAPV_fUwDy7-g=
VAPID_PUBLIC_KEY=BDAQuGwPbh1kbCV904adYXHvz9lLRaJHkiQkihRDPyBn3QmkAYbR21WHYoP8TkyG6dylG6IXpEVfLwdoW7fJVns=
# IP and session retention
# -----------------------
# Make sure to modify the scheduling of ip_cleanup_scheduler in config/sidekiq.yml
# to be less than daily if you lower IP_RETENTION_PERIOD below two days (172800).
# -----------------------
IP_RETENTION_PERIOD=2592000
SESSION_RETENTION_PERIOD=2592000
LOCAL_DOMAIN -> Provide the actual domain name that you want the site on.
SECRET_KEY_BASE - OTP_SECRET - VAPID_PRIVATE_KEY - VAPID_PUBLIC_KEY -> Replace the keys with the newly generated keys from the previous step.
SMTP -> For the email settings, provide the SMTP logins from Amazon SES account. (you can leave it empty if you do not have an SMTP account)
Edit the database.env
file,
nano database.env
Add the following lines of code into database.env
file and save it.
# postgresql configuration
POSTGRES_USER=mastodon
POSTGRES_DB=mastodon
POSTGRES_PASSWORD=v9MPbqBYrA6VNEpfv9MPbqBYrA6VNEpf
PGPASSWORD=v9MPbqBYrA6VNEpfv9MPbqBYrA6VNEpf
PGPORT=5432
PGHOST=postgresql
PGUSER=mastodon
# pgbouncer configuration
#POOL_MODE=transaction
#ADMIN_USERS=postgres,mastodon
#DATABASE_URL="postgres://mastodon:v9MPbqBYrA6VNEpfv9MPbqBYrA6VNEpf@postgresql:5432/mastodon"
# elasticsearch
ES_JAVA_OPTS=-Xms512m -Xmx512m
ELASTIC_PASSWORD=cUzQVpD4Qr8wpt1fcUzQVpD4Qr8wpt1f
# mastodon database configuration
#DB_HOST=pgbouncer
DB_HOST=postgresql
DB_USER=mastodon
DB_NAME=mastodon
DB_PASS=v9MPbqBYrA6VNEpfv9MPbqBYrA6VNEpf
DB_PORT=5432
REDIS_HOST=redis
REDIS_PORT=6379
CACHE_REDIS_HOST=redis-volatile
CACHE_REDIS_PORT=6379
ES_ENABLED=true
ES_HOST=elasticsearch
ES_PORT=9200
ES_USER=elastic
ES_PASS=cUzQVpD4Qr8wpt1fcUzQVpD4Qr8wpt1f
In this configuration, we're creating the Database and related settings for it.
The Database name, username and password are all newly created using the above configuration.
Replace the above mentioned password of your choice and ensure it's strong and long.
Mastodon preparation
Prepare the static files so that Nginx can serve them. Because Docker will be pulling all the images for the first time during this stage, it will take some time,
docker compose run --rm shell bash -c "cp -r /opt/mastodon/public/* /static/"
open the data layer.
docker compose up -d postgresql redis redis-volatile
Verify the containers' state,
watch docker compose ps
When the database is running (healthy), hit Ctrl + C and use the following command to initialise it.
docker compose run --rm shell bundle exec rake db:setup
Install Ngnix
Download and install the most recent version from the official Nginx repository.
Import the Nginx GPG key,
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
Add the repository for Nginx's stable version.
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg arch=amd64] \http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
Then, update the system's apt repositories,
apt update
Install Nginx using the apt
package manager,
apt install nginx
Check the version
nginx -v
Start and Enable Nginx,
systemctl start nginx
systemctl enable nginx
Install Let’s Encrypt SSL Certificate
Let's issue an SSL certificate for the domain, for this we will need a snap package for Ubuntu operating system.
We will update and install the snap package on the system:
apt update
apt install -y snapd
snap install core && sudo snap refresh core
Next, with the help of snap, we will install the certbot client which is used to create Let's Encrypt certificates:
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot
Install SSL Certificate:
Use the certbot command to issue a Let's Encrypt certificate. The command will auto-detect the domains available or configured in the vHost configuration:
certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m name@example.com -d dev.domainhere.info
Replace name@example.com with your email address and the domain dev.domainhere.info with the actual domain.
Generate a Diffie-Hellman group certificate,
openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096
To check whether the SSL renewal is working fine, do a dry run of the process.
certbot renew --dry-run
If you see no errors, you are all set. Your certificate will renew automatically.
Setting up Nginx
Edit the file /etc/nginx/nginx.conf
nano /etc/nginx/nginx.conf
Before the line include /etc/nginx/conf.d/*.conf
in /etc/nginx/nginx.conf
add the following lines of code,
server_names_hash_bucket_size 64;
Open the file /etc/nginx/conf.d/mastodon.conf
for edit,
nano /etc/nginx/conf.d/mastodon.conf
Add the Following lines of code into /etc/nginx/conf.d/mastodon.conf
file and save it.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream backend {
server 127.0.0.1:3000 fail_timeout=0;
}
upstream streaming {
server 127.0.0.1:4000 fail_timeout=0;
}
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;
server {
listen 80 default_server;
server_name dev.domainhere.info;
location / { return 301 https://$host$request_uri; }
}
server {
listen 443 ssl http2;
server_name dev.domainhere.info;
access_log /var/log/nginx/mastodon.access.log;
error_log /var/log/nginx/mastodon.error.log;
http2_push_preload on; # Enable HTTP/2 Server Push
ssl_certificate /etc/letsencrypt/live/dev.domainhere.info/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dev.domainhere.info/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/dev.domainhere.info/chain.pem;
ssl_session_timeout 1d;
# Enable TLS versions (TLSv1.3 is required upcoming HTTP/3 QUIC).
ssl_protocols TLSv1.2 TLSv1.3;
# Enable TLSv1.3's 0-RTT. Use $ssl_early_data when reverse proxying to
# prevent replay attacks.
#
# @see: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data
ssl_early_data on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
keepalive_timeout 70;
sendfile on;
client_max_body_size 80m;
# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
add_header X-Early-Data $tls1_3_early_data;
root /opt/mastodon/web/public;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
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 image/svg+xml image/x-icon;
add_header Strict-Transport-Security "max-age=31536000" always;
location / {
try_files $uri @proxy;
}
location ~ ^/(system/accounts/avatars|system/media_attachments/files) {
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Strict-Transport-Security "max-age=31536000" always;
root /opt/mastodon/;
try_files $uri @proxy;
}
location ~ ^/(emoji|packs) {
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Strict-Transport-Security "max-age=31536000" always;
try_files $uri @proxy;
}
location /sw.js {
add_header Cache-Control "public, max-age=0";
add_header Strict-Transport-Security "max-age=31536000" always;
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 X-Forwarded-Proto $scheme;
proxy_set_header Proxy "";
proxy_pass_header Server;
proxy_pass http://backend;
proxy_buffering on;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_cache CACHE;
proxy_cache_valid 200 7d;
proxy_cache_valid 410 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
add_header X-Cached $upstream_cache_status;
add_header Strict-Transport-Security "max-age=31536000" always;
tcp_nodelay on;
}
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 X-Forwarded-Proto $scheme;
proxy_set_header Proxy "";
proxy_pass http://streaming;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
error_page 500 501 502 503 504 /500.html;
}
# This block is useful for debugging TLS v1.3. Please feel free to remove this
# and use the `$ssl_early_data` variable exposed by NGINX directly should you
# wish to do so.
map $ssl_early_data $tls1_3_early_data {
"~." $ssl_early_data;
default "";
}
Replace dev.domainhere.info with actual domain name you are using.
Use to check the Nginx configuration,
nginx -t
Restart the Ngnix Server,
systemctl restart nginx
Start Mastodon
Tootctl CLI tool On Mastodon, management operations are carried by using the Tootctl CLI tool. We must enable host shell access to it,
nano /usr/local/bin/tootctl
Add the following lines into /usr/local/bin/tootctl
#!/bin/bash
docker compose -f /opt/mastodon/docker-compose.yml run --rm shell tootctl "$@"
Grant the file permission,
chmod +x /usr/local/bin/tootctl
Mastodon Service File
The systemd unit file makes starting the Mastodon containers more simpler than using the Docker compose command,
nano /etc/systemd/system/mastodon.service
Add the following lines of code into/etc/systemd/system/mastodon.service
[Unit]
Description=Mastodon service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/mastodon
ExecStart=/usr/bin/docker compose -f /opt/mastodon/docker-compose.yml up -d
ExecStop=/usr/bin/docker compose -f /opt/mastodon/docker-compose.yml down
[Install]
WantedBy=multi-user.target
To start the service file, restart the system daemon,
systemctl daemon-reload
Enable and start the Mastodon service,
systemctl enable --now mastodon.service
Check the status of the Docker containers,
watch docker compose -f /opt/mastodon/docker-compose.yml ps
Make an admin user for Mastodon and make a note of the password,
root@vps:/opt/mastodon# tootctl accounts create navjot --email support@gmail.com --confirmed --role Owner
[+] Building 0.0s (0/0)
[+] Building 0.0s (0/0)
OK
New password: c9e34cd759a2c251ae75a75f6c4aed8a
Use the following command to close user registrations,
tootctl settings registrations close
Issue the following command to reopen the registrations,
tootctl settings registrations open
Initialize Search
Before you can create and populate Elasticsearch indexes, you must toot. Make a toot and then give the following order,
tootctl search deploy
Output:
root@vps:/opt/mastodon# tootctl search deploy
[+] Building 0.0s (0/0)
[+] Building 0.0s (0/0)
/opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/progress.rb:76:in `total=': You can't set the item's total value to less than the current progress. (ProgressBar::InvalidProgressError)
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/base.rb:178:in `block in update_progress'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/output.rb:43:in `with_refresh'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/base.rb:177:in `update_progress'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/ruby-progressbar-1.11.0/lib/ruby-progressbar/base.rb:101:in `total='
from /opt/mastodon/lib/mastodon/search_cli.rb:67:in `deploy'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/invocation.rb:116:in `invoke'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor.rb:243:in `block in subcommand'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/command.rb:27:in `run'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/invocation.rb:127:in `invoke_command'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor.rb:392:in `dispatch'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/thor-1.2.1/lib/thor/base.rb:485:in `start'
from /opt/mastodon/bin/tootctl:9:in `block in <main>'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/chewy-7.2.4/lib/chewy/strategy.rb:57:in `wrap'
from /opt/mastodon/vendor/bundle/ruby/3.0.0/gems/chewy-7.2.4/lib/chewy.rb:154:in `strategy'
from /opt/mastodon/bin/tootctl:8:in `<main>'
Enter the website container shell in that instance.
docker exec -it mastodon-website-1 /bin/bash
execute the upcoming command.
sed -E '/progress.total = /d' -i lib/mastodon/search_cli.rb
Then Exit the container shell,
exit
Additional Helper Services
Let's build another service for deleting media files that have been downloaded,
nano /etc/systemd/system/mastodon-media-remove.service
Add the following lines into /etc/systemd/system/mastodon-media-remove.service
file and save it.
[Unit]
Description=Mastodon - media remove service
Wants=mastodon-media-remove.timer
[Service]
Type=oneshot
StandardError=null
StandardOutput=null
WorkingDirectory=/opt/mastodon
ExecStart=/usr/bin/docker compose -f /opt/mastodon/docker-compose.yml run --rm shell tootctl media remove
[Install]
WantedBy=multi-user.target
You can set up a timer service for the media removal if you wish to arrange it,
nano /etc/systemd/system/mastodon-media-remove.timer
Add the Following Lines into /etc/systemd/system/mastodon-media-remove.timer
file and save it.
[Unit]
Description=Mastodon - preview cards remove service
Wants=mastodon-preview_cards-remove.timer
[Service]
Type=oneshot
StandardError=null
StandardOutput=null
WorkingDirectory=/opt/mastodon
ExecStart=/usr/bin/docker compose -f /opt/mastodon/docker-compose.yml run --rm shell tootctl preview_cards remove
[Install]
WantedBy=multi-user.target
The Rich preview cards created with OpenGraph tags can be deleted using a different service that you can set up,
nano /etc/systemd/system/mastodon-preview_cards-remove.service
Add the following lines into it /etc/systemd/system/mastodon-preview_cards-remove.service
file and save it.
[Unit]
Description=Mastodon - preview cards remove service
Wants=mastodon-preview_cards-remove.timer
[Service]
Type=oneshot
StandardError=null
StandardOutput=null
WorkingDirectory=/opt/mastodon
ExecStart=/usr/bin/docker compose -f /opt/mastodon/docker-compose.yml run --rm shell tootctl preview_cards remove
[Install]
WantedBy=multi-user.target
Select the appropriate timer service.
nano /etc/systemd/system/mastodon-preview_cards-remove.timer
Add the following lines into it /etc/systemd/system/mastodon-preview_cards-remove.timer
and save it.
[Unit]
Description=Schedule a preview cards remove every week
[Timer]
Persistent=true
OnCalendar=Sat *-*-* 00:00:00
Unit=mastodon-preview_cards-remove.service
[Install]
WantedBy=timers.target
Reload the system daemon.
systemctl daemon-reload
Enable and start the timers.
systemctl enable --now mastodon-preview_cards-remove.timer
systemctl enable --now mastodon-media-remove.timer
List all the timers to check the schedule of the Mastodon services.
systemctl list-timers
.....
Sat 2023-01-07 00:00:00 UTC 6 days left n/a n/a mastodon-media-remove.timer mastodon-media-remove.service
Sat 2023-01-07 00:00:00 UTC 6 days left n/a n/a mastodon-preview_cards-remove.timer mastodon-preview_cards-remove.service
Now, Access the Mastdon site on your browser https://domain.example.com/
As you can see in the screenshot above, there are two users, one is set to be the administrator. Typically, this is not the case. Even after creating an administrator account, it does not initially appear on the home page. You can do that by logging into your instance, which will then direct you to the next page.
To access the settings, select Preferences from the right sidebar. Access Mastodon's administration panel from there, select the Administration option from the left menu.
From the left sidebar, select the Site settings option.
Here, provide your contact username and professional email, which will now appear on the home page of your server. To further personalise your Mastodon instance, add many more fields such as the server description, logo, and rules.
This concludes the installation of Mastodon on a Ubuntu 22.04 Server.
CrownCloud - Get a SSD powered KVM VPS at $4.5/month!
Use the code WELCOME
for 10% off!
1 GB RAM / 25 GB SSD / 1 CPU Core / 1 TB Bandwidth per month
Available Locations: LAX | MIA | ATL | FRA | AMS