Even tho the web is perfectly good platform to consume content, there’s something about not needing to leave the cozy darkness and simplicity of the terminal. Of course if you are like me and spend most of the time using terminal with IDE like neovim, you are very well accustomed to it and you don’t want to leave it. I got you. I’ve spend last few evenings porting this blog to be accessible with ssh.
You may be asking why? And the answer is simple.
Because I want to. And also because I want to play with wish. Not the Chinese shop, but the ssh server from Charm . Let’s see how it went.

Charm

Charm is company building not only their cloud and apps like Soft Serve a git server or Pop for sending emails from terminal, but also full Golang toolkit for building TUI(text user interface) with styling and animations. It’s well proven and production ready not only by Charm where they of course build all of their apps with it, but also by companies like Digital ocean and their doctl CLI for managing cloud resources. At the heart lies bubbletea framework with ELM like architecture for composing the UI. State management libraries like Redux are based on this pattern. It’s simple but powerful and contains three parts:

  • Model = Struct holding current state
  • View = Function rendering the components
  • Update = Function for updating the state based on messages

Let’s get to know all of the components and build it.

The App

To keep the app simple for now I’ve decide to just create a list of posts and detail of the post, kinda like the website. I’m planning to add more in future to both the website and to this app, but for now this will suffice. This blog is powered by Hugo so every post is just markdown file. For rendering markdown Charm have Glamour so rendering the content is easy, kind of more about that later. List is one of the components available from component library Bubbles . It contains almost all basic components you would need for building TUI apps, anything from text inputs to tables. Community around Bubbletea is growing and new components are being create all the time. Styling can be done with one if several libraries, but I choose to use Lipgloss . Putting these two components together was easy, but after filling it with content I’ve started to see issues. The list and rendered text started to flicker when scrolling. I’m still not 100% sure why and what was causing it, but reducing the amount of styling seemed to help. This is quite annoying and I will have to get to the root of this issue when I will be adding more features, but for first version I’m happy to prefer reduced styling over functionality.
One thing sadly missing from initial version is the ability to display images in the posts. There are terminal emulators like Kitty that can display images, but there’s not standard for it so the Bubbleatea renderer does not support it. So for now images are handled as links, hopefully something I can improve in future.
Now the hackers must be waiting for me to give them ssh access to my pc, so they can read the blog and also steal all of my data. But hold your horses, I’m not security expert but I’m not that stupid.
Charm build Ssh server for serving Bubbletea apps, making it easy and secure to deploy. But still probably don’t deploy it to your personal development machine.

Deployment

So how did I deployed it? Well it wasn’t easy task to do. Even tho Wish is secure and you cannot escape the program to enter shell, and it allows you to listen on any port you want, for good UX I still wanted it to be listening on port 22.
This way you can just ssh neurobug.com and enjoy the posts. I had some ideas how to do it with Nixos, but I was honestly too lazy to spin up new virtual machine. And I was also too cheap for it. So I was looking for alternatives, but hosting platforms with easy app hosting like Heroku (who uses it anymore anyway), DigitalOcean, Vercel are so focused on HTTP that having anything else hosted on their app platform is difficult.
But there one shining star in this cloudy landscape.
Fly.io
They fly machines don’t care if you want to deploy http servers, game servers, what ever servers or no server at all. You can deploy almost anything to fly and they don’t care. They created great platform for developers who don’t want to use raw virtual machines or kubernetes. Both are perfectly good for hosting and on my other projects I’m using both of them. But for these simple project, like personal page or blog you don’t need them. It’s awesome to see platform that’s clearly lead by smart developers who knows that HTTP is not the only thing. Even their dynamic scaling to 0 works with TCP listeners for ssh. Thanks to this Fly.io is slowly becoming my favourite platform to deploy to. Btw this is not sponsored by Fly.io.

Anyway the final deployment is composed of small Golang binary with both HTTP server and Ssh server listening on different ports, build and bundled with Docker and deployed to fly as one app.
To give it a try, just run ssh neurobug.com