UbuntuのRedmineをApacheで動かす (HTTPSとCORSに対応)

はじめに

以前の記事でUbutntuにRedmine 5.1をインストールする手順について紹介しました。その続きとして、WebサーバーにApacheを使った構成を紹介します。HTTPS, CORSにも対応しています。コピー&ペーストで実行できます。

前記事

UbuntuにRedmine 5.1/Ruby 3.2をインストールする
UbuntuにRedmine 5.1をインストールする手順をステップバイステップで紹介します。Ruby 3.2, MySQL 8.0を使っています。CORS対応, HTTPS化についても解説しています。コピー&ペーストで実行可能です。
UbuntuにRedmine 5.1/Ruby 2.7をインストールする
UbuntuにRedmine 5.1をインストールする手順をステップバイステップで紹介します。Ruby 2.7, MySQL 8.0を使っています。CORS対応, HTTPS化についても解説しています。コピー&ペーストで実行可能です。

TrelloとRedmineを比較している方、Redmineの現場展開に悩んでいる方、ぜひご一読を!

みんなが使いたくなる進捗報告ツール - RedmineとTrelloの連携
RedSyncはRedmineをTrelloと連携するツールです。プロジェクトメンバーの日々の作業を助けながら、プロマネによるタイムリーなスケジュールの展開や進捗の把握を可能にします。

補足 (2024/03/25)
大幅改訂しました。旧版は(こちら)にあります。

環境

ソフトウェアのバージョンは次の通りです。

  • OS: Ubuntu Server 22.04 LTS
  • Redmine: 5.1
  • Apache 2.4
  • Passenger 6.0

セットアップの手順

前記事では、Redmineのインストールと、CORS, HTTPS対応まで行いました。ただしWebサーバー (兼アプリサーバー)にはPumaを使用しました。本記事では、PumaをApache + Passengerで置き換えます。このため前記事の作業からの続きとなります。

  • Apacheのインストール
  • ApacheのHTTPS化
  • Passengerのインストール
  • Passengerの構成
  • CORSの構成

特に指定しない場合は、作業はホームディレクトリ (/home/redmine) で行うものとします。

サービスの停止

前記事でRedmineの起動をサービス化している場合は、サービスを停止します。

sudo systemctl stop redmine
sudo systemctl disable redmine

Apacheのインストール

参考資料

Install and Configure Apache | Ubuntu
Ubuntu is an open source software operating system that runs from the desktop, to the cloud, to all your internet connec...

まずレポジトリを最新化します。

sudo apt update

Apacheをインストールします。

sudo apt install apache2 apache2-dev

ブラウザで、http://<サーバー> にアクセスすると、デフォルトのページが表示されます。

Passengerのインストール

ApacheとRedmineをつなぐアプリケーションサーバーとして、Phusion Passengerを使用します。

Passengerのサイトに、ApacheとPassengerのインストール手順が掲載されているので、それに従ってインストールを行います。

参考資料

Installing Passenger - Passenger Library

以下は上記資料からの抜粋です。

この後の作業の前提となるソフトウェアをインストールします。

sudo apt-get install -y dirmngr gnupg apt-transport-https ca-certificates curl

(筆者の環境で実際にインストールが必要だったのは、apt-transport-httpsのみでした。他はインストール済みでした。)

Passengerのレポジトリの解凍に必要なPGPキーを取得しaptに登録します。

curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/phusion.gpg >/dev/null

Passengerのレポジトリをaptに追加します。

sudo sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger jammy main > /etc/apt/sources.list.d/passenger.list'
sudo apt-get update

Passengerをインストールします。

sudo apt-get install -y libapache2-mod-passenger

インストール結果を検査します。

sudo /usr/bin/passenger-config validate-install

検査対象を選択するように求められるので、Passenger, Apacheの両方を選択します。次のように表示されればOKです。

