How to Join the Fediverse with GoToSocial (Your Own Mastodon-Compatible Server, on 100 MB of RAM)

Mastodon showed that social media can be a network of independent servers talking the same protocol (ActivityPub). Running full Mastodon at home is heavy — Ruby, Sidekiq, Redis, Postgres, gigabytes of RAM. GoToSocial speaks the same protocol in a single Go binary that idles at under 100 MB: your own @john@example.com, followed by and following anyone on Mastodon, Pixelfed, Lemmy or PeerTube, used from the Mastodon apps you already know. For one person or a family, it's the right size.
Quick reference
| Task | What |
|---|---|
| Folder | ~/docker/gotosocial/compose.yaml |
| Public name | social.example.com (or the bare domain with a well-known redirect) through the proxy, HTTPS |
| Create a user | docker compose exec gotosocial /gotosocial/gotosocial admin account create --username john --email … --password … |
| Apps | Tusky, Fedilab (Android); Ice Cubes, Ivory, Mona (iOS); Elk, Phanpy, Semaphore (web) |
| Media | ./storage; set storage-s3-* for MinIO (162) if you like |
| Visibility | default post visibility and "discoverable" per account; instance can be invite-only |
1. The compose file
mkdir -p ~/docker/gotosocial/{data,storage} && cd ~/docker/gotosocial
sudo chown -R 1000:1000 data storage
nano compose.yaml
services:
gotosocial:
image: superseriousbusiness/gotosocial:latest
container_name: gotosocial
user: 1000:1000
ports:
- "127.0.0.1:8085:8080"
environment:
GTS_HOST: social.example.com
GTS_DB_TYPE: sqlite
GTS_DB_ADDRESS: /gotosocial/storage/sqlite.db
GTS_LETSENCRYPT_ENABLED: "false"
GTS_TRUSTED_PROXIES: "172.16.0.0/12,127.0.0.1/32"
GTS_ACCOUNTS_REGISTRATION_OPEN: "false"
GTS_MEDIA_REMOTE_CACHE_DAYS: 7
TZ: Europe/London
volumes:
- ./data:/gotosocial/storage
- ./storage:/gotosocial/storage/media
restart: unless-stopped
SQLite is fine for a handful of accounts. GTS_HOST is permanent — like Matrix's server name (126), choose it once. Using the bare example.com as the handle while hosting on social.example.com is possible with GTS_ACCOUNT_DOMAIN and a /.well-known/webfinger redirect on the main site; the simpler path is to host it at the handle's domain.
docker compose up -d
2. Reverse proxy
social.example.com → 127.0.0.1:8085 with HTTPS, client_max_body_size 40M (uploads), and the forwarding headers (28). Federation needs it reachable from the internet — a Cloudflare Tunnel (109) works well here, since it's all HTTP.
Check: https://social.example.com/.well-known/nodeinfo returns JSON.
3. Create your account
docker compose exec gotosocial /gotosocial/gotosocial admin account create --username john --email john@example.com --password 'a-long-password'
docker compose exec gotosocial /gotosocial/gotosocial admin account confirm --username john
docker compose exec gotosocial /gotosocial/gotosocial admin account promote --username john
(The container's binary path may be /gotosocial/gotosocial; docker compose exec gotosocial ls /gotosocial to confirm.) promote makes you admin. More accounts for the family the same way; registration stays closed.
4. Log in from an app
GoToSocial has a settings page (/settings) for your profile, avatar, header, bio, default post visibility and the instance's rules — but no timeline UI of its own. Open a Mastodon app, choose "other instance", enter social.example.com, log in. Tusky/Ice Cubes/Phanpy show your home timeline, notifications, and let you post. Web: Phanpy or Elk at their sites, pointed at your instance.
Follow @someone@mastodon.social; they see a follow from @john@social.example.com and can follow back. Posts, replies, boosts, images with alt text, polls — all federate.
5. Moving from a big instance
On the old account (mastodon.social, say): Preferences → Account → Move to a different account, after setting your new account as an alias (/settings → Migration → aliases) of the old one. Followers are transferred automatically; following list via export/import CSV. The old account becomes a redirect. Your identity moves with you — the thing a centralised platform never lets you do.
6. Keep it small and sane
- Remote media cache 7 days: images from other servers aren't kept forever (the main disk eater on fedi servers).
- Domain blocks (/settings/admin) for the instances you'd rather not hear from; import a community blocklist if you like.
- Backups: ./data (SQLite) and ./storage (your own media). Stop the container for a clean copy, or snapshots (97).
- Updates: GoToSocial moves fast; read the release notes, pin the minor version, update monthly.
Troubleshooting
Followers can't find you / "account not found". Webfinger: https://social.example.com/.well-known/webfinger?resource=acct:john@social.example.com must return JSON through the proxy.
Posts don't reach other servers. They can't reach yours: HTTPS and the name public (not VPN-only); GTS_TRUSTED_PROXIES includes the proxy's address.
App login fails. The app needs https://; and the account must be confirmed.
Disk growing. Remote media cache days too high; admin media prune commands clean up.
Wrapping up
One container, a permanent hostname behind HTTPS, an account created on the command line, a Mastodon app pointed at it. A social-media presence on your own domain that no company can suspend, followed from anywhere on the Fediverse, on a server that barely notices it's there.
