libreddit: Self-hosted reddit on the Tailscale network

If you have been following my posts, you might have noticed a trend recently, where I am looking for self-hostable alternatives for common websites and apps that I access. And I put them all on the Tailscale network so that they are easily accessible from other devices.

Today, I stumbled upon libreddit, a self-hosted, tracker-free reddit interface. It’s important to note that this is just an interface and does not allow accessing your reddit account through it.

Installation of libreddit

The installation process was fairly straightforward: SSH into my Raspberry Pi, and use the Docker instructions on libreddit homepage. That’s it — a libreddit UI would be available on 0.0.0.0:8080 on your computer, and if the Raspberry Pi was is connected to a Tailscale network, it becomes immediately available at the Tailscale node address as well. In my case, I can access the libreddit interface at http://mew:8080 too, thanks to Magic DNS.

Setup and usage

I like how libreddit is fast on desktop and mobile views, and is configurable in many ways: wide UI, theme, sorting of posts and comments, and most importantly, supports importing of existing subreddits that you follow. Here’s a guide on that process.

A screenshot from GitHub that shows instructions from the author of libreddit project to import subreddit subscriptions from reddit
A screenshot from GitHub that shows instructions from the author of libreddit project to import subreddit subscriptions from reddit

Since one doesn’t have to log into their reddit account, all of libreddit settings and subreddit subscriptions are stored locally. They will be lost when browser cookies are cleared, but libreddit goes one step further in allowing one to import back settings and subreddits using a link. Look for the details at the bottom of the libreddit settings page.

Whoogle on Tailscale

Access ad-free, tracker-free Google search results.

Hydroxide on Tailscale

Access your ProtonMail emails on a self-hosted, open-source bridge called Hydroxide.

Pi-hole on Tailscale

Install pi-hole on Tailscale, to get ad-blocker functionality on all devices

Overall, I am very happy with libreddit. I have made it available to my friend who is on my Tailscale network as well, using Tailscale ACLs, and the subreddits/settings he configures wouldn’t be visible at my end. Likewise, he cannot see what I configure.

Whoogle on the Tailscale network

I am a happy DuckDuckGo user of many years. It matches all of my requirements: good results, ability to jump to the first result with a keyword (using “\”), bangs to search within particular websites and tracker-free search results.

I recently learned about Whoogle though and I had been wanting to try that for a while. It’s a self-hosted, ad and tracker-free search engine that fetches results from Google. The project promises that it’s free of cookie and IP address tracking too. It’s open source and it seems that it can be set up on any device. I have two Raspberry Pi devices at home, both connected on my Tailscale network, acting as Pi-hole nodes to block ads. One of the two Raspberry Pis also acts as my Hydroxide node to fetch ProtonMail emails.

I decided to install Whoogle on the same Raspberry Pi that runs Hydroxide. The process turned out to be really simple. Whoogle has thoroughly documented instructions to install on a Raspberry Pi with Docker; I installed using these Docker Hub instructions:

docker pull benbusby/whoogle-search
docker run --publish 5000:5000 --detach --name whoogle-search benbusby/whoogle-search:latest

I ran into a hurdle involving a dependency’s compatibility with my Raspberry Pi image, but that was easily solvable. Once all that of was done, the Whoogle instance was available at 0.0.0.0:5000 but it was neatly exposed on the Tailscale interface too, thus being available at my Tailscale node’s IP address: 100.71.84.105:5000. Thanks to Tailscale’s Magic DNS, this instance becomes available at a readable address too: http://mew:5000. mew is the name of my Tailscale node. It’s configurable on the Tailscale admin.

An image showing a search query on my Whoogle instance.
An image showing a search query on my Whoogle instance

Since all of my devices are connected to the Tailscale network, my Android can access it as well:

An image showing a Whoogle search query on Android.
An image showing a Whoogle search query on Android

It’s nice overall. I am not bothered by the http queries as the communication between my device and the Raspberry Pi is end-to-end encrypted, thanks to Tailscale.

I configured access control lists on Tailscale to make this Whoogle instance available for my friends connected to the same Tailnet.

I plan on using Whoogle for a few weeks to see how it fits into my workflows. I will be missing out on some rich DuckDuckGo features like DuckDuckGo Bangs and jumping to the first result, and if it becomes too much to compromise on, I plan on going back to DuckDuckGo.

libreddit on Tailscale

Self-host a private, ad and tracker-free reddit frontend UI with libreddit.

Hydroxide on Tailscale

