https://pine32.be - © pine32.be 2026
Welcome! - 125 total posts. [RSS]
A Funny little cycle 2.0 [LATEST]


Search 125 posts with 52 unique tags


#1780951065


[ golang | wasm ]

In post 1757190021 I talked about the special SQLite lib I am using based around embedded wasm. A couple of months back, the library made a move to a new architecture. No more wasm but still no CGO. The solution: transpile a wasm build of SQLite to pure go code and compile that into your library. This gives us more type safety and better maintainability because the wasm build can be used as a “normal” go module. Also the boot time for applications is better because there is no waiting for the wasm module to load and “boot”. One downside is a clean build getting slower because you are rebuilding SQLite fully (still faster than any Rust build). Also the resulting binary is a bit bigger. But this is still a valid trade off to have no CGO dependency. I will keep using this library.

The transpiler, wasm2go, is also available for general use. I want to try it with libvips for one of my projects. But for now SIMD is not supported, not until the go api for it is stable. I could also build libvips myself with SIMD disabled but that sounds like work and messing with C build systems. So I will just wait, I’m not in a hurry.

#1780255277


[ homelab | networking ]

I just realized I havent talked about NetBird on this blog. NetBird is the peer-to-peer private network that I use for everything in my homelab. It is similar to Tailscale if you know that. But the main difference is that NetBird is able to be self-hosted, everything is opensource. I know that Headscale is a thing for Tailscale but it is not official and you are still reliant on closed-source clients. And a nice bonus for me is that NetBird is a German/European company.

So for my setup I selfhost NetBird on my VPS based Kubernetes cluster, it needs to have publics IPs to work properly when selfhosting. Then every server and device gets a client to connect. OIDC based for user clients, very nice. I am running a DaemonSet on all my Kubernetes cluster with host networking enabled. So each pod is automatically able to resolve private IPs and with some extra CoreDNS config also the private DNS. These clients on the nodes also function as gateways so all pods and services are available to the private network (with the right RBAC of course). And with some DNS forwarding in NetBird configured I can also resolve hostnames from Kubernetes services on my laptop, for example mb.default.svc.cluster.local. The setup is bit more complicated when using multiple k8s cluster, maybe something for a full-sized blogpost, going over how my network is set up in detail.

#1779738968


[ music | homelab ]

I really need some form of music “release radar” in my homelab with my move away from Spotify. Forever Live Sessions Vol 2 by Men I Trust has been out for more then a year now! Volume 1 is one of my all-time favourite albums and volume 2 quickly joined that list. Less “fast music” also means that I notice new music less “fast” I guess.

Cover Art
Tree Among Shrubs
Men I Trust

#1779009248


[ dev | golang | git ]

Last week when moving over to Codeberg (see post 1778177701) I noticed that I am using the github.com domain in my module names. For my projects (like mb) that fine, I just moved it to codeberg.org when moving the repo. But for libraries I can’t expect everybody to change their go.mod file every time I change were I host my code (not that anybody uses my libs but just go with it). Luckily the Go devs have though of this.

When trying to download a module, like github.com/ncruces/go-sqlite3 for example, go will make a http/https request like shown below. The webserver should then provide a special go-import meta tag that where and how it can pull the code.

curl -s 'https://github.com/ncruces/go-sqlite3?go-get=1' | grep go-import
<meta name="go-import" content="github.com/ncruces/go-sqlite3
    git https://github.com/ncruces/go-sqlite3.git">

Most code forges will handle this for you. But you can also deploy your own server on your own domain that handles this. And that is exactly what I have done, setup my own vanity URL. I made a simple stateless webserver for this that just takes a JSON config, source. Currently it will redirect to Codeberg but when I move my repos again I just have to change a basic config file and all modules will keep working as they are supposed to. I just have to make sure that go.pine32.be doesn’t go down. But it is a stateless app running 2 replicas on a highly available Kubernetes cluster, should be fine.

curl -s 'https://go.pine32.be/id?go-get=1' | grep go-import
<meta name="go-import" content="go.pine32.be/id
    git https://codeberg.org/Pineapple217/go-id">

#1778177701


[ dev | git ]

Lately I was already using my Forgejo instance a lot more the GitHub. Mainly for my private projects or projects where I don’t expect/want contributions. I did this because of all the AI data scraping and I don’t trust GitHub anymore. But I haven’t moved my public projects yet because I didn’t want to push my already niche projects to an even more niche platform. But now that GitHub is struggling to keep actual things online (84.35% uptime over last 90 days as of today) the general public is also looking for alternatives. So for me it was finally time to move my code to Codeberg, MB (this blog you are reading now) being the first project to move. Codeberg e.V.is a German non-profit organization that provides a public Forgejo instance that only allows opensource software. So it checks all boxes for me. And yes, I already have donated. Hopefully it can cover some cost of the GitHub refugees.

