しばたテックブログ

気分で書いている技術ブログです。

Application Request Routing(ARR)を使ったRedmineの設定について

blog.shibata.tech

以前に構築したWindows Server上のRedmineですが「IISと一緒に80番ポートでアクセスできる様にしたいなぁ。」と思ったのでリバースプロキシとしてApplication Request Routing(以降ARR)を導入してみました。

ARRを使ったRedmineの設定についてはググるといろいろなサイトでその手順が紹介されているのですが、割と古めの情報が多かったので、本エントリでは最新のARR 3.0を使いできるだけGUIに頼らない手順を紹介しようと思います。

参考サイト

ARRとは何ぞやといった話や、基本的な設定手順についてはMVPの田中さんの以下の記事が詳しく参考になります。

www.buildinsider.net

本エントリも基本的にはこの記事の内容に従っており、記事中ではC#で書かれている個所をPowerShellで書き直している感じになります。

0. はじめに

本エントリの前提として、Windows Serverに最小構成でRedmineをインストールするでRedmineをインストールした直後の状態からはじめます。

この環境にIISとARRをインストールし、RedmineにアクセスするためのURLの書き換えを行っていきます。

1. IISとARRのインストール

はじめにIISとARRをインストールします。
IISはWindowsの機能の追加、またはInstall-WindowsFeatureコマンドレットからインストール可能ですが、ARRと一緒にインストールするのであればWebPIからインストールするのが手っ取り早く確実です。

以下の手順でWebPIをサイレントインストールします。

# Web PI
# ダウンロード
Invoke-WebRequest -Uri "https://download.microsoft.com/download/C/F/F/CFF3A0B8-99D4-41A2-AE1A-496C08BEB904/WebPlatformInstaller_amd64_en-US.msi" -OutFile "$(Get-Location -PSProvider Filesystem)\WebPlatformInstaller_amd64_en-US.msi"
# インストール
Start-Process -FilePath "msiexec.exe" -ArgumentList @('/i', "$(Get-Location -PSProvider Filesystem)\WebPlatformInstaller_amd64_en-US.msi", '/passive') -Wait -PassThru
# PATH追加
$env:PATH = "C:\Program Files\Microsoft\Web Platform Installer;" + $env:PATH

WebPIをインストールしたらWebpiCmdコマンドが使える様になりますので、以下の様にWebpiCmd /InstallコマンドでIISとARRをインストールします。

# IIS + ARR 3.0のインストール
#   IIS-WebServer        IIS-WebServer
#   ARRv3_0              Application Request Routing 3.0
#   ManagementService    IIS: Management Service
WebpiCmd.exe /Install /Products:"IIS-WebServer,ARRv3_0,ManagementService" /AcceptEULA

f:id:stknohg:20171105210848p:plain

f:id:stknohg:20171105210903p:plain

補足としてWebpiCmdでインストール可能なプロダクトは以下のコマンドで確認することができます。
環境に応じてインストールするプロダクトを変えてやれば良いでしょう。

WebpiCmd.exe /List /ListOption:All

2. ARRの構成

ここからARRの構成を行います。
はじめにWebAdministrationをインポートしておきます。

Import-Module WebAdministration

リバースプロキシの有効化

Set-WebConfigurationPropertyコマンドでリバースプロキシを有効にします。

# リバースプロキシ有効化
Set-WebConfigurationProperty -Filter system.webServer/proxy -Name Enabled -Value $true

GUIだと以下の設定と等価になります。

f:id:stknohg:20171105211131p:plain


f:id:stknohg:20171105211148p:plain


f:id:stknohg:20171105211204p:plain

URL書き換え規則の設定 - その1

ここからURL書き換え規則を追加していきます。
書き換え規則はDefault Web Siteに対して行うものとし、

  • /http://localhost:3000/

に書き換えるルールを設定してみます。

ざっくり図にするとこんな感じです。

f:id:stknohg:20171105212112p:plain:w400

書き換え設定はGUI、CUIのどちらから行おうとも最終的にはWeb.configの設定に行きつきます。

なのでPowerShellで設定する場合でもAdd-WebConfigurationPropertySet-WebConfigurationProperty等を使ってひたすら該当する設定をしてやるしかありません。

以下の例ではReverseProxyInboundRule1という規則*1を作っています。

# Rewrite Ruleの設定
$REWRITE_SITE_PATH = "IIS:\Sites\Default Web Site"
$REWRITE_RULE_NAME = "ReverseProxyInboundRule1" # GUIで設定した時と同じ名前にしておく
$REVERSE_PROXY_HOST = "localhost:3000"
$rule = @{
    Name = $REWRITE_RULE_NAME; 
    PatternSyntax = 'ECMAScript';
    stopProcessing = 'True'
}
Add-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules" -Name "." -Value $rule
Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/action" -Name "url" -Value "http://$REVERSE_PROXY_HOST/{R:1}"
Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/action" -Name "type" -Value "Rewrite"
Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/match" -Name "url" -Value "(.*)"

GUIだと以下の設定と等価になります。

f:id:stknohg:20171105211319p:plain

f:id:stknohg:20171105211333p:plain

