SSH Hardening

Tested on: Ubuntu 24.04 LTS and AlmaLinux 9.4, OpenSSH 9.6 / 8.7 respectively. Configuration paths and directive names below are identical across both. Why this matters SSH is the front door to every server on this site. Three classes of failure account for almost every real-world SSH compromise: Password authentication accepting credentials harvested elsewhere. The root account directly logged into over SSH. A key from a former employee, contractor, or compromised workstation still present in ~/.ssh/authorized_keys six months later. This guide closes those holes and adds the minimum useful operational controls. It does not recommend changing the SSH port, fail2ban, or port-knocking as primary controls — those are noise reducers, not the security boundary. See “Gotchas” for why. ...

Last updated:  · 6 min · Paul Masterson

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

Last updated:  · 5 min · Paul Masterson

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

Last updated:  · 4 min · Paul Masterson

NIS2 at the Infrastructure Layer

Applies to: EU-established entities that fall in scope of NIS2 as essential or important entities, and the infrastructure teams that serve them. This is not legal advice — it is an infrastructure-focused reading of Article 21’s risk-management measures, intended to be operationally useful. Use it alongside formal legal review, not instead of it. Why this matters NIS2 — the Network and Information Security Directive, Directive (EU) 2022/2555 — is the regulation a lot of sysadmins are told to “comply with” without ever being told what that means at the level of files, configurations, and procedures. The directive is short by EU standards and intentionally outcome-focused: it lists ten risk-management measure areas in Article 21(2) and asks each entity to implement “appropriate and proportionate” measures in each. ...

Last updated:  · 8 min · Paul Masterson

Privacy by Design for a New Server Build

Applies to: any new Linux server intended for production where you will store, process, or transit personal data — including the metadata kind (IP addresses, user agents, login timestamps), which counts under GDPR whether or not your application has a “users” table. Why this matters GDPR Article 25 — Data protection by design and by default — is the legal text that turns “we should think about privacy” into “you must demonstrate that you thought about privacy, on paper, before you started processing.” It applies whether or not you have a website with a signup form. An Nginx access log with full client IPs is processing personal data. ...

Last updated:  · 10 min · Paul Masterson