What would you like to validate?
Use <space> to select.
If the menu doesn't display correctly, press '!'

   ⬢  Passenger itself
 ‣ ⬢  Apache

-------------------------------------------------------------------------

Checking whether there are multiple Apache installations...
Only a single installation detected. This is good.

-------------------------------------------------------------------------

 * Checking whether this Passenger install is in PATH... ✓
 * Checking whether there are no other Passenger installations... ✓
 * Checking whether Apache is installed... ✓
 * Checking whether the Passenger module is correctly configured in Apache... ✓

Apacheサーバーを再起動します。

sudo systemctl restart apache2

Passengerのプロセスが起動していることを確認します。

sudo /usr/sbin/passenger-memory-stats

次のようにApacheとPassengerのプロセスが表示されればOKです。

Version: 6.0.20
Date   : 2024-03-21 10:55:39 +0000

--------- Apache processes ----------
PID   PPID  VMSize     Private  Name
-------------------------------------
3801  1     82.2 MB    0.7 MB   /usr/sbin/apache2 -k start
3818  3801  1194.8 MB  0.7 MB   /usr/sbin/apache2 -k start
3819  3801  1194.8 MB  0.7 MB   /usr/sbin/apache2 -k start
### Processes: 3
### Total private dirty RSS: 2.01 MB


-------- Nginx processes --------

### Processes: 0
### Total private dirty RSS: 0.00 MB


---- Passenger processes -----
PID   VMSize    Private  Name
------------------------------
3803  294.6 MB  2.4 MB   Passenger watchdog
3806  849.3 MB  4.2 MB   Passenger core

Apacheの構成

Apacheの構成をPassengerのために設定します。また合わせてHTTPS化のための設定も行います。

参考資料

Introduction to configuring Passenger - Passenger Library
https://www.arubacloud.com/tutorial/how-to-enable-https-protocol-with-apache-2-on-ubuntu-20-04.aspx

まず前記事で作成した証明書と秘密鍵を/etc/certificateの下にコピーします。

sudo mkdir /etc/certificate
sudo cp certificate.crt /etc/certificate
sudo cp private.key /etc/certificate

PassengerでRedmineを呼び出すように構成ファイルを作成します。

sudo vim /etc/apache2/sites-available/redmine.conf

次の内容をコピーします。

<VirtualHost *:443>
    ServerName example.com
    DocumentRoot /opt/redmine/public
    PassengerRuby /home/redmine/.rbenv/shims/ruby
    # PassengerFriendlyErrorPages on

    SSLCertificateFile      /etc/certificate/certificate.crt
    SSLCertificateKeyFile   /etc/certificate/private.key
    SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
    SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
    SSLHonorCipherOrder On
    SSLCompression off
    SSLSessionTickets Off
    Header always set X-Frame-Options SAMEORIGIN
    Header always set X-Content-Type-Options nosniff
</VirtualHost>

<Directory /opt/redmine/public>
    Allow from all
    Options -MultiViews
    Require all granted
</Directory>
  • ServerName (要変更)
    サーバーのFQDN (Fully Qualified Domain Name) またはIPアドレスを指定 (前記事で作成した証明書のCN (Common Name) と一致)
  • DocumentRoot
    Redmineのpublicディレクトリを指定
  • PassengerRuby
    Rubyへのパスを指定
    指定しない場合、Apacheの起動時にRubyが見つからないとのエラーが発生
  • PassengerFriendlyErrorPages
    Passengerでエラーが発生したとき、詳細エラーをブラウザに表示 (コメントアウト)

