Install Redmine 346 on Centos 75 » History » Version 13

Version 12 (Franck Michel, 2018-11-19 13:59) → Version 13/14 (Franck Michel, 2019-01-09 15:27)

h1. Installation of Redmine 3.4.6 on CentOS 7.5 + MySQL 8, Apache 2.4, GIT, SVN, LDAP

{{>toc}}

This guide presents an installation procedure for Redmine 3.4.6 on a CentOS 7. I wrote it as I was painfully going through multiple HOW-TOs and forums, fixing one error after the other. As a result, there was much back-and-forth before coming up with the right procedure. I tried to detail things as much as I felt necessary.

The procedure results of a mix of many different sources for which I give the source URLs in text below.

Basics like installing CentOS, Apache, or configuring a certificate for Apache are not covered.

Here is the full configuration I got after this installation:
* CentOS Linux release 7.5.1804 (Core)
* Apache 2.4
* MySQL 8.0
* Redmine 3.4.6
* Ruby 2.4.4
* Apache Passenger 5.3.4
* Integration with Git and Svn
* Integration with LDAP

*IMPORTANT NOTE*:
This installation uses **Apache 2.4** in which there are quite some configuration syntax changes compared to 2.2. Directives Allow, Deny, Order are obsolete as of Apache 2.4, but you can still use them for compatibility reasons. However, mixing the new Require directives with the former ones has unexpected results. So, *do not blindly copy/paste examples you shall find on the Web*, most of them are deprecated and will screw your configuration! See "details":https://httpd.apache.org/docs/2.4/en/upgrading.html.

h2. Install MySQL 8

Adapted from "this page":https://www.if-not-true-then-false.com/2010/install-mysql-on-fedora-centos-red-hat-rhel/.

h3. Why MySQL 8?

Basically, I first mistakenly installed MySQL 8. Then I uninstalled it and installed 5.7, but then for some reason I could not complete the installation of Redmine. So I reinstalled MySQL 8, and it works fine so far.

<pre>
[As root/sudo]:
yum update -y
yum localinstall -y https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
yum --disablerepo=mysql80-community install mysql-community-server mysql-devel
systemctl start mysqld.service
systemctl enable mysqld.service
</pre>

If you prefer to stick to MySQL 5.7, replace the yum install line as follows:
<pre>
yum --disablerepo=mysql80-community --enablerepo=mysql57-community install mysql-community-server mysql-devel
</pre>

Get the password created at installation and run the secure procedure
<pre>
grep 'A temporary password is generated for root@localhost' /var/log/mysqld.log | tail -1
/usr/bin/mysql_secure_installation
</pre>

h3. Bind-address

By default, MySQL 8 has a bind-address set to 127.0.0.1. If you want to use another hostname, or if it is on a different server than Redmine, then set property bind-address appropriately in MySQL config file (likely @/etc/my.cnf@).

h3. Default password policy

By default, MySQL 8 sets the default password policy to "caching_sha2_password". Redmine can deal with it but not the Apache module that authenticated git/svn users against the database, and this will generate an error when accessing the repository. Therefore, change the default policy in MySQL config file (likely /etc/my.cnf) by uncommenting the line:
<pre>
default-authentication-plugin=mysql_native_password
</pre>

h2. Install Ruby 2.4

Adapted from "this page":https://tecadmin.net/install-ruby-previous-stable-centos/.

