Self-Hosted
After buying (the right to use) a VPS, I ended up self-hosting a handful of services. From a territory's point of view, I suppose that makes it a place that's more or less self-sufficient -- like a field growing its own crops.
This Site
First, obviously, the site you're on right now. Since it's a static blog, what actually gets deployed is just a handful of static files.
Those files are all open source, see here.
Code Hosting
I previously deployed a Sourcehut instance because I thought its code collaboration model -- which doesn't use the GitHub-style pull request -- was cool.
However, self-hosting it consumed quite a lot of hardware resources, so I eventually migrated away.
What's currently hosted at git.cytrogen.icu is Forgejo. It's very lightweight and fast.
Currently, the service runs on my desktop at home -- wonder how? You'll find out later -- and account registration is closed because I simply hate to manage it.
If you'd like to submit a patch, feel free to email me anytime. Though most of my projects are just /vibe/ tools for my own use, or some Emacs-configuration-style software...
Gemini Capsule
In addition to the web, I also made a Gemini version of the blog, hosted with agate at gemini://cytrogen.icu. You can read it using any Gemini client.
Thanks to Stalwart Mail Server, building and running your own mail server has become genuinely simple.
Worth mentioning: most VPS providers block port 25 by default. I had to specifically call IONOS to get it opened. If your provider refuses to budge, a relay like SMTP2GO or Resend is a reasonable fallback.
The bottom of the articles on this site also features a mail-based comment system that mimics the way mailing lists operate. So emails are received by Stalwart, passed to a resident process for parsing via an MTA Hook, and then assembled into a nested discussion tree by a scheduled task.
Alias Management
When an email address is exposed on the public internet, it inevitably gets resold or leaked by various services. I use a dedicated alias for every service I register for.
For example, Amazon gets amazon@.
Once a certain alias starts receiving unrelated spam, I know exactly who sold my address. To handle this, I wrote Alias Guard, which manages a blacklist of aliases.
XMPP
I set up an XMPP service using Prosody and registered cytrogen@xmpp.cytrogen.icu.
The reality is... almost no one around me uses it, haha...
Fediverse
I run a GoToSocial instance at gts.cytrogen.icu, with the account @cytrogen@gts.cytrogen.icu.
Some blog posts are synchronized there upon publication, so readers can like, boost, or reply directly on the Fediverse.
Incidentally, I made a static site for the monthly archives at gtsm.cytrogen.icu, and forked someone else's GoToSocial client at masto-fe.cytrogen.icu.
Push Notifications
ntfy is a minimalist push service. I use it to push various server events to my phone.
RSS Aggregator
FreshRSS is a fairly well-known RSS aggregator and reader, but since all my own devices already have their own local readers, I only use it to fetch my subscriptions.
Users require me to register them manually. If anyone wants to use this service, they can contact me. I'm just still considering whether I should help others host RSS aggregation services...
Server and Container Monitoring
Of course a VPS needs a monitoring setup. I went with Beszel, which is nice and lightweight -- beyond hardware resources, it also shows the status and logs of every Docker container.
The hub running at home also shows specific details.
Uptime Monitoring
I've set up Uptime Kuma probes for every public service. If anything goes down or a certificate is about to expire, I get alerted.
Telegram Bot
Not really a service for me... My roommate's favorite GPT-4 lineup got pulled by OpenAI, leaving only API access to GPT-4o or 4.1. On a computer that's fine -- you can still reach OpenAI's sandbox -- but on mobile, you really want a halfway-decent client. We settled on a Telegram bot. Being lazy, I went with pipedude's evi-run project, since it ships a Docker image.
Once actually deployed, a few rough edges showed up -- the big one being that the prompt was hardcoded into the source, which is not exactly elegant. So I switched it to read the prompt from a .txt file instead. Then there was the language issue: the author only shipped English and Russian, so I had to add Chinese myself.
Speaking of bots -- the second project I ever tinkered with, back when I was first learning to program, was a bot. QQ wasn't cracking down hard on third-party bots back then. Mine started out as Kami, later renamed Hoka. Once CQHttp fell out of favor I stopped messing with bots... though with QQNT around now, building one should be easier than it used to be. Maybe I'll pick bot development back up sometime.
However, I only run this service occasionally now. My roommate has already gotten used to GPT-5 and the subsequent 6.
Headscale
The heavy hitter!
To let the VPS and my home machines see each other without exposing them directly to the public internet, I used Headscale. Now my desktop, laptop, phone, and VPS are all connected to the same virtual internal network -- it's incredibly convenient!
With it, the services running at home don't need to occupy public ports or go through any third parties.
These are the services I don't open to the external network:
- Immich: Backing up photos and videos
- Jellyfin: Media library for watching movies and series
- Navidrome: Music streaming service
- Paperless-ngx: The home for paper documents... still learning how to use it
- Dawarich: Recording my location history, similar to Google Timeline
- MeTube: A web-based version of yt-dlp
- LibreTV: Lightweight TV
- RSSHub: Generating RSS feeds for websites that don't provide them
Access Control
For some services or panels not open to the public, I added a layer of login authentication using Authelia.
Webmention
This site has integrated Webmention.
The receiving end uses Eltrac's Weepinbell. I replaced the original webmention.io because it went down frequently, and the source code was rewritten by the original author using AI tools in a way that felt weird and unreliable to me. If anyone knows Clojure, feel free to contribute some code. Much appreciated.
Another troublesome one is brid.gy. Its logic for handling Fediverse interactions is very strange, so why not just write a service myself? After all, I just need to read notifications received by GoToSocial, convert them into Webmentions, and send them to Weepinbell.
So I wrote an additional service responsible for reverse-bridging likes, boosts, and replies from GoToSocial into Webmentions.
BentoPDF
pdf.cytrogen.icu runs BentoPDF, a PDF toolbox that is very easy to use and completes tasks locally in the browser.