Access your ProtonMail emails on a self-hosted, open-source bridge called Hydroxide.

Pi-hole on Tailscale

Install pi-hole on Tailscale, to get ad-blocker functionality on all devices

Exit nodes: Control internet access using Tailscale ACLs

I love Tailscale‘s exit nodes functionality. Makes it easy to tunnel out of a virtual machine in any country. The idea is very similar to commercial VPNs like Mullvad and NordVPN, but is self-hosted.

I share my Tailscale network with friends and family, mostly to allow their usage of my pi-hole nodes. I wanted to prevent them from using my exit nodes though.

Last week, I found that Tailscale engineers have a new Access Control Lists (ACLs) functionality to enable or disable internet access on such nodes. Add autogroup:internet:443,22 to your devices’ accept rule, and you are good to go.

A screenshot of a GitHub comment, which describes a new host to control internet access on the exit nodes using Tailscale Access Control Lists.
New host to control internet access

Every other device on your Tailscale network wouldn’t be able to use the public internet when they tunnel out of such nodes.

Excluding draft posts from search index

For a while, I have been thinking about excluding draft posts from search engines’ indexes. When I say draft posts, I am talking about the blog posts that aren’t worthy of being indexed; those that aren’t subjected to the level of quality that I expect the public to read. Think of draft blog posts similar to tweets. I have been trying to use my blog as a source of my thoughts, while being cross-posted to other social networks.

That’s why I started classifying my blog posts into two categories: links and posts.

Links are often short posts without an image, links or a featured image, or just a link with some content. On the other hand, posts are long-form articles that are worthy of being indexed on search engines for the general public to read.

Of course, anyone can read blog posts from the “links” category if they visit the blog.

The setup

Yoast is my choice for search engine optimization today. With some search, I found that they offer some filters to noindex blog posts, and to exclude them from the sitemap as well.

I found this snippet to automatically mark all blog posts in the links category as noindex:

add_filter( 'wpseo_robots', 'wpseo_robots' );

function wpseo_robots( $robotsstr ) {
	if ( is_single() && in_category( 1 ) ) {
		return 'noindex, follow';
	}
	return $robotsstr;
}

I found another snippet to exclude blog posts from this category on the sitemap:

add_filter( 'wpseo_exclude_from_sitemap_by_post_ids', function( $excluded_posts_ids ) {
	$args = array(
		'fields'         => 'ids',
		'post_type'      => 'post',
		'category__in'   => array( 1 ),
		'posts_per_page' => -1,
	);

	return array_merge( $excluded_posts_ids, get_posts( $args ) );
} );

Yoast has a built-in functionality to exclude a category (available on the category editor view of the WordPress wp-admin dashboard) archives, but that’s not quite my goal. My goal is to exclude individual posts.

My links category is basically the default WordPress category; that explains why the category ID is 1. This is particularly helpful when I blog on the go using the WordPress mobile app, meaning I don’t have to mark the blog posts on the links category explicitly. WordPress will default the blog post to it, thus being noindex‘d and removed from sitemaps.

Safari tip: Tab key to highlight next items in navigation

If you use Safari as your browser on Mac, here’s a Safari tip to easily navigate to the next field using tab. Enable Press tab to highlight each item on a web page setting under Safari > Preferences > Advanced.

An image showing the Safari browser's advanced settings, enable tab key functionality for navigation between fields of a web page.
Safari settings to enable tab key functionality for navigation between fields of a web page

This comes in handy for me, especially because I spend a lot of time on reddit’s old UI. After typing a comment, I need to navigate to the Save button, and that requires a tab input. Unlike the modern reddit UI (which is really bad), Cmd + Enter hotkey doesn’t work for submitting comments here. That’s a tradeoff I can live with, as long as old reddit UI is available.

Know any other Safari tip? Let me know; I am trying to make it my primary browser these days, at least on my personal M1 chip MacBook. The battery life on this thing is amazing (but that’s a story for a different blog post) and I can further improve it by using Safari over Firefox. Safari pretty much ticks all of my needs for personal usage.

Zoom live captions

Not much know about it, but if you have any kind of premium account on Zoom, enable closed captions feature on Zoom settings so that everyone joining your (your account being the host) call can benefit from captions. Instructions here: Enabling and managing closed captioning and live transcription.

Once that is enabled, all members on the call can optionally turn on/off captions as needed.

The feature has a neat transcription history too! If you have to step away from the call for a few minutes, and when you come back to it, you can read the history.

I pinged Zoom to consider enabling it by default for all premium accounts, but they haven’t responded just yet. There’s no reason not to enable it, as the functionality itself has to be activated during the call.

