How #Seppo! works
#Seppo! is meant for people[1] to operate their own, first-person (single-user) microblog. Therefore gentle onboarding and safe operation are paramount. And because server operation has it's pitfalls, #Seppo! encourages to rent cheap shared webspace and this way have professionals do the delicate but standard tasks (🏡 Webspace) on an affordable but sustainable business perspective.
You do not need privileged server access ('root') to have your own #Seppo! but you do need a CGI[2]-friendly webserver. E.g. nginx or caddy aren't.
Setup
#Seppo! is a CGI program driven by a webserver, e.g. Apache from a LAMP[3]-stack. Put seppo.cgi
(see 🌱 Installation) on your CGI-capable shared webspace and enter
the address in your browser's address bar, e.g.
https://example.org/sub/dir/seppo.cgi
. Being brand-new, the CGI doesn't find the
marker file delete-me-to-restore-missing
, unpacks all assets (xsl[4], css,
delete-me-to-restore-missing, etc.) and creates private and public facing files, finds no
app/etc/passwd.s
either and so asks to set login credentials. Then it tries to
create a symlink in the webspace's root /.well-known/webfinger/.htaccess
. Only if
self-hosting or not on Apache, you have to care about the webserver configuration. There are
config file samples in contrib/etc/
[5].
Discovery
In order to be found via WebFinger[6], a http GET
request to
https://example.org/.well-known/webfinger?resource=acct:alice@example.org
must
respond with the proper JRD[7]
document.
#Seppo! sets this up automatically, see S1002 for details.
Add a Post
For now via web-interface. Posting does:
- append the message to the global
app/var/db/o/p.s
- append to the most recent index page
app/var/db/o/p/0.s
or start a new one - re-create the public facing according blog page
o/p-0/index.xml
- evtl. change the symlink to the 'current' blog page
o/p/index.xml
- do likewise for tags
o/t/*-0/index.xml
and dailyo/d/*-0/index.xml
pages - queue a job to notify each follower in
app/var/spool/job/new/
- trigger queue processing and loop via minutely HTTP calls to itself
Delete a Post
Typically via web-interface. Deleting does:
- find the entry in the primary page index
app/var/db/o/p/0.s
- overwrite the post in the global
app/var/db/o/p.s
- re-create the public facing according blog page
o/p-0/index.xml
- re-create the according tags and daily overview pages
- queue a job to notify each follower in
app/var/spool/job/new/
- trigger queue processing and loop via minutely HTTP calls to itself
Incoming followed Posts
Incoming activities[8]:
Design Decisions
To work unattended, #Seppo! avoids risks wherever possible. Namely
- do as little as possible (Occams Razor)
- prefer safe over convenient or quick
- have a 2sec sleep on all login attempts
- ban after repeated failed logins
- never completely fill the disk
- do log swapping, not rotation
- have a timeout/max retries on everything
- all persistence to inspectable (mostly text) files
- Canonical S-Expressions for storage, no json nor xml
- no mandatory scripting, neither server nor client
- minimal Trusted Computing Base, few dependencies, both toolchain and runtime, no database, no scripting runtime, few small & seasoned libraries (e.g. tls[12], jsonm[13], xmlm[14], lambdasoup[15]) lean on transitive dependencies and from trusted authors (Mehnert, Bünzli, Bachin)
- only accept parsed and valid external data and never redistribute unattended
- accept incoming posts only from people followed
- best practices (e.g.
don't parse
,make undesired state unrepresentable
,immutability changes everything
) - a memory-safe programming language, 🐫 OCaml[16] with a competent, friendly community
- render html client-side via xsl
- built on solid web foundations, not the latest fads (Linux, Apache, CGI[2], Atom[17], XSL[4], XHTML[18], CSS)
* * *
- The Internet is for End Users (RFC8890), back^
- The Common Gateway Interface (CGI) (RFC3875), back^, back^
- LAMP (software_bundle), #Seppo needs the L and A, back^
- XSL Transformations (XSLT), back^, back^
- contrib/etc/, back^
- WebFinger (RFC7033), back^
- 4.4 JSON Resource Descriptor, back^
- 3.1 Activity Types, back^
- 2.5. Verifying a Signature, back^
- 3.2 Actor Types, back^
- https://codeberg.org/seppo/seppo/src/commit/973d3bb/as2_vocab/decode.ml#L380-L384, back^
- tls, back^
- jsonm, back^
- xmlm, back^
- lambdasoup, back^
- 🐫 OCaml, back^
- Atom (RFC4287, RFC4685, RFC5005), back^
- XHTML™ 1.1 - Module-based XHTML - Second Edition, back^