Software developer in Slagelse, Denmark. I have worked with PHP and Laravel since 2015, and have helped build a ticketing agency, a video streaming platform and a recruitment platform along the way. I like designing and delivering solid, tailored solutions — and I do not mind being the one who listens to what users are actually struggling with.
Available for work — jonas.kerwin.hansen@gmail.com
Right now I am building AthletOS: a training app that prescribes the weights and records what you actually lifted next to what it asked for. Rust backend, one FreeBSD box, two jails behind Caddy.
On the side, trongate.cloud: hosting for Trongate apps on Kubernetes. You push, we deploy. Still a work in progress.
I write occasionally at sasin91.xyz, mostly about things that broke and what fixed them.
- FreeBSD on a Hetzner Cloud VPS — installing 15.1 on root-on-ZFS unattended, from media you can verify, and the five things that went wrong
- One box, two jails and a five second deploy — what the boring infrastructure choices bought, measured rather than estimated
- trongate.cloud: you push, we deploy your Trongate app — hosting for Trongate apps, with the benchmarks behind it
- Trongate PHP — a framework that breaks with common standards, and why that turns out to be interesting
PHP · Laravel · Symfony · Go · Rust · Nuxt · React · Kubernetes · Linux · FreeBSD
This repository is the source of sasin91.xyz — a static site generated by a small Rust binary from Djot content. See docs/development.md to build it.
Developing the site
With mise, mise install sets up Rust, Node and
watchexec, and these tasks cover the day to day:
mise run serve # build, then serve ./public at http://localhost:8000
mise run dev # the same, rebuilding and restarting on every change
mise run check # everything CI checksWithout mise, the same thing in plain cargo:
cargo run --release # build into ./public
cargo run --release -- serve [port] # build, then serve it (default port 8000)serve is a small built-in server (src/serve.rs) that resolves URLs the way
the live Caddy config does, /blog → /blog/ redirect included.
Checks, as CI runs them:
cargo fmt --check
cargo clippy -- -D warnings
cargo test
node --test js/retrieval.test.mjs # after a build; Node 22+, nothing to installPosts live in content/blog/, the CV in content/cv.toml, and the AI
article's knowledge nodes in content/ai/ — see
docs/knowledge-nodes.md.
sasin91.xyz/cv is itself the source of the
downloadable cv_jonas_hansen_software_developer.pdf:
the site binary writes cv_jonas_hansen_software_developer.pdf directly from
the same content/cv.toml the page renders from, so the content cannot
diverge even though the two layouts differ. The CV is edited in
content/cv.toml, never in a PDF editor.






