Quick note on HTTP security headers

I recently ran my site through securityheaders.com and realized I was missing a few useful headers. Here is the set I ended up adding to my Nginx config. The headers add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self';" always; What each one does: X-Content-Type-Options prevents browsers from guessing the MIME type of a response. Without this, a browser might interpret a text file as HTML and execute scripts in it. X-Frame-Options prevents your site from being embedded in an iframe on another domain. This mitigates clickjacking attacks. Referrer-Policy controls how much referrer information is sent when navigating away from your site. strict-origin-when-cross-origin is a sensible default. Permissions-Policy explicitly disables browser features your site does not use. A static blog has no need for camera or microphone access. Content-Security-Policy restricts where resources can be loaded from. The policy above only allows resources from the same origin, which is exactly right for a self-contained static site with no external dependencies. The always keyword Note the always parameter on each header. Without it, Nginx only adds headers to successful responses (2xx and 3xx). With always, headers are included on error pages too. This matters because error pages are also potential attack vectors. ...

March 8, 2026 · 2 min · Martin Lindqvist

Linux security basics for a personal server

After setting up my VPS, security was the next priority. A server on the public internet gets probed constantly. Within hours of going live, the auth log fills up with failed SSH login attempts from all over the world. This post covers the measures I took. None of this is novel, but having it written down in one place is useful. SSH hardening SSH is the primary way you access a Linux server, which makes it the primary target for attackers. The default configuration is functional but permissive. ...

October 25, 2025 · 5 min · Martin Lindqvist

Understanding TLS certificates and Let's Encrypt

When I first set up HTTPS on my server, I realized I did not fully understand what was happening behind the scenes. I knew I needed a certificate, and I knew Let’s Encrypt was free, but the details were fuzzy. So I dug into it. What TLS actually does TLS (Transport Layer Security) provides three things for a connection between a client and a server: Encryption. The data in transit cannot be read by anyone observing the network. Authentication. The client can verify it is talking to the intended server, not an impostor. Integrity. The data cannot be modified in transit without detection. When your browser connects to a site over HTTPS, a TLS handshake happens before any HTTP data is exchanged. During this handshake, the server presents its certificate. ...

September 28, 2025 · 5 min · Martin Lindqvist