How To Deploy Your Own Mastodon Server in Docker

This is based off the LinuxServer Mastodon Image and I believe this simplifies the bare basics of get things going because Mastodon is fairly complex but well worth the effort.

Why Mastodon?

For me, it's about having social freedom, when you use big tech there are MANY negative things that happen.

1.) They tap and mine all of your data for profit.

2.) You have 0 privacy and 0 benefits (no possible profits).

3.) 0 control over your social future, they can shadow ban you, content strike you, or directly ban or delete you at any point for any reason with 0 recourse.

4.) If you get hacked there is 0 recourse or at least not timely recovery.  Some argue that some of the "big tech" platforms are made to be exploited and some report never getting back in.

With Mastodon you are now in control of your own social future, if you get hacked just redeploy your Mastodon server, no worrying about Zombie account run by hackers/state actors is being used to target and hack your contacts.

And finally no one can really censor you, perhaps some of the Mastodon servers could try to blacklist you but your contacts can always connect to you and see your posts no matter what happens.

Prerequisites

https://docs.joinmastodon.org/user/run-your-own/

1.) Docker

If you need to learn about Docker follow our tutorial here.

2.) A domain name.  Buy one if you don't have one already.

3.) A public IP that your domain points to with a DNS A Record.

4.) A server to run Docker on, many will start by using a VPS.

Technical Prequisities:

  1. Redis DB
  2. PostgreSQL DB
  3. Separate Network in Docker

RAM: 4GB minimum (8G+ recommended and scale as your server grows)

Disk Space: 60G (scale as you grow)

Here are the stats on my single user Mastodon server with several posts:

We can see it uses about 1.2G of RAM.


CONTAINER ID   NAME                 CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O        PIDS
123   mymasto   0.75%     1.203GiB / 488.7GiB   0.64%     13.1MB / 6.99MB   3.76MB / 235MB   89

 

Getting Started

Step 1.) Create Private Mastodon Docker Network

docker network create testnet

Of course change "testnet" to whatever you want to call your docker network.  Adjust later in the mastodon docker command.

Step 2.) Setup our Redis and PostgreSQL Docker Containers

PostgreSQL Setup:

docker run -d \
  --name=db \
  --network=testnet \
  -e POSTGRES_DB=mastodon \
  -e POSTGRES_USER=mastodon \
  -e POSTGRES_PASSWORD=mastodon \
  -v $(pwd)/postgres-data:/var/lib/postgresql/data \
  --restart unless-stopped \
  postgres:15-alpine

Redis container Setup:

docker run -d --name=redis --network=testnet redis:7-alpine 

Step 3.) Create Keys!

A series of keys are required for Mastodon to function which are:

  • secret key base
  • otp secret

  • VAPID Private Key
  • VAPID Public Key

  • ACTIVE Record Deterministic Key
  • ACTIVE Record Key Derivation Salt
  • ACTIVE Record Primary Key

What we will do is create those keys and then assign them as variables in our shell/terminal so the command I provide "just works".

Create secret key base and otp secret:

secretkeybase=`openssl rand -hex 32`
otpsecret=`openssl rand -base64 24 | tr -d '+/=' | cut -c1-32`


Create VAPID Keys

docker run --rm -it --entrypoint /bin/bash lscr.io/linuxserver/mastodon:latest generate-vapid
VAPID_PRIVATE_KEY=L0NFoPp88NF1Bztfm6oB5av8CCxRTdtC0TotPq2l0sM=
VAPID_PUBLIC_KEY=BCpd6zkBm2vAlYOcLLm3xDh0Nwoqn1-iFHk4Ga2_MbKOuPg4qu9oMaYB11AEFjIYwMO9unHuweexmn5-_Qt3mek=

Copy and paste your output/those variables above to your shell or the next steps will not work.  Do not copy our example above!


Create Active Record Keys

docker run --rm -it --entrypoint /bin/bash lscr.io/linuxserver/mastodon:latest generate-active-record
Add the following secret environment variables to your Mastodon environment (e.g. .env.production), ensure they are shared across all your nodes and do not change them after they are set: 