<pre>
[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
curl -sSL https://rvm.io/mpapis.asc | gpg --import -
curl -L get.rvm.io | bash -s stable
source /etc/profile.d/rvm.sh
rvm reload
rvm requirements run
rvm install 2.4
rvm list
ruby --version
</pre>

Find the Gem installation path and set the $GEMS variable accordingly, we will use it in later steps, e.g. in my case that was:
<pre>
export GEMS=/usr/local/rvm/gems/ruby-2.4.4/gems
</pre>

h2. Install Redmine

Adapted from "this page":https://www.redmine.org/projects/redmine/wiki/RedmineInstall.

Below, Redmine is installed in directory /home/username/

h3. Download and untar Redmine, install Ruby packages:

<pre>
[As non-root]:
cd /home/username
wget https://www.redmine.org/releases/redmine-3.4.6.tar.gz
tar xvfz redmine-3.4.6.tar.gz
export REDMINE=/home/username/redmine-3.4.6
cd $REDMINE
cp config/database.yml.example config/database.yml
</pre>

Customize $REDMINE/config/database.yml as explained in the "procedure":https://www.redmine.org/projects/redmine/wiki/RedmineInstall#Step-3-Database-connection-configuration.

Install GEMS dependencies:
<pre>
[As root/sudo]:
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 redmine:load_default_data
</pre>

Let's now make sure that Redmine can start using Webricks (later on we shall Apache instead, but that helps checks if there are any issues so far):
<pre>
[As root/sudo]:
cd $REDMINE
bundle exec rails server webrick -e production
</pre>
and browse to http://localhost:3000/. Alternatively, this other command should work exactly the same:
<pre>
[As root/sudo]:
ruby bin/rails server webrick -e production
</pre>

Note that at this point some HOW-TOs recommand the installation of FastCGI. In this configuation described on this page, I found out that was not necessary.

h3. Install Apache Passenger (an Apache plugin for Ruby environments)

Adapted from "this page":https://www.vincentliefooghe.net/content/utilisation-apache-passenger-pour-redmine.
<pre>
[As root/sudo]:
yum install -y httpd-devel libcurl-devel apr-devel apr-util-devel mod_ssl
cd $REDMINE
gem install passenger
</pre>

Find out the installation path of Passenger, and call the Apache module installer, e.g. in my case:
<pre>
$GEMS/passenger-5.3.4/bin/passenger-install-apache2-module
</pre>

Follow the steps indicated by the tool. This should include creating an Apache module configuration file. I created /etc/httpd/conf.modules.d/pasenger.conf, you should adapt the Ruby and Passenger paths according to the versions installed above:
<pre>
LoadModule passenger_module /usr/local/rvm/gems/ruby-2.4.4/gems/passenger-5.3.4/buildout/apache2/mod_passenger.so
<IfModule mod_passenger.c>
PassengerRoot /usr/local/rvm/gems/ruby-2.4.4/gems/passenger-5.3.4
PassengerDefaultRuby /usr/local/rvm/gems/ruby-2.4.4/wrappers/ruby
</IfModule>
</pre>

h3. Configure Apache as the front end for Redmine

As root, create a virtual host entry in /etc/httpd/conf.d/redmine.conf (adapt the paths to your installation):
<pre>
<VirtualHost *:80>
ServerName youserver.domain.org
DocumentRoot "/home/username/redmine-3.4.6/public"

ErrorLog logs/redmine_error_log
LogLevel warn

<Directory "/home/username/redmine-3.4.6/public">
Options Indexes ExecCGI FollowSymLinks
Require all granted
AllowOverride all
</Directory>
</VirtualHost>
</pre>

Give Apache write access to some directories. Check the Apache user by looking for propertues @User@ and @Group@ in the Apache main configuraton file (in /etc/httpd/conf or /etc/apache/conf). This is "apache" in my case, but could also be "www-data" in different packagings.
<pre>
cd $REDMINE
chown -R apache:apache files log tmp vendor
</pre>
Restart apache:
<pre>
systemctl restart httpd
</pre>
There you go: browse to http://youserver.domain.org, you should get the login page. Hurah!
Login with default login "admin" and password "admin", and of course, change the admin password immediatly.

h3. Email config with sendmail

As non-root, edit @$REDMINE/config/configuration.yml@ and uncomment the 2 lines concerning sendmail:
<pre>
email_delivery:
delivery_method:sendmail
</pre>

And install sendmail if it is not yet installed:
<pre>
[As root/sudo]:
yum install -y sendmail sendmail-cf
</pre>

h3. LDAP authentication

Ask the LDAP details to your administrator and set them in the Web interface: Admin > LDAP authentication

h2. SCM Repos integration - Preliminary

Enable the Web Service for repository management: go to "Administration -> Settings -> Repository" and check "Enable WS for repository management", then clik on "Generate a key" to create a new WS key and save the key that you will use below.

The reposman.rb script needs @activeresource@ to work, run this (if this is already installed, this will just do nothing):
<pre>
[As root]:
cd $REDMINE
gem install activeresource
</pre>

To restrict the access to the WS, secure the Apache configuration by adding this to the
VirtualHost configuration (/etc/httpd/conf.d/redmine.conf above). Reminder: this is an Apache 2.4 syntax.
<pre>
<Location /sys>
Require host youserver.domain.org sparks-vm5.i3s.unice.fr localhost
Require all denied
</Location>
</pre>

Install Apache packages needed to use the database for authentication (with Git as well as Svn):
<pre>
[As root/sudo]:
yum install -y mod_perl perl-DBI perl-DBD-MySQL perl-Digest-SHA1 perl-LDAP
</pre>

Unlike in other HOW-TOs, there should be no need to use CPAN to install the DBI Perl module for Apache, it must have been installed with perl-DBI. Check where @DBI.pm@ was installed. In my case, it was in /usr/lib64/perl5/vendor_perl, not in /usr/lib/perl5/Apache as often mentioned in other HOW-TOs. Therefore, in the config below, I simply changed the "PerlLoadModule Apache::DBI" (that I found in many examples) into "PerlLoadModule DBI".

Also, link $REDMINE/extra/svn/Redmine.pm into Apache's PERL scripts. You should check the appropriate path, in my case this is /usr/lib64/perl5/vendor_perl/.
<pre>
[As root/sudo]:
mkdir /usr/lib64/perl5/vendor_perl/Apache/Authn
ln -s $REDMINE/extra/svn/Redmine.pm /usr/lib64/perl5/vendor_perl/Authn/Apache
</pre>

Optional: to allow for LDAP authentication, install the Simple LDAP modules with CPAN. In my cases, it required dependencies Modules::Build and Params::Validate:
<pre>
[As root/sudo]:
cpan
install Modules::Build
install Params::Validate
install Authen::Simple::LDAP
</pre>

Update the Apache Redmine configuration (redmine.conf) as shown below:
<pre>
PerlLoadModule Apache::Authn::Redmine
PerlLoadModule Redmine

# Enable connection pooling (useful for checkouts with many files)
PerlModule DBI
PerlOptions +GlobalRequest

# Enable LDAP(S) authentication (optional)
PerlLoadModule Authen::Simple::LDAP
PerlLoadModule IO::Socket::SSL
</pre>

*Possible authentication issue*: MySQL 8 sets the default password policy to "caching_sha2_password". @Redmine.pm@ is not compatible with that and will generate a weird error in the Apache redmine_error_log, like this:
<pre>
Can't call method "prepare" on an undefined value at /usr/lib64/perl5/vendor_perl/Apache/Redmine.pm line 364, <DATA> line 747.\n
</pre>
A closer look at the regular Apache error_log shows another error:
<pre>
DBI connect('database=redmine;host=127.0.0.1','redmine',...) failed: Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/lib64/mysql/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory at /usr/lib64/perl5/vendor_perl/Apache/Redmine.pm line 557.
</pre>

To fix this, change MySQL's password policy for user redmine (found "here":https://my.oschina.net/johnsken/blog/1840348):
<pre>
mysql -uroot -p
mysql> show variables like 'default_authentication_plugin';
+-------------------------------+-----------------------+
| Variable_name | Value |
+-------------------------------+-----------------------+
| default_authentication_plugin | caching_sha2_password |
+-------------------------------+-----------------------+

mysql> select host,user,plugin from mysql.user;
+-----------+------------------+-----------------------+
| host | user | plugin |
+-----------+------------------+-----------------------+
| localhost | mysql.infoschema | caching_sha2_password |
| localhost | mysql.session | caching_sha2_password |
| localhost | mysql.sys | caching_sha2_password |
| localhost | redmine | caching_sha2_password |
| localhost | root | caching_sha2_password |
+-----------+------------------+-----------------------+

mysql> ALTER USER 'redmine'@'localhost' IDENTIFIED WITH mysql_native_password BY '<YOUR REDMINE PASSWORD>';
Query OK, 0 rows affected (0,10 sec)

mysql> select host,user,plugin from mysql.user;
+-----------+------------------+-----------------------+
| host | user | plugin |
+-----------+------------------+-----------------------+
| localhost | mysql.infoschema | caching_sha2_password |
| localhost | mysql.session | caching_sha2_password |
| localhost | mysql.sys | caching_sha2_password |
| localhost | redmine | mysql_native_password |
| localhost | root | caching_sha2_password |
+-----------+------------------+-----------------------+
</pre>

h2. SVN integration

h3. Repositories access control with Apache 2.4 with mod_dav_svn and mod_perl

Adapted from "this page":https://www.redmine.org/projects/redmine/wiki/HowTo_configure_Redmine_for_advanced_Subversion_integration, section "Using apache/mod_dav_svn/mod_perl".

Make sure SVN CLI packages are already installed.
<pre>
yum -y install svn
</pre>

Create the directory where all SVN repos will/have to be stored:
<pre>
[As root/sudo]:
export SVN=/var/lib/svn
mkdir $SVN
chown apache:apache $SVN
chmod 0750 $SVN
</pre>

Then, there are two options to attach an SVN repository to a project:

_1. Explicitly attach a repo to a project_

Copy an existing repository to $SVN, or create an new empty repository, and change its owner, like this:
<pre>
svnadmin create $SVN/<repo_name>
chown -R apache:apache $SVN/<repo_name>
</pre>

Then, on the web interface, select the project you want to attach the repo to, go to Settings > Repositories > New repository. The repo URL should be @/var/lib/svn/<repo_name>@ in the example above.

_2. Automatically create SVN repos for declared projects_
You can also ask Redmine to automatically create SVN repos for each declared project: the new repo will be name after the project name.

<pre>
[As root/sudo]:
cd $REDMINE/extra/svn
ruby reposman.rb --redmine https://youserver.domain.org --svn-dir $SVN \
--owner apache --url http://youserver.domain.org/svn/ \
--verbose --key=<ws_key>
</pre>

In my case, I had declared a single test project, here is the result:
<pre>
querying Redmine for active projects with repository module enabled...
retrieved projects
processing project test (test)
repository /var/lib/svn/test created
repository /var/lib/svn/test registered in Redmine with url http://youserver.domain.org/svn/test
</pre>

h3. SVN access from Apache

At this point, we have Redmine configured to create repositories for existing projects. We now have to configure Apache to allow browsing the repos from outside Redmine (typically with an SVN client but also simply with a web browser).

Install Apache needed packages:
<pre>
[As root/sudo]:
yum install -y mod_dav_svn
</pre>

The installation should add loading of DAV and SVN modules to the Apache configuration. Check and fix this if necessary:
<pre>
$ cat /etc/httpd/conf.modules.d/00-dav.conf
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule dav_lock_module modules/mod_dav_lock.so

$ cat /etc/httpd/conf.modules.d/10-subversion.conf
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
LoadModule dontdothat_module modules/mod_dontdothat.so
</pre>

Update the Apache Redmine configuration (redmine.conf) as shown below. Note that there is no need for a <Location /svn-private> section as shown in older HOW-TOs.

<pre>
# Enable SVN access from outside Redmine (web browser, SVN client)
<Location /svn>
DAV svn
SVNParentPath "/var/lib/svn"
SVNReposName "Subversion Repository"
Require all denied

# Uncomment the following line when using subversion 1.8 or newer
# (see http://subversion.apache.org/docs/release-notes/1.8.html#serf-skelta-default)
# SVNAllowBulkUpdates Prefer

# If a client tries to svn update which involves updating many files,
# the update request might result in an error Server sent unexpected
# return value (413 Request Entity Too Large) in response to REPORT
# request, because the size of the update request exceeds the limit
# allowed by the server. You can avoid this error by disabling the
# request size limit by adding the line LimitXMLRequestBody 0
LimitXMLRequestBody 0

# Only check Authentication for root path, nor again for recursive folder.
# Redmine core does only permit access on repository level, so this
# doesn't hurt security. On the other hand it does boost performance a lot!
SVNPathAuthz off

PerlAccessHandler Apache::Authn::Redmine::access_handler
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
AuthType Basic
AuthName "Redmine SVN Repository"
AuthUserFile /dev/null

# Read-only access
<Limit GET PROPFIND OPTIONS REPORT>
# Match either the valid user or local source conditions (equivalent to "Satisfy any" in Apache 2.2)
<RequireAny>
Require valid-user
Require local
</RequireAny>
</Limit>

# Write access (methods POST, PUT)
<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
</LimitExcept>

# Mysql config. You may use localhost instead of <your.mysql.hostname> if MySQL is on the same server
RedmineDSN "DBI:mysql:database=redmine;host=<your.mysql.hostname>"
RedmineDbUser "redmine"
RedmineDbPass "<password>"
</Location>
</pre>



h2. Git integration

Create the directory where all GIT repos will/have to be stored:
<pre>
[As root/sudo]:
export GIT=/var/lib/git
mkdir $GIT
chown apache:apache $GIT
chmod 0750 $GIT
</pre>

Note: Redmine can only deal with bare Git repositories (see http://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/). You can get a bare Git repo in two ways: "git init --bare" or "git clone --bare ...".

In the case of a fresh new local repository (git init --bare), Redmine will be able to display its content only after the first commit. Try this:

<pre>
[As root/sudo]:
# Create a local bare repo
mkdir -p $GIT/test.git
chown apache:apache $GIT/test.git/
cd $GIT/test.git/
git init --bare
chown -R apache:apache $GIT/test.git/


# Create another repo as a clone of the previous one, make one commit and push.
cd ..
mkdir -p $GIT/test.local.git
cd $GIT/test.local.git/
git init
touch TEST.txt
git add TEST.txt
git commit -m "repository initalization"
git push $GIT/test.git/ master
</pre>

Now that there is commit in your bare repo, you can browse it via Redmine: create a project and attach test.git as the main repo. Then go to the Repository tab, you should see the log of the first commit.

Update the Apache Redmine configuration (redmine.conf) as shown below. Note that there is no need for a <Location /git-private> section as shown in older HOW-TOs.

<pre>
#--- Enable Git access from outside Redmine
ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/

SetEnv GIT_PROJECT_ROOT /var/lib/git
SetEnv GIT_HTTP_EXPORT_ALL

<Location /git>
SSLRequireSSL
PerlAccessHandler Apache::Authn::Redmine::access_handler
PerlAuthenHandler Apache::Authn::Redmine::authen_handler
AuthType Basic
AuthName "Redmine Git Repository"
AuthUserFile /dev/null
Require all denied

<Limit GET PROPFIND OPTIONS REPORT>
Options Indexes FollowSymLinks MultiViews
# Match either the valid user or local source conditions (equivalent to "Satisfy any" in Apache 2.2)
<RequireAny>
Require valid-user
Require local
</RequireAny>
</Limit>

# Mysql config. You may use localhost instead of <your.mysql.hostname> if MySQL is on the same server
RedmineDSN "DBI:mysql:database=redmine;host=<your.mysql.hostname>"
RedmineDbUser "redmine"
RedmineDbPass "<password>"
RedmineGitSmartHttp yes
</Location>
</pre>