How to Install Mastodon on Ubuntu 24

Mastodon is a decentralised social network that operates on an open-source framework belonging to the ActivityPub “fediverse.” Unlike typical social media platforms that are centralised, Mastodon allows you to set up your own instance while interacting with users from a multitude of other Servers. This guide will help you establish your own Mastodon instance on Ubuntu 24, granting you full authority over your community’s data management, moderation strategies, and available features. The installation process will be covered thoroughly, including common troubleshooting tips to ease your setup experience.
Understanding Mastodon’s Functionality
Mastodon is constructed with Ruby on Rails and has a React-based frontend, utilising PostgreSQL for data storage and Redis for caching and live functionalities. Its architecture includes various interacting components:
- Web Process: Manages HTTP requests and delivers the web interface
- Streaming API: Facilitates real-time updates via WebSockets
- Sidekiq Workers: Handle background tasks such as federation, email dispatching, and media processing
- PostgreSQL: Houses all application data including posts, account details, and connections
- Redis: Responsible for caching, session storage, and managing job queues
- Elasticsearch: Enables full-text search capabilities (optional but advised)
The system’s federation feature relies on ActivityPub, allowing your instance to interact with other Mastodon Servers and compatible platforms like PeerTube, Pixelfed, and Pleroma. When a user from your instance follows someone on another server, your instance subscribes to their updates.
System Requirements and Prerequisites
Before getting started with the installation, let’s outline the necessary requirements. Mastodon is relatively resource-intensive, especially if planning to federate with multiple instances.
Component | Minimum | Recommended | Notes |
---|---|---|---|
RAM | 2GB | 4GB+ | More required for larger instances |
CPU | 1 core | 2+ cores | Background processes benefit from additional cores |
Storage | 10GB | 50GB+ | Media files can accumulate rapidly |
Bandwidth | Unmetered | Unmetered | Federation generates considerable traffic |
Additionally, you’ll need a domain name directed towards your server, and an email service for user communication is recommended. Let’s begin with a clean installation of Ubuntu 24.04.
Step-by-Step Installation Instructions
Step 1: Update System and Install Basic Dependencies
To start, make sure your system is up-to-date and install the essential packages:
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget gnupg apt-transport-https lsb-release ca-certificates
Step 2: Install Node.js and Yarn
Mastodon needs Node.js 18+ and Yarn for frontend asset compilation:
# Install Node.js 20.x
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
Install Yarn
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update && sudo apt install -y yarn
Step 3: Install and Configure PostgreSQL
PostgreSQL is essential for storing your Mastodon data:
sudo apt install -y postgresql postgresql-contrib libpq-dev
sudo -u postgres createuser --createdb mastodon
sudo -u postgres psql
While in the PostgreSQL prompt, set up your database:
\password mastodon
CREATE DATABASE mastodon_production OWNER mastodon;
\q
Step 4: Install Redis
Redis will manage caching and help with background job queues:
sudo apt install -y redis-server
sudo systemctl enable redis-server
sudo systemctl start redis-server
Step 5: Install Ruby Using rbenv
You need a specific Ruby version for Mastodon, and using rbenv allows better version management:
# Create mastodon user
sudo adduser --disabled-login mastodon
Switch to mastodon user
sudo su - mastodon
Install rbenv
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
exec bash
Install ruby-build
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
Install Ruby 3.2.2 (check Mastodon documentation for the current version)
rbenv install 3.2.2
rbenv global 3.2.2
Install bundler
gem install bundler --document
Step 6: Download and Configure Mastodon
Still logged in as the mastodon user:
cd ~
git clone https://github.com/mastodon/mastodon.git live
cd live
git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)
Install Ruby and Node.js dependencies:
bundle config deployment 'true'
bundle config without 'development test'
bundle install -j$(getconf _NPROCESSORS_ONLN)
yarn install --pure-lockfile
Step 7: Configure Mastodon
Generate the configuration file:
RAILS_ENV=production bundle exec rake mastodon:setup
This interactive setup will prompt you for:
- Your domain name
- Database connection particulars
- Redis connection particulars
- Email settings (SMTP configuration)
- File storage options (local or cloud)
The setup process generates a .env.production
file containing your settings. Here’s what a standard configuration appears like:
# Domain and URLs
LOCAL_DOMAIN=your-domain.com
WEB_DOMAIN=your-domain.com
Database
DB_HOST=localhost
DB_PORT=5432
DB_NAME=mastodon_production
DB_USER=mastodon
DB_PASS=your_password
Redis
REDIS_HOST=localhost
REDIS_PORT=6379
SMTP
SMTP_SERVER=smtp.your-provider.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=your_smtp_password
[email protected]
Security keys (generated by setup)
SECRET_KEY_BASE=very_long_random_string
OTP_SECRET=another_long_random_string
Step 8: Set Up Systemd Services
Return to your standard user account, then create systemd service files. Start with the web service:
sudo nano /etc/systemd/system/mastodon-web.service
[Unit]
Description=mastodon-web
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=3000"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
ExecReload=/bin/kill -SIGUSR1 $MAINPID
TimeoutSec=15
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Create the streaming service:
sudo nano /etc/systemd/system/mastodon-streaming.service
[Unit]
Description=mastodon-streaming
After=network.target
[Service]
Type=simple
User=mastodon
WorkingDirectory=/home/mastodon/live
Environment="RAILS_ENV=production"
Environment="PORT=4000"
ExecStart=/usr/bin/node ./streaming
TimeoutSec=15
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Establish the Sidekiq service for background processes:
sudo nano /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=25"
ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25
TimeoutSec=15
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Step 9: Configure Nginx
Install Nginx and set up the reverse proxy:
sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/mastodon
Here’s a production-ready Nginx configuration:
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/mastodon clean_time=30d levels=2 keys_zone=mastodon:10m max_size=1g;
server { listen 80; listen [::]:80; server_name your-domain.com; root /home/mastodon/live/public; location /.well-known/acme-challenge/ { allow all; } location / { return 301 https://$host$request_uri; } }
server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name your-domain.com;
ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; # SSL certificates (configure after obtaining Let's Encrypt certs) ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; keepalive_timeout 70; sendfile on; client_max_body_size 99m; root /home/mastodon/live/public; gzip on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/atom+xml image/svg+xml; location / { try_files $uri @proxy; } location ~ ^/(emoji|packs|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; try_files $uri @proxy; } location /sw.js { add_header Cache-Control "public, max-age=604800, must-revalidate"; 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 mastodon; 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; tcp_delay 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_delay on; } error_page 500 501 502 503 504 /500.html;
}
Enable the site and create the cache directory:
sudo ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/ sudo mkdir -p /var/cache/nginx/mastodon sudo chown www-data:www-data /var/cache/nginx/mastodon sudo nginx -t
Step 10: Set Up SSL Certificates
For Let’s Encrypt SSL certificates, install Certbot:
sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx -d your-domain.com
Configure automatic renewal:
sudo crontab -e # Add this line: 0 12 * * * /usr/bin/certbot renew --quiet
Step 11: Activate All Services
Enable and launch all Mastodon services:
sudo systemctl daemon-reload sudo systemctl enable mastodon-web mastodon-streaming mastodon-sidekiq nginx sudo systemctl start mastodon-web mastodon-streaming mastodon-sidekiq nginx
Verify that everything is operational:
sudo systemctl status mastodon-web mastodon-streaming mastodon-sidekiq nginx
Creating Your First Admin Account
To utilise your instance, you need to create an admin account:
sudo su - mastodon cd live RAILS_ENV=production bin/tootctl accounts create yourusername --email [email protected] --confirmed --role Owner
This will generate a temporary password, which can be changed through the web interface once you log in.
Common Problems and Solutions
Memory-Related Issues
For smaller VPS setups, memory issues may arise. Here are a few optimisation tips:
# Lower Sidekiq concurrency in .env.production DB_POOL=5 # Update the systemd service accordingly
You might also consider adding swap space:
sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Federation-Related Issues
If federation encounters issues, check for common pitfalls:
- Ensure your domain’s SSL certificate is valid and reachable
- Confirm that the streaming service is operational and reachable
- Inspect firewall settings for outbound HTTPS permissions
- Look at Sidekiq logs for failures in federation jobs
# Verify federation status
sudo su - mastodon
cd live
RAILS_ENV=production bin/tootctl self-destruct --dry-run
Monitoring Performance
Keep track of your instance’s performance with these commands:
# Service status checks
systemctl status mastodon-*
Resource usage monitoring
htop
Database performance analysis
sudo -u postgres psql mastodon_production -c "SELECT schemaname,tablename,attname,n_distinct,correlation FROM pg_stats WHERE tablename='statuses';"
Evaluate Sidekiq queues
sudo su - mastodon
cd live
RAILS_ENV=production bin/tootctl statuses count
Mastodon in Comparison with Other Platforms
Here’s how Mastodon compares to other fediverse platforms:
Platform | Language | Resource Use | Features | Ideal For |
---|---|---|---|---|
Mastodon | Ruby/Rails | High | Feature-rich, similar to Twitter | Large communities |
Pleroma | Elixir | Low | Lightweight and customisable | Smaller instances |
Misskey | Node.js | Medium | Distinctive UI, interactions | Creative communities |
GoToSocial | Go | Very Low | API-focused | Personal instances |
Best Practices and Security Tips
Enhancing Security
Consider implementing these security measures for better protection:
# Activate the firewall
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
Install and set up fail2ban
sudo apt install -y fail2ban
sudo systemctl enable fail2ban
Create a fail2ban configuration for Mastodon:
sudo nano /etc/fail2ban/jail.local
[mastodon]
enabled = true
port = http,https
filter = mastodon
logpath = /home/mastodon/live/log/production.log
maxretry = 5
bantime = 3600
Backup Strategy
Execute regular backups with the following script:
#!/bin/bash
# backup-mastodon.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/home/backups/mastodon"
Database backup
sudo -u postgres pg_dump mastodon_production > $BACKUPDIR/db$DATE.sql
Media files backup
tar -czf $BACKUPDIR/media$DATE.tar.gz /home/mastodon/live/public/system
Configuration backup
cp /home/mastodon/live/.env.production $BACKUPDIR/env$DATE.backup
Cleanup old backups (retain 7 days)
find $BACKUP_DIR -name ".sql" -mtime +7 -delete
find $BACKUP_DIR -name ".tar.gz" -mtime +7 -delete
Monitoring and Maintenance
Establish log rotation and monitoring:
# Add to /etc/logrotate.d/mastodon
/home/mastodon/live/log/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
copytruncate
su mastodon mastodon
}
Real-World Use Cases and Performance Data
From actual deployments, here’s what performance looks like:
- Small instance (10-50 users): 2GB RAM, 1 CPU core, ~500MB daily federation traffic
- Medium instance (100-500 users): 4GB RAM, 2 CPU cores, ~2GB daily federation traffic
- Large instance (1000+ users): 8GB+ RAM, 4+ CPU cores, ~10GB+ daily federation traffic
A typical small instance federating with major instances like mastodon.social may observe:
- ~50,000 federation jobs daily
- Database expansion by ~100MB monthly
- Media storage increasing by ~1GB each month (with media retention policies)
Performance tuning becomes vital as your instance grows. Consider using external media storage, such as S3-compatible services, and implementing CDN caching for static files.
For comprehensive documentation and updates, refer to the Mastodon documentation and the GitHub repository. The community maintains additional resources at Fediverse.info for a broader ecosystem overview.
Your Mastodon instance now should be operational and ready to connect with the wider fediverse. Running a social media platform is an ongoing responsibility that involves regular updates, moderation, and community involvement. Begin small, master the processes, and expand as your community evolves.
This article uses information and resources from various online platforms. We recognise and appreciate the contributions of all original authors, publishers, and sites. Efforts have been made to credit the source material properly; any unintentional oversights or omissions shall not constitute copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe any content in this article infringes upon your copyright, please contact us for review and prompt action.
This article is for informational and educational purposes only and does not infringe on the rights of copyright holders. Should any copyrighted material be utilized without proper attribution or in violation of copyright law, this is unintentional and will be rectified promptly upon notification. Please note that republishing, redistribution, or reproduction of any part or all of the content in any form is forbidden without express written consent from the author and website owner. For permissions or further inquiries, please reach out to us.