Installation of Redmine 4.2.x on CentOS 7 + SELinux, Apache 2.4, Passenger

Edit August 17, 2021: This guide was originally written for Redmine 4.2.1, but shortly after publishing 4.2.2 was released. The steps in this guide should work equally well for any 4.2.x version of Redmine, but please note that it has only been tested on 4.2.1 and 4.2.2.

This guide will walk you through the installation procedure for Redmine 4.2.x on CentOS7, including support for SELinux. Much of what follows is based off the excellent guide by Franck Michel which can be found here.

This guide will not cover installing and configuring a database for Redmine; that's something that is covered in many other guides and is pretty straightforward. This guide will also not cover any SCM repos, or integration with LDAP, but will cover how to go about getting Redmine working with SELinux enabled in CentOS7. Every Redmine HOWTO I've come across makes use of the Passenger GEM, however the GEM doesn't come with any SELinux policies. Though there is an SELinux HOWTO here, following it didn't really help me. This guide represents many hours of painfully reading Redmine, Passenger, and SELinux error logs. I hope you find it useful!

The full configuration used in this guide is:

  • CentOS Linux release 7.9.2009 (Core)
  • Apache 2.4.6
  • Redmine 4.2.2
  • Ruby 2.7.3
  • Apache Passenger 6.0.8
  • SELinux tweaks

Initial Configuration

To begin, I'd recommend a fresh CentOS install. You will, of course, have to install an RDBMS of your choice, either on the same server or on a dedicated server.

Install necessary packages

We'll install all the packages necessary to install Ruby. Additionally, we're installing Apache and mod_ssl, which we'll need to serve Redmine.

[As root/sudo]:
yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel openssl-devel make bzip2 autoconf automake libtool bison iconv-devel sqlite-devel wget mysql-devel httpd mod_ssl

Install Ruby 2.7.3

Adapted directly from Franck's guide here.

[As root/sudo]:
gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -L get.rvm.io | bash -s stable
source /etc/profile.d/rvm.sh
rvm reload
rvm requirements run
rvm install 2.7
rvm list
ruby --version 

Install Redmine 4.2.2

Latest version is 4.2.2 at the time of writing. This is adapted from Frank's guide here.
I like to install Redmine in /var/www/

Download and untar Redmine

wget https://redmine.org/releases/redmine-4.2.2.tar.gz
tar xvfz redmine-4.2.2.tar.gz
mv redmine-4.2.2 /var/www/
export REDMINE=/var/www/redmine-4.2.2
cd $REDMINE
cp config/database.yml.example config/database.yml 

This will install Redmine into the /var/www directory. This works well with Apache and SELinux.

Customize your `database.yml` file. You can refer to guide for additional help.

vi config/database.yml 

Install Gems and Create Database Schema

cd $REDMINE
gem install bundler
bundle install --without development test
bundle exec rake generate_secret_token
RAILS_ENV=production REDMINE_LANG=en bundle exec rake db:migrate
RAILS_ENV=production REDMINE_LANG=en bundle exec rake redmine:load_default_data 

Install Passenger 6.0.8

Here is where this guide will diverge considerably from Franck's guide. That guide, and all others I could find for Apache, make use of the Passenger Gem, which you'd install by doing something like this:

gem install passenger

However, as you work through that installation process, the installer actually warns you that the recommended method for installing Passenger on RHEL type systems is using a package manager, as that will include the SELinux policies necessary for Passenger to function properly. That's what we're going to do here. These steps are adapted from the excellent Passenger installation guide which can be found here.

yum install -y epel-release yum-utils
yum-config-manager --enable epel
yum clean all && sudo yum update -y
yum install -y pygpgme curl
curl --fail -sSLo /etc/yum.repos.d/passenger.repo https://oss-binaries.phusionpassenger.com/yum/definitions/el-passenger.repo
yum install -y mod_passenger 

Once Passenger is installed you can verify the installation using:

