Programs and space for creative people.

/ technology / Tej Pochiraju

On building a new website that protects user privacy

All Jaaga sites, and indeed most of our personal sites, have long used Google Analytics to measure web visits and understand how to improve engagement - all the usual "wants" of building and hosting a website.

However, every Google UA code snippet embedded in a page is grist to the Google personalised advertising mill. Shaken out of our stupor by this excellent article and the Data Detox exhibit at MozFest this year, we made a conscious choice to not leak our web visitor information to behemoths such as Google, Facebook or Twitter. This post is a quick summary of changes we made while building this brand new site.

Step 1 - Remove Social Media Embeds [10-15 minutes, Beginner]

This one is easy. Every social media widget or even share buttons provided by Facebook/Twitter/A.N.Other tracks visitors. Remove them - they slow the site down and don't add much that you can't achieve with links to your social media pages. We chose to go with Font Awesome icon links in the footer that link to our pages on these platforms.



<div class="field is-grouped"> <a class="button has-no-border" href="" target="_blank"> <span class="icon"><i class="fa fa-facebook is-size-5"></i></span> </a>&nbsp; <a class="button has-no-border" href="" target="_blank"> <span class="icon"><i class="fa fa-twitter is-size-5"></i></span> </a> <a class="button has-no-border" href="" target="_blank"> <span class="icon"><i class="fa fa-instagram is-size-5"></i></span> </a> </div>

Step 2 - Go HTTPS [15-30 minutes, Intermediate]


This site is built on the incredibly beautiful Ghost blogging platform with a custom theme coded from scratch. Our Ghost instance is a Docker container deployed using docker-compose. All of this is easy enough, the most important security value comes from using NGINX as a reverse proxy in front of this Ghost container.

Setting up SSL on NGINX for the route

We followed this easy-to-read tutorial from Digital Ocean to understand the steps and adapted it to our Ghost use case. They essentially boil down to using Let's Encrypt to generate the SSL certificates and configuring NGINX with the file below:


server { listen 80; server_name; return 301$request_uri; } server { listen 443 ssl; expires $expires; server_name; #ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_certificate /etc/letsencrypt/live/; ssl_certificate_key /etc/letsencrypt/live/; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; ssl_prefer_server_ciphers on; location / { proxy_pass; proxy_set_header Host $http_host; proxy_http_version 1.1; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; } }

Generating SSL keys with certbot/letsencrypt-auto

Again we refer to some excellent Digital Ocean documentation to generate free SSL certificates for our new domain and renew automatically before expiry (since Let's Encrypt certificates only last 90 days).

The only change we needed to make from the tutorial was to use the standalone mode for generating and renewing certificates as we can't run certbot from within webroot for Ghost. Running certbot in standalone mode requires port binding to 443 (HTTPS) which is also where NGINX is listening. So we have to shut down NGINX before running certbot. This is easy enough to do for the setup but we need to ensure maximum uptime during renewals. We deleted the default /etc/cron.d/daily/ cronjob that certbot creates (this WILL fail due to port binding) and use this instead:

`# m h dom mon dow command

0 3 * * * systemctl stop nginx && certbot renew && systemctl start nginx

This job runs everyday at 3am, shuts down nginx, checks for renewal and starts nginx again. Our tests show this whole thing takes less than 3s. We can live with that at 3am!

A slight aside: users, check out HTTPS Everywhere - a free plugin for Firefox and Chrome from the Electronic Frontier Foundation. This ensures that you will always use the secure version of a website, if available.

Step 3 - Move over, Google Analytics. Enter Piwik [30 minutes, Intermediate]

Remember what we said at the start of this now-pretty-long blog post? Google makes it super-easy to install analytics on your site but is also using it to collect invasive information about all your users. Once we understood how this works, we did not feel comfortable being a honeypot for Google any longer.
It didn't take much ducking for us to find Piwik which appeared well-maintained with strong documentation and community support. Piwik is a self-hosted replacement for Google Analytics that gives you a ton of options to optimise for privacy of your users (see image below for an example).


Given we are already using Docker to host our website, it made sense to seek out a Docker image for Piwik. Installing and setting it up was easy using the instructions here. However, we did modify the docker-compose.yml to remove all the custom network blocks.

Before you start and configure Piwik, you will want to set up your (sub)domain name for Piwik + NGINX reverse proxy with SSL as above. Piwik needs a trusted domain and this will save you some reconfiguration and error messages.

Step 4 - Communicate About Privacy

It's not enough to make these changes to your website - empower your users by educating them on privacy. Have a strong privacy policy, share links to the Data Detox Kit and give them the option to opt out of tracking analytics.

User without Do Not Track enabled.
User with Do Not Track enabled.

Step 5 - Do a Periodic Review

We are currently using hosted versions of FontAwesome and Google Fonts. Moving at least the Google Fonts onto our server seems possible. However, as of this writing we haven't been able to do this successfully with Ghost. If you know how, please get in touch. If we figure it out, we will post an update.
Besides these technical changes, we also realised that our underlying infrastructure affects privacy. We host on AWS and use Mailchimp for our subscription list. Our users are, in blindness, agreeing to the terms and conditions of those vendors too. While AWS' policy seems pretty clear on customer privacy, Mailchimp's is less clear[1]. And therein lies the challenge - it may be impossibly difficult for small organisations like ours to do everything. But as Tesco would like to keep reminding us,

Every little helps.

  1. For now, while we evaluate other solutions, we have moved back to using Google Sheets for all our email lists via the incredible Zapier. ↩︎