A more privacy-friendly blog
When I started this blog, I embraced free services like Disqus and Google Analytics. These services are invasive to users’ privacy. Over the years, I have worked to eliminate them and reach a point where I do not rely on any “privacy-hostile” service.
Analytics#
- Before: Google Analytics
- After: nothing
Google Analytics is a ubiquitous way to get powerful analytics for free. It also feeds data about your visitors to Google—also for free. Self-hosted alternatives exist, like Matomo, GoatCounter, or Plausible.
I opted for a simpler solution: no analytics at all. This also lets me believe that my blog attracts thousands of visitors every day.
Update (2019-02)
For server-side logs, IP addresses are anonymized using ipscrub, a module for nginx. However, non-HTML assets are served through Amazon CloudFront.1
Fonts#
- Before: Google Fonts
- After: self-hosted
Google Fonts is a popular font library and hosting service that relies on the
generic Google Privacy Policy. The google-webfonts-helper service makes
it easy to self-host any font from Google Fonts. With help from
pyftsubset, I only include the characters used in this blog. The
font files are lighter and more complete: no problem spelling “Antonín
Dvořák.”
Videos#
- Before: YouTube
- After: self-hosted
Some articles include a video—like “OPL2LPT: an AdLib sound card for the
parallel port.” I previously used YouTube, mostly because it was the only
free platform with an option to disable ads. Streaming on-demand videos is
usually considered difficult. For example, if you just use the <video> tag,
you may push a video too large for people with a slow connection. However, it is
not that hard: hls.js enables us to deliver video sliced in segments
available at different bitrates. Users with JavaScript disabled are still
delivered with a progressive version of medium quality.
In “Self-hosted videos with HLS,” I explain this approach in more detail.
Comments#
Disqus is a popular comment solution for static websites. Zeta Global, a marketing company, acquired them, and their business model relies solely on ads. On the technical side, Disqus also loads several hundred kilobytes of resources. Many websites therefore load Disqus on demand. That is what I did. This does not solve the privacy problem and I felt people were less eager to leave a comment when they had to perform an additional action.
Update (2019-01)
A year later, comments increased significantly after removing this additional step. Between 2011 and 2015, the site collected about 140 comments. In 2016, Disqus was no longer loaded automatically and the number of comments halved. In 2018, after switching to Isso and automatic loading, there were 158 comments.
For some time, I considered building my own comment system around Atom feeds. Each page would get its own feed of comments. A piece of JavaScript would turn these feeds into HTML, and comments could still be read without JavaScript, thanks to the default rendering browsers provide. People could also subscribe to these feeds: no need for mail notifications! The feeds would be served as static files and updated on new comments by a small piece of server-side code. This could also work without JavaScript.