DuckDuckGo Email Protection: First impressions

When DuckDuckGo announced DuckDuckGo Email Protection on the 20th of July, 2021, I was thrilled about it. As a pi-hole user, the idea of blocking trackers (ads as well) for all emails excites me. The idea is simple: you give away your DuckDuckGo address instead of your actual email address, DuckDuckGo receives it, removes trackers and forwards the email to you.

Note about replying to emails

Replying to the email reveals your primary address to the sender. DuckDuckGo is not an alias service like SimpleLogin or Anonaddy.

They promise to delete the email once they forward it, but we can never confirm as the service does not seem to be open source. Given DuckDuckGo’s track record though, I trust them with my emails.

An image illustrating how the DuckDuckGo Email Protection service works. It shows two mailboxes, one being the DuckDuckGo alias, and the other being the actual inbox where the email is forwarded to, with trackers removed
DuckDuckGo Email Protection

At WWDC 2021, Apple announced a client-wide email blocking functionality, but that’s limited to the default Apple Mail client. I wanted something that works irrespective of what email client I use. pi-hole works in a way, because it blocks all DNS requests for these trackers, but I haven’t done a detailed analysis of what kind of email trackers it actually blocks. Perhaps there a blocklist specifically tailored to email trackers.

HEY.com is another alternative and perhaps the trend-setter. I gave up after an year, because I wanted to use my email account on any IMAP client, vs being limited to proprietary web clients. The HEY.com web client is nicely done; just wasn’t what I wanted. The address remains mine forever though. I have configured [email protected] to forward to my DuckDuckGo address, which in turn sends to my primary email address, with all trackers removed.

Signup and setup

I signed up for DuckDuckGo’s on the day of announcement. Because they were rolling out invites in batches, I didn’t get my invitation until today.

The service is straightforward. Once you receive the invitation, you choose your username and set an email address to forward to. The destination must be one that you reply from, not another email forwarding service.

You can distribute this personal address, or generate unique aliases per site, newsletter or app.

When you receive your emails, DuckDuckGo will prepend the number of trackers removed, with a privacy report link attached to it, or a notice that there weren’t any trackers.

Image showing an email with DuckDuckGo's notice about the number of email trackers removed, and it has a link to a privacy report
Image showing an email with DuckDuckGo’s notice about the number of email trackers removed, and it has a link to a privacy report
Image showing an email with DuckDuckGo's notice about the email not containing any trackers
Image showing an email with DuckDuckGo’s notice about the email not containing any trackers

The arrow next to the notice points me to a privacy report web page, where details of the domain removed is listed. It also allows me to turn off the throwaway DuckDuckGo alias if needed.

Image showing DuckDuckGo Email Protection service's privacy report page for an email that I received. It shows details of the tracker removed and an option to turn off the throwaway DuckDuckGo alias
Image showing DuckDuckGo Email Protection service’s privacy report page for an email that I received. It shows details of the tracker removed and an option to turn off the throwaway DuckDuckGo alias

There’s a dashboard where one can look at the number of addresses generated (but not the actual addresses or an option to turn them off), address being forwarded to, and some links to submit feedback or download browser add-ons. I was hoping to see an option to change the address being forwarded to, but that doesn’t seem to be available. Guess one has to go through support to do that.

My setup: SimpleLogin + DuckDuckGo Email Protection + HEY.com

I am a very happy SimpleLogin user today. While it doesn’t block trackers, I have found a way to use the two together.

I will continue generating SimpleLogin aliases for all websites, but configure my DuckDuckGo address as the receiver, which in turn forwards to my primary address.

Because DuckDuckGo sets the original sender in the Reply-To header, my response to the email reaches the original sender, not DuckDuckGo.

To: [email protected]
Subject: Test email sent to [email protected]
Date: Mon, 09 Aug 2021 17:13:30 +0000
Duck-Original-Sender: DuckDuckGo <[email protected]>
From: "DuckDuckGo (via duck.com)" <[email protected]>
Reply-To: [email protected]

This part is tricky because the address in the Reply-To header in my setup is a SimpleLogin reverse-alias, rather than the actual sender.

Since reverse-alias can accept emails only for the mailbox that it is delivered to (in this case, the DuckDuckGo address), I had to add my regular email address to be an authorized sender too.

Image showing a setting on the SimpleLogin website's mailbox settings page, to add an authorized sender address
Image showing a setting on the SimpleLogin website’s mailbox settings page, to add an authorized sender address

