- Caddy[2] web server with Let's Encrypt certificates, working as reverse proxy.
The rest is a very lazy 2010's solution:
- A Go server for HTTP (static files, uploads, maintaining server-sent-event channels). It also reads and writes events in a custom format to a local socket, for the interactive parts.
- A Python server for the widgets, communicating with the Go server.
- Source code edited manually in-place (SSH or SSHFS[3], with Git) and restarted as needed. I know, I know, awful practice. But as I'm the only user, uptime during development is not a concern.
- Startup is handled by a @reboot cronjob and a bash one liner.
- Text files for "structured storage" (RSS feed items, authenticated sessions, mapping of uploaded file names).
As horrible as it might all sound, it has survived ten years and two cloud vendors. Nowadays I might containerize it, or rewrite as one Rust server, but I think I made the right choices at the time.
8/10 given the unusual requirements.