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.
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.
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.
RAM: 4GB minimum (8G+ recommended and scale as your server grows)
Disk Space: 60G (scale as you grow)
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
docker network create testnet
Of course change "testnet" to whatever you want to call your docker network. Adjust later in the mastodon docker command.
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
A series of keys are required for Mastodon to function which are:
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!
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!
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:

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.

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.
First find a relay you want at a place like 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.

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.
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,