# Do NOT change these variables once they are set
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=d32iIjMgcSeePIwKGTHo699SO6VZE1br
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=7C1l6CGfAF5phaHZ1xeMP9DY5UN9VyOm
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=ey66K7Rpz40iMXdTqkn3DWGOxf62wEvX

 

Copy and paste your output/those variables above to your shell or the next steps will not work.  Do not copy our example above!

Let's start Mastodon!

Remember to update --network=testnet if your network is not "testnet".

Update local_domain and web_domain to "thedomain.com" that you bought and pointed to your server.

 

docker run -d \
  --network=testnet \
  --name=mastodon \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Etc/UTC \
  -e LOCAL_DOMAIN=example.com \
  -e REDIS_HOST=redis \
  -e REDIS_PORT=6379 \
  -e DB_HOST=db \
  -e DB_USER=mastodon \
  -e DB_NAME=mastodon \
  -e DB_PASS=mastodon \
  -e DB_PORT=5432 \
  -e ES_ENABLED=false \
  -e ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY="$ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY" \
  -e ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY="$ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY" \
  -e ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT="$ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT" \
  -e SECRET_KEY_BASE="$secretkeybase" \
  -e OTP_SECRET="$otpsecret" \
  -e VAPID_PRIVATE_KEY="$VAPID_PRIVATE_KEY" \
  -e VAPID_PUBLIC_KEY="$VAPID_PUBLIC_KEY" \
  -e SMTP_SERVER=mail.example.com \
  -e SMTP_PORT=25 \
  -e SMTP_LOGIN= \
  -e SMTP_PASSWORD= \
  -e SMTP_FROM_ADDRESS=notifications@example.com \
  -e S3_ENABLED=false \
  -e WEB_DOMAIN=mastodon.example.com `#optional` \
  -p 80:80 \
  -p 443:443 \
  -p 9394:9394 `#optional` \
  -v /path/to/mastodon/config:/config \
  --restart unless-stopped \
  lscr.io/linuxserver/mastodon:latest

 

If this Mastodon is ONLY for you, then I recommend setting this environment variable too:

  -e SINGLE_USER_MODE=true

That makes it so the server is in single user mode, so when you visit mastodon.example.com your main Mastodon/root page it will show all of your posts, otherwise users will see nothing unless they know your explicit account name/handle.
 

If all went well, you should be able to browse to "yourdomain.com" and see something like below:

 

 

Configure Your Mastodon Account

First create your admin user account and change "yourusername" to the username you want and of course "you@mail.com" to your e-mail address.

docker exec -it mastodon /tootctl accounts create yourusername --email you@mail.com --confirmed --role Owner
INFO  2026-02-09T07:16:55.002Z pid=759 tid=1xj: Sidekiq 8.0.9 connecting to Redis with options {size: 10, pool_name: "internal", url: "redis://redis:6379/0", driver: :hiredis}
OK
New password: yourautocreatedpass
 

The account won't work until you set it to "approved":

docker exec -it mastodon /tootctl accounts modify youruser --approve
OK

 

After that go to your mastodon domain and click login, use the e-mail address you set and the autogenerated password from earlier.

 

Example of my Mastodon home page with single user mode enabled.

 

 

What Next?

Aside from posting, you may want to join some relays to help blast out your posts to other Mastodon servers.  Visibility will mainly be determined by hashtag #s.

How to add a relay

First find a relay you want at a place like relaylist.com

https://relaylist.com/

Copy and paste the URL that says "Mastodon Endpoint" eg. below you would use "https://relay.toot.io/inbox" don't just use the raw relay.toot.io as that is not the right URL and you will not get added if you use that wrong non Mastodon endpoint URL.

 

Go to your admin panel, then click "Administration" and then "Relays" and click the "Add new relay" button.

Now click "Add new relay"

 

 

Paste the URL of the relay endpoint and click "Save and Enable"

