Every centralized platform eventually changes its rules, its algorithm, or its ownership, and you find out about it the same day everyone else does. Mastodon, the open-source social network built on ActivityPub, lets you run your own server instead: your own moderation policy, your own uptime, your own data, while still talking to millions of accounts across the wider fediverse. The hard part has never been Mastodon itself, it is reaching it reliably from a domain that will still work in five years. This guide covers installing Mastodon with Docker Compose and exposing it correctly with Localtonet.
Why Run Your Own Corner of the Fediverse
Joining someone else's Mastodon instance solves the platform-ownership problem, but not the platform-dependency problem. Your account, your followers, and your posting history still live on infrastructure someone else controls, and that admin's decisions, downtime, and moderation calls become yours by default.
Running your own instance keeps every one of those decisions in your hands, while ActivityPub still lets you follow, and be followed by, accounts on every other Mastodon, Pixelfed, and Lemmy server out there.
You are not leaving the network, you are just hosting your own piece of it.
What Is Mastodon?
Mastodon is an open-source, AGPLv3-licensed social network built on Ruby on Rails, first released in 2016 by Eugen Rochko. It speaks ActivityPub, the same federation protocol behind Pixelfed and Lemmy, which is what lets independently run servers interoperate as one network instead of walled gardens.
Mastodon's Sidekiq background workers and media processing are the heaviest part of running it. Plan for at least 4GB of RAM and a 2-core CPU for a single-user instance, 8GB and 4 cores if you expect other people to sign up, plus 50GB of storage minimum. A single-user instance can run comfortably on hardware as modest as a Raspberry Pi 4 with 4GB of RAM.
Install Mastodon With Docker Compose
๐ Generate the required secrets
Mastodon needs three secret values before it will start: SECRET_KEY_BASE, OTP_SECRET, and a VAPID key pair for push notifications.
docker run --rm tootsuite/mastodon:v4.5.10 bundle exec rake secret
docker run --rm tootsuite/mastodon:v4.5.10 bundle exec rake secret
docker run --rm tootsuite/mastodon:v4.5.10 bundle exec rails mastodon:webpush:generate_vapid_key
Save all four values, you will paste them into your environment file next.
โ๏ธ Configure the environment file
Create .env.production with your domain, database, Redis, SMTP, and the secrets from the previous step. The LOCAL_DOMAIN value is the one setting you should treat as permanent, more on that below.
LOCAL_DOMAIN=mastodon.example.com
SECRET_KEY_BASE=your_generated_value
OTP_SECRET=your_generated_value
VAPID_PRIVATE_KEY=your_generated_value
VAPID_PUBLIC_KEY=your_generated_value
DB_HOST=db
DB_NAME=mastodon
DB_USER=mastodon
DB_PASS=your_db_password
REDIS_HOST=redis
SMTP_SERVER=your_smtp_host
SMTP_PORT=587
SMTP_LOGIN=your_smtp_user
[email protected]
๐ณ Start the stack
A minimal Docker Compose setup runs five services: db (Postgres), redis, web (the Rails app on port 3000), streaming (the WebSocket API on port 4000), and sidekiq (background jobs).
docker compose up -d db redis
docker compose run --rm web bundle exec rails db:migrate
docker compose up -d
Remote Access With Localtonet
Mastodon's own documentation notes that the streaming API can run on its own subdomain, which avoids needing a local reverse proxy just to split traffic between the two services. That maps directly onto two separate Localtonet HTTP tunnels, each with a custom domain and free auto-provisioned HTTPS.
Point your DNS at Localtonet
Create records for both mastodon.example.com and streaming.example.com using Localtonet's DNS Manager, or your own DNS provider if you manage records elsewhere.
Tunnel the web service
Create an HTTP tunnel at localtonet.com/tunnel/http pointing to 127.0.0.1:3000, and map mastodon.example.com to it as a custom domain.
Tunnel the streaming service
Create a second HTTP tunnel pointing to 127.0.0.1:4000, mapped to streaming.example.com.
Set STREAMING_API_BASE_URL
In .env.production, add STREAMING_API_BASE_URL=wss://streaming.example.com so Mastodon's own web client knows where to open its WebSocket connection, then restart the stack.
Once other servers have federated with your instance under a given domain, changing LOCAL_DOMAIN breaks that federation history, your account identity is tied to the domain, not just a database row. Decide on your domain before your first post goes out, not after.
๐ Security and Moderation
๐ Turn on two-factor authentication
Enable 2FA on your own account from the security settings the moment setup finishes, before you invite anyone else or start posting.
๐ค Consider single-user mode
If this instance is just for you, single-user mode disables public registration entirely and redirects the homepage straight to your profile, removing an entire category of moderation work.
๐ซ Federation is a moderation tool too
You can block or limit federation with specific servers at the instance level, not just mute individual accounts. Use it if a server is a consistent source of abuse toward your instance.
๐ Keep Mastodon updated
Security patches land in point releases regularly. Follow the project's own account for release notifications, and budget time for the database migration step that follows most upgrades.
Keep It Running Permanently
Set restart: unless-stopped on every service in your Docker Compose file so the stack survives a Docker restart. For the tunnels themselves to survive a full machine reboot, install the Localtonet client as a service once with localtonet --install-service --start-service, both custom domains come back automatically without you touching anything.
Self-Hosted Mastodon vs. an Existing Instance vs. Twitter/X
| Feature | Twitter / X | Joining an existing instance | Self-hosted Mastodon |
|---|---|---|---|
| Who sets the moderation rules | The company | That instance's admin | You |
| Account portability | None | Possible, but you rely on that server staying up | Full control over uptime and history |
| Cost | Free tier with ads, paid tiers for more | Usually free or a small donation | Your own hosting, roughly the cost of a small VPS or spare hardware |
| Setup effort | None | None | An evening, plus ongoing maintenance |
The honest trade-off: joining an existing, well-run instance is genuinely the lower-effort path into the fediverse, someone else handles updates, moderation, and uptime for you. Self-hosting is worth the extra effort specifically when you want your account identity, your moderation policy, and your uptime to answer to no one but you.
๐ Tips for Running a Healthy Instance
Troubleshooting Common Issues
| Symptom | Likely cause | Fix |
|---|---|---|
| Blocked hosts error in the browser | The domain you are visiting is not in Rails' allowed host list | Confirm LOCAL_DOMAIN in .env.production matches the domain you mapped to the tunnel exactly |
| Live timeline never updates | The web client cannot reach the streaming service | Confirm STREAMING_API_BASE_URL points to the streaming tunnel's domain and that tunnel is running |
| No confirmation or password reset emails | SMTP is not configured or credentials are wrong | Test SMTP settings directly with a mail testing tool before assuming Mastodon itself is broken |
| Database migration fails during an upgrade | Insufficient RAM during asset precompilation | Add temporary swap space or upgrade RAM before running the migration step |
Frequently Asked Questions
Can I change my instance's domain later?
Not without breaking federation history. Your account identity on the fediverse is tied to your domain, so pick one you intend to keep for good before you start posting.
Do I need two separate domains for a working instance?
No, a single domain with a local reverse proxy routing paths works too. Two domains, one for the web app and one for streaming, is simply the path Mastodon's own documentation describes as avoiding extra proxy overhead, and it maps cleanly onto two Localtonet tunnels.
How much does self-hosting Mastodon cost?
Mastodon itself is free and open source. Your actual cost is whatever hardware or VPS you run it on, plus optional S3 storage if you offload media, roughly what a small VPS costs per month if you are not already running suitable hardware.
Will my instance be able to follow accounts on mastodon.social or other servers?
Yes. ActivityPub federation works the same way regardless of who runs the server, your instance and any other Mastodon, Pixelfed, or Lemmy server can follow and interact with each other by default.
Do I need to run this for multiple users?
No. Single-user mode is a supported, first-class configuration that disables public registration and points the homepage at your own profile.
Does my server need to stay online all the time?
Federated posts are delivered asynchronously, so brief downtime does not lose data, but extended downtime delays delivery and can affect how other servers see your instance's reliability. Running the stack and the Localtonet client as background services keeps this from being a manual chore.
Is Mastodon hard to keep updated?
Updating means pulling new container images and running a database migration, which is straightforward but can be memory-intensive during asset precompilation. Budget a maintenance window and enough RAM or swap for the migration step.
Ready to Run Your Own Corner of the Fediverse?
Deploy Mastodon with Docker Compose, then reach it through a permanent custom domain with Localtonet, no port forwarding, no server rental. Free to start, no credit card required.
Get Started Free โ