Web Monetization Sidecar Proxy [Grant For The Web Hackathon Submission]
Tags: gftwhackathon, webmonetization
Published: 2020-05-25 00:22:36

[Instructions]: # (To submit to the Grant For The Web x DEV Hackathon, please fill out all sections.)


## What I built

![Architecture diagram. Request comes in money comes out.](https://dev-to-uploads.s3.amazonaws.com/i/tr330fz79dvz9wy7vbo2.png)

A simple proof-of-concept sidecar proxy<sup>1</sup> that injects Web Monetization `meta` tags into HTML responses from the backend application. Offloading this responsibility to a sidecar is valuable for several reasons:

1. It allows applications to benefit from Web Monetization without having to change the code of the application itself. Useful for cases where there are many applications being deployed or when the application is not modifiable (e.g. commercial off the shelf software).
2. Platform operators could automatically deploy these sidecars across their entire cluster without application developer intervention.

While the proxy I built for this Hackathon is far from production ready, I hope that this proof-of-concept can inspire further work. One idea might be writing a [WASM filter](https://banzaicloud.com/blog/envoy-wasm-filter/) for Envoy proxies that does this work.

Included with the code is an example Kubernetes `Deployment` that showcases how the proxy can easily be added to an existing `Pod` as a sidecar container.

_<sup name="footnote-1">1</sup> - What is a sidecar proxy? It is a [sidecar container](https://docs.microsoft.com/en-us/azure/architecture/patterns/sidecar) that runs a proxy sitting in front of your "main" application container. Sidecars are frequently used by [service meshes](https://buoyant.io/2017/04/25/whats-a-service-mesh-and-why-do-i-need-one/) to enable features like intelligent load balancing, rate-limiting, certificate / TLS management, and more. [Envoy](https://www.envoyproxy.io/learn/service-mesh) is a commonly used sidecar proxy._

### Submission Category: 
Foundational Technology

## Demo

**Demo:** https://monetization-proxy.k8s.downey.dev/

![Firefox Browser showing a Ghost blog with Web Monetization capabilities](https://dev-to-uploads.s3.amazonaws.com/i/fa71mpa91fth99k6p2me.png)

I've deployed a sample Ghost blog running with the monetization proxy sidecar to a small development Kubernetes cluster running on Digital Ocean<sup>2</sup>. The site can be accessed at [here](https://monetization-proxy.k8s.downey.dev/). Additionally, you can view the Kubernetes deployment configuration [here](https://github.com/tcdowney/web-monetization-proxy/blob/master/hack/example-deployment.yaml).

_<sup>2</sup> - This cluster costs money so I will tear it down in a few weeks._

## Link to Code

{% github tcdowney/web-monetization-proxy %}

The proxy is available as a [Docker image here](https://hub.docker.com/repository/docker/downey/web-monetization-proxy).

## How I built it 

The proxy is built using Go and uses an [`httputil.NewSingleHostReverseProxy`](https://golang.org/pkg/net/http/httputil/#NewSingleHostReverseProxy) to do a lot of the heavy lifting around proxying. A response modifying function is applied to each response from the backend and does the following:

1. Checks to see if the response `Content-Type` is HTML. If it is not, we leave the response alone since we don't want to inject `meta` tags into Javascript or CSS responses!
1. If it _is_ HTML, we parse the DOM and inject the Web Monetization `meta` tag into the document head.

For unit testing I used https://github.com/sclevine/spec which provided some lightweight BDD goodies to Go's built-in testing library. It was my first time using it (I traditionally have used [Ginkgo](https://onsi.github.io/ginkgo/) and [Gomega](https://onsi.github.io/gomega/)) and I found it to be easy to work with.

For building the OCI images I used the Go [Cloud Native Buildpack](https://buildpacks.io/) and [`kbld`](https://get-kbld.io/) to streamline the build/push/deploy to Kubernetes flow. More details on that are in the project README.

To deploy the demo I set up a Kubernetes cluster on Digital Ocean. I used [NGINX as my Ingress controller](https://github.com/kubernetes/ingress-nginx) and set up automatic provisioning of TLS certificates using [Cert-Manager](https://cert-manager.io/) and [LetsEncrypt](https://letsencrypt.org/). 

## Additional Resources/Info 

This was a fun little project for me. I got to write some Go, set up a a new K8s cluster, and play around with some new libraries / tools.

One thought I had while working on this though was "I sure wish there was just a Web Monetization HTTP header" instead of having to rely on `meta` tags. This would have let me just use an off-the-shelf sidecar proxy like Envoy which supports header manipulation and would have opened it up to support non-HTML applications.