Project: Guestbook TUI - Overview and Setup
In my spare time I have been building a Claude wrapper (I know). It’s on around its 4th or 5th iteration by now. I have gone from pure text files, to more pure text files, to a whole Electron app (this one took a long time), and then I decided to make a Terminal User Interface (TUI). First I went Rust because I was looking for something new to learn, then TypeScript to make it work better with the Agent SDK (TypeScript or Python at the moment). When I was fighting against Ink — which is what Claude Code is currently written in, as far as I know — I found Charm.
I am still building the wrapper, but I wanted a smaller project I could actually finish, while exploring interesting tech that was new to me.
Be my guest
I thought a little guestbook would be nice — someone SSHs into my site, gets a terminal interface, and can leave a message that shows up on the web. So the plan is as follows; Go backend with a TUI, a database to store the entries, and an HTTP API to return them to the frontend. One binary, two interfaces.
A Drop in the Ocean
The first step is picking a cloud provider. I didn’t want something overly complex, but I also didn’t want something that did everything for me. I don’t have a lot of experience with devops, so dealing with a real VM felt like the right level of friction. I chose DigitalOcean.
A basic droplet — 512MB RAM, 1 CPU, 10GB SSD — costs $4 a month. Enough to run a Go binary and a SQLite file. I skipped the managed database upsell ($15/month was a bit rich for me) and picked Ubuntu 24.04.
A Guided Dip
I am using Claude to guide me through this. The thing I’ve come to appreciate about working with AI in unfamiliar territory is that conversational learning is very powerful. I asked a lot of obvious questions and got a lot of very polite responses.
It turned out I already had an SSH key on my machine, so I copied the public key into DigitalOcean during setup and connected straight in as root. First thing Claude had me do was create a normal user and stop logging in as root. After that: disable root login in the SSH config, restart the SSH daemon, and set up the firewall, allow SSH and finally, enable it.
The whole thing took about fifteen minutes and I found it very interesting. Each step was logical, I could follow the reasoning, and if I was unsure about anything I could ask my AI companion. For example, I now know there is a ufw command which stands for Uncomplicated Firewall.
Dependencies
With the server secured, we need two things installed: Go and nginx.
Go is straightforward — sudo apt install golang-go — and we end up with version 1.22.2. nginx takes one command too. What nginx does is sit in front of the Go application and act as a reverse proxy. I am not great with DevOps language like “reverse proxy”, but it seems to be pretty simple. It takes requests from the internet instead of your app, handles things like TLS, and forwards traffic through. We open the firewall for it.
A Record
The next thing is pointing a subdomain at the droplet. I head over to my registrar who is hosting my DNS, add an A record with the host set to tui and the value set to the droplet’s IP, and I had tui.matthewwbuckley.com. After DNS propagation that is.
HTTPS
With the subdomain live, we can get an SSL certificate. Claude suggested certbot so I went ahead and installed it. Let’s Encrypt proves you own the domain by temporarily serving a file at a known URL and checking it’s reachable. If it can then you clearly control the server behind that domain and the certificate is issued. certbot also edits the nginx config to use it and sets up a cron job to auto-renew every 90 days. The whole thing is automated and free, which feels slightly miraculous.
nginx config
The last piece is telling nginx what to actually do with incoming requests. By default it just serves a placeholder page. We create a config file in /etc/nginx/sites-available/ which says: any request for tui.matthewwbuckley.com, forward it to localhost:8080. That’s where the Go webserver app will listen. There’s nothing on port 8080 yet, but the plumbing is in place.
Reflections on a droplet
It all went pretty smoothly and I found it pretty interesting to be guided through the setup process. The server is ready to accept HTTP requests but there is some setup still for SSH, which the TUI will use. I will go over that in the next post where I will be using AI to help me again, this time with a Charming Golang TUI.
Wish me luck.