#1777583272


[ homelab | k8s ]

Finally got around to setting up storage on my Dell OptiPlex k8 cluster using Omni. I abandoned the idea of using Rook-Ceph, way to complicated for my needs (maybe skill issue). So back to Longhorn it is. I have set up Longhorn a couple of times so that setup went smooth. But I first needed to get the disks partitioned and setup via Talos OS. That took way to long to figure out. But now I know how to do it and I have a fully declarative config for it, so it was worth it. The full cluster config is just 50 lines! The new disk overview in Omni was a nice help (see img). So now that everything is setup I have 3 TiB of schedulable (sata) ssd storage, so 1 - 1,5 TiB with replication usable. Should be plenty, I only need 200 GB for my music.

Omni node disk view

#1776978473


[ dev | golang ]

Echo, the web framework I mainly use, recently got a new major release, v5. A big one I like is moving from a custom logger to the default log/slog for the stdlib. Most other breaking changes or not that interesting on their own but they create more room for future expansions. A lot of feature requests where parked until v5 so I hope that we will get a lot of nice things the coming year.

// New type safe API for parsing
id, err := echo.PathParam[int](c, "id")
user, err := echo.ContextGet[*User](c, "user")

#1776283702


[ music | navidrome ]

All I play is you!! Oh every game I lose!!

Cover Art
Play
Hana Vu

I have been using Navidrome more and more. I think around 50% of my music listening is on Navidrome now. Still need to get an app that works with Android Auto. I still have a lot of music ready that I haven’t listened yet so the percentage will only go up.

When I am using Navidrome I also listen more to full albums. So aside from it being better because I actually own the music I think it also improves the way I consume music in a major way, less “fast music” (as in fast fashion or fast food). Fast music is still fun, but maybe not all the time.

#1775126093


[ chess ]

I was looking for interesting chess engines to test and I came across Patricia, the most aggressive chess engine ever seen. It is currently rated 3466 on Stefan Pohl’s website (compared to Stockfish 18’s rating of 3910). It is a very strong engine but probably wont ever be the best. But when it wins, it often does so in a brutal way. Bellow is a game played as part of a tournament against RofChade 3.1 with a respectable elo of 3536 (higher then Patricia but still close). The book stats with equal material with a slight position advantage for white. Patricia starts sacrificing early and doesn’t stop until a final rook sacrifice to start the push for mate. White is behind on material the entire game but still wins.

gif of chess game

Engine play starts at move 7

Download PGN

#1773945124


[ webdev ]

I am giving Tailwindcss one more change. Mainly because I want to try out templui for my next project. Seems handy to get up and running faster and it is a perfect match for HTMX. The setup is not the cleanest but it is working fine up to now. I am using bun to run the Tailwind CLI.

#1773268866


[ music | rock ]

Cause nothing ever changes

Cover Art
Nothing Ever Changes
Max Baby

#1772925659


[ mimir | chess ]

Mimir is up to version 1.2 in the mean time and available on Lichess. It is still not super strong but a fun challenge as a human if you give yourself enough time.

https://lichess.org/@/MimirBot

The setup was relatively simple using the lichess-bot adapter. Just plugin in my UCI engine and the API key.

#1772138346


[ mimir | odin | chess ]

Mimir V1 is done! The last commit for V1 was adding UCI, which took a bit of testing because it needs some small async things. But it is working now, and I immediate put it up against Stockfish 18. of course not the full version, I limited it using the UCI_Elo option to 1600 elo. Still feels like a fair starting point for Mimir’s first game ever. And it won convincingly with no major mistakes. This is of course not a full evaluation, but now that it works with UCI, I can start building my full test suite to get a real Elo value for this first version. This is of course still the start!

gif of chess game

Download PGN

#1771316193


[ mimir | odin | chess ]

I have been working again on my chess engine writing in Odin, Mimir. It is still far from finished but it is now able to complete a full perft test. This basically means that is able to generate all valid moves (and only valid moves) in every position given. Those move results are validated against known move counts so it is 99,99999 % correct. Next up is doing minimax algorithm and some board eval function. Then it should be able to play its first game. Will also write some more about Odin as I am getting used to it.

#1770402595


[ homelab | k8s ]

