安裝 Redmine 3.3

摘要

此文章將說明如何在 Ubuntu 安裝 Redmine,並使用 Let’s Encrypt 簽發 SSL 憑證以建立安全連線,但不包含安裝 MySQL,MySQL 必須自行先準備好。

Ubuntu + Nginx + MySQL + Redmine

Stack 如下。

  • Redmine 3.3
  • MySQL 5.7
  • Rails 4.2
  • Ruby 2.3, Gem 2.6
  • RVM 1.28
  • Phusion Passenger + Nginx 1.10
  • Security Updates
  • Ubuntu 16.04 LTS

基礎更新

此章節將說明如何更新基礎項目,例如安全性更新。

更新 APT List

把 package 清單抓下來,第一次會比較久。

sudo apt-get update

更新 Ubuntu 16.04 的安全性更新

建議執行此步驟,至少要把洞補一補。

安裝 unattended-upgrades

如果沒有 unattended-upgrades,記得去裝一下。

sudo apt-get install unattended-upgrades

安裝安全性更新

注意!unattended-upgrade 沒有 s

sudo unattended-upgrade

安裝 RVM

RVM 全名為 Ruby Version Manager。此章節將說明如何安裝 RVM。

這裡不採用 RVM 官方首頁提供的安裝方法,而是改用 RVM 官方提供的 RVM Installer 去安裝 RVM。

安裝 RVM 的過程,基本上都不需要 sudo。若需要,RVM 會跟你講它需要權限,通常 RVM 會告訴你要怎麼執行來讓它獲得權限。

安裝 RVM Public Key

將 RVM 的公鑰抓下來,之後將會使用此公鑰驗證 RVM。

gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3

下載 RVM Installer

將 RVM Installer 下載下來。指令前面加反斜線 \ 的意思是指示使用原始的指令,避免使用到別名(alias)。

\curl -O https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer
\curl -O https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer.asc

此時應該會有兩個檔案,rvm-installerrvm-installer.asc

驗證 RVM Installer Signature

使用方才抓下來的公鑰來驗證我們下載的 RVM Installer 是否正確無誤。

gpg --verify rvm-installer.asc &&

執行 RVM Installer

承上述的驗證,RVM Installer 驗證過了才會接著執行 && 後的指令。這裡安裝的是 stable 版 RVM。

bash rvm-installer stable

設定 User Group

如果使用者帳號沒在 rvm 群組裡,記得加一下。<your_username> 是你的使用者名稱,例如 kevin

sudo usermod -a -G rvm <your_username>

讓 RVM 可使用

建議重登或重開機,但也可以直接執行 source ~/.rvm/scripts/rvm 來使用 RVM。

檢查 RVM 版本

rvm -v

安裝 Ruby

此章節將說明如何安裝 Ruby 及 Gem (Rubygems)。

使用 RVM 安裝 Ruby 相關套件

安裝 Ruby 會用到的相關套件,安裝其相依性。

rvm requirements

開始安裝 Ruby

Redmine 官方寫 Redmine 3.3 支援到 Ruby 2.3。我們選擇安裝 Ruby 2.3.3。

rvm install 2.3.3

設定 Ruby 預設版本

如果沒有特別指名 Ruby 版本,則會使用預設的版本,這裡使用的 Ruby 預設版本為 2.3.3。

rvm use 2.3.3 --default

檢查 rubygem 版本

ruby -v
gem -v

更新 Rubygems 至 Ruby 2.3.3 所使用的版本

rvm rubygems current

檢查 gem 版本

gem -v

安裝 Rails

此章節將說明如何安裝 Ruby on Rails

切換 Ruby 版本

如果沒把 ruby 的 default 設為 2.3.3 版,請在安裝 Rails 前手動切換 ruby 版本。

rvm 2.3.3

安裝 Rails 4.2.7.1

這裡選擇不安裝文件檔。另外,Redmine 官方寫 Redmine 3.3 僅支援到 Rails 4.2。

gem install rails -v 4.2.7.1 --no-rdoc --no-ri

檢查 Rails 版本

rails -v

(可選)建立 Gem Sets

可使用 RVM 來建立 gemset,可直接將 Ruby 和 Rails 版本合起來弄成一包,切換 Ruby 及 Rails 時版本會比較方便。

挑選 Ruby & Rails 版本

以 Ruby 2.3.3 + Rails 4.2.7.1 為例。

rvm 2.3.3
gem install rails -v 4.2.7.1

建立 Gem Set

rvm gemset create rails4271

