Live chess: now live

This is a follow-up to Live chess over Gemini (and a short history of streaming).


About 16 days ago, I stated my intention to "continue polishing [my live chess prototype] and potentially host it on a new Gemini capsule", and I am here to announce having done exactly that (and a little bit more).

If you want to check it out and play a game of chess with a friend, you can now do so at gemini://gemini.echo.ls:51454 (I will provide an explanation for the odd URL later in this page).

Top of page (/chess)
Lower on page

Short story

Originally, I intended to build yet-another-CGI-based Gemini server; however, pure CGI architecture makes it challenging to implement edge cases such as forced buffering, streaming, and shared states between simultaneous clients (without a database). As a result, I settled on a registry system for independent apps to attach to different sub-domains which are tied together through a shared server, abstracting away transit and TLS. The principle example of this edge-case Gemini app is the blocking-state chess server. In addition, there is a component which allows for recursive static .gmi file hosting from a specified directory.

This hybrid structure of registry + static files, although less elegant than a pure static or true CGI approach, makes it easy for me to build experimental features and host any type of Gemini application in a single capsule. As a reference to this somewhat haphazard design, I am dubbing my server "EGGS":

███████╗ ██████╗  ██████╗ ███████╗
██╔════╝██╔════╝ ██╔════╝ ██╔════╝
█████╗  ██║  ███╗██║  ███╗███████╗
██╔══╝  ██║   ██║██║   ██║╚════██║
███████╗╚██████╔╝╚██████╔╝███████║
╚══════╝ ╚═════╝  ╚═════╝ ╚══════╝

  echo.ls Gemini gateway server

Current hosting

For ease, I wrapped the project as a Docker image and am hosting it currently on Railway which automatically handles CI/CD, allowing me to focus on the aspects of the project which appeal the most to me. However, Railway does not support arbitrary external ports. In particular, this means that I cannot simply map [my domain]:1965 to the internal :1965.

The next best option (which I am currently using), is to enable Railway's TCP proxy service. This provides me with a proxy domain and port (in my case, that is switchyard.proxy.rlwy.net:51454) which will be mapped to my project's port :1965. Using simple DNS, I can make the access URL a bit little nicer, which is how I arrive at [my domain]:51454.

As a final wrinkle, the root of my domain (echo.ls) is already allocated to a different Railway service to host my website on the WWW and Railway prevents me from using an identical FQDN for multiple services, even when the ports would not conflict; this is why I chose a subdomain name: gemini.

This slightly convoluted mess is how I arrived at the not-ideal gemini://gemini.echo.ls:51454. However, for ease of use and low cost (Railway estimates a usage of $0.07/month for this service!), it's hard to justify switching to a VPS… at least not yet.

Future developments for this project are definitely possible, in particular, I would like to eventually add a matchmaking system/queue so that players do not need to ever coordinate outside of the Gemini network, but the actual implementation is largely uninteresting to me at the moment so no guarantees for updates in the near future.


Last updated May 15, 2026