Ollama Hardening

Tested on: Ubuntu 24.04 LTS, Ollama 0.30.9 (June 2026 stable line), NVIDIA driver 555-series with CUDA 12.x, Caddy 2.8 as the reverse proxy. The Ollama binary moves fast; verify the systemd unit and environment-variable names against the release you are installing. This guide assumes you have already worked through ubuntu-baseline or rhel-baseline and the ssh-hardening guide. Ollama is layered on top of a defensible host, not a fresh provider image. If the underlying box is not hardened, hardening the model server on top of it is theatre. ...

10 min

Making a Static Site Agent-Ready: What I Changed, What I Didn't, and Why

Tested on: Hugo 0.147.0 (extended), Cloudflare Pages (Free plan), 23 May 2026. The standards in this space are moving fast — re-check the IANA Link Relations registry and the IETF Content-Signal draft before copying anything verbatim into a production site. The phrase “agent-ready” covers a moving target. Twelve months ago it meant “have a sitemap.” Today it touches RFC 8288 Link headers, the IETF Content-Signal draft, IANA registered relations, content negotiation for text/markdown, llms.txt, AI sitemaps, and /.well-known/agent-skills/. Most of those are drafts or vendor experiments. Some of them are stable enough to ship now. Others are worth watching but not worth wiring up yet. ...

11 min

Building Agentic AI for Security: Architecture, Threat Modelling, and the Audit Trail You Will Actually Need

The first article in this series covered the strategic and governance considerations for deploying agentic AI in a security context — control postures, the human-in-loop vs on-loop distinction, and the compliance position. If you have not read it, I would suggest starting there. This article is for the architects and engineers who now need to build the system. I will cover reference architecture, how to threat model an agentic pipeline, practical prompt-injection defences, and what your audit trail needs to look like if it is going to hold up under scrutiny. ...

12 min

Agentic AI in Security: Why Control Posture Matters More Than Capability

Agentic AI is no longer a research concept. It is arriving in security tooling right now — in vulnerability management platforms, in SIEM enrichment pipelines, in incident response workflows. Whether your organisation has made a deliberate decision about it or not, the probability is high that it is already touching your environment in some form. My concern is not the capability. The capability is genuinely impressive. My concern is that most of the conversation around agentic AI in security is being led by vendors and AI engineers — not by the people who will be held accountable when something goes wrong. ...

8 min

Deploying a Flask Tools Site on a Hardened VPS Behind Caddy

Tested on: Ubuntu 24.04 LTS, Python 3.12.3, Caddy 2.x, gunicorn 23.0, Flask 3.x, SQLite as the data store. The pattern is portable to any small Python web app — drop in whichever Flask / Starlette / FastAPI codebase you have. Why this matters Most Flask deployment tutorials end at flask run --host 0.0.0.0 and a hand-wave about Nginx. That gap — between “the app starts” and “the app is a service my colleagues would trust at 2am” — is where the operationally interesting decisions live: which user runs it, how it talks to the reverse proxy, where its secrets live, how it survives a reboot, how its certificate renews itself. ...

11 min

Encrypted Backups with restic

Tested on: Ubuntu 24.04 LTS and AlmaLinux 9.4, restic 0.16.x. The patterns translate to restic 0.15+ unchanged; older versions have a few CLI differences flagged inline. Why this matters The most common “we had backups, but…” incidents reduce to one of four failures: The backup was on the same disk as the data. When the disk failed, both went together. The backup tool never encrypted anything. A misconfigured S3 bucket leaked the entire database — including the personal data the business had promised to protect. The encryption passphrase died with the original server. The off-site backups still exist; nobody can read them. The backup ran nightly and the most recent twelve failed silently. No alert, no log review, no drill. restic addresses every one of these as a default. It encrypts in the client, deduplicates, supports a wide range of off-site targets, exposes a clean check command for integrity, and reports non-zero exit codes on failure that integrate cleanly with cron and CI. It is not the only acceptable choice — borgbackup is the close runner-up, and for some local-first workloads it is the better fit — but for the EEA-region, S3-compatible, off-site target this site recommends, restic is the path of least resistance. ...

10 min

Log Minimisation Recipes — Nginx, Apache, PostgreSQL, Applications

Tested on: Ubuntu 24.04 LTS, Nginx 1.26.x, Apache 2.4.x, PostgreSQL 16.x, Python 3.12. The principles are language- and stack-independent; the recipes are concrete examples. Why this matters Default logging on every component in a typical stack captures more personal data than the operator usually realises. A standard Nginx access log line: 192.0.2.42 - - [17/May/2026:14:01:12 +0000] "GET /search?q=password+reset+for+alice%40example.com HTTP/2.0" 200 4231 "https://example.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4) AppleWebKit/605.1.15..." …retains, for as long as the log is kept: ...

9 min

Nginx Rate Limiting — limit_req, limit_conn, and fail2ban

Tested on: Ubuntu 24.04 LTS, Nginx 1.26.x (nginx.org stable repository). All directives are core Nginx — no third-party modules required. Why this matters A web tier with no rate limiting fails in three predictable ways: Authentication brute force. A WordPress, application, or admin-panel login form with no rate cap is one credential-stuffing tool away from compromise. Signup / forgot-password abuse. Endpoints that send email, provision accounts, or issue tokens are expensive and attractive to spammers. Single-tenant noise becomes shared-tenant outage. One misbehaving client (or one bot) hammering an endpoint can starve FPM workers, application-server threads, and database connections. Rate limiting is not DDoS protection — that lives at the CDN / WAF layer if you need it. Nginx rate limiting is for the predictable, day-to-day class of behaviour: too many requests from too few sources to too few endpoints. Get this right and your origin survives even when something at the edge fails. ...

7 min

WordPress Hardening for Agencies

Tested on: WordPress 6.5.x on Ubuntu 24.04 LTS, Nginx 1.26.x, PHP-FPM 8.3, MariaDB 10.11. Most settings translate directly to Apache; Nginx-specific blocks are clearly marked. Why this matters WordPress powers a large share of the web, which makes it the most attacked CMS. Most WordPress incidents are not novel — they are one of: An out-of-date plugin with a known CVE, exploited within days of public disclosure. wp-login.php brute-force, succeeding because an admin reused a password leaked from elsewhere. Filesystem permissions that let the web server write to source files, so a single PHP RCE becomes persistent. A backup containing the entire database, stored unencrypted, exposed via a misconfigured S3 bucket. For an agency hosting multiple client sites, the blast radius compounds: one compromised site can pivot to siblings via shared filesystem, shared database server, or shared PHP-FPM pool. This guide gives you a baseline that addresses each of the above and isolates per-site risk. ...

8 min

Hardened RHEL / AlmaLinux VPS Baseline

Tested on: AlmaLinux 9.4 (kernel 5.14.x). The same steps apply to Rocky Linux 9 and Red Hat Enterprise Linux 9.x — all three share the same package set, service names, and SELinux profile. Why this matters A fresh RHEL-family cloud image differs from Ubuntu’s defaults in two important ways: SELinux is in enforcing mode by default — which is good, until an operator hits a denied syscall, panics, and runs setenforce 0. The baseline below assumes you’ll keep SELinux on and learn to tune it. The default firewall is firewalld, not ufw — same idea, different vocabulary. Internal-API hosts often ship with firewalld enabled but permissive; never trust the defaults without inspecting. Otherwise the threat model and the order of operations match the Ubuntu baseline: create a non-root user, harden SSH, enforce a host firewall, enable automatic security updates, turn on auditing, fix time. This guide is the RHEL-family-specific translation. ...

7 min