Most of what I write comes back to one thing: running software you own, on hardware you control, without hoping it is safe. The aim of this blog is to distill what I have learned into something you can reuse, the idea first, then a worked example, and where it earns the space, a procedure you can follow step by step.
Two habits hold it together. Own what you run, and name what each choice costs. Nothing here is free, and every post says where the bill lands.
If you read only this page, take these six ideas with you. Each one is a post if you want the depth, but the idea is the part worth keeping.
What I keep coming back to
Run the container as nobody. Drop root and an app bug can no longer rewrite the system or climb to the host. It is the highest-value line in the whole setup, and it costs nothing. A hardened Dockerfile walks through this and the rest of building a small, tamper-resistant image.
Publish no ports. A published port punches through the host firewall without telling you, so a server you locked down is open anyway. Reach the container through a proxy on a shared network instead. A hardened compose file covers that, plus freezing the filesystem and keeping the secret out of docker inspect.
A pinned base image rots in silence. Pinning a version and rebuilding it on a schedule are one practice, not two. Do the first without the second and you serve known holes behind a lock that looks shut. CI that builds, gates, and publishes shows the pipeline and the monthly rebuild that keeps the base honest.
Test the artifact you ship, the way it ships. A container that passes a plain run can still fall over under a read-only filesystem and dropped privileges, the conditions it meets in production. The smoke test that tested the wrong container is the afternoon I learned that the hard way.
Deploy by pulling. Let the server pull the new image when CI sends a signed signal, and CI never has to hold a key to production. Deploying without an SSH key in CI builds that, signature and all.
Fix before the gate, not in it. Format and lint the moment before a commit, and the pipeline only ever has to verify, never to send you back a lap. Your CI shouldn’t be your formatter is the fifteen-line version.
The bigger picture
These six sit on one path: building, running and shipping a container. Around it are other tracks I am filling in, storage and backups, the homelab hardware under it all, and cloud architecture for when one machine stops being enough. Under everything are the basics the posts lean on without stopping to teach: the shell, Linux permissions, Git, SSH, Docker itself.
The map matters less than the two habits at the top. Own what you run, and know where every risk went. Read the post that fits what you are building, and skip the rest with a clear conscience.
Find your way in
Browse every topic, or follow a series from its first post to its last.