With this in place, my incoming email setup looks like this:

Incoming

Sender to SimpleLogin alias to Duck address to regular inbox.

And here’s how my outgoing email setup looks like:

Outgoing

Regular inbox to SimpleLogin “reverse alias” to sender (sender sees the SimpleLogin alias, not my regular address or the “reverse alias”)

I also configured my HEY.com address to forward to my Duck address, rather than my regular inbox.

Hydroxide as a headless bridge for ProtonMail on Tailscale

I had fun setting up Hydroxide on the Tailscale network so that I can access my ProtonMail inbox from any IMAP client. If you are not familiar with ProtonMail, it’s an encrypted email provider. Given the nature of this product, they do not offer IMAP access as other standard email providers do. Rather, they require a paid account and a connector by the name ProtonMail Bridge for desktop IMAP clients to work.

That works great for most users, but what about IMAP clients on mobile devices? Access on the mobile devices is limited to the official ProtonMail app. As a ProtonMail customer of over 3 years, I haven’t seen any significant improvements in the mobile front. They did promise an update to the ProtonMail Android app, seemingly with support for threaded conversations, but that was a long time ago.

My favorite IMAP clients on Android are Nine Mail and K-9 Mail at the moment. I have been using K-9 Mail only since a week, and my experience so far has indicated that the two are not any different. Nine Mail has a free trial, but the latter is free forever and is donation-supported.

Tailscale to the rescue

Since I previously set up pi-hole on the Tailscale network, I started exploring the idea of using ProtonMail on the Tailscale network.

While ProtonMail Bridge is open source, it’s limited to Windows, Mac and Linux at the moment. That’s a GUI version. ProtonMail Bridge is not available in a headless format, but it appears to be planned.

I wanted the headless version to run on my Raspberry Pi so that it’s accessible from any Tailscale-authenticated node.

In exploring for third-party Bridges, I found Hydroxide which seems open source and popular among users. It also seems to support any ProtonMail account, while the official ProtonMail Bridge is only for paid users.

Setting up the bridge

Setting up Hydroxide is rather simple, but I ran into some challenges along the way.

For starters, it appears Proton recently modified their authentication API endpoint that prevented generating the Bridge password on Hydroxide. Some users found workarounds, but updating to the old endpoint didn’t quite work for me.

I found another workaround that involves using a SessionID from a web-authenticated ProtonMail session, and that worked for me.

Secondly, I had to get Hydroxide listening on the Tailscale network instead of 127.0.0.1, which would be a local address. There are flags that allow configuring a different network interface, but entering my Raspberry Pi Tailscale node address didn’t quite work. So, I ended up updating the default network interface within the Hydroxide code. The lines below had to be replaced with my Raspberry Pi node address.

An image that describes replacing the local host and ports with Tailscale node address.
Replacing the local host and ports with Tailscale node address

With this done, all that I had to do was enter my Raspberry Pi Tailscale node address as the IMAP and SMTP server on my mobile IMAP clients. The official ProtonMail Bridge documentation recommends adding a SSL exception for desktop clients. I couldn’t quite figure out how to configure a similar exception on the mobile clients. Also because both devices (my mobile device and Raspberry Pi running Hydroxide) are within the same Tailscale network, I chose to authenticate without SSL. That means my Bridge password being visible somewhere along the communication between the device and Raspberry Pi, but that’s alright as it’s a private network.

Preventing Hydroxide bridge access for others on my Tailnet

Since my friends and family use my Tailscale network (I share my pi-hole ad blocker with them) as well, I configured access control rules (Tailscale ACLs) on the Tailscale web admin.

An image from my Tailscale admin that shows access control rules for my Hydroxide ports.
An image from my Tailscale admin that shows access control rules for my Hydroxide ports

This setup is safe in my understanding, as Hydroxide runs on a hardware that I control. And, it is available only within my Tailscale network. To authentication on this Tailscale network, one requires my approval. I use a GitHub organization as a multi-user tailnet. Even if someone manages to get in, ACLs must prevent them from accessing the Hydroxide IMAP and SMTP ports.

I am not a network engineer but enjoy hacking on things by self. Don’t treat this guide as a bulletproof workflow if you value secure, encrypted communication.

Whoogle on Tailscale

Access ad-free, tracker-free Google search results.

libreddit on Tailscale

Self-host a private, ad and tracker-free reddit frontend UI with libreddit.

Pi-hole on Tailscale

Install pi-hole on Tailscale, to get ad-blocker functionality on all devices