前回、フォームのデータをcgiモジュールを使って受け取りました。
Docker + Alpine3.5 + Apache2.4 + Python3.6で、フォームのデータを標準モジュールcgiで受け取ってみた - メモ的な思考的な
今回は、ApacheのSSI(Server Side Include)を、公式チュートリアルを見ながら試してみます。
Apache チュートリアル: Server Side Includes 入門 - Apache HTTP サーバ バージョン 2.4
目次
環境
- Mac OS X 10.11.6
- Docker for Mac 17.03.1-ce-mac12
- Alpine3.5 + Apache2.4.25 + Python 3.6.1
なお、Dockerfileは前回のものを流用します。
また、コンソールで「Dockerのコンテナを起動する」とした場合は、以下のコマンドを入力しています。
参考:docker container / image コマンド新旧比較 - Qiita
$ docker container stop ssi
$ docker container rm $(docker container ls -a -q)
$ docker container prune
$ docker image ls
REPOSITORY TAG IMAGE ID
alpine python3_httpd24_ssi 658225783800
$ docker image rm 658225783800
$ docker image build -t alpine:python3_httpd24_ssi .
$ docker container run -p 8081:80 --name ssi -v `pwd`/htdocs/:/usr/local/apache2/htdocs alpine:python3_httpd24_ssi
$ docker container run -p 8081:80 --name ssi -v `pwd`/htdocs/:/usr/local/apache2/htdocs -v `pwd`/cgi/:/usr/local/apache2/cgi-bin/ alpine:python3_httpd24_ssi
AddOutputFilterを使って、shtmlファイルのみSSIを有効にする
まずは、SSIが動くか試してみます。
そのため、
<html>
<head>
<meta charset="UTF-8">
<title>例</title>
</head>
<body>
<h1>SSIサンプル(Echo)</h1>
<!--#echo var="DATE_LOCAL" -->
</body>
</html>
を
として2つ用意し、両方ともドキュメントルートの中に入れます。
ホスト上のパーミッションは以下の通りです。
$ ls -al
...
-rw-r--r-- 1 you staff 182 5 14 15:28 echo.html
-rw-r--r-- 1 you staff 182 5 14 15:15 echo.shtml
次に、httpd.confを修正します。
- SSIを使うため、
include_module
をLoadModule
- Directoryディレクティブに以下を追加
- Options Includes
- AddType text/html .shtml
- AddOutputFilter INCLUDES .shtml
とします。
なお、Web上ではAddOutputFilter INCLUDES
とAddHandler server-parsed
の2つの方法がありました。
Apacheのドキュメントによると、
とのことなので、2.4系の今回はAddOutputFilter
を使います。
httpd.conf
...
LoadModule include_module modules/mod_include.so
...
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
AllowOverride None
Require all granted
Options Includes
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
</Directory>
Dockerコンテナを起動し、curlで確認します。
# htmlファイルではダメ
$ curl http://localhost:8081/echo.html
...
<body>
<h1>SSIサンプル(Echo)</h1>
<!--#echo var="DATE_LOCAL" -->
</body>
# shtmlファイルでは、SSI動作
$ curl http://localhost:8081/echo.shtml
...
<body>
<h1>SSIサンプル(Echo)</h1>
Sunday, 14-May-2017 06:36:59
</body>
shtmlファイルのみSSIが動作しました。
ソースコード全体は以下です。
https://github.com/thinkAmi-sandbox/Docker_Apache-sample/tree/master/alpine_apache_python36_ssi/ssi_shtml_echo_using_outputfilter
AddOutputFilterを使って、shtml・htmlファイルでSSIを有効にする
htmlファイルでもSSIが動作するよう、httpd.confにてhtmlをAddOutputFilter
へ追加します。
httpd.conf
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
AllowOverride None
Require all granted
Options Includes
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml .html
</Directory>
ホストのパーミッションには変更ありません。
$ ls -al
-rw-r--r-- 1 you staff 182 5 14 15:28 echo.html
-rw-r--r-- 1 you staff 182 5 14 15:15 echo.shtml
Dockerコンテナを起動し、curlで確認します。
# shtmlファイル
$ curl http://localhost:8081/echo.shtml
...
<body>
<h1>SSIサンプル(Echo)</h1>
Sunday, 14-May-2017 06:45:58
</body>
# htmlファイル
$ curl http://localhost:8081/echo.html
...
<body>
<h1>SSIサンプル(Echo)</h1>
Sunday, 14-May-2017 06:46:01
</body>
shtml・htmlファイルでSSIが動作しました。
ソースコード全体は以下です。
https://github.com/thinkAmi-sandbox/Docker_Apache-sample/tree/master/alpine_apache_python36_ssi/ssi_html_echo_using_outputfilter
XBitHack onを使って、htmlファイルのみでSSIを有効にする
AddOutputFilter以外の方法を探したところ、公式チュートリアルにXBitHack on
を使う方法が記載されていました。
XBitHack は、ファイルの実行ビットが立っている場合、 SSI ディレクティブにより解析することを Apache に伝えます。 従って、SSI ディレクティブを現在のページに加えるためには、 ファイル名を変更しなくてもよく、単に chmod を使用してファイルを実行可能にするだけで済みます。
SSI を許可するためのサーバの設定 | Apache チュートリアル: Server Side Includes 入門 - Apache HTTP サーバ バージョン 2.4
httpd.confを変更し、OptionsとXBitHackを使うようにします。
httpd.conf
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
AllowOverride None
Require all granted
Options Includes
XBitHack on
</Directory>
Dockerコンテナを起動し、curlで確認します。
まずはパーミッションがそのままの場合です。
$ curl http://localhost:8081/echo.shtml
...
<body>
<h1>SSIサンプル(Echo)</h1>
<!--#echo var="DATE_LOCAL" -->
</body>
$ curl http://localhost:8081/echo.html
...
<body>
<h1>SSIサンプル(Echo)</h1>
<!--#echo var="DATE_LOCAL" -->
</body>
いずれもSSIは動作しませんでした。
続いて、ホストのパーミッションを変更します。
$ chmod +x echo.html
$ chmod +x echo.shtml
$ ls -al
-rwxr-xr-x 1 you staff 182 5 14 15:28 echo.html
-rwxr-xr-x 1 you staff 182 5 14 15:15 echo.shtml
念のため、Dockerコンテナにあるファイルのパーミッションも確認します。
$ docker exec -it `docker ps | grep ssi | awk '{print $1}'` /bin/bash
bash-4.3# ls ./htdocs -al
...
-rwxr-xr-x 1 root root 182 May 14 06:47 echo.html
-rwxr-xr-x 1 root root 182 May 14 06:47 echo.shtml
ホストと同期されています。
パーミッションが変更されていたので、curlにて確認します。
$ curl http://localhost:8081/echo.shtml
...
<body>
<h1>SSIサンプル(Echo)</h1>
<!--#echo var="DATE_LOCAL" -->
</body>
$ curl http://localhost:8081/echo.html
...
<body>
<h1>SSIサンプル(Echo)</h1>
Sunday, 14-May-2017 07:06:21
</body>
htmlファイルのみSSIが有効になりました。
ソースコード全体は以下です。
https://github.com/thinkAmi-sandbox/Docker_Apache-sample/tree/master/alpine_apache_python36_ssi/ssi_html_cgi_using_xbithack_on
XBitHack onを使って、html・shtmlファイルでSSIを有効にする
XBitHackディレクティブのドキュメントを見ると、
on
ユーザの実行ビットが設定されている text/html ファイルは全てサーバで解析する html ドキュメントとして扱われます。
XBitHack ディレクティブ | mod_include - Apache HTTP サーバ バージョン 2.4
との記載がありました。
そのため、AddType
でshtml
を追加すれば、shtmlでも有効になると考えられたため、試してみました。
httpd.conf
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
AllowOverride None
Require all granted
Options Includes
AddType text/html .shtml
XBitHack on
</Directory>
パーミッションは両方とも実行可能です。
$ ls -al htdocs/
drwxr-xr-x 4 you staff 136 5 14 16:08 .
drwxr-xr-x 7 you staff 238 5 14 16:08 ..
-rwxr-xr-x 1 you staff 182 5 14 16:08 echo.html
-rwxr-xr-x 1 you staff 182 5 14 16:08 echo.shtml
Dockerコンテナを起動し、curlで確認します。
$ curl http://localhost:8081/echo.shtml
...
<body>
<h1>SSIサンプル(Echo)</h1>
Sunday, 14-May-2017 07:15:58
</body>
$ curl http://localhost:8081/echo.html
...
<body>
<h1>SSIサンプル(Echo)</h1>
Sunday, 14-May-2017 07:16:03
</body>
両方ともSSIが動作しました。
ソースコード全体は以下です。
https://github.com/thinkAmi-sandbox/Docker_Apache-sample/tree/master/alpine_apache_python36_ssi/ssi_shtml_echo_using_xbithack_on
XBitHack onを使って、CGIを動かす
SSIの動作が確認できたため、今度はCGIを動かしてみます。
httpd.confにCGIの記述を追加します。
httpd.conf
LoadModule alias_module modules/mod_alias.so
LoadModule cgid_module modules/mod_cgid.so
ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/"
<Directory "/usr/local/apache2/cgi-bin">
AllowOverride None
Options ExecCGI
SetHandler cgi-script
Require all granted
</Directory>
続いて、標準出力に現在時刻を出すCGI用Pythonスクリプトを作成します。
now.py
import datetime
print('Content-Type: text/plain;charset=utf-8')
print('')
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
if __name__ == '__main__':
pass
確認用のHTMLファイルも作成します。
CGIが正しく動作しているかを確認するため、JavaScriptでも現在時刻を取得します。PythonがUTC、JavaScriptがJSTとタイムゾーンが異なりますが、今回は確認するだけなのでそのままとします*2。
cgi.html
<html>
<head>
<meta charset="UTF-8">
<title>例</title>
</head>
<body>
<h1>SSIサンプル(CGI)</h1>
<p>CGIの時間(UTC):<!--#include virtual="/cgi-bin/now.py" --></p>
<p>JSの時間(JST) :<span id="js_time"></span></p>
<script>
document.getElementById("js_time").innerHTML = function(){
var now = new Date();
var year = now.getFullYear();
var mon = now.getMonth() + 1;
var day = now.getDate();
var hour = now.getHours();
var min = now.getMinutes();
var sec = now.getSeconds();
return `${year}-${mon}-${day} ${hour}:${min}:${sec}`
}();
</script>
</body>
</html>
また、htmlとPythonスクリプトを実行可能にします。
$ cd ../ssi_html_cgi_using_xbithack_on/
# 両方とも実行可能に変更
$ chmod +x cgi/now.py
$ chmod +x htdocs/cgi.html
# それぞれのファイルのパーミッションを確認
$ ls -Ral
...
./cgi:
-rwxr-xr-x 1 you staff 179 5 14 16:23 now.py
./htdocs:
-rwxr-xr-x 1 you staff 194 5 14 16:23 cgi.html
Dockerコンテナを起動します。CGI用のディレクトリもホストと共有します。
$ docker container run -p 8081:80 --name ssi -v `pwd`/htdocs/:/usr/local/apache2/htdocs -v `pwd`/cgi/:/usr/local/apache2/cgi-bin/ alpine:python3_httpd24_ssi
ブラウザでhttp://localhost:8081/cgi.html
へアクセスして確認します。
SSIサンプル(CGI)
CGIの時間(UTC):2017-05-14 08:43:18
JSの時間(JST) :2017-5-14 17:43:18
再度アクセスします。
SSIサンプル(CGI)
CGIの時間(UTC):2017-05-14 08:43:58
JSの時間(JST) :2017-5-14 17:43:58
更新されているようです。
ソースコード全体は以下です。
https://github.com/thinkAmi-sandbox/Docker_Apache-sample/tree/master/alpine_apache_python36_ssi/ssi_shtml_echo_using_xbithack_on
XBitHack fullを使って、CGIを動かす
XBitHackディレクティブの公式ドキュメントを見ると、
注意 他の CGI を #include するかもしれないものや、各アクセスに対して違う出力を生成する (もしくは後のリクエストで変わるかもしれないもの) すべての SSI スクリプトに対してグループ実行ビットが 設定されていないことを確認できない場合は、full は使わない方が良い でしょう。
XBitHack ディレクティブ | mod_include - Apache HTTP サーバ バージョン 2.4
とあったため、試してみます。
httpd.confでXBitHackをfullに修正します。
httpd.conf
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
AllowOverride None
Require all granted
Options Includes
XBitHack full
</Directory>
Dockerコンテナを起動し、ブラウザでhttp://localhost:8081/cgi.html
へアクセスして確認します。
SSIサンプル(CGI)
CGIの時間(UTC):2017-05-14 08:46:52
JSの時間(JST) :2017-5-14 17:46:52
再度アクセスします。
SSIサンプル(CGI)
CGIの時間(UTC):2017-05-14 08:46:52
JSの時間(JST) :2017-5-14 17:47:8
CGIの時間が初回アクセス時と同一のため、キャッシュが使われているようです。
よって、ドキュメントにもある通り、CGIを使う場合にはXBitHack on
の方が良さそうです。
ソースコード全体は以下です。
https://github.com/thinkAmi-sandbox/Docker_Apache-sample/tree/master/alpine_apache_python36_ssi/ssi_html_cgi_using_xbithack_full
CGIを動かす際、includeやexecなどいくつかのパターンを試す
Apacheの公式ドキュメントを読むと、CGIでPythonスクリプトを動かすには、
- include virtual
- exec cgi
- exec cmd
- exec cmd python3
などが使えそうでしたので、試してみます。
基本要素 | mod_include - Apache HTTP サーバ バージョン 2.4
HTMLにはそれぞれの動かし方と、PythonスクリプトでのContent-Type出力の有無のパターンを記載します。
cgi.html
<html>
<head>
<meta charset="UTF-8">
<title>例</title>
</head>
<body>
<h1>SSIサンプル(CGI: XBitHack on)</h1>
<h2>CGIにcontent-typeあり</h2>
<ul>
<li>include virtual: <!--#include virtual="/cgi-bin/with_content_type.py" --></li>
<li>exec cgi: <!--#exec cgi="/cgi-bin/with_content_type.py" --></li>
<li>exec cmd: <!--#exec cmd="/usr/local/apache2/cgi-bin/with_content_type.py" --></li>
<li>exec cmd python3: <!--#exec cmd="python3 /usr/local/apache2/cgi-bin/with_content_type.py" --></li>
</ul>
<h2>CGIにcontent-type無し</h2>
<ul>
<li>include virtual: <!--#include virtual="/cgi-bin/witout_content_type.py" --></li>
<li>exec cgi: <!--#exec cgi="/cgi-bin/witout_content_type.py" --></li>
<li>exec cmd: <!--#exec cmd="/usr/local/apache2/cgi-bin/witout_content_type.py" --></li>
<li>exec cmd python3: <!--#exec cmd="python3 /usr/local/apache2/cgi-bin/witout_content_type.py" --></li>
</ul>
</body>
</html>
Pythonスクリプトでは、Content-Typeを出すものと出さないものを用意します。
with_content_type.py
import datetime
print('Content-Type: text/plain;charset=utf-8')
print('')
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
witout_content_type.py
import datetime
print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
Dockerコンテナを起動し、ブラウザでhttp://localhost:8081/cgi.html
へアクセスして確認します。
CGIにcontent-typeあり
・include virtual: 2017-05-14 09:49:46
・exec cgi: 2017-05-14 09:49:46
・exec cmd: Content-Type: text/plain;charset=utf-8 2017-05-14 09:49:46
・exec cmd python3: Content-Type: text/plain;charset=utf-8 2017-05-14 09:49:46
CGIにcontent-type無し
・include virtual: [an error occurred while processing this directive]
・exec cgi:
・exec cmd: 2017-05-14 09:49:46
・exec cmd python3: 2017-05-14 09:49:47
エラーが発生したり、表示されないものがありました。Dockerのログも見てみます。
[cgid:error] Premature end of script headers: witout_content_type.py
[include:error] unable to include "/cgi-bin/witout_content_type.py" in parsed file /usr/local/apache2/htdocs/cgi.html, subrequest returned 500
[cgid:error] Premature end of script headers: witout_content_type.py
これより、
- Content-Typeが必要なパターン
- include virtual, exec cgi
- Content-Typeは不要なパターン
- exec cmd, exec cmd python3
と分かりました。
ソースコード全体は以下です。
https://github.com/thinkAmi-sandbox/Docker_Apache-sample/tree/master/alpine_apache_python36_ssi/ssi_options_includes_using_xbithack_on
CGIを動かす際、OptionsディレクティブでIncludesNOEXECを使う
今までOptionsディレクティブはIncludes
を指定してきました。
ただ、SSIではIncludesNOEXEC
という指定もできます。
Options ディレクティブ | core - Apache HTTP サーバ バージョン 2.4
ドキュメントによると、include virtual
だけが使えるようですので、試してみます。
httpd.confを修正します。
httpd.conf
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
AllowOverride None
Require all granted
Options IncludesNOEXEC
XBitHack on
</Directory>
Dockerコンテナを起動し、ブラウザでhttp://localhost:8081/cgi.html
へアクセスして確認します。
CGIにcontent-typeあり
・include virtual: 2017-05-14 09:51:38
・exec cgi: [an error occurred while processing this directive]
・exec cmd: [an error occurred while processing this directive]
・exec cmd python3: [an error occurred while processing this directive]
CGIにcontent-type無し
・include virtual: [an error occurred while processing this directive]
・exec cgi: [an error occurred while processing this directive]
・exec cmd: [an error occurred while processing this directive]
・exec cmd python3: [an error occurred while processing this directive]
SSIで動かす時にinclude virtual
以外ではエラーが出ています。
Dockerのログも見ます。
[cgid:error] AH01271: exec used but not allowed in /usr/local/apache2/htdocs/cgi.html
[cgid:error] AH01271: exec used but not allowed in /usr/local/apache2/htdocs/cgi.html
[cgid:error] Premature end of script headers: witout_content_type.py
[include:error] unable to include "/cgi-bin/witout_content_type.py" in parsed file /usr/local/apache2/htdocs/cgi.html, subrequest returned 500
[cgid:error] AH01271: exec used but not allowed in /usr/local/apache2/htdocs/cgi.html
[cgid:error] AH01271: exec used but not allowed in /usr/local/apache2/htdocs/cgi.html
[cgid:error] AH01271: exec used but not allowed in /usr/local/apache2/htdocs/cgi.html
ドキュメント通り、include virtual
だけが正常に動作しました。
ソースコード全体は以下です。
https://github.com/thinkAmi-sandbox/Docker_Apache-sample/tree/master/alpine_apache_python36_ssi/ssi_options_includes_noexec_using_xbithack_on
GitHubに上げました。alpine_apache_python36_ssi
ディレクトリの中が今回のものです。
thinkAmi-sandbox/Docker_Apache-sample