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. ...

Last updated:  · 8 min · Paul Masterson

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. ...

Last updated:  · 11 min · Paul Masterson

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. ...

Last updated:  · 10 min · Paul Masterson

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: ...

Last updated:  · 9 min · Paul Masterson

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. ...

Last updated:  · 7 min · Paul Masterson

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. ...

Last updated:  · 8 min · Paul Masterson

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. ...

Last updated:  · 7 min · Paul Masterson

Hardened Ubuntu VPS Baseline

Tested on: Ubuntu 24.04 LTS (Noble Numbat), kernel 6.8.x, on a Hetzner Cloud CX22 instance. Steps are valid on any cloud VPS image of the same Ubuntu version. Why this matters A fresh Ubuntu cloud image is fine for a tutorial and unsuitable for production. Out of the box: The root account often accepts SSH key auth. No host firewall is enforced (the cloud provider’s network firewall is not a substitute, especially for internal traffic). Security updates apply only if you manually run apt upgrade. Time can drift by minutes, breaking TLS verification and log correlation. Audit logging is not enabled, so post-incident investigation depends on whatever syslog happens to have captured. This baseline closes those gaps in an opinionated order that minimises the window during which the server is reachable but not yet hardened. Before running step 1, pick your processors and decide your logging posture — some of the choices below depend on it. ...

Last updated:  · 6 min · Paul Masterson

PostgreSQL Backups — Logical, Physical, and Off-Site

Tested on: PostgreSQL 16.x on Ubuntu 24.04 LTS, restic 0.16.x. The patterns are version-portable to PostgreSQL 14+ with minor command differences; the principles are unchanged. Why this matters A backup you have never restored is a hope. Most “we have backups” incidents reduce to: The backup ran nightly for two years and the most recent twelve failed silently. The backup ran successfully, but the dump’s permissions excluded a schema the application started using six months ago. The backup ran successfully and is intact, but lives on the same disk as the database — so when the disk dies, both die. The backup ran successfully, off-site, encrypted, restorable — but the encryption key was on the same server, and that server is the one that just died. This guide gives you a PostgreSQL backup baseline that survives each of those failure modes. It covers logical backups (pg_dump) for portability, physical backups with WAL archiving for point-in-time recovery, encrypted off-site storage, and a restoration drill cadence. ...

Last updated:  · 7 min · Paul Masterson

Redis Hardening

Tested on: Ubuntu 24.04 LTS, Redis 7.2.x (from the official redis apt repository at packages.redis.io). Configuration paths use /etc/redis/redis.conf — RHEL-family installs use /etc/redis/redis.conf as well, so the file paths below are portable. Why this matters Almost every newsworthy Redis incident reduces to one of three failures: The server was bound to 0.0.0.0 “for testing” and reachable from the internet. There was no password (or the password was the example one from a tutorial). FLUSHALL, CONFIG, or DEBUG were left available, so a connected client could wipe data, exfiltrate keys, or write arbitrary files through CONFIG SET dir / BGSAVE. Redis is fast, in-memory, and trusts its clients by default. That trust is appropriate inside a private subnet with disciplined access controls. It is catastrophic everywhere else. This guide closes those three holes and adds the obvious next layer (TLS, resource limits, persistence safety). ...

Last updated:  · 6 min · Paul Masterson