Self-Hosting Fathom analytics behind Apache

I’m hosting Fathom on my domain at /fathom. It runs its own web server, so I’ve done this using a reverse proxy that makes the Fathom server accessible at that virtual directory. Their self-hosting instructions do have an example configuration for using Fathom with a reverse proxy through NGINX, but not Apache.

Fortunately the idea’s the same, so adapting it for Apache doesn’t involve too much. It does mean modifying the httpd.conf (or appropriate site-specific config file), and enabling a few additional Apache modules.

The Apache modules needed are mod_proxy, mod_proxy_http and mod_substitute. These can be enabled using a2enmod and restarting Apache:

sudo a2enmod proxy proxy_http substitute && sudo service apache2 restart

Now to enable the reverse proxy, I’ve added a new Location directive the VirtualHost in my site’s config file:

<Location "/fathom">
# Host and port of the Fathom instance
ProxyPass http://127.0.0.1:8999

# Updates redirect headers in responses from Fathom
ProxyPassReverse http://127.0.0.1:8999

# Send original Host header to Fathom
ProxyPreserveHost On

# Enables replacing of URLs in HTML elements
ProxyHTMLEnable On

# Load default mapping of attribute -> HTML elements that need replacing
Include /etc/apache2/mods-available/proxy_html.conf

# Define the regex in which to use to replace URLs in HTML
ProxyHTMLURLMap ^(.*)$ /fathom/$1 [R]

# Update the location of the /api/ calls in JavaScript responses from Fathom
AddOutputFilterByType SUBSTITUTE application/javascript
Substitute "s|/api/|/fathom/api/|niq"
</Location>

A little more on what each of those directives are doing:

ProxyPass http://127.0.0.1:8999
Creates an entry point at the URL in the Location directive (the first line, in this case it’s /fathom), which in turn forwards those requests on to the Fathom server defined in this ProxyPass directive.

ProxyPassReverse http://127.0.0.1:8999
Replaces redirects sent from Fathom (in the Location header) with the location that the client browser can access. In other words, when Fathom tries to redirect to an internal Login page (127.0.0.1:8999/login), this directive tells Apache to replace that with an externally-accessible URL (/fathom/login).

ProxyPreserveHost On
Fathom’s example NGINX configuration explicitly passes on the Host header from the proxy to the upstream server (Fathom), so it’s safe to assume we should too.

ProxyHTMLEnable On
Include /etc/apache2/mods-available/proxy_html.conf
ProxyHTMLURLMap ^(.*)$ /fathom/$1 [R]
These next few directives replace URLs in various HTML elements before sending them back to the browser. For example, and tags will need to be updated to point to the virtual directory (subfolder). Including the proxy_html.conf file imports a default mapping of attributes to elements so that Apache knows which attributes on which elements to update.

AddOutputFilterByType SUBSTITUTE application/javascript
Substitute "s|/api/|/fathom/api/|niq"
These final directives tell Apache to update URLs in JavaScript files. This is specifically needed for Fathom’s assets/js/scripts.js file, which makes multiple requests to files in the API folder. Just a note that Substitute uses a sed-like syntax for replacing text.