Redmine, Phusion Passenger, Ruby Enterprise Edition, Apache and ... SELinux

Disclaimer: Please make sure you understand the steps detailed below before applying them. I take no responsibility when things go wrong!! Especially software such as Security Enhanced Linux can cause any part of the system to malfunction. Please make sure you test this in an environment you can afford to reinstall, or that you are able to restore the system in another way to a good state. Keep in mind that this has been written with CentOS 5.5 in mind. Another distribution might do things differently. That being said, these instructions worked fine for me.

This guide has been tested with the following software and versions:

I will not go into installing these projects. The first three have excellent documentation on their own websites, and the last three come with the operating system.

What I wish to accomplish

Mostly, when SELinux is causing problems, the general advice is to disable it. And I know, it can be a real PITA! But it can provide lots of added security as well, so I wish to try to keep it running, at least in targeted mode. Some systems might have problems with a setup like this, such as servers under control of webhosting software. Please consider these things before trying this. I recommend using a test setup to start with.


  • You have at least some experience with commands such as chown, chmod, chcon (change ownership, change permissions, change SELinux security label).
  • The software referenced above has been installed in a pretty much default way as described on its website.
  • The software runs well when SELinux is disabled or running in permissive mode.
  • The same user account on the system is used to run Apache, Phusion Passenger, and thus Redmine. If not, adapt accordingly.
  • The root user is owner of the websites files, and apache is the group owner, meaning Apache cannot just write to any file or directory. If not, adapt accordingly.

Before executing the commands below, you will want to stop Apache, and start it again when finished.

Acronyms and paths

  • Ruby Enterprise will be referred to as RE, and is installed in some path named ${RE}.
  • Phusion Passenger will be referred to as PP, and is installed in some path named ${PP}. This will probably be some path below RE, such as ${RE}/ruby/gems/1.8/gems/passenger-x.x.x.
  • Redmine will be referred to as RM, and is installed in some path named ${RM}.


We are going to be dealing with two different sets of permissions here. First, there are the filesystem permissions. Files have to be readable, perhaps writable, or even executable by the webserver user. Second, there are the SELinux permissions. If filesystem permissions disallow access, then access is disallowed. If filesystem permissions allow access, then SELinux can still disallow access based upon its own set of rules.

The apache user runs with a certain security label that SELinux understands. Based upon this security label certain actions are allowed or disallowed. For example, the SELinux policy (= rules database) says that the process running with the security label httpd_t (= apache) can listen on port 80. The policy also allows it to read files labeled httpd_sys_content_t.

We are going to make sure that the filesystem permissions as well as the SELinux permissions allow read/write/execute permissions where needed, using just existing SELinux labels, and that the two sets of permissions are in agreement with each other.

Ruby Enterprise Edition and Phusion Passenger

Basic permissions