One of my Kubernetes nodes recently went down without me noticing (issue with VPS provider, not my fault). It was nice that all my services stayed online without any hiccups. But I would like to know in the future when my infra goes down. So time to get the classic stack online Grafana (now with build in Alertmanager), Node Expoter, CAdvisor, kube-state-metrics but no Prometheus this time. I am running VictoriaMetrics instead. It is a drop in replacement for Prometheus and is still written in Go but it is made to be more cost effective. It uses 7 times less memory, CPU and storage then Prometheus. And from my testing those numbers seem to be right. Currently I am storing 28.6 billion datapoints using just 4.37 GiB of storage. Below you can see the stats (for everything monitoring) with a current ingest rate at around 20K rec/s.

Resource consumption

#1769462323


[ homelab | k8s ]

I finally got S3-compatible buckets online, using a Hetzner storage box as the storage. I know they got S3 buckets as well but I am cheap and it will only be used for backups so I don’t care about speed.

For the setup I first used the Kubernetes SMB CSI driver to be able to use my storage box as regular PVC’s. On top of that I am running the Versity gateway. It is a completely stateless S3 server that can use a normal posix filesystem for the storage. It stores everything as plain files, so even without the gateway my files are still fully accessible. I could also spin up a gateway instance wherever I need one, even if my k8 cluster goes down. And I can run it in high availability on my cluster. All these things makes it perfect for backups. And it has nice web interface as a bonus. And of course it is written in Go.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: versitygw-s3
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: smb
  resources:
    requests:
      storage: 30Gi

#1768730464


[ music ]

I finally have more songs in my offline library then on Spotify. 5859 in my own lib and 5856 on Spotify. I still can’t fully replace Spotify yet but getting closer everyday.

Cover Art
obsessed
wenszy

#1767859312


[ homelab | git ]

Just got my own git forge setup done with Forgejo and added Woodpecker CI. I already didn’t have any builds running on GitHub because I don’t trust them and my lack of trust is only getting more justified by the day. I am happy with this setup for my own semi-private projects. But for project where I would like some contributions I will need some other platform. It will probably end up being Codeberg, basically a public Forgejo instance run as a non-profit by a German team. And also using Woodpecker for CI, so moving over will be easy. It is 24€ per year but seems like a fair price for the service they provide, and they don’t profit of my data.

#1767130804


[ music ]

Put your hands on me

Cover Art
Hands
Billy Sane

Last post of the year

#1766588690


[ golang ]

New go feature soon to be released in 1.26, the runtime/secret package.

secret.Do(func() {
    // Some secrets that should not be in
    // memory any time time long then need
})

As soon as this new Do function exits all registries, stack and heap values get deleted as soon as possible, even if a panic occurs. Great to see that Go is still adding features for better explicit control over memory, even though it still uses a garbage collector.

#1765830037


[ photography ]

Wide-angle lens dump
A bit of stretch to call this photography but still

sqr_dump_6_3 sqr_dump_6_1 sqr_dump_6_2 sqr_dump_6_4

sqr_dump_6

#1765230859


[ homelab | k8s ]

MB is now officially running on a highly available Kubernetes cluster. Don’t know if uptime is going to be better because I don’t have a real load balancer. Currently it is just using DNS. So if one node goes down I will need to remove a DNS record and hope propagates fast enough. Still better then one node, at least I have still some control.

Non-authoritative answer:
Name:    mb.pine32.be
Address: 176.57.188.254
Name:    mb.pine32.be
Address: 185.211.6.112
Name:    mb.pine32.be
Address: 185.216.75.171

#1764875711


[ homelab | linux ]

I’m setting up some new servers and was going over the usual hardening configs for ssh etc. Then I came across google-authenticator-libpam, a PAM module that allows you to secure ssh (or other things) with the standard 6 number time-based one-time password. It is created by Google but any authenticator app will work for this. It also has some build in rate limiting, I think this will scare of most automated attacks so I don’t think fail2ban will be needed. I will not be ssh-ing into these servers after the first setup (k8) so I don’t mind the extra auth step.

#1764269123


[ docker | http ]

I was looking for a small web server for service static files bundled in a container image. Most people just use nginx because it fast and well maintained. But the base image is 68.6 MB! Even going to the alpine-slim instead of latest only gets us down to 5.27 MB. You can also use BusyBox to serve HTTP or even better compile your own BusyBox and strip everythong down as show in this blog. That gets use down to 154 KB. This is already a huge improvement but we can go down to double digits using darkhttpd, 62.8 KB. Bundling one image in your static site would already negate all the improvements of not using nginx but it is still cool to see that we still can get things done with something that would fit on a floppy disk.

#1763662379


[ music ]

I cast vicious mockery

Cover Art