# Abdellatif Housni: TIL > Short, practical write-ups on things learned while building -- Linux, containers, Kubernetes/RKE2, infrastructure-as-code, TLS and the tooling around them. 85 entries across 22 topics, each one a self-contained page. Every entry is published as markdown next to its HTML, at the same path with `.md` in place of `.html`; the links below point at the markdown. Sections are topics. Each line gives the entry's first-publication date, its place in a reading series where it has one, and how it opens. ## ansible - [Starting an Ansible role project with uv for the venv](https://til.housni.eu/ansible/starting-a-role-with-uv-venv.md): 2026-09-05. Ansible needs a Python environment (ansible-core, plus ansible-lint/molecule if you're testing), but a role's directory layout is fixed by ansible-galaxy — not something uv init's project… - [Using the Foreman/Satellite dynamic inventory plugin](https://til.housni.eu/ansible/foreman-dynamic-inventory-plugin.md): 2026-09-05. theforeman.foreman.foreman pulls hosts straight out of Foreman (or Red Hat Satellite, which is built on it) as live Ansible inventory — no manually maintained host list to fall out of sync with… - [Targeting hosts the same way, whether the inventory is static or dynamic](https://til.housni.eu/ansible/targeting-hosts-static-and-dynamic-inventory.md): 2026-09-05. The host patterns Ansible accepts on the command line and in a playbook's hosts: line don't care where the hosts came from — a plain INI file, a YAML static inventory, or a dynamic plugin like the… - [Storing an Ansible Galaxy token as an environment variable, not in ansible.cfg](https://til.housni.eu/ansible/galaxy-token-as-environment-variable.md): 2026-09-05. ansible-galaxy needs a token to install from or publish to anything other than the fully public Galaxy — a private Automation Hub, a self-hosted galaxy_ng, or even the public Galaxy for publishing… - [git tag basics, grounded in how Ansible collection releases actually use them](https://til.housni.eu/ansible/git-tag-basics-collection-releases.md): 2026-09-12. git tag looks simple until a release process actually depends on getting it right. Ansible collection releases are a good concrete example — the tag isn't decorative, tooling reads it back. - [Deploying a Podman Quadlet stack on RHEL9 with linux-system-roles](https://til.housni.eu/ansible/podman-quadlet-caddy-adminer-php-linux-system-roles.md): 2026-09-16. Earlier I hand-wrote Quadlet files for Caddy + PHP-FPM directly on the host. The linux-system-roles.podman role turns that into something declarative: instead of writing .container/.network unit… - [Ansible Vault encrypts the secret in git; Podman's default driver stores it in plaintext](https://til.housni.eu/ansible/ansible-vault-podman-secrets.md): 2026-09-20. Encrypting a variable with ansible-vault and rendering it into a Podman secret for a rootless container looks like the secret is protected end to end. It isn't, by default — verified from both the… - [What Ansible Vault actually encrypts, and where that protection stops](https://til.housni.eu/ansible/what-ansible-vault-actually-encrypts.md): 2026-09-24. Ansible's own vault guide opens with a warning worth reading before anything else about the tool: "Encryption with Ansible Vault ONLY protects 'data at rest'." That's a precise boundary, not a vague… - [Handling deployment failures with Ansible's block/rescue/always](https://til.housni.eu/ansible/block-rescue-always-error-handling.md): 2026-09-29. Saw a LinkedIn post comparing Ansible's block/rescue/always to try/catch — deploy, roll back automatically on failure, alert the team, clean up regardless. It's a real, built-in Ansible feature… - [Building an Ansible execution environment from a locked requirements file](https://til.housni.eu/ansible/execution-environment-from-a-locked-requirements-file.md): 2026-09-29. Part 3 of 7 in the Ansible development environment series. Third entry in the Ansible development environment series. An execution environment (EE) is a container image holding the whole Ansible runtime: ansible-core, ansible-runner, Python packages,… - [Locking an Ansible development environment: pip, venv, pip-tools, uv or an execution environment](https://til.housni.eu/ansible/locking-an-ansible-dev-environment-pip-to-ee.md): 2026-09-29. Part 1 of 7 in the Ansible development environment series. First entry in the Ansible development environment series. An Ansible project needs a runtime on the control node, the machine that runs ansible-playbook. That runtime has five layers, and each tool… - [Pinning ansible-core with pip-tools, uv and Poetry](https://til.housni.eu/ansible/pinning-ansible-core-pip-tools-uv-poetry.md): 2026-09-29. Part 2 of 7 in the Ansible development environment series. Second entry in the Ansible development environment series; the first ranks all the options. pip-tools, uv and Poetry all do the same job for an Ansible project. They record the exact ansible-core a… - [Where to run an Ansible development environment: venv, Dev Container, Remote-SSH, code-server or Dev Spaces](https://til.housni.eu/ansible/where-to-run-an-ansible-dev-environment.md): 2026-09-29. Part 4 of 7 in the Ansible development environment series. Fourth entry in the Ansible development environment series. The first three decide what the runtime is made of and how to lock it. This one decides where the editor and tools run. There are five… - [Ansible Development Tools (ADT): one install, and the Python version decides what you get](https://til.housni.eu/ansible/ansible-development-tools-adt.md): 2026-09-29. Part 5 of 7 in the Ansible development environment series. Fifth entry in the Ansible development environment series. Part 4 chose where the tools run; this one is about the tools themselves. ADT (Ansible Development Tools) is the PyPI package… - [Committing the VS Code Ansible settings with the repository](https://til.housni.eu/ansible/vscode-ansible-settings-per-repository.md): 2026-09-29. Part 6 of 7 in the Ansible development environment series. Sixth entry in the Ansible development environment series. Part 4 chose where VS Code runs and part 5 installed the tools. This part makes every developer's editor behave the same way on a given… - [Running playbooks locally in the execution environment production uses](https://til.housni.eu/ansible/develop-against-the-production-execution-environment.md): 2026-09-30. Part 7 of 7 in the Ansible development environment series. Seventh entry in the Ansible development environment series. Part 6 pointed the editor at the team's execution environment (EE), the container image that AAP (Red Hat Ansible Automation Platform)… ## apache - [A conditional redirect that skips one path, on Apache 2.2 through 2.4](https://til.housni.eu/apache/conditional-redirect-exclude-one-path.md): 2026-09-18. A 2018 Stack Overflow question from Maddprof, "Apache redirection based on URL from the same webserver", has a scenario worth revisiting: redirect everything under /zabbix/ to HTTPS, except… ## claude-code - [Starting with Jev in Claude Code: a plugin that adds a skill, and an API key for experiments](https://til.housni.eu/claude-code/typesafe-jev-plugin.md): 2026-09-29. Jev is TypeSafe's first "System One" model. It doesn't write text or code. You send it some state and a map of typed questions, and it answers each one with a number or a label: a yes/no… ## cloud-init - [Layering extra cloud-init config without fighting Terraform/OpenTofu's auto-generated user-data](https://til.housni.eu/cloud-init/vendor-data-alongside-terraform-user-data.md): 2026-09-07. When a VM is provisioned with the bpg/proxmox Terraform/OpenTofu provider, the initialization block's user_account/ip_config settings get turned into cloud-init's user-data automatically. Wanting to… ## git - [Installing git, gh, and glab, and the auth each one actually needs](https://til.housni.eu/git/git-gh-glab-install-and-auth.md): 2026-09-12. Three separate tools, three separate installs, and — the part that isn't obvious until it bites you — three separate credential stores. git itself doesn't know about GitHub or GitLab; gh and glab… - [Syncing a diverged fork: take the pipeline fixes, not the content](https://til.housni.eu/git/sync-a-diverged-fork-without-its-content.md): 2026-09-27. This TIL collection started as a fork of simonw/til, and since then the fork has diverged completely. The articles are mine, the build is mine (see static-site-instead-of-datasette.md), and… - [Configuring a repository for coding agents: what the guidance actually says](https://til.housni.eu/git/repo-guardrails-for-coding-agents.md): 2026-09-27. This repo is mostly written with a coding agent (Claude Code, running in a cloud session). The agent opens branches and PRs and fixes CI. After a few rounds of that I wondered whether there's any… - [A branch you fetched was force-pushed: keep the old tip, then `rebase --onto`](https://til.housni.eu/git/resync-clone-after-force-push.md): 2026-09-27. A coding agent pushed a commit to my branch (2913eb4), and I fetched it. It then amended the commit message, force-pushed the new version (504a439, same code), and pushed its next step (d23665b) on… ## github-pages - [Publishing a TIL collection as a static GitHub Pages site](https://til.housni.eu/github-pages/static-site-instead-of-datasette.md): 2026-09-05. I forked simonw/til to start my own "Today I Learned" collection, but its publishing pipeline was built around Simon's own infrastructure: build_database.py compiled every entry into a sqlite… - [Adding an Atom feed and syntax highlighting to a static site build script](https://til.housni.eu/github-pages/atom-feed-and-syntax-highlighting.md): 2026-09-05. Continuing on from publishing this TIL collection as a static site, I wanted two things a real TIL site should have: an Atom feed people can subscribe to, and syntax-highlighted code blocks instead… - [Rendering Mermaid diagrams in a Python-Markdown static site](https://til.housni.eu/github-pages/mermaid-diagrams-in-markdown.md): 2026-09-12. Wanted to drop a Mermaid diagram into a TIL and found out build_site.py had no idea what to do with one. simonw/til (the site this repo's pattern is adapted from) doesn't support it either — it's… ## gitlab-ci - [A simple GitLab CI pipeline for ansible-lint on a custom Python image](https://til.housni.eu/gitlab-ci/ansible-lint-custom-python-image.md): 2026-09-05. Installing ansible-lint with pip inside every single pipeline run works, but it's slow and re-downloads the same packages on every commit. Building a small custom image once — based on the official… ## http - [Getting a remote file's properties with curl, without downloading it](https://til.housni.eu/http/curl-remote-file-properties-without-downloading.md): 2026-09-05. A GET request pulls the whole body. Most of the time I actually want is in the headers — size, type, whether it changed — and there's a way to get each of those without pulling anything. ## kubernetes - [What Kubernetes actually is, and how it works](https://til.housni.eu/kubernetes/what-is-kubernetes-and-how-it-works.md): 2026-09-17. Part 1 of 11 in the RKE2/Kubernetes from scratch series. Starting a series on learning Kubernetes via RKE2 from scratch. Before touching RKE2 specifically, the part worth getting solid first: what a Kubernetes cluster is made of, and the one idea —… - [Cleanly stopping an RKE2 node for planned maintenance](https://til.housni.eu/kubernetes/rke2-node-maintenance-drain-reboot.md): 2026-09-17. Draining and stopping a node the right way for a patch/reboot is mostly ordinary Kubernetes practice; the one RKE2-specific trap is reaching for the wrong bundled script to actually stop it. - [Installing a single-node RKE2 server for a lab](https://til.housni.eu/kubernetes/rke2-single-node-lab-install.md): 2026-09-18. Part 3 of 11 in the RKE2/Kubernetes from scratch series. Third entry in the RKE2/Kubernetes series. A lab needs the minimum viable cluster: one machine running rke2-server, which acts as both control plane and worker — no separate node to join, no agent… - [Getting kubectl to work against RKE2 from off the node](https://til.housni.eu/kubernetes/kubectl-off-node-rke2-tls-san.md): 2026-09-18. Part 4 of 11 in the RKE2/Kubernetes from scratch series. Fourth entry in the RKE2/Kubernetes series. The lab-install entry got a node running and pointed out the trap without fixing it: the generated kubeconfig only works from the node itself. Here's why,… - [What RKE2 actually is, and how its pieces fit together](https://til.housni.eu/kubernetes/what-is-rke2-and-how-it-works.md): 2026-09-18. Part 2 of 11 in the RKE2/Kubernetes from scratch series. A closer look at the "packaging" the Kubernetes-fundamentals entry waved at: what RKE2 specifically is, why it exists as a separate thing from plain kubeadm Kubernetes or Rancher's own older RKE,… - [Pods, Deployments, Services — the minimum object model](https://til.housni.eu/kubernetes/pods-deployments-services-object-model.md): 2026-09-18. Part 5 of 11 in the RKE2/Kubernetes from scratch series. Fifth entry in the RKE2/Kubernetes series. kubectl has been reachable from off the node since the previous entry; this is the first one to actually point it at something — the three objects that… - [RKE2's default CNI is Canal, and you pick it before the first start](https://til.housni.eu/kubernetes/rke2-cni-canal-and-alternatives.md): 2026-09-18. Part 6 of 11 in the RKE2/Kubernetes from scratch series. Sixth entry in the RKE2/Kubernetes series. Everything in the previous entry — Pods getting IPs, a Service reaching Pods that might be on another node — quietly assumed pod networking already worked.… - [RKE2's ingress default moved to Traefik, because ingress-nginx is ending](https://til.housni.eu/kubernetes/rke2-ingress-traefik-nginx-retirement.md): 2026-09-18. Part 8 of 11 in the RKE2/Kubernetes from scratch series. Eighth entry in the RKE2/Kubernetes series. The storage entry was about something RKE2 never shipped. This one is about something it did ship, for years, as the obvious default — and has now moved… - [RKE2 ships no default StorageClass, and a PVC will sit Pending forever](https://til.housni.eu/kubernetes/rke2-no-default-storageclass.md): 2026-09-18. Part 7 of 11 in the RKE2/Kubernetes from scratch series. Seventh entry in the RKE2/Kubernetes series. The CNI entry covered something RKE2 bundles and makes permanent; this one covers the opposite — a thing it deliberately doesn't bundle at all, where the… - [Going HA with RKE2: three servers, one address, and the datastore choice](https://til.housni.eu/kubernetes/rke2-ha-embedded-etcd-external-datastore.md): 2026-09-18. Part 9 of 11 in the RKE2/Kubernetes from scratch series. Ninth entry in the RKE2/Kubernetes series. Everything so far has run on the single node from the lab install, where "the control plane" and "that one machine" are the same thing. This is what… - [RKE2's etcd snapshots run on schedule, but a fresh cluster starts with none](https://til.housni.eu/kubernetes/rke2-etcd-snapshot-restore-drill.md): 2026-09-19. Part 10 of 11 in the RKE2/Kubernetes from scratch series. Tenth entry in the RKE2/Kubernetes series. The HA entry closed on a warning: snapshots run without being configured, but quorum surviving a node dying and cluster state being recoverable are… - [Restoring RKE2 etcd across an HA cluster, and backing snapshots up to S3](https://til.housni.eu/kubernetes/rke2-etcd-ha-restore-and-s3-backup.md): 2026-09-20. The etcd snapshot/restore drill on this site covers the single-node case end to end, including the two gotchas that aren't in RKE2's own docs — the server: URL check that blocks cluster-reset, and… - [RKE2 leaves its servers schedulable, so your workloads have been running on the control plane all along](https://til.housni.eu/kubernetes/rke2-node-scheduling-labels-taints-tolerations.md): 2026-09-20. Part 11 of 11 in the RKE2/Kubernetes from scratch series. Eleventh entry in the RKE2/Kubernetes series. Ten entries in, every Pod created along the way has landed on a node without anyone choosing which one — including on the multi-server cluster from the… ## linux - [What cgroups v2 actually is, and how Podman and Kubernetes use it](https://til.housni.eu/linux/cgroups-v2-podman-kubernetes.md): 2026-09-18. Both Podman and Kubernetes ultimately enforce container resource limits the same way: by writing numbers into files under /sys/fs/cgroup. What "cgroup v2" changes is the shape of that filesystem,… - [Building a custom WSL2 kernel on GitHub Actions: `KCFLAGS`, not `CFLAGS`](https://til.housni.eu/linux/wsl2-kernel-on-github-actions.md): 2026-09-28. A custom WSL2 kernel is one bzImage file and one line in .wslconfig. Compiling it takes a full Linux toolchain and a quarter of an hour of four cores. GitHub Actions provides both. Standard runners… - [Checking new firewall rules with nc and Python: open, refused, or dropped](https://til.housni.eu/linux/check-firewall-rules-with-nc-and-python.md): 2026-09-29. The security team has opened these flows for dar-servera: ## nixos - [First steps on NixOS: the whole system is one file, and every change is a boot entry](https://til.housni.eu/nixos/first-steps-configuration-generations-rollback.md): 2026-09-25. Coming to NixOS from RHEL or Ubuntu, the instinct is to install a package, edit something under /etc, and restart a service. NixOS supports a version of that, but it isn't the model. The model is… - [NixOS on WSL2: a short admin runbook, and the files WSL manages instead of NixOS](https://til.housni.eu/nixos/nixos-wsl-admin-runbook.md): 2026-09-25. NixOS-WSL runs a full NixOS inside WSL2, with systemd, nixos-rebuild and generations included. Everything in the first-steps entry still applies. What changes is that WSL owns a few files NixOS… - [Oh My Zsh on NixOS: the plugin list installs nothing, and NixOS aliases win](https://til.housni.eu/nixos/zsh-oh-my-zsh-declarative.md): 2026-09-26. NixOS can configure Zsh and Oh My Zsh from configuration.nix, with no ~/.zshrc to back up. The module writes everything into a generated /etc/zshrc, and the order of that file explains most of the… - [Testing a NixOS configuration on GitHub Actions: evaluate on every push, boot it where KVM is](https://til.housni.eu/nixos/nixos-config-tests-github-actions.md): 2026-09-26. A NixOS configuration can be tested in CI at two levels. The first evaluates it: nothing is built and nothing boots, so it runs on any runner. The second boots the machine in QEMU and checks it from… - [Testing a NixOS configuration on self-managed GitLab CE: the eval job runs anywhere, the VM test needs a runner you prepare](https://til.housni.eu/nixos/nixos-config-tests-gitlab-ce.md): 2026-09-26. This is the GitLab counterpart of the GitHub Actions entry, with the same two levels and the same repo, dar-nixos. The evaluation job needs nothing from the runner. The VM test needs /dev/kvm inside… - [Home Manager as a NixOS module: dotfiles in the same rebuild, and the file that's in the way](https://til.housni.eu/nixos/home-manager-nixos-module.md): 2026-09-27. Home Manager declares a user's packages and dotfiles in Nix. As a NixOS module, it is built and activated by nixos-rebuild, with the rest of the machine. Checked against Home Manager release-26.05… - [A user's PATH on NixOS: declare packages, and know which settings reach services](https://til.housni.eu/nixos/user-path-packages-shells-services.md): 2026-09-28. The usual advice on NixOS is right. Declare packages instead of adding /nix/store/... directories to PATH, and add your own script directory through Home Manager or a shell profile. The details… ## oauth2 - [GitLab with OAuth 2.0 / OIDC — the simple principle](https://til.housni.eu/oauth2/gitlab-oauth2-oidc-principle.md): 2026-09-12. This guide uses GitLab as the application a user wants to access and an external identity provider (IdP)—for example Keycloak, Microsoft Entra ID, Okta, or Authentik—as the OAuth 2.0 / OpenID… ## packer - [What Packer actually is, and how it works](https://til.housni.eu/packer/what-is-packer-and-how-it-works.md): 2026-09-17. Part 2 of 4 in the HashiCorp infrastructure tooling series. Second entry in the HashiCorp infrastructure series. Terraform/OpenTofu manages the lifecycle of infrastructure over time; Packer's job stops the moment it hands you a finished image. That… - [Kickstart, cloud-init and Image Builder are three layers, not three choices](https://til.housni.eu/packer/rhel-template-kickstart-cloud-init-image-builder.md): 2026-09-20. Asking which of kickstart, cloud-init or Red Hat Image Builder is the right way to provision a RHEL 9/10 template with Packer sounds like a three-way comparison. Checked against each tool's own… ## podman - [Hosting a simple PHP page with Podman + Caddy, with automatic HTTPS](https://til.housni.eu/podman/caddy-php-fpm-automatic-https.md): 2026-09-05. I wanted to serve a small PHP page with a real Let's Encrypt certificate, without installing PHP, a web server, or certbot on the host. Two rootless Podman containers do the whole job: Caddy as… - [Moving a container image between hosts with podman save + scp + load, no registry](https://til.housni.eu/podman/save-scp-load-image-between-hosts.md): 2026-09-05. Sometimes the easiest way to get an image onto another machine isn't pushing it to a registry — especially for a one-off image, or a homelab box with no registry set up at all. podman save / podman… - [Sanity-checking a fresh Docker or Podman install with each engine's own hello-world](https://til.housni.eu/podman/docker-and-podman-hello-world.md): 2026-09-06. After installing either engine, the fastest way to confirm pull + run + registry access all actually work end-to-end is each project's own tiny smoke-test image — no Dockerfile, no app code, just… - [Podman equivalents to Docker's Dive image-layer explorer](https://til.housni.eu/podman/podman-equivalent-to-docker-dive.md): 2026-09-12. There's no single Podman subcommand that reproduces Dive's interactive layer browser and wasted-space score. But Dive itself already speaks Podman natively, and Podman's own commands cover most of… - [Root vs rootless Podman on RHEL 10 and Ubuntu 26.04](https://til.housni.eu/podman/root-vs-rootless-rhel10-ubuntu2604.md): 2026-09-13. Podman has no daemon either way — root and rootless are two different ways of running the same podman binary, distinguished by whether the containers it starts get a real root-owned process on the… - [Auto-updating the Caddy/Adminer/PHP Quadlet stack needs more than one AutoUpdate key](https://til.housni.eu/podman/quadlet-autoupdate-caddy-adminer-php.md): 2026-09-21. The hand-written Quadlet entry got Caddy and PHP-FPM surviving reboots, and the linux-system-roles version added Adminer on top of the same idea, deployed declaratively. The next obvious step is… - [Pointing Podman at an Artifactory mirror without editing a single image name](https://til.housni.eu/podman/artifactory-as-a-pull-through-mirror.md): 2026-09-21. Putting a local Artifactory in front of Docker Hub has two quite different implementations, and the choice decides whether every unit file on every host has to be rewritten. The interesting parts —… ## proxmox - [Installing a RIPE Atlas software probe in a Proxmox LXC](https://til.housni.eu/proxmox/ripe-atlas-software-probe-lxc.md): 2026-09-05. RIPE Atlas probes are little devices (or software) that measure Internet connectivity from wherever you run them, and contribute that data back to a global measurement network. I wanted to run one… - [Injecting qemu-guest-agent into an Ubuntu cloud template, from the CLI](https://til.housni.eu/proxmox/inject-qemu-guest-agent-ubuntu-template.md): 2026-09-07. A cloud image straight from Ubuntu doesn't have qemu-guest-agent installed, so every VM cloned from a template built on one starts without it — no IP reporting, no clean shutdown/snapshot… - [A libvirt RHEL Kickstart example ported to Proxmox, minus the one flag with no equivalent](https://til.housni.eu/proxmox/rhel-kickstart-libvirt-example-ported.md): 2026-09-20. flozanorht/kickstart is a small, real, MIT-licensed pair of Kickstart files and virt-install scripts written to accompany a Red Hat Developer article on libvirt. Read directly from the repo rather… - [Debugging a Proxmox VM whose cloud-init config didn't apply](https://til.housni.eu/proxmox/debugging-cloud-init-on-first-boot.md): 2026-09-20. A VM boots but the user, SSH key, or network config from cloud-init never showed up. Before guessing, cloud-init's own diagnostic commands narrow this down to "cloud-init never ran," "cloud-init ran… - [A Proxmox VM on demand, NixOS from Git: OpenTofu builds a skeleton, nixos-anywhere replaces it, and the host key exists before the VM](https://til.housni.eu/proxmox/nixos-on-demand-opentofu-nixos-anywhere-sops.md): 2026-09-27. The goal is a Proxmox VM created on demand that ends up as a NixOS machine described in Git, with its secrets, and with no hand-made template. It takes three tools, each doing one thing: ## python - [A regex link checker breaks on the exact HTML it was meant to check](https://til.housni.eu/python/regex-vs-htmlparser-for-dead-links.md): 2026-09-05. I noticed one of my own TIL entries had a dead link: the second entry linked to a sibling post using [text](static-site-instead-of-datasette.html), a relative link to the markdown source file. That… - [Getting a newer Python on RHEL without touching the system python3](https://til.housni.eu/python/newer-python-with-uv-without-touching-system-python-rhel.md): 2026-09-29. RHEL (and Rocky/Alma/CentOS Stream) ties /usr/bin/python3 to whatever version the OS release shipped with. dnf and a bunch of system tooling depend on that exact interpreter, so replacing it is how… ## seo - [Don't hand-write a sitemap.xml, generate it from data you already have](https://til.housni.eu/seo/generating-a-sitemap-from-existing-data.md): 2026-09-05. A sitemap.xml just tells crawlers every URL on your site plus when it last changed, so they don't have to discover pages purely by following links. For a static site build script, there's no reason… - [robots.txt for a small static site is basically a pointer to the sitemap](https://til.housni.eu/seo/robots-txt-is-mostly-just-pointing-at-the-sitemap.md): 2026-09-05. I'd assumed robots.txt needed some thought — which paths to block, which crawlers to allow or disallow. For a small public site with nothing private on it, it turns out to be three lines: - [A schema.org Person block is what actually helps you rank for your own name](https://til.housni.eu/seo/schema-org-person-for-name-search.md): 2026-09-05. I wanted my TIL site to show up when someone searches my name, and went looking for an "SEO script" to do it. There isn't one — nothing you paste in makes a search engine rank you first. What… - [Verifying a GitHub Pages site with Bing Webmaster Tools (no DNS needed)](https://til.housni.eu/seo/verifying-a-github-pages-site-with-bing.md): 2026-09-05. Bing Webmaster Tools also feeds DuckDuckGo and Yahoo results, so submitting a sitemap there covers more ground than just Google — worth doing once a sitemap already exists. The usual way to prove… ## ssh - [Useful ~/.ssh/config patterns for IaC-provisioned hosts](https://til.housni.eu/ssh/ssh-config-patterns-for-iac.md): 2026-09-17. Plain default SSH behavior assumes a small, stable set of hosts you connect to by hand. IaC (Terraform/OpenTofu, Ansible) breaks that assumption constantly: hosts get created and destroyed, the same… ## terraform - [What Terraform/OpenTofu actually is, and how it works](https://til.housni.eu/terraform/what-is-terraform-opentofu-and-how-it-works.md): 2026-09-17. Part 1 of 4 in the HashiCorp infrastructure tooling series. Starting a second from-scratch series, this time on HashiCorp's infrastructure tooling: Terraform/OpenTofu, Packer, and Nomad. First subject: what Terraform/OpenTofu actually does under the hood,… - [What Terraform/OpenTofu, Nomad, and Packer are, and how they relate](https://til.housni.eu/terraform/terraform-opentofu-nomad-packer-how-they-relate.md): 2026-09-17. Part 3 of 4 in the HashiCorp infrastructure tooling series. Third entry in the HashiCorp infrastructure series. Each tool so far has been introduced on its own; this one is the point of doing that — seeing where each one's job actually starts and stops,… - [Terraform state locking just dropped its DynamoDB requirement](https://til.housni.eu/terraform/state-locking-inspection-refactoring-drift.md): 2026-09-23. Part 4 of 4 in the HashiCorp infrastructure tooling series. Fourth entry in the HashiCorp series. The Terraform/OpenTofu fundamentals entry covered the state file as "Terraform's memory of what it created" and moved on; this one is the deep dive it deferred… - [What Terraform, OpenTofu, and Packer promise about secrets, and where each promise stops](https://til.housni.eu/terraform/what-terraform-opentofu-and-packer-promise-about-secrets.md): 2026-09-29. The Ansible Vault entry on this site was framed around a boundary Ansible states outright: encryption there "ONLY protects data at rest." Terraform's equivalent — the sensitive argument — makes no… ## tls - [Checking a TLS certificate's dates, issuer, and SANs with openssl](https://til.housni.eu/tls/openssl-checking-cert-dates-and-details.md): 2026-09-05. A handful of openssl x509 flags cover almost everything I need when I just want to inspect a certificate — no need to dump the whole thing with -text unless I'm actually debugging something… - [Splitting a .pfx into a certificate, key, and CA chain with openssl](https://til.housni.eu/tls/splitting-pfx-into-pem-crt-and-ca-chain.md): 2026-09-05. A .pfx/.p12 file bundles a certificate, its private key, and (usually) the CA chain into one password-protected file — common on Windows and from some CAs. Most Linux tools (nginx, Apache, HAProxy)… - [Adding a certificate to a Java keystore/truststore with keytool](https://til.housni.eu/tls/keytool-import-certificate-java-truststore.md): 2026-09-05. keytool ships with every OpenJDK install — no separate package needed. It manages both kinds of Java cert stores: a keystore (holds a private key plus its certificate, for a service presenting TLS)… ## vscode - [Pointing VS Code's Dev Containers extension at Podman](https://til.housni.eu/vscode/dev-containers-podman-instead-of-docker.md): 2026-09-19. One setting switches the Dev Containers extension from Docker to Podman — but a devcontainer.json written with only that setting still breaks the moment it bind-mounts the workspace, for a reason… ## windows - [Finding and force-closing a locked file on a Windows SMB share](https://til.housni.eu/windows/close-open-smb-files-powershell.md): 2026-09-18. Someone leaves for the day with a spreadsheet still open over the network, or a desktop app crashes without releasing its file handle, and now everyone else gets: "The document filename is locked… - [RDP into Windows 11 with a Microsoft account: the password, not the PIN, and `MicrosoftAccount\`](https://til.housni.eu/windows/rdp-microsoft-account-login.md): 2026-09-28. RDP to a Windows 11 PC signed in with a Microsoft account usually fails for two reasons. RDP needs the account's password, not the Windows Hello PIN. And the username often has to name the account… - [Oh My Posh in PowerShell and in WSL2 zsh, with one config file](https://til.housni.eu/windows/oh-my-posh-pwsh-and-wsl-zsh.md): 2026-09-28. Oh My Posh draws the same prompt in any shell from one JSON config. On a Windows machine with WSL2, that means PowerShell and the Linux zsh can share a prompt. There are two installs, one font, and… - [Installing PowerShell 7 on Windows, Debian and RHEL, the way Microsoft documents it](https://til.housni.eu/windows/install-powershell-7-windows-debian-rhel.md): 2026-09-29. PowerShell 7 (pwsh) is the cross-platform PowerShell. On Windows, it installs next to Windows PowerShell 5.1 (powershell.exe) rather than replacing it. On Linux, Microsoft's preferred source is its… ## Optional - [Homepage](https://til.housni.eu/): the rendered site, with the same entries grouped by topic. - [Atom feed](https://til.housni.eu/feed.atom): stamped by last modification, not first publication. - [Sitemap](https://til.housni.eu/sitemap.xml): every HTML page, including the per-topic indexes. - [Source repository](https://github.com/abdelhousni/til): the markdown these pages are built from.