以下はセキュリティ関連の設定です。参考資料などを元に設定しましたが、筆者は門外漢なので分かる範囲で …

  • SSLCertificateFile
    前記事で作成した証明書を指定
  • SSLCertificateKeyFile
    前記事で作成した秘密鍵を指定
  • SSLCipherSuite
    暗号化の方式を指定 (スイートの名前の通り、暗号化に関連する複数の要素を含む)
  • SSLProtocol
    通信方式を指定 (Allで全て、そこから -SSLv2などで脆弱性のあるものを除外)
  • SSLHonorCipherOrder
    暗号化方式として、クライアント (ブラウザ)、サーバーのどちらを優先するかを指定 (onでサーバー側)
  • SSLCompression
    SSL通信でデータ圧縮を行うかどうかを指定 (圧縮しない方が安全とのこと)
  • SSLSessionTickets
    前方秘匿性を保つためにオフに指定 (セッションキーの暗号化に使われる秘密鍵が漏洩した場合も安全とのこと)
  • X-Frame-Options
    Webページが、<iframe>など他のページに読み込まれることを許可するかどうかを指定
    SAMEORIGINで同一サーバーのページには読み込み可能に (Redmine的にはDENYでも良さそう)
  • X-Content-Type-Options
    MIMEタイプをブラウザ側で推定 (sniff = 匂いを嗅ぐ) して変更しないように指定 (nosniffのみ指定可能)

設定を組み込みます。

sudo a2ensite redmine
sudo a2ensite default-ssl
sudo a2enmod ssl
sudo a2enmod headers

Apacheサーバーを再起動します。

sudo systemctl restart apache2

構成をテストします。

sudo apache2ctl configtest

次のメッセージが出ればOKです。FQDNが見つからないとのメッセージは気持ち悪いですが、Redmineへのアクセスには問題ありません。

AH00558: apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1. Set the ‘ServerName’ directive globally to suppress this message
Syntax OK

(redmine.confでServerNameをVirtualHostの外に定義すればこの警告は消えます。しかしdefault-ssl.confの定義が優先されるようになるのでRedmineが起動できなくなります。定義の仕方を見直すべきかも知れません …)

ブラウザで、https://<サーバー> にアクセスします。自己署名証明書のため警告がでますが、指示に従って警告を受け入れると、Redmineのページが表示されます。

前記事ではHTTPS化のための秘密鍵は暗号化せずに作成しました。Apacheの起動時にパスフレーズの入力が必要になるからです。これはサービス化されたApacheを起動する場合はエラーとなります。暗号化された秘密鍵を使いたい場合は、パスフレーズを返すスクリプトを用意して、Apacheに読み込ませることができます。

mod_ssl - Apache HTTP Server Version 2.4

SSLPassPhraseDialogディレクティブを使ってスクリプトを指定します。

セキュリティ警告の回避方法について

インターネット上に公開されるサーバーであれば、正式な証明書を組み込むことで警告を回避できます。証明書の発行には、Let’s Encryptのような無料のサービスもあります。

イントラネットの場合は、イントラネット内にプラベート認証局を立てて、その認証局で署名した証明書を使うことで警告を回避できます (筆者もこの方法を使っています)。

プライベート認証局によるサーバー証明書の発行
プライベート認証局(オレオレ認証局)を構築して、Webサーバー向けのサーバー証明書を発行する手順について紹介します。認証局の証明書をWebブラウザやOSの証明書ストアに読み込むことで、自己署名証明書を使ったサーバーに、警告なしにアクセスすることができます。

更に簡便に済ますなら、作成したオレオレ証明書 (certificate.crt) を、ルート証明書としてブラウザにインポートすることで、警告を回避できます。ただしこの方法は、サーバーを追加すると、その度に証明書をブラウザに追加する必要があります。 またブラウザによっては、ルート証明書としてインポートできません。

自己署名証明書を作ってルート証明書として読み込んでみた
自己署名証明書 (オレオレ証明書) をルート証明書としてインポートしたときのブラウザの挙動をテストしてみました。ブラウザと証明書の作成方法によって挙動が違うことが判ったので、その結果を報告します。

Apacheの構成ファイルについて

Apacheの構成ファイルは構造化され複数のファイルに分かれています。

メインの構成ファイルとして、

/etc/apache2/apache2.conf