使用 Gem Set 並安裝 Rails

不安裝 Rails 的文件。如果要裝 Rails 的文件,請不要加 --no-rdoc --no-ri

rvm 2.3.3@rails4271
gem install rails -v 4.2.7.1 --no-rdoc --no-ri

使用 Gem Set 並檢查版本

rvm 2.3.3@rails4271 ; rails -v

部署在正式伺服器上

部署在正式環境通常不會安裝文件檔,如果不想每次 gem install 都加 --no-rdoc --no-ri 參數,請在 ~/.gemrc/etc/gemrc 加上 gem: --no-rdoc --no-ri,這樣就不用每次 gem install 都要打 --no-rdoc --no-ri 了。

安裝 Nginx

此章節將說明如何安裝 Nginx

這裡的 Nginx 不會是一般 Linux 發行版所提供的版本,會使用 Phusion Passenger。Phusion Passenger 是一個可與 Apache 或 Nginx 整合的一套 web 兼 app 的 server。安裝過程會需要編譯 Nginx。

關於 Virtual Hosts 管理方法,筆者這部分偷懶,沒採用 site-available、site-enable 的作法。

(可選)移除發行版提供的 Nginx

如果你不想保留內建的 Nginx,可依照下列步驟移除 Nginx。

sudo apt-get purge nginx nginx-common

安裝 Passenger

gem install passenger --no-rdoc --no-ri
passenger-install-nginx-module

安裝 Passenger 時遇到 Permission problems

如果安裝過程遇到 permission problems,請依照 passenger-install-nginx-module 的指示來執行,接著才重新安裝。

export ORIG_PATH="$PATH"
rvmsudo -E /bin/bash
export PATH="$ORIG_PATH"
<ruby_path> <passenger-install-nginx-module_path>

請把 <ruby_path><passenger-install-nginx-module_path> 替換成實際上使用的路徑。

我們使用了 RVM 安裝 ruby 及 passenger,最後一條命令可以不用打那麼長,直接執行 passenger-install-nginx-module 即可。

如果依照 passenger-install-nginx-module 指示執行,遇到下列警告

Warning: can not check `/etc/sudoers` for `secure_path`, falling back to call via `/usr/bin/env`, this breaks rules from `/etc/sudoers`. Run:

的話,請將下列 shell 片段加到你在用的 shell 以處理此警告。例如 ~/.profile ~/.bash_profile

export rvmsudo_secure_path=0

記得要重登,若不想重登,請直接執行 export rvmsudo_secure_path=0

設定 Nginx

此節將說明如何設定 Nginx。

設定 Virtual Hosts

如果沒有域名(domain name)可用,可以跳過此節,直接用 IP 設定。

開啟 nginx.conf 檔案。

vim /opt/nginx/conf/nginx.conf

