How to configure WordPress as a Tor hidden service

I decided I wanted to host my WordPress installation as a hidden service on Tor instead of backporting all my existing content to Hugo. I previously ran Hugo on my onion site and even though I still want to make that move eventually, for now, I’m sticking with what I already know. Besides, putting arguably the worst content management system ever invented on the dark web seemed like a fun venture.

I won’t rely on any third party plugins to manage a “multi-domain” installation, but instead I’ll take advantage of available WordPress filter hooks to modify data at runtime. In short, I will replace all permalinks pointing to blog.paranoidpenguin.net with slackiuxopmaoigo.onion using my existing WordPress installation.

Getting started with hidden services

After installing Tor, getting your hidden service (onion site) up and running is just a matter of adding two lines to your torrc configuration. Have a look at this sample torrc file and review the section documenting hidden services. Yep, it’s that easy.

Virtual host configuration

I’ll be configuring tree separate virtual hosts for serving content from both my onion and clearnet site. These virtual hosts will be owned by the same unix user/group providing a common document root. The vhosts will also share a php-fpm pool owned by the aforementioned user/group. Shown below is an example of what such a configuration might look like (actual paths and ports have been changed to protect the innocent).

# Hidden service configuration (torrc)
HiddenServiceDir /var/lib/tor/secret
HiddenServicePort 7776 127.0.0.1:7776
...

# slackiuxopmaoigo.onion vhost
<VirtualHost 127.0.0.1:7776>
  ServerName slackiuxopmaoigo.onion
  DocumentRoot /home/username/public
</VirtualHost>

# blog.paranoidpenguin.net vhost (HTTP)
<VirtualHost *:80>
  ServerName blog.paranoidpenguin.net
  DocumentRoot /home/username/public
  Redirect permanent / https://blog.paranoidpenguin.net/
</VirtualHost>

# blog.paranoidpenguin.net vhost (HTTPS)
<VirtualHost *:443>
  ServerName blog.paranoidpenguin.net:443
  DocumentRoot /home/username/public
</VirtualHost>

Adding filter hooks to your theme

As previously mentioned, I’ll be using a collection of WordPress filter hooks to modify content referencing my primary domain before it’s rendered in the browser. It’s also advisable to avoid having the theme load static resources like web fonts and scripts from external domains. We don’t want any traffic seeping out to the clearnet from our safe onion haven.

In the end the job didn’t require much effort. I only had to spend some time identifying the applicable filters by reviewing the comprehensive WordPress Plugin API/Filter Reference. Your needs may differ though depending on theme functionality and installed plugins. For my frugal pureRegression theme, all that was needed was to add the following hooks to my theme’s functions.php:

pureRegression WordPress filter hooks

These hooks are executed whenever a visitor loads my onion site and effectively removes all references to blog.paranoidpenguin.net.
The above-mentioned code is available from github.com.

Addendum

How to configure Hugo as a Tor hidden service