Now you can see your relay status and which ones are approved/active.

More Servers

You can search content aggregators like https://joinmastodon.org/servers to find other servers of like minded people and then follow them and start commenting to get found.   You can still comment and follow users from other servers even though you are not part of their server since "Mastodon's talk to each other".

Of course use any legacy/censored social media platforms to let all of your friends know about your Mastodon and encourage them to get their own.  Even without your own server, such as joining mastodon.social is much better because you can at least save and export your account at any point which means you have full control over your content and can restore at will on your own Mastodon or another Mastodon server.

 

 


Tags:

deploy, mastodon, server, dockerthis, linuxserver, simplifies, basics, benefits, profits, ban, content, delete, recourse, hacked, timely, quot, platforms, exploited, redeploy, hackers, actors, hack, contacts, sensor, servers, blacklist, posts, prerequisites, https, docs, joinmastodon, org, user, docker, tutorial, domain, ip, dns, vps, technical, prequisities, redis, db, postgresql, ram, gb, recommended, grows, disk, testnet, adjust, containers, postgres_db, postgres_user, postgres_password, pwd, postgres, var, lib, restart, alpine, container, otp, vapid, active, deterministic, derivation, primary, assign, variables, shell, terminal, secretkeybase, openssl, rand, hex, otpsecret, tr, rm, entrypoint, bin, bash, lscr, io, generate, vapid_private_key, nfopp, nf, bztfm, ob, av, ccxrtdtc, totpq, sm, vapid_public_key, bcpd, zkbm, valyocllm, xdh, nwoqn, ifhk, ga, _mbkoupg, qu, omayb, aefjiywmo, unhuweexmn, _qt, mek, output, env, ensure, nodes, active_record_encryption_deterministic_key, iijmgcseepiwkgtho, vze, br, active_record_encryption_key_derivation_salt, cgfaf, phahz, xemp, dy, vyom, active_record_encryption_primary_key, ey, rpz, imxdtqkn, dwgoxf, wevx, update, local_domain, web_domain, thedomain, pointed, puid, pgid, tz, etc, utc, redis_host, redis_port, db_host, db_user, db_name, db_pass, db_port, es_enabled, secret_key_base, otp_secret, smtp_server, smtp_port, smtp_login, smtp_password, smtp_from_address, notifications, _enabled, optional, config, browse, yourdomain,

Latest Articles

  • Virtualbox VBox Guest-utils drag and drop files stops working with Windows VMs
  • How To Remove Ubuntu Netplan and Go Back to /etc/network/interfaces
  • How To Force Flash an AMD Instinct GPU To Another Model Using Debian Ubuntu Mint Linux
  • How To compile ollama from source to use unsupported AMD GPU with rocm in Ubuntu Debian
  • QEMU KVM Virtio GPU Windows Cannot Select 1080P
  • Linux Gnome Desktop Ubuntu Mint Debian Gets Slower After Weeks
  • Firefox How to Save Full Page As Screenshot/PDF
  • Nvidia Datacenter Driver Tesla Slow nvidia-smi response and high utilization with 0 usage
  • ffmpeg how to normalize / increase the volume of your audio
  • kdenlive audio blips pops cracks artifacts solution fix
  • haproxy / nginx certbot SSL issues
  • nginx how to see the real IP when behind a CDN
  • Docker how to find real container child process ID
  • Alibaba Aliyun how to reset password solution 'Setup does not meet the requirements, please resetting'
  • RTL88X Series 80Mhz hostapd mode for Linux Debian Kali
  • How To Deploy Your Own Mastodon Server in Docker
  • ffmpeg burning subtitles in non-English errors [Parsed_subtitles_0 @ 0x561d3a0b3b80] Glyph 0x6709 not found, selecting one more font for (Sans, 700, 0)
  • rsyslog in container config
  • Interesting Whisper AI CPU vs GPU Test
  • How to install pytorch with cuda capability for AI acceleration with Nvidia Tesla etc.. GPUs