開啟 nginx.conf 後,在 http { } 裡新增 include vhost/*.conf;

接著建立 vhost 目錄。

mkdir -p /opt/nginx/conf/vhost

編寫並建立 redmine.conf

vim /opt/nginx/conf/vhost/redmine.conf

redmine.conf 設定如下。

其中 your.domain.name 是你的域名,例如 redmine.mycompany.com。redmine 將會裝在 /opt/redmine

server {
    listen 80;
    server_name your.domain.name;

    root /opt/redmine/public;
    passenger_enabled on;

    # redirerct server error pages to the static page /50x.html
    #
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root html;
    }
}

設定 Nginx Service

此節將說明如何讓 Nginx 透過 systemd 啟動 Nginx 服務。之後會使用 systemctl 來管理服務。

編寫並建立 nginx.service

sudo vim /lib/systemd/system/nginx.service

nginx.service 內容如下。

[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/opt/nginx/logs/nginx.pid
ExecStartPre=/opt/nginx/sbin/nginx -t
ExecStart=/opt/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

啟動 Nginx 服務

sudo systemctl daemon-reload
sudo systemctl start nginx

檢查 Nginx 網路狀態

sudo netstat -plntu | grep nginx

安裝 Redmine

此章節將說明如何安裝 Redmine

下載 Redmine

\curl -O http://www.redmine.org/releases/redmine-3.3.2.tar.gz

解壓縮 Redmine

tar zxvf redmine-3.3.2.tar.gz

重命名解壓縮後的 Redmine 目錄

mv redmine-3.3.2 redmine

建立安裝路徑

在這裡我們將會把 Redmine 安裝在 /opt/redmine/

將 Redmine 移到安裝目錄

mv redmine /opt/

設定 Redmine

此節將說明如何設定 Redmine。

複製 Redmine 設定檔

把 Redmine 提供的設定檔範例複製一份出來

cd /opt/redmine
cp config/configuration.yml.example config/configuration.yml
cp config/database.yml.example config/database.yml

修改 Redmine MySQL 設定

如果尚未備妥 MySQL,請先準備。筆者已經有另外準備一台獨立的 MySQL,所以此節範例將不使用本地端的 MySQL,而是使用已經預先配置好的 MySQL。

vim config/database.yml

設定 MySQL production,範例如下。

production:
  adapter: mysql2
  database: redmine
  host: 104.199.123.123
  username: redmine
  password: "redmine"
  encoding: utf8mb4

encoding 請根據你實際上使用的 collation 來設定,這裡預先架好的 MySQL redmine collation 是 utf8mb4_unicode_ci,character set 是 utf8mb4

如果你要使用 SSL 來連 MySQL,範例如下。其他 MySQL 連線設定可以參考 Ruby Mysql2

production:
  adapter: mysql2
  database: redmine
  host: 104.199.123.123
  username: redmine
  password: "redmine"
  encoding: utf8mb4
  sslca: "/path/to/server-ca.pem"
  sslcert: "/path/to/client-cert.pem"
  sslkey: "/path/to/client-key.pem"

安裝 Redmine 相依性

在安裝 Redmine 時,adapter 若是使用 mysql2,則得先安裝 libmysqlclient-dev。Redmine 相依於RMagick,必須要安裝 imagemagicklibmagickwand-dev。若還有缺其他項目,請依照 bundler 的指示處理。

安裝 libmysqlclient-dev

sudo apt-get install libmysqlclient-dev

安裝 imagemagicklibmagickwand-dev

sudo apt-get install imagemagick libmagickwand-dev

開始安裝 Redmine

gem install bundler
bundle install --without development test

產生 secret token 並產生資料庫

產生 secret token 後,接著連線至設定的 MySQL DB,然後建立並初始化 tables。

bundle exec rake generate_secret_token
RAILS_ENV=production bundle exec rake db:migrate
RAILS_ENV=production bundle exec rake redmine:load_default_data

執行 RAILS_ENV=production bundle exec rake redmine:load_default_data 的過程中,會詢問你要使用哪一個語系,請依照需求選擇使用語言。這裡使用 zh-TW

重新啟動 Nginx

sudo systemctl restart nginx

使用測試

試著連到剛架好的 Redmine。

Redmine

登入 Redmine

Redmine 的預設第一組帳號密碼是 admin/admin,務必要馬上登入並修改密碼,Redmine 預設會讓 admin 第一次登入時強制更新密碼

Redmine Login

使用 Let’s Encrypt 建立 SSL

此章節將說明如何使用 Let’s Encrypt 為 Redmine 網站建立安全連線。

安裝 Let’s Encrypt 工具

Let’s Encrypt 官方推薦使用 Certbot 來建立憑證,在 Ubuntu 上的 letsencrypt 本身就是 Certbot,在其他發行版或自行下載的 Certbot 名稱通常是 certbot

sudo apt-get install letsencrypt

使用 Certbot 簽發憑證

Certbot certonly 提供兩種 plugins 來簽發憑證,一是 webroot,二是 standalone,這裡我們採用 webroot,之後要自動更新憑證時會用到。這裡不使用 Certbot 的互動式介面視窗來填資料,如果想使用互動式介面視窗,請把參數 --email--agree-tos 拿掉。其中 --webroot 得指定 -w-d 才能作用。

sudo letsencrypt certonly --email redmine@mycompany.com --agree-tos --webroot \
    -w /opt/redmine/public -d redmine.mycompany.com

這裡我們只為 redmine.mycompany.com 簽發 SSL 憑證,如果要加簽其他域名,或要指定某域名的根目錄在別處的話,範例如下。

sudo letsencrypt certonly --email redmine@mycompany.com --agree-tos --webroot \
    -w /opt/redmine/public -d redmine.mycompany.com \
    -w /opt/nginx/html -d mycompany.com -d www.mycompany.com

檢查憑證是否已簽發

Certbot 執行後會顯示是否成功簽發憑證,但也可以自行手動檢查憑證檔案是否確實存在。產生的憑證位在 /etc/letsencrypt/live/live/ 底下會有以域名為名稱的目錄,例如 redmine.mycompany.com。另外,憑證理應只有 root 可以存取。

sudo ls /etc/letsencrypt/live/redmine.mycompany.com/

應該會看到下列四個檔案。

  • cert.pem
  • chain.pem
  • fullchain.pem
  • privkey.pem

有看到的話,就代表成功了。

產生 Strong Diffie-Hellman Group

此節要解決 Diffie-Hellman Group 的預設金鑰長度過短的問題,因此我們必須重產一個來取代。這裡我們採用 2048-bit 長的金鑰。

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

修改 Nginx SSL 設定

修改 /opt/redmine/conf/vhost/redmine.conf,將 http 自動轉址至 https,並根據 Cipherli.st 的建議,調整 SSL 設定。

關於 Nginx SSL 設定,其實可以把 SSL 相關設定抽出來獨立為另一個檔案,然後在各個有使用 SSL 的 Virtual Hosts 設定檔裡面 include 該 SSL 設定檔,例如 ssl.conf,但筆者偷懶沒弄。

另外,這裡使用 Mozilla SSL Configuration Generator 產生的建議來設定。

server {
    listen 80 default_server;
    server_name redmine.mycompany.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name redmine.mycompany.com;

    root /opt/redmine/public;
    passenger_enabled on;

    # SSL
    ssl_certificate            /etc/letsencrypt/live/redmine.mycompany.com/fullchain.pem;
    ssl_certificate_key        /etc/letsencrypt/live/redmine.mycompany.com/privkey.pem;

    ssl_session_cache    shared:SSL:50m;
    ssl_session_timeout    1d;
    ssl_session_tickets off;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    ssl_stapling on;
    ssl_stapling_verify on;

    ssl_trusted_certificate    /etc/letsencrypt/live/redmine.mycompany.com/chain.pem;

    add_header Strict-Transport-Security "max-age=15768000; includeSubdomains";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    # redirerct server error pages to the static page /50x.html
    #
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root html;
    }
}

另外,也可以用 QUALYS SSL LABS 檢測網站 SSL。

重啟 Nginx

檢查 Nginx 設定有沒有錯誤。

sudo /opt/nginx/sbin/nginx -t

確認無誤後,重啟 Nginx。

sudo systemctl restart nginx

試著瀏覽網站,可以瀏覽且看到有安全連線後,就 OK 了。

自動更新 Let’s Encrypt SSL 憑證

Certbot 提供了 renew 指令可以自動判斷是否需要更新,只要 crontab 設定好就行了。

sudo crontab -e

根據 Certbot 對 cron, systemd 的建議,將會設定一天執行兩次。根據 Certbot 官方的說法,每次執行可能會發生問題,renew 最好隨機挑某分來執行。範例如下。

# First Let's Encrypt renew task
23 5 * * * sudo letsencrypt renew >> /var/log/letsencrypt-renewal.log 2>&1

# Second Let's Encrypt renew task
37 19 * * * sudo letsencrypt renew >> /var/log/letsencrypt-renewal.log 2>&1

執行後的結果將會輸出到 /var/log/letsencrypt-renewal.log

(可選)啟用 HTTP/2

此章節將說明如何在 Nginx 啟用 HTTP/2。

修改 Nginx HTTP/2 設定

Nginx 啟用非常簡單,在設定檔的 listen 加上 http2 即可。承先前設定 SSL 的 conf 檔,範例如下。

server {
    listen 80 default_server;
    server_name redmine.mycompany.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name redmine.mycompany.com;

    root /opt/redmine/public;
    passenger_enabled on;

    # SSL
    ssl_certificate            /etc/letsencrypt/live/redmine.mycompany.com/fullchain.pem;
    ssl_certificate_key        /etc/letsencrypt/live/redmine.mycompany.com/privkey.pem;

    ssl_session_cache    shared:SSL:50m;
    ssl_session_timeout    1d;
    ssl_session_tickets off;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    ssl_stapling on;
    ssl_stapling_verify on;

    ssl_trusted_certificate    /etc/letsencrypt/live/redmine.mycompany.com/chain.pem;

    add_header Strict-Transport-Security "max-age=15768000; includeSubdomains";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    # redirerct server error pages to the static page /50x.html
    #
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root html;
    }
}

接著確認 Nginx 設定無誤後,重啟 Nginx。

sudo /opt/nginx/sbin/nginx -t
sudo systemctl restart nginx

檢查是否成功啟用 HTTP/2

可以到 KeyCDN HTTP/2 Test 測試是否有成功啟用 HTTP/2。

參考資料

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

本文鏈接:https://xenstalker.tw/2017/04/14/redmine-installation/