.. . .. ..
... . .... ...
... . . . . ... .. . . . . ... ...
.. . . .. . . .. . .. .. . .
., . . . . .. . .. . .
. . . .. .. .... . . . . .. ..
. .. ... . . . . . .. . .
. . . .. . .. ...' .. . . . . .
. . . . . __ . .__ _ __ ,; .'. . . ....
. . . / /____ ___ /./_(_) /__ .' .. . . . .
.. ... . . . /.__/ _ \/ _ \/ __/./ '_/. . .. . . .
.' ... . \__/\___/\___/\__/_/_/\_\ . . . .
. . . . . . ... ... . . ..
.. .. . . .... .. . . .. . . . . . ... ....' .
... . . . .. . ... ... . .. .. .,.. .....
. .. ...... . .''. . .. . . . ...
' . .. .. .. . . ... ......::. .. .,. . .. .... ..
. .... . ..... . .. . . ... . .,'. . .. ,.. ..
. . . . . .. . . .. . . .. .. . . . . . . .'
. .... '... ... . . .. . ... . '. ' ...
# localhost.localdomain:8443
Welcome, fedinaut! localhost.localdomain:8443 is an instance of tootik, a federated nanoblogging service.
ββββ
π» My feed
π Mentions
β‘οΈ Followed users
π My profile
π‘ Local feed
ποΈ Communities
π₯ Hashtags
π Find user
π Search posts
π£ New post
βοΈ Settings
π Statistics
π Help
tootik is a federated nanoblogging service for the small internet. With tootik, you can interact with your friends, including those on Mastodon, Lemmy and other ActivityPub-compatible servers, from the comfort of a minimalistic, text-based interface in the small internet:
Gemini ActivityPub (HTTPS)
β β
βββββββββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββββββββββ
β Bob's Gemini client βββ¬ββ€ tootik instance βββ¬ββ€ Another tootik instance β
βββββββββββββββββββββββββ€ β βββββββββββββββββββ€ β βββββββββββββββββββββββββββ
β2024-01-01 alice β β β$ ./tootik ... β β ββββββββββββββββββ
β> Hi @bob and @carol! β β βββββββββββββββββββ βββ€ Something else β
β... β β β ββββββββββββββββββ
βββββββββββββββββββββββββ β β βββββββββββββββββββββ
βββββββββββββ΄ββββββββββββ βββ€ Mastodon instance βββ
β Alice's Gemini client β βββββββββββββββββββββ β
βββββββββββββββββββββββββ€ ββββββββββββββββββββ΄βββββ
β2024-01-01 bob β β Carol's web browser β
β> Hi @alice! β βββββββββββββββββββββββββ€
β... β ββββ alice β
βββββββββββββββββββββββββ ββββ 17h agoβ
βHi @bob and @carol! β
β β
β βββ bob β
β βββ 16h agoβ
β Hi @alice! β
βββββββββββββββββββββββββ€
βββββββββββββββββββββββββ
ββ Hola ββPublishββ
βββββββββββββββββββββββββ
βββββββββββββββββββββββββ
tootik is lightweight, private and accessible social network:
- Its UI is served over Gemini, Gopher, Finger and Guppy: there's a wide variety of clients to choose from and some work great on old devices.
- Rich content is reduced to plain text and links: it's a fast, low-bandwidth UI suitable for screen readers.
- Anonymity: you authenticate using a TLS client certificate and don't have to share your email address or real name.
- No promoted content, tracking or analytics: social networking, with the slow and non-commercial vibe of the small internet.
- It's a single static executable, making it easy to set up your own instance instead of joining an existing one.
- All instance data is stored in a single file, a sqlite database that is easy to backup and restore.
- It's lightweight: a <=$5/mo VPS or a SBC is more than enough for a small instance.
- It implements the subset of ActivityPub required for its feature set but not more, to stay small, reliable and maintainable.
- It's written in two languages (Go and SQL), making the codebase suitable for educational purposes and easy to hack on.
- It's permissively-licensed.
- Good compatibility with various fediverse servers
- Text posts, with 3 privacy levels
- Public
- To followers
- To mentioned users
- Sharing of public posts
- Users can follow each other to see non-public posts
- With support for Mastodon's follower synchronization mechanism, aka FEP-8fcf
- Multi-choice polls
- Lemmy-style communities
- Follow to join
- Mention community in a public post to start thread
- Community sends posts and replies to all members
- Full-text search within posts
- Upload of posts and user avatars, over Titan
- Account migration, in both directions
You can join an existing instance or set up your own.
go generate ./migrations
Then:
go build ./cmd/tootik -tags fts5
or, to build a static executable:
go build -tags netgo,sqlite_omit_load_extension,fts5 -ldflags "-linkmode external -extldflags -static" ./cmd/tootik
βββββββββ ββββββββββ βββββββββββ βββββββββββ
β notes β β shares β β persons β β follows β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€
βobject β βnote β βactor β βfollower β
βauthor β βby β β... β βfollowed β
β... β β... β β β β... β
βββββββββ ββββββββββ βββββββββββ βββββββββββ
Most user-visible data is stored in 4 tables in tootik's database:
notes
, which contains Object objects that represent postsshares
, which records "user A shared post B" relationshipspersons
, which contains Actor objects that represent usersfollows
, which records "user A follows user B" relationships
notes.author
, shares.by
, follows.follower
and follows.followed
point to a row in persons
.
shares.note
points to a row in notes
.
βββββββββ ββββββββββ βββββββββββ βββββββββββ βββββββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ β£ββββββββββ« β£ββββββββββ«
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ βββββββββββ βββββββββββ βββββββββββ βββββββββββ
Federation happens through two tables, inbox
and outbox
. Both contain Activity objects that represent actions performed by the users in persons
.
inbox
contains activities by users on other servers, while outbox
contains activities of local users.
βββββββββββββββββββ
β gemini.Listener β
ββββββββββ³βββββββββ
ββββββββββ»βββββββββ
β front.Handler β
βββββββ³ββββββββββββ
βββββββββ ββββββββββ ββββββΈβββββ βββββββββββ βββββββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ ββββββ°βββββ βββββββββββ βββββββββββ βββββββββββ
βββββββββ»βββββββ
β fed.Resolver β
ββββββββββββββββ
gemini.Listener is a Gemini server that handles requests through Handler. It adds rows to persons
during new user registration and changes rows when users change properties like their display name.
Resolver is responsible for fetching Actors that represents users of other servers. The fetched objects are cached in persons
.
βββββββββββββββββββ
β gemini.Listener β
ββββββββββ¬βββββββββ
ββββββββββ΄ββββββββββ
βββββββββββββ₯ front.Handler β
β ββ°βββββββββ¬ββββββββ°β
βββββΈββββ ββββββββΈββ ββββββ΄βββββ ββΈβββββββββ βββββββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ ββββββ¬βββββ βββββββββββ βββββββββββ βββββββββββ
βββββββββ΄βββββββ
β fed.Resolver β
ββββββββββββββββ
In addition, Gemini requests can:
- Add rows to
notes
(new post) - Change rows in
notes
(post editing) - Add rows to
shares
(user shares a post) - Remove rows from
shares
(user no longer shares a post) - Add rows to
follows
(user A followed user B) - Remove rows from
follows
(user A unfollowed user B) - ...
βββββββββββββββββββ
β gemini.Listener β
ββββββββββ¬βββββββββ
ββββββββββ΄ββββββββββ
βββββββββββββ€ front.Handler βββββββββββββ
β ββ¬βββββββββ¬ββββββββ¬β β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄βββββββββ βββΈββββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ ββββββ¬βββββ βββββββββ°ββ ββ°βββββββββ βββββββββββ
βββββββββ΄βββββββ ββ»βββββ»ββββββ
β fed.Resolver β β fed.Queue β
ββββββββββββββββ βββββββββββββ
Each user action (post creation, post deletion, ...) is recorded as an Activity object written to outbox
.
fed.Queue is responsible for sending activities to followers from other servers, if needed.
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ³ββββββ³ββββββ
βββββββββββββ€ front.Handler ββββββββββββββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββΈβ βββ΄βΈβββββββ βββββββββββ
β notes β β shares β β persons β β follows β β outbox β β inbox β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€
βobject β βnote β βactor β βfollower β βactivity β βactivity β
βauthor β βby β β... β βfollowed β βsender β βsender β
β... β β... β β β β... β β... β β... β
βββββββββ ββββββββββ ββββββ¬βββββ βββββββββ¬ββ ββ¬βββββββββ βββββββββββ
βββββββββ΄βββββββ ββ΄βββββ΄ββββββ
β fed.Resolver β β fed.Queue β
ββββββββββββββββ βββββββββββββ
tootik may perform automatic actions in the name of the user:
- Follow the new account and unfollow the old one, if a followed user moved their account
- Update poll results for polls published by the user, and send the new results to followers
- Handle disagreement between
follows
rows for this user and what other servers know
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ¬ββββββ¬ββββββ ββββββββββββββββ
βββββββββββββ€ front.Handler ββββββββΌββββββ ββββ« fed.Listener β£βββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ β βββββββ³βββββββββ β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββ΄β βββ΄β΄βββββΈββ ββββββΈβββββ β
β notes β β shares β β persons β β follows β β outbox β β inbox β β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ β
βobject β βnote β βactor β βfollower β βactivity β βactivity β β
βauthor β βby β β... β βfollowed β βsender β βsender β β
β... β β... β β β β... β β... β β... β β
βββββββββ ββββββββββ ββββββ¬βββββ βββββββββ¬ββ ββ¬βββββββββ βββββββββββ β
βββββββββ΄βββββββ ββ΄βββββ΄ββββββ β
β fed.Resolver β β fed.Queue β β
βββββββββ°βββββββ βββββββββββββ β
β β
β β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββ
Requests from other servers are handled by fed.Listener, a HTTP server.
It extracts the signature and key ID from a request using httpsig.Extract, uses Resolver to fetch the public key if needed, validates the request using Verify and inserts the received Activity object into inbox
.
In addition, fed.Listener allows other servers to fetch public activity (like public posts) from outbox
, so they can fetch some past activity by a newly-followed user.
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ¬ββββββ¬ββββββ ββββββββββββββββ
βββββββββββββ€ front.Handler ββββββββΌββββββ ββββ€ fed.Listener ββββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ β βββββββ¬βββββββββ β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββ΄β βββ΄β΄βββββ΄ββ ββββββ΄βββββ β
β notes β β shares β β persons β β follows β β outbox β β inbox β β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ β
βobject β βnote β βactor β βfollower β βactivity β βactivity β β
βauthor β βby β β... β βfollowed β βsender β βsender β β
β... β β... β β β β... β β... β β... β β
βββββ°ββββ βββββ°βββββ ββββββ¬βββββ ββββββ°βββ¬ββ ββ¬βββββββββ ββββββββ°βββ β
β β βββββββββ΄βββββββ β ββ΄βββββ΄ββββββ βββββββ»ββββββββ β
β β β fed.Resolver β β β fed.Queue β β inbox.Queue β β
β β βββββββββ¬βββββββ β βββββββββββββ βββ³ββ³ββ³ββββββββ β
β β β βββββββββββββββββββββββ β β β
β βββββββββββββΏββββββββββββββββββββββββββββββββββββ β β
βββββββββββββββββββββββΏββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββ
Once inserted into inbox
, inbox.Queue processes the received activities:
- Adds new posts received in
Create
activities tonotes
- Edits post in
notes
according toUpdate
activities - Records
Announce
activities inshares
- Marks a follower-followed relationship in
follows
as accepted, when the followed user sends anAccept
activity - Adds a new row to
follows
when a remote user sends aFollow
activity to a local user - ...
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ¬ββββββ¬ββββββ ββββββββββββββββ
βββββββββββββ€ front.Handler ββββββββΌββββββ ββββ€ fed.Listener ββββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ β βββββββ¬βββββββββ β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββ΄β βββ΄β΄βββββ΄ββ ββββββ΄βββββ β
β notes β β shares β β persons β β follows β β outbox β β inbox β β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ β
βobject β βnote β βactor β βfollower β βactivity β βactivity β β
βauthor β βby β β... β βfollowed β βsender β βsender β β
β... β β... β β β β... β β... β β... β β
βββββ¬ββββ βββββ¬βββββ ββββββ¬βββββ ββββββ¬βββ¬ββ ββ¬ββββββββ°β ββββββββ¬βββ β
β β βββββββββ΄βββββββ β ββ΄βββββ΄ββββββ β βββββββ΄ββββββββ β
β β β fed.Resolver β β β fed.Queue β βββββ₯ inbox.Queue β β
β β βββββββββ¬βββββββ β βββββββββββββ βββ¬ββ¬ββ¬ββββββββ β
β β β βββββββββββββββββββββββ β β β
β βββββββββββββΌββββββββββββββββββββββββββββββββββββ β β
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββ
Sometimes, a received or newly created local Activity is forwarded to the followers of a local user:
- When a remote user replies in a thread started by a local user, the received Activity is inserted into
outbox
and forwarded to all followers of the local user. - When a user creates a new post, edits a post or deletes a post in a local community, the Activity is inserted into
outbox
and forwarded to all community members.
βββββββββββββββββ
βββββββββββββββββββ β outbox.Mover β
β gemini.Listener β β outbox.Poller β
ββββββββββ¬βββββββββ β fed.Syncer β
ββββββββββ΄ββββββββββ βββββ¬ββββββ¬ββββββ ββββββββββββββββ
βββββββββββββ€ front.Handler ββββββββΌββββββ ββββ€ fed.Listener ββββ
β ββ¬βββββββββ¬ββββββββ¬β β ββ β βββββββ¬βββββββββ β
βββββ΄ββββ ββββββββ΄ββ ββββββ΄βββββ ββ΄ββββββββ΄β βββ΄β΄βββββ΄ββ ββββββ΄βββββ β
β notes β β shares β β persons β β follows β β outbox β β inbox β β
βββββββββ€ ββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ βββββββββββ€ β
βobject β βnote β βactor β βfollower β βactivity β βactivity β β
βauthor β βby β β... β βfollowed β βsender β βsender β β
β... β β... β β β β... β β... β β... β β
βββββ¬ββββ βββββ¬βββββ ββββββ¬βββββ ββββββ¬βββ¬ββ ββ¬ββββββββ¬β ββββββββ¬βββ β
β β βββββββββ΄βββββββ β ββ΄βββββ΄ββββββ β βββββββ΄ββββββββ β
β β β fed.Resolver β β β fed.Queue β βββββ€ inbox.Queue β β
β β βββββββββ¬ββ°βββββ β βββββββββββββ βββ¬ββ¬ββ¬ββ°ββββββ β
β β β β βββββββββββββββββββββββ β β β β
β βββββββββββββΌββββββββββββββββββββββββββββββββββββ β β β
βββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββ β β
βββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββ
To display details like the user's name and speed up the verification of future incoming replies, inbox.Queue uses Resolver to fetch the Actor objects of mentioned users (if needed).
tootik is free and unencumbered software released under the terms of the Apache License Version 2.0; see LICENSE for the license text.
The ASCII art logo at the top was made using FIGlet.