<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Andy Dixon: Blog</title>
  <subtitle>Daily technical writing by Andy Dixon: Go and Rust internals, Linux and security how-tos, cryptography and UK privacy law, checked against source.</subtitle>
  <link href="https://dixon.cx/blog/feed.xml" rel="self" type="application/atom+xml"></link>
  <link href="https://dixon.cx/blog" rel="alternate" type="text/html"></link>
  <id>https://dixon.cx/blog</id>
  <updated>2026-09-05T06:55:27Z</updated>
  <author>
    <name>Andy Dixon</name>
    <uri>https://dixon.cx/</uri>
  </author>
  <rights>Copyright 2026 Andy Dixon</rights>
  <entry>
    <title>Why Your Go Worker Pool Deadlocks: An Unbuffered Channel Post-Mortem</title>
    <link href="https://dixon.cx/blog/go-worker-pool-unbuffered-channel-deadlock.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-worker-pool-unbuffered-channel-deadlock.html</id>
    <published>2026-09-05T06:55:27Z</published>
    <updated>2026-09-05T06:55:27Z</updated>
    <summary>A Go worker pool that deadlocks under load, traced back to an unbuffered results channel, with the fix and why bigger buffers only postpone the problem.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="concurrency"></category>
    <category term="channels"></category>
    <category term="debugging"></category>
    <category term="worker-pool"></category>
  </entry>
  <entry>
    <title>A Practical Guide to Hardening SSH: Ciphers, MACs and Key Exchange Algorithms Worth Disabling</title>
    <link href="https://dixon.cx/blog/hardening-ssh-ciphers-macs-kex-algorithms.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/hardening-ssh-ciphers-macs-kex-algorithms.html</id>
    <published>2026-09-04T10:16:03Z</published>
    <updated>2026-09-04T10:16:03Z</updated>
    <summary>A walkthrough of sshd_config&#39;s KexAlgorithms, Ciphers and MACs directives: what to strip out, why, and how to verify the change without locking yourself out.</summary>
    <category term="Security"></category>
    <category term="ssh"></category>
    <category term="cryptography"></category>
    <category term="linux"></category>
    <category term="security"></category>
    <category term="openssh"></category>
    <category term="hardening"></category>
  </entry>
  <entry>
    <title>Go&#39;s sync.Once Isn&#39;t a Mutex: What Actually Happens When f() Panics</title>
    <link href="https://dixon.cx/blog/go-sync-once-panic-behaviour.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-sync-once-panic-behaviour.html</id>
    <published>2026-09-03T10:16:03Z</published>
    <updated>2026-09-03T10:16:03Z</updated>
    <summary>sync.Once does not retry after f() panics: it quietly marks itself done, while OnceValue re-panics forever. Verified against the Go source.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="concurrency"></category>
    <category term="sync-once"></category>
    <category term="panic"></category>
    <category term="error-handling"></category>
    <category term="debugging"></category>
  </entry>
  <entry>
    <title>Certificate Transparency Logs: What They Actually Prove About a TLS Certificate, and What They Don&#39;t</title>
    <link href="https://dixon.cx/blog/certificate-transparency-logs-what-they-prove.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/certificate-transparency-logs-what-they-prove.html</id>
    <published>2026-09-02T10:16:03Z</published>
    <updated>2026-09-02T10:16:03Z</updated>
    <summary>CT logs make TLS certificate issuance publicly auditable, but they do not validate domain control, check revocation or stop mis-issuance. The actual guarantee.</summary>
    <category term="Security"></category>
    <category term="tls"></category>
    <category term="certificate-transparency"></category>
    <category term="security"></category>
    <category term="pki"></category>
    <category term="cryptography"></category>
    <category term="x509"></category>
  </entry>
  <entry>
    <title>How to Set Up Secure Boot with Your Own Keys Using sbctl</title>
    <link href="https://dixon.cx/blog/secure-boot-own-keys-sbctl-linux.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/secure-boot-own-keys-sbctl-linux.html</id>
    <published>2026-09-01T10:16:03Z</published>
    <updated>2026-09-01T10:16:03Z</updated>
    <summary>Create, enrol and maintain your own UEFI Secure Boot signing keys on Linux with sbctl, without turning the next reboot into a recovery exercise.</summary>
    <category term="Security"></category>
    <category term="linux"></category>
    <category term="secure-boot"></category>
    <category term="uefi"></category>
    <category term="sbctl"></category>
    <category term="key-management"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>Rust&#39;s Async Drop Doesn&#39;t Exist: Why You Can&#39;t Await Inside a Destructor</title>
    <link href="https://dixon.cx/blog/rust-async-drop-doesnt-exist.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/rust-async-drop-doesnt-exist.html</id>
    <published>2026-08-31T10:16:03Z</published>
    <updated>2026-08-31T10:16:03Z</updated>
    <summary>Rust has no async destructor, and it isn&#39;t an oversight. Why Drop::drop can&#39;t await, and the spawn/block_on/explicit-close patterns people use instead.</summary>
    <category term="Rust"></category>
    <category term="rust"></category>
    <category term="async"></category>
    <category term="drop"></category>
    <category term="tokio"></category>
    <category term="raii"></category>
    <category term="resource-management"></category>
  </entry>
  <entry>
    <title>Go&#39;s %w Error Wrapping: Why errors.Is Silently Breaks the Moment You Forget One Verb</title>
    <link href="https://dixon.cx/blog/go-errorf-w-verb-errors-is-silent-break.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-errorf-w-verb-errors-is-silent-break.html</id>
    <published>2026-08-30T10:16:03Z</published>
    <updated>2026-08-30T10:16:03Z</updated>
    <summary>A single %v where you meant %w compiles cleanly and passes go vet, but it quietly severs the error chain that errors.Is depends on.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="error-handling"></category>
    <category term="errors-is"></category>
    <category term="fmt-errorf"></category>
    <category term="debugging"></category>
    <category term="static-analysis"></category>
  </entry>
  <entry>
    <title>How to Set Up Borg Backup with Append-Only Repositories for Ransomware-Resistant Backups</title>
    <link href="https://dixon.cx/blog/borg-backup-append-only-ransomware-resistant.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/borg-backup-append-only-ransomware-resistant.html</id>
    <published>2026-08-29T10:16:03Z</published>
    <updated>2026-08-29T10:16:03Z</updated>
    <summary>Configure BorgBackup with a server-enforced append-only repository, so a compromised client can add backups but never delete or rewrite them.</summary>
    <category term="Systems Programming"></category>
    <category term="borgbackup"></category>
    <category term="backups"></category>
    <category term="ransomware"></category>
    <category term="ssh"></category>
    <category term="linux"></category>
    <category term="systemd"></category>
  </entry>
  <entry>
    <title>Go&#39;s GOMAXPROCS Ignores Container CPU Limits: Why a Pod&#39;s Go Service Still Thrashes the Scheduler</title>
    <link href="https://dixon.cx/blog/go-gomaxprocs-container-cpu-limits.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-gomaxprocs-container-cpu-limits.html</id>
    <published>2026-08-28T10:16:03Z</published>
    <updated>2026-08-28T10:16:03Z</updated>
    <summary>A Go service capped at 0.5 CPU in Kubernetes still spins up dozens of OS threads and gets throttled. Why GOMAXPROCS cannot see the limit, and how to fix it.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="containers"></category>
    <category term="kubernetes"></category>
    <category term="linux"></category>
    <category term="performance"></category>
    <category term="cgroups"></category>
  </entry>
  <entry>
    <title>Subject Access Requests Under UK GDPR: What Organisations Can Legally Redact, and Where They Routinely Overreach</title>
    <link href="https://dixon.cx/blog/subject-access-requests-redaction-overreach-uk-gdpr.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/subject-access-requests-redaction-overreach-uk-gdpr.html</id>
    <published>2026-08-27T10:16:03Z</published>
    <updated>2026-08-27T10:16:03Z</updated>
    <summary>The DPA 2018 exemptions that let organisations lawfully redact a subject access request, and the patterns of overreach that turn a redaction into a breach.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="gdpr"></category>
    <category term="data-protection"></category>
    <category term="subject-access-request"></category>
    <category term="privacy"></category>
    <category term="ico"></category>
  </entry>
  <entry>
    <title>How to Set Up Remote LUKS Unlocking on a Headless Linux Server with Dropbear in initramfs</title>
    <link href="https://dixon.cx/blog/remote-luks-unlock-dropbear-initramfs.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/remote-luks-unlock-dropbear-initramfs.html</id>
    <published>2026-08-26T10:16:03Z</published>
    <updated>2026-08-26T10:16:03Z</updated>
    <summary>A step-by-step guide to embedding a minimal Dropbear SSH server in initramfs so you can type a LUKS passphrase over the network on a headless server reboot.</summary>
    <category term="Security"></category>
    <category term="linux"></category>
    <category term="luks2"></category>
    <category term="dropbear"></category>
    <category term="initramfs"></category>
    <category term="cryptsetup"></category>
    <category term="ssh"></category>
  </entry>
  <entry>
    <title>Linux Capabilities vs setuid Root: Why CAP_NET_BIND_SERVICE Is the Better Way to Bind Port 80 in Go</title>
    <link href="https://dixon.cx/blog/linux-capabilities-vs-setuid-root-cap-net-bind-service-go.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/linux-capabilities-vs-setuid-root-cap-net-bind-service-go.html</id>
    <published>2026-08-25T10:16:03Z</published>
    <updated>2026-08-25T10:16:03Z</updated>
    <summary>Binding to port 80 as a non-root Go process without setuid tricks, using Linux capabilities, CAP_NET_BIND_SERVICE, setcap and systemd&#39;s AmbientCapabilities.</summary>
    <category term="Systems Programming"></category>
    <category term="go"></category>
    <category term="linux"></category>
    <category term="security"></category>
    <category term="capabilities"></category>
    <category term="setuid"></category>
    <category term="networking"></category>
  </entry>
  <entry>
    <title>bcrypt&#39;s 72-Byte Truncation: The Password Hashing Bug Hiding in Plain Sight</title>
    <link href="https://dixon.cx/blog/bcrypt-72-byte-truncation.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/bcrypt-72-byte-truncation.html</id>
    <published>2026-08-24T10:16:03Z</published>
    <updated>2026-08-24T10:16:03Z</updated>
    <summary>bcrypt silently ignores everything past the 72nd byte of a password. Why the limit exists, how it produces real collisions, and how to handle it properly in Go.</summary>
    <category term="Cryptography"></category>
    <category term="go"></category>
    <category term="cryptography"></category>
    <category term="bcrypt"></category>
    <category term="password-hashing"></category>
    <category term="security"></category>
    <category term="blowfish"></category>
  </entry>
  <entry>
    <title>How to Set Up FIDO2 Hardware Key Authentication for SSH with Resident Keys</title>
    <link href="https://dixon.cx/blog/fido2-ssh-resident-keys.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/fido2-ssh-resident-keys.html</id>
    <published>2026-08-23T10:16:03Z</published>
    <updated>2026-08-23T10:16:03Z</updated>
    <summary>A practical guide to generating resident FIDO2 SSH keys with ssh-keygen, setting a PIN, and recovering the credential onto a new machine with ssh-keygen -K.</summary>
    <category term="Security"></category>
    <category term="ssh"></category>
    <category term="fido2"></category>
    <category term="webauthn"></category>
    <category term="security"></category>
    <category term="hardware-key"></category>
    <category term="linux"></category>
  </entry>
  <entry>
    <title>Timing Side Channels in Go: Why == on a MAC Verification Is a Security Bug</title>
    <link href="https://dixon.cx/blog/timing-side-channels-go-mac-verification.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/timing-side-channels-go-mac-verification.html</id>
    <published>2026-08-22T10:16:03Z</published>
    <updated>2026-08-22T10:16:03Z</updated>
    <summary>Comparing a computed HMAC with == looks correct and compiles fine, but it leaks timing information an attacker can use to forge a valid MAC byte by byte.</summary>
    <category term="Cryptography"></category>
    <category term="go"></category>
    <category term="cryptography"></category>
    <category term="timing-attack"></category>
    <category term="hmac"></category>
    <category term="constant-time"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>SCM_RIGHTS and File Descriptor Passing: The Unix Socket Trick systemd Uses to Hand Off Privileged Sockets</title>
    <link href="https://dixon.cx/blog/scm-rights-file-descriptor-passing-systemd.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/scm-rights-file-descriptor-passing-systemd.html</id>
    <published>2026-08-21T10:16:03Z</published>
    <updated>2026-08-21T10:16:03Z</updated>
    <summary>How SCM_RIGHTS lets one Unix process hand an open file descriptor to another, with a working Go example and a look at where systemd genuinely uses it.</summary>
    <category term="Systems Programming"></category>
    <category term="linux"></category>
    <category term="unix-sockets"></category>
    <category term="systemd"></category>
    <category term="file-descriptors"></category>
    <category term="go"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>How to Set Up Fail2ban to Stop SSH Brute-Force Attacks on Linux</title>
    <link href="https://dixon.cx/blog/fail2ban-ssh-brute-force-linux.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/fail2ban-ssh-brute-force-linux.html</id>
    <published>2026-08-20T10:16:03Z</published>
    <updated>2026-08-20T10:16:03Z</updated>
    <summary>Install and configure fail2ban on Linux to block SSH brute-force attempts automatically: jail.local, the systemd journal backend and the common pitfalls.</summary>
    <category term="Security"></category>
    <category term="fail2ban"></category>
    <category term="ssh"></category>
    <category term="linux"></category>
    <category term="security"></category>
    <category term="brute-force"></category>
    <category term="systemd"></category>
  </entry>
  <entry>
    <title>Unix Domain Sockets vs TCP on Loopback: The Localhost Attack Surface Most Go Services Ignore</title>
    <link href="https://dixon.cx/blog/unix-domain-sockets-vs-tcp-loopback-attack-surface.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/unix-domain-sockets-vs-tcp-loopback-attack-surface.html</id>
    <published>2026-08-19T10:16:03Z</published>
    <updated>2026-08-19T10:16:03Z</updated>
    <summary>Binding to 127.0.0.1 feels private, but loopback TCP has no concept of &#34;who&#39;s asking&#34;. Unix domain sockets do, and Go makes using them easy.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="security"></category>
    <category term="unix-sockets"></category>
    <category term="linux"></category>
    <category term="containers"></category>
    <category term="networking"></category>
  </entry>
  <entry>
    <title>Rust&#39;s Drop Order Isn&#39;t What You Think: Why RAII Cleanup Can Fire in the Wrong Sequence</title>
    <link href="https://dixon.cx/blog/rust-drop-order-raii-cleanup-sequence.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/rust-drop-order-raii-cleanup-sequence.html</id>
    <published>2026-08-18T10:16:03Z</published>
    <updated>2026-08-18T10:16:03Z</updated>
    <summary>Rust drops locals in reverse order but struct fields in declaration order. That asymmetry is a documented footgun for locks, file handles and temp directories.</summary>
    <category term="Rust"></category>
    <category term="rust"></category>
    <category term="drop"></category>
    <category term="raii"></category>
    <category term="ownership"></category>
    <category term="memory-safety"></category>
    <category term="debugging"></category>
  </entry>
  <entry>
    <title>How to Set Up Mutual TLS Between Two Go Services with Your Own Private CA</title>
    <link href="https://dixon.cx/blog/mutual-tls-go-services-private-ca.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/mutual-tls-go-services-private-ca.html</id>
    <published>2026-08-17T10:16:03Z</published>
    <updated>2026-08-17T10:16:03Z</updated>
    <summary>Build a minimal private CA in Go and configure two services to authenticate each other with mutual TLS, including the identity check most tutorials skip.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="mtls"></category>
    <category term="tls"></category>
    <category term="pki"></category>
    <category term="x509"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>Go&#39;s os.Exit Skips Every Deferred Function: Why Your Cleanup Never Runs</title>
    <link href="https://dixon.cx/blog/go-os-exit-skips-deferred-functions.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-os-exit-skips-deferred-functions.html</id>
    <published>2026-08-16T10:16:03Z</published>
    <updated>2026-08-16T10:16:03Z</updated>
    <summary>os.Exit ends a Go process immediately without unwinding the stack, so no deferred function runs. Why, and how to structure main() so it does not bite you.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="os-exit"></category>
    <category term="defer"></category>
    <category term="error-handling"></category>
    <category term="debugging"></category>
    <category term="cli"></category>
  </entry>
  <entry>
    <title>filepath.Clean Cannot Contain an Attacker: Using openat2 to Stop Symlink Escapes in Go</title>
    <link href="https://dixon.cx/blog/filepath-clean-openat2-symlink-escapes-go.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/filepath-clean-openat2-symlink-escapes-go.html</id>
    <published>2026-08-15T10:16:03Z</published>
    <updated>2026-08-15T10:16:03Z</updated>
    <summary>Why lexical path checks cannot stop symlink escapes, and how Linux openat2 provides race-resistant directory confinement for Go services.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="linux"></category>
    <category term="security"></category>
    <category term="openat2"></category>
    <category term="symlinks"></category>
    <category term="path-traversal"></category>
  </entry>
  <entry>
    <title>How to Set Up a Default-Deny Firewall with nftables on Linux</title>
    <link href="https://dixon.cx/blog/default-deny-firewall-nftables-linux.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/default-deny-firewall-nftables-linux.html</id>
    <published>2026-08-14T10:16:03Z</published>
    <updated>2026-08-14T10:16:03Z</updated>
    <summary>Build, test and persist a default-deny nftables firewall without breaking IPv6, flushing container rules or locking yourself out of SSH.</summary>
    <category term="Security"></category>
    <category term="nftables"></category>
    <category term="linux"></category>
    <category term="firewall"></category>
    <category term="security"></category>
    <category term="networking"></category>
    <category term="ipv6"></category>
  </entry>
  <entry>
    <title>Go&#39;s Default HTTP Client Has No Timeout: The Footgun Every Tutorial Ships With</title>
    <link href="https://dixon.cx/blog/go-default-http-client-no-timeout.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/go-default-http-client-no-timeout.html</id>
    <published>2026-08-13T10:16:03Z</published>
    <updated>2026-08-13T10:16:03Z</updated>
    <summary>http.Get and http.DefaultClient have no timeout at all. Here&#39;s exactly which phases of a request are bounded, which aren&#39;t, and how to fix it properly.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="net-http"></category>
    <category term="timeouts"></category>
    <category term="networking"></category>
    <category term="debugging"></category>
  </entry>
  <entry>
    <title>Nonce Reuse in AES-GCM: Why Reusing It Once Is Enough to Break Everything</title>
    <link href="https://dixon.cx/blog/nonce-reuse-aes-gcm.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/nonce-reuse-aes-gcm.html</id>
    <published>2026-08-12T10:16:03Z</published>
    <updated>2026-08-12T10:16:03Z</updated>
    <summary>AES-GCM fails catastrophically, not gracefully, if a nonce is ever reused. Here&#39;s what actually breaks, why, and how to stop it happening.</summary>
    <category term="Cryptography"></category>
    <category term="cryptography"></category>
    <category term="aes-gcm"></category>
    <category term="go"></category>
    <category term="encryption"></category>
    <category term="security"></category>
    <category term="nonce-reuse"></category>
  </entry>
  <entry>
    <title>How to Set Up a WireGuard Site-to-Site VPN Between Two Linux Servers</title>
    <link href="https://dixon.cx/blog/wireguard-site-to-site-vpn-linux.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/wireguard-site-to-site-vpn-linux.html</id>
    <published>2026-08-11T10:16:03Z</published>
    <updated>2026-08-11T10:16:03Z</updated>
    <summary>Join two LANs over WireGuard: key generation, subnet routing, firewall rules, MTU pitfalls and how to verify the tunnel is actually carrying traffic.</summary>
    <category term="Systems Programming"></category>
    <category term="wireguard"></category>
    <category term="vpn"></category>
    <category term="linux"></category>
    <category term="networking"></category>
    <category term="site-to-site"></category>
    <category term="systemd"></category>
  </entry>
  <entry>
    <title>The Data (Use and Access) Act 2025: What Actually Changed for UK GDPR Compliance</title>
    <link href="https://dixon.cx/blog/data-use-and-access-act-2025-uk-gdpr-changes.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/data-use-and-access-act-2025-uk-gdpr-changes.html</id>
    <published>2026-08-10T10:16:03Z</published>
    <updated>2026-08-10T10:16:03Z</updated>
    <summary>The Data (Use and Access) Act 2025 amends UK GDPR rather than replacing it: new lawful bases, looser automated decision rules and a new transfer test.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="gdpr"></category>
    <category term="data-protection"></category>
    <category term="privacy"></category>
    <category term="pecr"></category>
    <category term="ico"></category>
  </entry>
  <entry>
    <title>HKDF Explained: Why Hashing Your Key Material Twice Isn&#39;t the Same as Deriving It Properly</title>
    <link href="https://dixon.cx/blog/hkdf-explained-key-derivation.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/hkdf-explained-key-derivation.html</id>
    <published>2026-08-09T10:16:03Z</published>
    <updated>2026-08-09T10:16:03Z</updated>
    <summary>A look at why sha256(sha256(secret)) is not key derivation, what HKDF&#39;s extract-and-expand construction actually buys you, and how to use it correctly in Go.</summary>
    <category term="Cryptography"></category>
    <category term="cryptography"></category>
    <category term="go"></category>
    <category term="hkdf"></category>
    <category term="key-derivation"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>How to Set Up DNS-over-TLS with Unbound for Network-Wide Privacy on Linux</title>
    <link href="https://dixon.cx/blog/dns-over-tls-unbound-network-wide-privacy.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/dns-over-tls-unbound-network-wide-privacy.html</id>
    <published>2026-08-08T10:16:03Z</published>
    <updated>2026-08-08T10:16:03Z</updated>
    <summary>Run Unbound as a validating, caching DNS-over-TLS resolver on Linux so every device on the network gets encrypted, DNSSEC-checked lookups with no per-app setup.</summary>
    <category term="Security"></category>
    <category term="dns"></category>
    <category term="dns-over-tls"></category>
    <category term="unbound"></category>
    <category term="dnssec"></category>
    <category term="linux"></category>
    <category term="privacy"></category>
  </entry>
  <entry>
    <title>context.Context Cancellation Doesn&#39;t Stop Anything: Why Your Goroutines Keep Running Anyway</title>
    <link href="https://dixon.cx/blog/context-cancellation-doesnt-stop-anything.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/context-cancellation-doesnt-stop-anything.html</id>
    <published>2026-08-07T10:16:03Z</published>
    <updated>2026-08-07T10:16:03Z</updated>
    <summary>context cancellation in Go is cooperative, not preemptive: it closes a channel and nothing more. Here&#39;s where that quietly fails, and how to actually stop work.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="concurrency"></category>
    <category term="context"></category>
    <category term="goroutines"></category>
    <category term="debugging"></category>
  </entry>
  <entry>
    <title>Why io_uring Doesn&#39;t Automatically Make Your Linux Network Service Faster</title>
    <link href="https://dixon.cx/blog/io-uring-network-service-not-automatically-faster.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/io-uring-network-service-not-automatically-faster.html</id>
    <published>2026-08-06T10:16:03Z</published>
    <updated>2026-08-06T10:16:03Z</updated>
    <summary>io_uring&#39;s benchmarks are real, but most of its wins are in storage and syscall-bound workloads. Why bolting it onto a network service often buys nothing.</summary>
    <category term="Systems Programming"></category>
    <category term="linux"></category>
    <category term="io_uring"></category>
    <category term="networking"></category>
    <category term="performance"></category>
    <category term="security"></category>
    <category term="epoll"></category>
  </entry>
  <entry>
    <title>How to Set Up Automated Encrypted Backups with restic and a Remote SFTP Target</title>
    <link href="https://dixon.cx/blog/restic-encrypted-backups-sftp.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/restic-encrypted-backups-sftp.html</id>
    <published>2026-08-05T10:16:03Z</published>
    <updated>2026-08-05T10:16:03Z</updated>
    <summary>A practical guide to backing up a Linux machine with restic over SFTP: repository setup, password handling, systemd timers, retention, and verifying restores.</summary>
    <category term="Systems Programming"></category>
    <category term="restic"></category>
    <category term="backups"></category>
    <category term="sftp"></category>
    <category term="encryption"></category>
    <category term="linux"></category>
    <category term="systemd"></category>
  </entry>
  <entry>
    <title>Technical Capability Notices Under the Investigatory Powers Act: What They Can Actually Compel a Company to Do</title>
    <link href="https://dixon.cx/blog/technical-capability-notices-investigatory-powers-act.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/technical-capability-notices-investigatory-powers-act.html</id>
    <published>2026-08-04T10:16:03Z</published>
    <updated>2026-08-04T10:16:03Z</updated>
    <summary>What a technical capability notice under the Investigatory Powers Act can require, why the Apple ADP dispute turned on one phrase, and why it is secret.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="investigatory-powers-act"></category>
    <category term="encryption"></category>
    <category term="surveillance"></category>
    <category term="privacy"></category>
    <category term="apple"></category>
  </entry>
  <entry>
    <title>PECR and Cookie Banners: Why Most UK &#39;Reject All&#39; Buttons Are Still Non-Compliant</title>
    <link href="https://dixon.cx/blog/pecr-cookie-banners-reject-all-non-compliant.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/pecr-cookie-banners-reject-all-non-compliant.html</id>
    <published>2026-08-03T10:16:03Z</published>
    <updated>2026-08-03T10:16:03Z</updated>
    <summary>Why UK cookie banners with a working &#39;reject all&#39; button still breach PECR, from consent-timing bugs to IAB TCF legitimate interest loopholes.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="pecr"></category>
    <category term="privacy"></category>
    <category term="cookies"></category>
    <category term="gdpr"></category>
    <category term="dark-patterns"></category>
  </entry>
  <entry>
    <title>A Practical Guide to GPG Subkeys: Keeping Your Master Key Offline While Signing and Encrypting Daily</title>
    <link href="https://dixon.cx/blog/gpg-subkeys-offline-master-key-guide.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/gpg-subkeys-offline-master-key-guide.html</id>
    <published>2026-08-02T10:16:03Z</published>
    <updated>2026-08-02T10:16:03Z</updated>
    <summary>How to split a GPG identity into an offline certify-only master key and day-to-day sign, encrypt and auth subkeys, with backup and rotation steps.</summary>
    <category term="Security"></category>
    <category term="gpg"></category>
    <category term="pgp"></category>
    <category term="subkeys"></category>
    <category term="key-management"></category>
    <category term="cryptography"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>TLS Hides Your Data, Not Your Behaviour: What Traffic Analysis Can Still See</title>
    <link href="https://dixon.cx/blog/tls-traffic-analysis-metadata-leaks.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/tls-traffic-analysis-metadata-leaks.html</id>
    <published>2026-08-01T10:16:03Z</published>
    <updated>2026-08-01T10:16:03Z</updated>
    <summary>TLS encrypts the contents of your connections, but packet sizes, timing, SNI and DNS still leak enough to fingerprint sites, videos and even keystrokes.</summary>
    <category term="Security"></category>
    <category term="tls"></category>
    <category term="traffic-analysis"></category>
    <category term="privacy"></category>
    <category term="networking"></category>
    <category term="encryption"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>SQLite in WAL Mode: Why Concurrent Writers Still Block, and How Go&#39;s database/sql Pool Makes It Worse</title>
    <link href="https://dixon.cx/blog/sqlite-wal-mode-concurrent-writers-go-database-sql-pool.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/sqlite-wal-mode-concurrent-writers-go-database-sql-pool.html</id>
    <published>2026-07-31T10:16:03Z</published>
    <updated>2026-07-31T10:16:03Z</updated>
    <summary>WAL mode lets SQLite readers and writers coexist, but writers still queue for one lock. Go&#39;s connection pool can turn that into &#39;database is locked&#39; errors.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="sqlite"></category>
    <category term="concurrency"></category>
    <category term="database"></category>
    <category term="wal"></category>
    <category term="database-sql"></category>
  </entry>
  <entry>
    <title>How to Set Up SSH Certificate Authentication with Your Own Minimal CA</title>
    <link href="https://dixon.cx/blog/ssh-certificate-authentication-minimal-ca.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/ssh-certificate-authentication-minimal-ca.html</id>
    <published>2026-07-30T10:16:03Z</published>
    <updated>2026-07-30T10:16:03Z</updated>
    <summary>Replace sprawling authorized_keys files with a small self-hosted SSH certificate authority: user and host certificates, principals and revocation.</summary>
    <category term="Security"></category>
    <category term="ssh"></category>
    <category term="pki"></category>
    <category term="certificates"></category>
    <category term="linux"></category>
    <category term="security"></category>
    <category term="access-control"></category>
  </entry>
  <entry>
    <title>Data Retention Notices Under the Investigatory Powers Act: What ISPs Actually Have to Log, and for How Long</title>
    <link href="https://dixon.cx/blog/ipa-data-retention-notices-what-isps-log.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/ipa-data-retention-notices-what-isps-log.html</id>
    <published>2026-07-29T10:16:03Z</published>
    <updated>2026-07-29T10:16:03Z</updated>
    <summary>Section 87 retention notices under the Investigatory Powers Act 2016: what UK ISPs must log, the 12-month cap, entity versus events data, and why it is secret.</summary>
    <category term="Privacy Law"></category>
    <category term="uk-law"></category>
    <category term="investigatory-powers-act"></category>
    <category term="privacy"></category>
    <category term="isp"></category>
    <category term="data-retention"></category>
    <category term="surveillance"></category>
  </entry>
  <entry>
    <title>fsync Lies: What Linux Actually Guarantees About a &#39;Durable&#39; Write</title>
    <link href="https://dixon.cx/blog/fsync-lies-linux-durable-write-guarantees.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/fsync-lies-linux-durable-write-guarantees.html</id>
    <published>2026-07-28T10:16:03Z</published>
    <updated>2026-07-28T10:16:03Z</updated>
    <summary>fsync() returning zero feels like a promise the bytes are safe. Page cache, errseq_t, directory entries and disk caches make that promise weaker than it looks.</summary>
    <category term="Systems Programming"></category>
    <category term="linux"></category>
    <category term="fsync"></category>
    <category term="filesystems"></category>
    <category term="durability"></category>
    <category term="go"></category>
    <category term="storage"></category>
  </entry>
  <entry>
    <title>How to Set Up TPM2-Backed LUKS Unlocking with systemd-cryptenroll</title>
    <link href="https://dixon.cx/blog/tpm2-luks-unlocking-systemd-cryptenroll.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/tpm2-luks-unlocking-systemd-cryptenroll.html</id>
    <published>2026-07-27T10:16:03Z</published>
    <updated>2026-07-27T10:16:03Z</updated>
    <summary>Enrolling a TPM2 chip into a LUKS2 volume with systemd-cryptenroll: PCR selection, PIN protection and the kernel-update trap that locks people out.</summary>
    <category term="Security"></category>
    <category term="linux"></category>
    <category term="luks2"></category>
    <category term="tpm2"></category>
    <category term="systemd"></category>
    <category term="encryption"></category>
    <category term="cryptsetup"></category>
  </entry>
  <entry>
    <title>The Online Safety Act&#39;s Encryption Clash: What &#39;Technically Feasible&#39; Client-Side Scanning Would Actually Require</title>
    <link href="https://dixon.cx/blog/online-safety-act-encryption-technically-feasible-scanning.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/online-safety-act-encryption-technically-feasible-scanning.html</id>
    <published>2026-07-26T10:16:03Z</published>
    <updated>2026-07-26T10:16:03Z</updated>
    <summary>Ofcom&#39;s section 121 powers under the Online Safety Act, what client-side CSAM scanning would involve, and why &#39;technically feasible&#39; may be a category error.</summary>
    <category term="Security"></category>
    <category term="online-safety-act"></category>
    <category term="encryption"></category>
    <category term="privacy"></category>
    <category term="csam-scanning"></category>
    <category term="uk-law"></category>
    <category term="security"></category>
  </entry>
  <entry>
    <title>Passkeys Under the Hood: What WebAuthn Actually Signs, and Why Phishing Can&#39;t Replay It</title>
    <link href="https://dixon.cx/blog/webauthn-what-gets-signed-phishing-resistance.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/webauthn-what-gets-signed-phishing-resistance.html</id>
    <published>2026-07-25T10:16:03Z</published>
    <updated>2026-07-25T10:16:03Z</updated>
    <summary>A byte-level look at what a WebAuthn assertion signs: the origin, the challenge and the RP ID hash, and why that binding defeats classic phishing proxies.</summary>
    <category term="Security"></category>
    <category term="webauthn"></category>
    <category term="passkeys"></category>
    <category term="security"></category>
    <category term="cryptography"></category>
    <category term="phishing"></category>
  </entry>
  <entry>
    <title>A Practical Guide to LUKS2 Full-Disk Encryption with a Detached Header on a USB Key</title>
    <link href="https://dixon.cx/blog/luks2-detached-header-usb-key.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/luks2-detached-header-usb-key.html</id>
    <published>2026-07-24T10:16:03Z</published>
    <updated>2026-07-24T10:16:03Z</updated>
    <summary>How to set up LUKS2 disk encryption with the header on a separate USB key: the commands, the backup steps, and what it does and does not protect against.</summary>
    <category term="Security"></category>
    <category term="linux"></category>
    <category term="luks2"></category>
    <category term="encryption"></category>
    <category term="cryptsetup"></category>
    <category term="security"></category>
    <category term="usb"></category>
  </entry>
  <entry>
    <title>Cancellation Safety in Tokio: Why select! Can Silently Drop Your Work</title>
    <link href="https://dixon.cx/blog/tokio-select-cancellation-safety.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/tokio-select-cancellation-safety.html</id>
    <published>2026-07-23T10:16:03Z</published>
    <updated>2026-07-23T10:16:03Z</updated>
    <summary>tokio::select! drops the losing branch&#39;s future, and for some Tokio methods that means silently lost bytes and desynced protocols. How to spot and fix it.</summary>
    <category term="Rust"></category>
    <category term="rust"></category>
    <category term="tokio"></category>
    <category term="async"></category>
    <category term="concurrency"></category>
    <category term="networking"></category>
  </entry>
  <entry>
    <title>Argon2id in Go: Picking Parameters You Can Actually Defend</title>
    <link href="https://dixon.cx/blog/argon2id-go-parameters.html" rel="alternate" type="text/html"></link>
    <id>https://dixon.cx/blog/argon2id-go-parameters.html</id>
    <published>2026-07-22T10:16:03Z</published>
    <updated>2026-07-22T10:16:03Z</updated>
    <summary>How to choose Argon2id memory, time and parallelism parameters in Go that you can actually defend, with a working hash-and-verify implementation.</summary>
    <category term="Go"></category>
    <category term="go"></category>
    <category term="security"></category>
    <category term="cryptography"></category>
    <category term="password-hashing"></category>
    <category term="argon2"></category>
  </entry>
</feed>