があり、ここに次のディレクトリ群に入っている個別の構成ファイルを読み込むようになっています。

/etc/apache2/(conf|mods|sites)-available
/etc/apache2/(conf|mods|sites)-enabled

個別の構成ファイルの入るディレクトリは、availableとenabledのペアとなっています。availableにファイルの実体を配置し、その中で実際に使うものをenabledにリンクしてあります。Apacheは起動時に、enabledからファイルを読み込んで、メインの構成ファイルに組み込みます。enabledにリンクするには、次のコマンドを使います。

a2ensite
a2enconf
a2enmod

CORSの構成

Cross-Origin Resource Sharing (CORS) は、ブラウザ内からRedmineのRest APIを呼び出す場合に必要になります。筆者の場合は、TrelloのPower-Up (プラグイン) を開発しており、CORS対応が必要となっています。通常のRedmineの使用では必要ありません。

CORSをサポートする方法には2つあります。

  • rack-corsの組み込み
  • ApacheによるHeaderとStatus Codeの書き換え

rack-corsの組み込み

前記事で使用した方法です。PassengerはRack対応ということで、rack-corsとの組み合わせでCORS対応を実現できます。前記事でrack-corsを組み込んでいればそのまま有効になります。追加の設定は必要ありません。

ApacheによるHeaderとStatus Codeの書き換え

より一般的な方法として、ApacheにHeaderとStatus Codeを書き換えさせることができます。(この場合は、rack-corsはアンインストールする必要があります)

CORSのための設定ファイルを作成します。

sudo vim /etc/apache2/conf-available/cors.conf

次の内容をコピーします。

<Location />
  <IfModule mod_headers.c>
    Header always set Access-Control-Allow-Origin "*"
    Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT, PATCH"
    Header always set Access-Control-Max-Age "7200"
    Header always set Access-Control-Allow-Headers "Content-Type, x-redmine-api-key"
  </IfModule>

  <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_METHOD} OPTIONS
    RewriteRule ^(.*)$ $1 [R=200,L]
  </IfModule>
</Location>

最初のヘッダー書き換えは、Access-Control-Allow-Originなど、CORSで要求されるヘッダー情報をレスポンスに追加します。

2番目はOPTIONSに対するステータスコードを書き換えます。OPTIONSはCORSに付随してブラウザからサーバーに発行されるリクエストで、CORSをサポートするかどうか事前に問い合わせます。RedmineはOPTIONSに対しては404を返すので、それを200に書き換えて返しています。

設定を組み込み、Apacheサーバーを再起動します。

sudo a2enconf cors
sudo a2enmod rewrite
sudo systemctl restart apache2

変更履歴

日時内容
2024/03/25Passengerのインストール方法を変更 (Passenger 5.0 -> 6.0)
自己署名証明書の作成を省略 (前記事で作成したものをそのまま使用)
SSLとPassengerの設定をredmine.confに統合
Apacheのインストールで作成された構成ファイルを変更しないように変更
2023/04/1122.04.2 LTS Amd64 でPassengerのプロセスが起動しない問題について記述
2023/04/08自己署名証明書の作成コマンドを変更 (OPENSSL COOKBOOKに準拠)
Apacheのインストール時に、apache2-devをインストールするように変更
2023/03/27自己署名証明書の作成時に指定する Common Name について説明を追加
2022/06/25自己署名証明書の作成時に、秘密鍵を最初から暗号化せずに生成するように変更
2022/06/21自己署名証明書の作成ステップを修正
> chmod 400 server.key -> chmod 400 private.key
> 上記chmodを別ラインに分割 (直前のコマンドでPass Phraseの入力が正しく行われないため)
redmine.confの記述を修正
> /home/redmine/redmine -> /opt/redmine
rack-corsの設定について補足
2022/06/20秘密鍵を復号化するように変更
セキュリティ警告の回避方法について記載
2022/06/10CORSに関する記述にrack-corsを追加
2022/06/07初版リリース