Fix Tor Onion Services on CentOS or Fedora (without disabling SELinux!)

Feb 18, 2018

Learn how to set up a Tor Onion Service on CentOS or Fedora without needing to disable SELinux.

You’re probably reading this page because you run CentOS or Fedora, and you’re trying to host a Tor onion service which is just refusing to work. Hopefully I can help there.

Problem Overview

There are many reasons why CentOS and Fedora are both attractive distributions for webserver use. CentOS is rock-solid stable and comes with a 10-year support period, and Fedora has all the shiny new features and packages that you might want for development. Both distributions are also attractive in that they enable the SELinux kernel security tool out of the box.

Before we go any further, I just want to join the chorus of sysadmins and security gurus who like to shout at people to stop disabling SELinux! It can be a pain, but it offers great protection and it can be tamed where necessary.

If you’re reading this page then you will no doubt have noticed that attempting to set up a Tor onion service with SELinux enabled will throw up a confusing permissions error that might look something like:

Nov 09 22:05:18 hostname tor[7561]: Nov 09 22:05:18.245 [warn] Directory /var/lib/tor/hiddenservice/ cannot be read: Permission denied

or maybe:

Nov 09 22:12:33.119 [warn] /var/lib/tor/hiddenservice/ is not owned by this user (root, 0) but by toranon (997). Perhaps you are running Tor as the wrong user

I posted about this issue on Stack Exchange way back in 2015 and yet it still seems to remain an issue here in 2018. But there is an easy fix!

The Fix

As Sean McLemon suggests in his blog post here, one thing we can do is attempt to start the tor service as normal after adding our hidden service lines to the Tor config, and then use audit2allow to generate an SELinux policy as follows:

sudo ausearch -c 'tor' --raw | audit2allow -M tor-selinux-workaround

The above command will parse recent SELinux permission denials and generate a policy file called tor-selinux-workaround.pp, which we can then load into SELinux with the semodule command.

The SELinux Common Intermediate Language

The method described above works fine, but I’m not a huge fan of using audit2allow and leaving it at that. The .pp modules it generates are a binary file format, and this makes them difficult to parse to ensure that they’re only adding exceptions for what is strictly necessary and not catching anything else that might also have been in the logs.

We can sort this out by adding an extra step to the process, converting our binary files into the human-readable Common Intermediate Language format, which we can then edit manually:

cat tor-selinux-workaround.pp | /usr/libexec/selinux/hll/pp > tor-selinux-workaround.cil

The .cil file can then be opened in a regular text editor and edited. After narrowing down to the absolute minimum number of exceptions that Tor needs in order to work with onion services, my file has only two lines:

(typeattributeset cil_gen_require tor_t)
(allow tor_t self (capability (dac_override dac_read_search)))

We can then load this into SELinux with:

sudo semodule -i tor-selinux-workaround.cil

After loading this, try restarting the Tor daemon and it should work as expected with onion services configured!


If you skipped straight to this section for a quick fix and don’t care how it works, then simply download this file, load it as shown below, and then restart Tor:

sudo semodule -i tor-selinux-workaround.cil