/usr/bin/passenger-config validate-install

Which should give you an output like this:

 * Checking whether this Passenger install is in PATH... ✓
 * Checking whether there are no other Passenger installations... ✓ 

Now, this is where things get a little tricky. As part of its' installation process `RVM` installs whichever version of Ruby you ask it to, but also installs the System version of Ruby (at the time of writing, this is 2.0.0.648-36.el7 for CentOS7, which is woefully out of date). When Passenger is installed, the System Ruby package is a requirement, and Passenger is "pointed" at the System version of Ruby. This will cause all sorts of problems for us as Redmine needs at least Ruby 2.4, but we'd like to use something that isn't EOL. Luckily, Passenger's documentation covers this:
"Once installed, you can run Passenger's Ruby parts under any Ruby interpreter you want, even if that Ruby interpreter was not the one you originally installed Passenger with."

Excellent! Let's go about doing that. Before we leave this section, we need to determine where the RVM Ruby interpreter was installed. Use this command for that:

/usr/bin/passenger-config --ruby-command 

This should return something like:

passenger-config was invoked through the following Ruby interpreter:
  Command: /usr/local/rvm/gems/ruby-2.7.2/wrappers/ruby
  Version: ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux]
  To use in Apache: PassengerRuby /usr/local/rvm/gems/ruby-2.7.2/wrappers/ruby
  To use in Nginx : passenger_ruby /usr/local/rvm/gems/ruby-2.7.2/wrappers/ruby
  To use with Standalone: /usr/local/rvm/gems/ruby-2.7.2/wrappers/ruby /usr/bin/passenger start

## Notes for RVM users
Do you want to know which command to use for a different Ruby interpreter? 'rvm use' that Ruby interpreter, then re-run 'passenger-config about ruby-command'. 

Configure Apache

Create a new virtual host config file in apache: /etc/httpd/conf.d/redmine.conf. Again, the majority of this section comes from Franck's guide, but with one key addition. This first line, comes from the output of the command in the previous section, tells Passenger which Ruby interpreter to use.

PassengerRuby /usr/local/rvm/gems/ruby-2.7.2/wrappers/ruby

<VirtualHost *:80>
    ServerName yourserver.domain.org
    DocumentRoot "/var/www/redmine-4.2.2/public" 

    ErrorLog logs/redmine_error_log
    LogLevel warn

    <Directory "/var/www/redmine-4.2.2/public">
        Options Indexes ExecCGI FollowSymLinks
        Require all granted
        AllowOverride all
    </Directory>
</VirtualHost> 

Permissions and SELinux Policies

Now the time has come to set permissions and SELinux policies. We'll begin by setting the normal Linux permissions on the entire Redmine folder. Some other guides only apply this to some sub folders, but I found that with SELinux enabled it was necessary to chown everything as apache:apache.

cd $REDMINE
cd ..
chown -R apache:apache redmine-4.2.2 

Next, we will set the SELinux policies. These were taken from this guide.

# Set SELinux permissions
chcon -R -t httpd_log_t redmine-4.2.2/log/
chcon -R -t httpd_tmpfs_t redmine-4.2.2/tmp/
chcon -R -t httpd_sys_script_rw_t redmine-4.2.2/files/
chcon -R -t httpd_sys_script_rw_t redmine-4.2.2/public/plugin_assets/
restorecon -Rv redmine-4.2.2/ 

Environment Variables

Passenger might complain that it isn't able to install a native support .so file. We can suppress this warning by adding the following lines to:

vi /etc/sysconfig/httpd

PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY=0
PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0 

That's it!

At this point, restart Apache.

systemctl restart httpd 

You should be able to access Redmine at the domain you entered in step X above.

Additional Considerations

A few additional considerations:

  • It would be wise to install some kind of firewall (iptables or firewalld) to protect your server.
  • If you install themes or plugins to Redmine you will have to repeat the chown procedure above.