f:id:stknohg:20171105211348p:plain

f:id:stknohg:20171105211404p:plain

URL書き換え規則の設定 - その2

先ほどの設定で基本的な内容は理解できたかと思いますが、これではあまり使い勝手がよくありません。

そこで追加例として、

  • /redminehttp://localhost:3000/redmine

に書き換えるルールを設定してみます。

このルールであれば/redmine/*の場合だけRedmineを、その他URLの場合はIISを利用することができます。
(/redminehttp://localhost:3000/としていないのは、このルールだとRedmine側でCSS等のパスが合わなくなるためです)

f:id:stknohg:20171105212217p:plain:w400

Redmineの設定変更

このルールに合わせるため、URL書き換えの前にRedmine側でURLにプリフィックス(/redmine)を付ける設定変更をしておきます。
Redmineでプリフィックスを付けるにはいくつか方法がある様ですが、今回は/config/environment.rbを書き換える方法を採ります。

以下の手順で/config/environment.rb

Redmine::Utils::relative_url_root = "/redmine"

の1行を追加します。

# CSS等のパスを変えるために ./config/environment.rb にPrefix設定を追加。
# http://www.redmine.org/projects/redmine/wiki/HowTo_Install_Redmine_in_a_sub-URI
$REDMINE_VER = '3.4.2'
$REDMINE_INSTALL_ROOT = 'C:\'
$REDMINE_INSTALL_PATH = Join-Path $REDMINE_INSTALL_ROOT "redmine-$REDMINE_VER"
@"
#
Redmine::Utils::relative_url_root = "/redmine"
"@ -replace "`n","`r`n" | Add-Content (Join-Path $REDMINE_INSTALL_PATH "config\environment.rb") -Encoding Default

/config/environment.rbの設定を変更した後は、Thinの起動引数に--prefixを付ける変更をしてRedmineを起動しなおします。

# サービス設定を変更
$REDMINE_SERVICE_NAME = "Redmine"
$REDMINE_INSTALL_PORT = 3000
$REDMINE_URL_PREFIX = "/redmine"
Stop-Service $REDMINE_SERVICE_NAME
thin_service remove -N $REDMINE_SERVICE_NAME
thin_service install -N $REDMINE_SERVICE_NAME -c "$REDMINE_INSTALL_PATH" -p $REDMINE_INSTALL_PORT -e production --prefix $REDMINE_URL_PREFIX
Start-Service $REDMINE_SERVICE_NAME

これでプリフィックスを付けてRedmineを起動することができ、

でアクセス可能になります。

URL書き換えルールの設定

最後にURL書き換えルールを設定します。
その1で追加したルールを以下のコマンドで書き換えます。

Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/action" -Name "url" -Value "http://$REVERSE_PROXY_HOST/{R:0}"
Set-WebConfigurationProperty -PSPath $REWRITE_SITE_PATH -Filter "system.webServer/rewrite/rules/rule[@name='$($REWRITE_RULE_NAME)']/match" -Name "url" -Value "redmine(.*)"

GUIだとこう書き換えています。

f:id:stknohg:20171105211509p:plain


f:id:stknohg:20171105211530p:plain

結果

最終的に/redmineでアクセスした場合はRedmineに、

f:id:stknohg:20171105212958p:plain

それ以外のURLでアクセスした場合はIIS(ここではデフォルトサイト)にアクセス可能になり

f:id:stknohg:20171105213110p:plain

RedmineとIISのサイトを併用可能にすることができました。

*1:GUIで設定した場合につく名前と同じ

Windows 10のPowerShellモジュール変更点まとめ

まとめ、というか作成予定地です。

Windows 10の各バージョンごとでのPowerShellモジュールの変更点についてGistに簡単なメモをまとめたのでリンクを張っておきます。
時間があればちゃんとした記事としてまとめ直したいと思います。

変更点の調査方法

各バージョン毎に新規インストールした環境、または手元の開発環境に対して簡単なスクリプトを流して、実行環境のモジュールの一覧・コマンドレットや関数の一覧・パラメーターの一覧をまとめてJSONファイルに保存し、Diffをとって変更点を調べています。

割とざっくり調べているので抜け・漏れは普通にあると思いますので結果については軽く見てください。

スクリプトはちょいちょい修正しているのでもう少し内容が固まったら公開しても良いかなといった感じです...

Windows 10 May 2021 Update (21H1)での変更点

Windows 10 October 2020 Update(20H2)での変更点

Windows 10 May 2020 Update (20H1, 2004)での変更点

Windows 10 November 2019 Update (19H2, 1909)での変更点

Windows 10 May 2019 Update (19H1, 1903)での変更点

Windows 10 October 2018 Update (RS5, 1809)での変更点

Windows 10 Spring Creators Update (RS4, 1803)での変更点

Windows 10 Fall Creators Update (RS3, 1709)での変更点

Windows 10 Creators Update (RS2, 1703)での変更点

Windows 10 Anniversary Update (RS1, 1607)での変更点

Windows 10 November Update (TH2, 1511)での変更点

PowerShell 6.0からファイル出力に関わるエンコーディングが変わります

現在開発中のPowerShell 6.0ではクロスプラットフォーム化することを主な契機としてファイル出力のエンコーディングに大きな破壊的変更が入ります。

現在最新のPowerShell 6.0 Beta.9でその変更が一部反映されたため本エントリで紹介します。

1. -Encodingパラメーターの型が変わります

これまでのPowerShellでは、例えばOut-Fileなどのファイル出力に係わるコマンドレットの-Encodingパラメーターはstring*1であり、主に以下の内容を指定可能でした。

手元のWindows PowerShell 5.1環境ではざっとこんな感じです。

コマンドレット -Encodingパラメーターの型
Add-Content Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding
Export-Clixml System.String
Export-Csv System.String
Export-PSSession System.String
Get-Content Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding
Import-Csv System.String
Out-File System.String
Select-String System.String
Set-Content Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding

-Encodingパラメータの値 対応する.NET Frameworkのエンコーディング
unknown System.Text.Encoding.Unicode
string System.Text.Encoding.Default
unicode System.Text.Encoding.Unicode
bigendianunicode System.Text.Encoding.BigEndianUnicode
utf8 System.Text.Encoding.UTF8
utf7 System.Text.Encoding.UTF7
utf32 System.Text.Encoding.UTF32
ascii System.Text.Encoding.ASCII
default System.Text.Encoding.Default
(PowerShell Core 6.0だとUTF8)
oem GetOEMCP()関数で得られるコードページのエンコーディング

PowerShell 6.0 Beta.9からは-Encodingパラメーターは全てSystem.Text.Encoding型に統一されます。

一応これまでのパラメーターも全てではないもののstringSystem.Text.Encodingへの変換をしてくれるのでそのまま使えます。

この変更により、Out-Fileなどのコマンドレットで使用可能なエンコーディングの制限がなくなるので利用範囲がより増えることになります。

# 例) たとえばOut-FileでEUC出力するなんてことも可能に
$encoding = [Text.Encoding]::GetEncoding(51932)
"鉄はホットなうちにビートダウン!" | Out-File -FilePath .\sample.txt -Encoding $encoding

非互換のパラメーターについて

今回の変更によりGet-ContentSet-Content-EncodingではByteを指定することが出来なくなりました。
代わりにAsByteStreamパラメーターを使う必要があります。

# PowerShell 5.1まで
Get-Content -Path .\Sample.bin -Encoding Byte

# PowerShell 6.0からは -AsByteStream を使う
Get-Content -Path .\Sample.bin -AsByteStream

2. デフォルトのファイル出力エンコーディングがBOM無しUTF-8になります

こちらは多くの人が望んでいた変更かと思います。
PowerShellがクロスプラットフォーム化したことでより多くの環境にマッチする動作をするための変更となります。

この変更については、もともとRFCで提案されていたものが承認され、前項の変更に合わせてPowershell 6.0 Beta.9で"部分的に"導入されました。

github.com

例として以下の様なリダイレクト演算子やエンコーディング指定のないOut-Fileコマンドレットを実行した場合、これまではBOM付きのUTF-16で出力されましたが、PowerShell 6.0ではBOM無しUTF-8になります。

# PowerShell 5.1まではBOM付きUTF-16、PowerShell 6.0からはBOM無しUTF-8のファイルが作成される
"鉄はホットなうちにビートダウン!" > .\sample.txt

"鉄はホットなうちにビートダウン!" | Out-File .\sample.txt

この変更に合わせて前項の-Encodingパラメーターに新たに

  • utf8BOM
  • utf8NoBOM

と、BOMの有無を明示したものが追加されました。

f:id:stknohg:20171104214636p:plain

RFCの未実装部分について

RFCを最後まで読むとわかるのですが、このRFCではデフォルトのエンコーディングを変える他に、これまでのWindows PowerShellとの互換を図るため$PSDefaultEncoding変数を追加し、従来の挙動と今回変更された挙動を切り替えることができる様にすると記載されています。

この機能については現在のところ未実装でPowerShell 6.0のリリース後要望があれば実装するとの事です。*2

その要望を集めるためのIssueが

github.com

に上げられているので互換性が必要だと思う方はこちらにコメントすると良いでしょう。

注意事項

ちょっとややこしいのですが、今回の変更はファイル出力に係わるエンコーディングのはなしであるため、$OutputEncoding変数や[Console]::OutputEncodingについては変更がありませんので注意してください。

【2017/12/25追記】

本件とは別件でPowerShell 6.0 RC1から$OutputEncodingの既定値がBOM無しUTF8に変更されました。

細かい経緯は

github.com

をご覧ください。
(余談ですが、はじめは既定値をISO-8859-1(いわゆるLatin-1)にする方針で思わずコメントしてしまいました...)

最後に

とりあえずこんな感じです。

今回の変更はPowerShell 6.0で発生する破壊的変更の中でも最大級のものですが、否定的な反応はさほど出ないのではと個人的には思っています。

*1:またはMicrosoft.PowerShell.Commands.FileSystemCmdletProviderEncoding型

*2:細かい話は https://github.com/PowerShell/PowerShell/pull/5080#discussion_r144723400 あたりのコメントを読んでください