Page MenuHomePhabricator

Deploy a KISS Google Font proxy for Wikimedia Italia
Closed, ResolvedPublic

Description

Preamble

Lot of WordPress themes have very cute but complex Theme Editors (from now: "Automagic Theme Editors"). This is a nice feature allowing the stupidest of monkeys (→ like me in the morning) to change whatever wonderful frontend area in a snap without imploding their brain handling evil CSS rules.

This works thanks to hammered minified JavaScript and CSS injected in every page of your website unicorn's magic powder.

NOTE: Obviously these Automagic Theme Editors does not really allow to change whatever frontend area. Sadly they usually miss that option from your innermost desires. I'm just trying to say that they allow to change lot of stuff. That's the point.

Here you can see a live example:

image.png (1×1 px, 170 KB)

image.png (769×970 px, 221 KB)

Just some random WordPress theme editors. Look at all these automagic options. Especially font options.
Yes. Just think about a font name, press Save, and start having serious business in Comic Sans + Futura + Times New Roman.

Under the hood, these Fancy Theme Editors with font pickers work thanks to third parts services like "Google Font" (https://en.wikipedia.org/wiki/Google_Fonts). This service effectively allows to load dozen of fonts from a single external don't-care CSS file.

To make things even more efficient (or vendor lock-in?) Google Font smartly returns a different response for each User-Agent. For example:

  • if you have Mozilla Firefox - Google Fonts sends you very old font formats (yup, even if Mozilla Firefox supports them all)
  • you have Google Chrome - Google Fonts sends you faster font formats (!)
  • more features in the FAQ: https://developers.google.com/fonts/faq

This makes Google Font even more automagic and difficult to be replaced.

In short, Google Font is damn widespread.

Description of the issue

In short, Google Font is so widespread that, if you have a WordPress website, very probably:

  • Google discovers your visitors' info (exact operating system, exact browser version, your languages, your IP address, and more)
  • Google is technically allowed to inject whatever CSS rule in your website (NSA? have you listened this opportunity?)
  • it's not a 5-minute fix
  • if fix that, you probably have overrided some parts of your Automagic Theme Editor
    • causing errors like: «Uh? I've changed the fonts from the editor but it does not work! You are fired! Damn Ghanoo plus Leenoocs nerd!»

In short, you should replace Google Font, but it's not that simple.

Proposed solution

Recently I started playing with Apache HTTPd and its features and I've found out that you can create a KISS (keep-it-simple-and-stupid) Google Font proxy in 5 minutes in any Debian GNU/Linux toaster.

What does it mean:

  • you can create a drop-in replacement of Google Fonts: just change one URL to got the hell out of Google Fonts from the visitor perspective
  • GDPR super-friendly: you have something in the middle doing requests to Google Fonts (never reveal again your visitors' data to Google)
  • netiquette friendly: this solution does not flood Google Fonts with requests from a single server (because it caches similar requests)
    • I mean. Yes. Google has enough bandwidth but... let's avoid to be banned for stupid reasons.
  • super-simple: the configuration is just a copy-pasta configuration
  • zero maintenance: Apache HTTPd is smart enough to kill old cache entries

Further reading:

Implementation for Wikimedia Italia

ssh intreccio.wikimedia.it
$ mkdir /var/www/wmi/google-font-proxy

$ a2enmod cache
Enabling module cache.
To activate the new configuration, you need to run:
  systemctl restart apache2

$ a2enmod substitute
Enabling module substitute.
To activate the new configuration, you need to run:
  systemctl restart apache2

$ # create an amazing homepage with link to this task
$ nano /var/www/wmi/google-font-proxy/index.html

$ # paste my config from https://gitpull.it/T776
$ nano /etc/apache2/include/google-font-proxy.conf

$ # create a couple of dummy virtualhosts including that config
nano /etc/apache2/sites-available/it-wikimedia-test-{txt,ssl}.conf

$ a2ensite it-wikimedia-test-txt.conf 
Site it-wikimedia-test-txt already enabled

$ certbot certonly --webroot --webroot-path=/var/www/html -d test.wikimedia.it                                                                                       
Saving debug log to /var/log/letsencrypt/letsencrypt.log                                                
Plugins selected: Authenticator webroot, Installer None                                                 
Obtaining a new certificate                                                                             
Performing the following challenges:                                                                    
http-01 challenge for test.wikimedia.it                                                                 
Using the webroot path /var/www/html for all unmatched domains.                                         
Waiting for verification...                                                                             
Cleaning up challenges                                                                                  
                                                                                                        
IMPORTANT NOTES:                                                                                        
 - Congratulations! Your certificate and chain have been saved at:                                      
   /etc/letsencrypt/live/test.wikimedia.it/fullchain.pem                                                
   Your key file has been saved at:                                                                     
   /etc/letsencrypt/live/test.wikimedia.it/privkey.pem                                                  
   Your cert will expire on 2021-08-09. To obtain a new or tweaked                                      
   version of this certificate in the future, simply run certbot                                        
   again. To non-interactively renew *all* of your certificates, run                                    
   "certbot renew"                                                                                      
 - If you like Certbot, please consider supporting our work by:                                         
                                                                                                        
   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate                                   
   Donating to EFF:                    https://eff.org/donate-le  

$ a2ensite it-wikimedia-test-ssl.conf
Enabling site it-wikimedia-test-ssl.
To activate the new configuration, you need to run:
  systemctl reload apache2

$ # enable Apache's cache cleaner builtin in Debian
$ systemctl status apache-htcacheclean

$ apachectl graceful

Example usage:

Roadmap:

Event Timeline

You can also re-use https://fontcdn.toolforge.org/ which is the exact same (a proxy for Google Fonts).

You can also re-use https://fontcdn.toolforge.org/ which is the exact same (a proxy for Google Fonts).

It's just me or... it's somehow borked now?

403 Forbidden

In short, you should replace Google Font, but it's not that simple.

Uh? It's very simple, just use a font that you serve locally.

In short, you should replace Google Font, but it's not that simple.

Uh? It's very simple, just use a font that you serve locally.

Yup! But 5 minutes later:

A: *Drriiin* «Yeah?»
B: «Uh? I've changed the fonts from the editor but it does not work! You are fired! Damn Ghanoo plus Leenoocs nerd!»

ihih

Why would that happen? You just serve the very same files. The WMIT websites use very few fonts so it's not hard.

Why would that happen? You just serve the very same files. The WMIT websites use very few fonts so it's not hard.

I have not a strong opinion on this but

  • it's nice to allow frontend changes
  • It's not nice to fix every frontend change (← me and you here ihih)

Well. Let's try this toy.

https://fonts.wikimedia.it/css?family=Open+Sans%3Aregular%2C700|Khand%3A500&subset=latin-ext%2Clatin-ext%2Clatin-ext%2Clatin-ext%2Clatin-ext%2Clatin-ext%2Clatin-ext%2Clatin-ext

Another fun fact: WordPress also used to do this stuff:

<head>
  ...
  <link rel='dns-prefetch' href='//fonts.googleapis.com' />
</head>

Putting all the pieces together, I threw everything away with this snippet:

1<?php
2/*
3 * Enable a Google Font proxy
4 *
5 * Author: Valerio Bozzolan
6 * License: GNU General Public License v2 or later
7 * Date: 2021
8 *
9 * See https://phabricator.wikimedia.org/T282613
10 * See https://gitpull.it/T776
11 * See https://gitpull.it/R26:f8b39ca15e8ba48a92fb0d58c2772e9b02691059
12 */
13
14/**
15 * Local Google Font cache
16 */
17define( 'GOOGLE_FONT_PROXY', 'fonts.wikimedia.it' );
18
19/**
20 * Convert a Google Font domain to your local proxy cache
21 *
22 * See https://phabricator.wikimedia.org/T266998
23 */
24function convert_google_font_to_local_proxy( $url ) {
25 return str_replace( 'fonts.googleapis.com', GOOGLE_FONT_PROXY, $url );
26}
27
28/**
29 * Avoid Google Fonts in your stylesheets
30 *
31 * https://phabricator.wikimedia.org/T282613
32 */
33add_filter( 'style_loader_src', 'convert_google_font_to_local_proxy' );
34
35/**
36 * Avoid Google Fonts in your DNS prefetch
37 *
38 * https://phabricator.wikimedia.org/T282613
39 */
40add_filter( 'wp_resource_hints', function( $urls ) {
41 foreach( $urls as & $url ) {
42 $url = convert_google_font_to_local_proxy( $url );
43 }
44 return $urls;
45} );