NIS2 Technical Readiness Checklist

Scope A technical self-assessment for entities in scope of the NIS2 Directive (Directive (EU) 2022/2555). Each item is a thing a sysadmin can verify on a host now — a command output, a config flag, a file’s contents, an external scan result — not a policy approval or a named role. This is the box-level companion to nis2-infrastructure. That guide explains why each Article 21(2) measure matters and how to implement it; this checklist is the “is it actually configured?” layer. ...

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

tls-audit

What this script does tls-audit runs a read-only audit against a deployed HTTPS endpoint and reports on each item from the Nginx TLS 2026 guide and the nginx-tls config generator: Protocol support — TLS 1.0 and 1.1 should be rejected; TLS 1.2 and 1.3 should be accepted. Certificate — covers the hostname, not expired (and not expiring in the next 21 days), modern key algorithm, complete chain with at least one intermediate, not self-signed. OCSP stapling — the server should be stapling an OCSP response. HSTS — Strict-Transport-Security header present, max-age of at least one year, includeSubDomains directive set, preload flagged if present (informational, not a recommendation). Security headers — X-Content-Type-Options: nosniff and Referrer-Policy present; a Server header that leaks a version number is flagged. It uses only openssl s_client, curl, and standard text tools — no external scanner like testssl.sh required. Designed to run from a machine other than the host being audited, with no privilege. ...

9 min

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

6 min

Nginx TLS Configuration — 2026 Baseline

Tested on: Ubuntu 24.04 LTS, Nginx 1.26.x (from nginx.org stable repository), Let’s Encrypt via certbot 2.x. The same config works on RHEL 9 / AlmaLinux 9 with path adjustments noted inline. Why this matters Most Nginx TLS configurations on the internet were copy-pasted from a tutorial written three to seven years ago. That means they typically have one or more of the following problems: TLS 1.0 and 1.1 still enabled “for compatibility” with browsers that no longer exist. A hand-rolled cipher list that excludes modern AEAD suites or includes long-deprecated ones (3DES, RC4, CBC-mode without AEAD). ssl_prefer_server_ciphers on — which was correct advice once but is now the wrong default for TLS 1.3. No OCSP stapling, so every visitor’s browser does a side-channel OCSP lookup to the CA on first connection. HSTS missing, or HSTS set without includeSubDomains on a domain that has subdomains people forgot about. HTTP-only Strict-Transport-Security header (it must be served over HTTPS to be honoured at all). This guide gives you a single, opinionated baseline that addresses all of the above. It targets the Mozilla “Intermediate” profile — broad client compatibility without enabling anything embarrassing. ...

5 min

PostgreSQL Hardening

Tested on: Ubuntu 24.04 LTS, PostgreSQL 16.x (apt package from pgdg repository). Commands assume the default data directory at /etc/postgresql/16/main/. Why this matters PostgreSQL ships with defaults that are reasonable for a development laptop and wrong for an internet-exposed server. Three settings in particular cause most real-world incidents: listen_addresses = 'localhost' is fine — until someone changes it to '*' for “convenience” and the database is suddenly reachable from anywhere the firewall lets through. pg_hba.conf defaults still allow trust and md5 in some packaging. trust is no authentication. md5 is no longer considered safe and should be replaced with scram-sha-256. TLS is off by default. Application traffic to the database — including passwords and query results — travels in cleartext on the loopback or on the LAN. This guide fixes those three problems and tightens a handful of related items. It does not cover row-level security, backup hardening, or replication — those get their own guides. ...

4 min