Python3 CGIを使ったWebページのデバッグ環境構築 on Mac

MacローカルにWebサーバを用意し,Python3ベースのCGIが組み込まれたWebページを正しく表示させる方法をメモ.

**<font color=”red”>なお,この中の説明では`System Integrity Protection(SIP)`で保護されたファイルを編集する作業があるため,事前にTime Machine等を用いてシステムのバックアップを取ることを強くお勧めする.</font>**

##Python3のインストール
Mac OSには,デフォルトではPython 2系しか環境がインストールされていない.Python 3系の環境をインストールする際に`pyenv`を用いてインストールすれば,Python2系と3系の切り替えを容易に行えて便利なのだが,ここではHomebrewからPython3をインストールする.具体的には以下のコマンドを実行する.

```
$ brew install python3
```

##Apache環境の準備
MacにはApacheサーバがあらかじめインストールされている.設定ファイルは`/private/etc/apache2/`以下にある.

###httpd.conf
まずは,`httpd.conf`を以下のDiffを参考に編集する.

```diff
sh-3.2# diff httpd.conf.backup httpd.conf
157c157
< #LoadModule cgi_module libexec/apache2/mod_cgi.so
 — -
> LoadModule cgi_module libexec/apache2/mod_cgi.so
419c419
< #AddHandler cgi-script .cgi
 — -
> AddHandler cgi-script .cgi
540a541
> Include /private/etc/apache2/site-enabled/*.conf
```

編集できたら,Webサイトごとの設定ファイルを保存する`site-available/`ディレクトリと,ここから有効にする設定ファイルをシンボリックリンクで保存する`site-enabled/`ディレクトリを以下のコマンドで作成する.

```
# mkdir /private/etc/apache2/{site-available,site-enabled}
```

###VirtualHost
各サイトごとの設定ファイルを,`site-available/`ディレクトリの下に作成する.設定ファイルのサンプル(`sample.conf`)を以下に載せる.

```apacheconf
Listen 58001

<Directory /Users/USERNAME/sample/>
 Options -Indexes +FollowSymlinks +ExecCGI
 AllowOverride All
 Require all granted
</Directory>

<VirtualHost *:58001>
 ServerName localhost
 DocumentRoot “/Users/USERNAME/sample”
</VirtualHost>
```

ポート番号をベースにしたバーチャルホストを活用することで,同時に複数サイトのローカルデバッグが行えるようにしている.

設定ファイルを作成できたら,以下のようなコマンドを実行して`site-enabled/`にリンクを張り,Apacheが設定ファイルを読み込めるようにする.

```
# ln -s /private/etc/apache2/site-available/sample.conf /private/etc/apache2/site-enabled/sample.conf
```
###PATH環境変数に値を追加
デフォルトのApacheでは,Shebangに`/usr/bin/env python3`という風な指定をしたCGIプログラムを動作させる際に参照される`PATH`環境変数には`/usr/bin:/bin:/usr/sbin:/sbin`しか入っていない.先ほどインストールしたPython3本体へのリンクは`/usr/local/bin/`の下にあるため,Apacheが`PATH`環境変数を通して実行することができない(もちろん,Shebangに直接Python3のリンクへの絶対パスを記述すれば実行可能ではあるが…).

そこで,`PATH`環境変数の先頭に`/usr/local/bin`を追加し,ApacheからPython3のリンクが見えるようにする.これを実現するためには`/System/Library/LaunchDaemons/org.apache.httpd.plist`を編集する必要があるのだが,このファイルが`/System/`以下にあることから最近のMac OSで実装された`System Integrity Protection(SIP)`の影響で管理者権限でも編集できない.なので,まずはSIPの一時的な無効化を行う.

####SIP無効化
SIPの無効化を行うために,まずは`⌘`+`R`を押しながら再起動してリカバリーモードに入る.リカバリーモードに入れたらターミナルを起動し,以下のコマンドを実行する.

```
# csrutil disable
```

これでSIPが無効化されたので,いつも通りの再起動を行う.

####値の追加
前述の操作でSIPが無効化されたので,`/System/Library/LaunchDaemons/org.apache.httpd.plist`を編集できる.具体的には,以下のように編集する.

```xml
<?xml version=”1.0" encoding=”UTF-8"?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version=”1.0">
<dict>
 <key>Disabled</key>
 <true/>
 <key>Label</key>
 <string>org.apache.httpd</string>
 <key>EnvironmentVariables</key>
 <dict>
 <key>XPC_SERVICES_UNAVAILABLE</key>
 <string>1</string>
 <key>PATH</key>
 <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
 </dict>
 <key>ProgramArguments</key>
 <array>
 <string>/usr/sbin/httpd-wrapper</string>
 <string>-D</string>
 <string>FOREGROUND</string>
 </array>
 <key>OnDemand</key>
 <false/>
</dict>
</plist>
```

追加したのは`<key>EnvironmentVariables</key>`の`<dict></dict>`内にある`<key>PATH</key>`と`<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>`の二つ.`/usr/local/bin`を先頭に記述することで,`PATH`環境変数を用いて実行ファイルを見つける際に`/usr/local/bin`を優先して扱ってくれる.

####SIPの有効化
ファイルの編集が終わったら,忘れずにSIPを再び有効にしておく.`⌘`+`R`を押しながら再起動してリカバリーモードに入り,ターミナルを起動して以下のコマンドを実行する.

```
# csrutil enable
```

これでSIPが有効化されたので,いつも通りの再起動を行う.

##動作テスト
さて,以上の作業でデバッグ環境は構築できたので,動作テストを行う.
VirtualHost設定の際に指定したドキュメントルートディレクトリを作成し,その下にHTMLファイルなどを置いていく.動作テストに用いるWebページだが,[Gistで公開しているもの](https://gist.github.com/trileg/7f5b593d107f5dcd48faab4e22ad4df7)を使えばいい.

なお,cgiファイルについてはApacheから実行可能なように権限を付与する必要がある.具体的には以下のコマンドを実行する.

```
$ chmod +x ~/sample/sample.cgi
```

Webページの準備ができたら,以下のコマンドを順に実行し,Apacheの起動と念のための設定リロードを行う.

```
# apachectl start
# apachectl graceful
```

起動と設定ファイルの読み込みができたらブラウザで`http://localhost:58001/`にアクセスしてほしい.`It works!`という表示とその下の`CGI Output:`の右に現在の日時が表示されていれば,正しく動作している.

なお,Apacheのログファイルは`/private/var/log/apache2/`以下にあるので,正しく表示されない場合はここを参照してほしい.