First, we will give the root user ownership and revoke all execute permissions on REE files. Then we will restore execute permissions on directories only, so they can be entered. Next we will set a default SELinux user and label, so REE can be used normally (actually, you'll need to follow the steps below as well for this to work).

  1. Give the root user ownership:
    chown -R root:root ${RE}
  2. Revoke all execute permissions, but allow the owner read/write, and everyone else read acces:
    chmod -R u=rw,g=r,o=r ${RE}
  3. Restore execute permissions for directories only (note that the X in a+X here is a capital X):
    chmod -R a+X ${RE}
  4. Set a default SELinux user and label:
    chcon -R -u system_u -t usr_t ${RE}


Now we will restore execute permissions on REE system libraries, and give them the SELinux label for library types.

  1. Set execute permissions on all "*.so" files:
    find -P ${RE} -type f -name "*.so*" -exec chmod a+x {} \;
  2. Set the SELinux library label on "*.so" files:
    find -P ${RE} -type f -name "*.so*" -exec chcon -t lib_t {} \;
  3. Set execute permissions on "*.a" files:
    find -P ${RE} -type f -name "*.a" -exec chmod a+x {} \;
  4. Set the SELinux library label on "*.a" files:
    find -P ${RE} -type f -name "*.a" -exec chcon -t lib_t {} \;


Here we will restore execute permissions on REE binaries, and set their SELinux label.

  1. Set execute permissions on all files in bin directories:
    find -P ${RE} -type d -name "bin" -exec chmod -R a+x {} \;
  2. Set the SELinux binary label for all files in bin directories:
    find -P ${RE} -type d -name "bin" -exec chcon -R -t bin_t {} \;

Apache module

Next we will make sure Apache can load Phusion Passenger as a module. SELinux contains a label for that (httpd_modules_t). Without this label on the module, apache will not be allowed to load it as such. Phusion Passenger in turn executes a file called ApplicationPoolServerExecutable, which must be executable as well. Since it is not in a bin directory, the file has not been marked executable by the actions described above.

  1. Enable Phusion Passenger to run the ApplicationPoolServerExecutable:
    chmod a+x ${PP}/etc/apache2/ApplicationPoolServerExecutable
    chcon -t bin_t ${PP}/etc/apache2/ApplicationPoolServerExecutable
  2. Enable Apache to run Phusion Passenger as a module:
    chmod a+x ${PP}/etc/apache2/
    chcon -t httpd_modules_t ${PP}/etc/apache2/

More on Phusion Passenger: the temporary directory

Passenger needs a temporary directory where it can write to. I suggest creating one that will only be used by PP, instead of the system default, as I seem to remember this doesn't work anyway when SELinux is enabled. See this part of the documentation for some details.

The PP temporary directory is set by the PassengerTempDir directive in Apaches configuration. Set it there, create the directory, and adjust permissions:

chown -R apache:apache ${PP_TEMP_DIR}
chmod -R u=rwX,g=rX,o-rwx ${PP_TEMP_DIR}
chcon -R -u system_u -t httpd_tmpfs_t ${PP_TEMP_DIR}

The httpd_tmpfs_t label grants some additional rights needed by the passenger module, such as creating special files like sockets or fifos.

Up until now

You can download the steps I have described up until now as a bash script file: RubyAndSELinux. Please do not just execute this file. Make sure you understand it, and change the filesystem paths near the top according to your setup.

There is also a script for making the SELinux changes persistent across a filesystem relabel: RubyAndSEmanage. Note that this does not change any filesystem permissions, nor does it apply the policy. It includes the changes described within the Ruby Enterprise and Phusion Passenger part excluding for the temporary directory part. To apply the policy, do a

touch /.autorelabel
and reboot. Again, make sure you know what you are doing! You might need to understand some regular expression syntax in order to adapt this file to your particular situation.


If you have made it this far using these instructions, then the next part will be easy to understand.

Redmine needs some directories to be writable to function. These are: ${RM}/log, ${RM}/tmp, ${RM}/files, and ${RM}/public/plugin_assets.

First we set the basic permissions (again, the X in ug+X is a capital X):

chown -R root:apache ${RM}
chmod -R u=rw,g=r,o-rwx ${RM}
chmod -R ug+X ${RM}
chcon -R -u system_u -t httpd_sys_content_t ${RM}

And then we apply permissions for individual directories:

chown -R apache:apache ${RM}/log
chcon -R -t httpd_log_t ${RM}/log

chown -R apache:apache ${RM}/tmp
chcon -R -t httpd_tmpfs_t ${RM}/tmp

chown -R apache:apache ${RM}/files
chcon -R -t httpd_sys_script_rw_t ${RM}/files

chown -R apache:apache ${RM}/public/plugin_assets
chcon -R -t httpd_sys_script_rw_t ${RM}/public/plugin_assets

You can download the second part I have described as a bash script file as well: RedmineAndSELinux. Please do not just execute this file. Make sure you understand it, and change the filesystem paths near the top according to your setup.


  • The default install of Ruby Enterprise Edition seems to have some executable permissions on *.rb-files that I think should not be there. We've fixed this.
  • The default SELinux label for files in the Ruby installation has been set to usr_t, for libraries to lib_t, for executables to bin_t, and for the Apache module (Phusion Passenger, aka mod_rails) to httpd_modules_t.
  • Phusion Passenger has a working directory where it can store its files, uploads and sockets.
  • Redmine can write to its logs, files directory, temporary directory, and plugin_assets directory.


I would suggest to stick with Passenger 2.2.15.
While it's possible to get 3.0.2 working it will flood your audit log with denials.

gem uninstall passenger
gem install passenger -v=2.2.15

RubyAndSELinux - Shell script implementing the commands in the REE and PP part. (1.99 KB) Sascha Sanches, 2010-09-18 21:14

RedmineAndSELinux - Shell script implementing the commands in the Redmine part. (1.15 KB) Sascha Sanches, 2010-09-18 21:14

RubyAndSEmanage - Shell script implementing SELinux policy changes for the REE part excluding the PP work directory changes. (815 Bytes) Sascha Sanches, 2010-09-18 21:14