I still think this is a great idea. But I did not feel like developing and maintaining a new comment system. Several self-hosted alternatives exist, notably Isso and Commento. Isso is a bit more featureful, with notably an imperfect import from Disqus. Both struggle with maintenance and try to become sustainable with a paid hosted version.2 Commento is more privacy-friendly as it does not use cookies at all. However, cookies from Isso are not essential and can be filtered with nginx:
proxy_hide_header Set-Cookie; proxy_hide_header X-Set-Cookie; proxy_ignore_headers Set-Cookie;
In Isso, there is currently no mail notifications, but I have
added an Atom feed for each comment thread.
Update (2019-01)
Mail notifications were recently added and I have just enabled them here. As absolutely nobody ever used the Atom feeds, I have removed them.
Another option would have been to drop comments entirely. However, I have received great contributions as comments and I also think they serve as a form of peer review for blog articles: they are a weak guarantee that the content is not wrong.
Search engine#
- Before: Google Search
- After: DuckDuckGo
One way to add a search engine to a personal blog is to embed a form for a public search engine, like Google. That is what I did. I also slapped some JavaScript on top of it to make it look like not Google.
The solution here is easy: switch to DuckDuckGo, which lets you customize a bit the search experience:
<form id="lf-search" action="https://duckduckgo.com/"> <input type="hidden" name="kf" value="-1"> <input type="hidden" name="kaf" value="1"> <input type="hidden" name="k1" value="-1"> <input type="hidden" name="sites" value="vincent.bernat.ch/en"> <input type="submit" value=""> <input type="text" name="q" value="" autocomplete="off" aria-label="Search"> </form>
The JavaScript part is also removed as DuckDuckGo does not provide an API. Since fewer than three people likely use the search engine in a year, it seems wise not to spend too much time on this non-essential feature.
Update (2023-07)
As an alternative, Pagefind is a search engine tailored for static websites, relying on JavaScript. In my case, I do not think this is worth the effort and I will stick with DuckDuckGo.
Newsletter#
- Before: RSS feed
- After: RSS feed
but also a MailChimp newsletter
Nowadays, RSS feeds are far less popular than they used to be. I am still baffled as to why a technical audience would not use RSS, but some readers prefer to receive updates by mail.
MailChimp is a common solution for sending newsletters. It integrates with RSS feeds to trigger a mail each time new items appear in the feed. From a privacy standpoint, MailChimp seems like a good citizen: data collection is mainly limited to what is needed to operate the service. Privacy-conscious users can still avoid it and use the RSS feed.
Update (2019-12)
I have removed the newsletter. There were not many subscribers (around 40) and I felt bad about advertising such a service. Instead, I have added links to RSS-to-email services.
Less JavaScript#
- Before: third-party JavaScript code
- After: self-hosted JavaScript code
Many privacy-conscious people disable JavaScript or use extensions like uMatrix or NoScript. Except for comments, I used JavaScript only for non-essential features:
- rendering mathematical content—like in “TLS computational DoS mitigation;”
- moving footnotes as sidenotes when the screen is large enough;3
- enhancing videos to use HLS—see “Self-hosted videos with HLS;” and
- enhancing photo galleries with a lightbox—see “Debian on ThinkPad Edge 11.”
For mathematical formulae, I have switched from MathJax to KaTeX. The latter is faster and enables server-side rendering: the client-side JavaScript is not needed anymore.
For sidenotes, I have turned the JavaScript code doing the transformation into Python code, with pyquery. No more client-side JavaScript for this aspect either.
The remaining code is still present but self-hosted.
Memento: CSP#
The HTTP Content-Security-Policy header controls the resources a user agent
can load for a given page. It serves as both a safeguard and a reminder of the
external resources a site uses. Mine is moderately complex and shows what to
expect from a privacy standpoint:
Content-Security-Policy: default-src 'self' blob:; script-src 'self' blob: d2pzklc15kok91.cloudfront.net 'sha256-Yv7kZY+BkmpZYTujeN0YNmI0uRKpS5CY7E4enn1TRL0='; style-src 'self' 'unsafe-inline' data: d2pzklc15kok91.cloudfront.net; font-src 'self' data: d2pzklc15kok91.cloudfront.net; object-src 'self' d2pzklc15kok91.cloudfront.net media.bernat.ch; img-src 'self' data: d2pzklc15kok91.cloudfront.net; frame-src d2pzklc15kok91.cloudfront.net media.bernat.ch; worker-src blob:; media-src 'self' blob: about: media.bernat.ch d2pzklc15kok91.cloudfront.net; connect-src 'self' media.bernat.ch comments.luffy.cx; base-uri 'none'; frame-ancestors 'none'; form-action duckduckgo.com;
I am quite happy having been able to reach this result. 😊
-
I have no issue with using a CDN like CloudFront: it is a paid service and Amazon is not in the business of tracking users. ↩︎
-
For Isso, look at comment.sh.For Commento, look at commento.io. ↩︎ -
You may have noticed I am a footnote sicko and use them all the time for pointless stuff. ↩︎