前回、フォームのデータをcgiモジュールを使って受け取りました。
Docker + Alpine3.5 + Apache2.4 + Python3.6で、フォームのデータを標準モジュールcgiで受け取ってみた - メモ的な思考的な
今回は、ApacheのSSI(Server Side Include)を、公式チュートリアルを見ながら試してみます。
Apache チュートリアル: Server Side Includes 入門 - Apache HTTP サーバ バージョン 2.4
目次
- 環境
- AddOutputFilterを使って、shtmlファイルのみSSIを有効にする
- AddOutputFilterを使って、shtml・htmlファイルでSSIを有効にする
- XBitHack onを使って、htmlファイルのみでSSIを有効にする
- XBitHack onを使って、html・shtmlファイルでSSIを有効にする
- XBitHack onを使って、CGIを動かす
- XBitHack fullを使って、CGIを動かす
- CGIを動かす際、includeやexecなどいくつかのパターンを試す
- CGIを動かす際、OptionsディレクティブでIncludesNOEXECを使う
- ソースコード
環境
なお、Dockerfileは前回のものを流用します。
また、コンソールで「Dockerのコンテナを起動する」とした場合は、以下のコマンドを入力しています。
参考:docker container / image コマンド新旧比較 - Qiita
# Docker container runしたのとは別のターミナルで実行 ## Dockerのssiコンテナを停止 $ docker container stop ssi # Docker container runしたターミナルで実行 ## Dockerコンテナを削除 $ docker container rm $(docker container ls -a -q) ## もしくは起動していないDockerコンテナを全削除 $ docker container prune ## 削除したいDockerイメージのIDを知る $ docker image ls REPOSITORY TAG IMAGE ID alpine python3_httpd24_ssi 658225783800 ## Dockerイメージを削除 $ docker image rm 658225783800 ## DockerfileからDockerイメージをビルド $ docker image build -t alpine:python3_httpd24_ssi . ## Dockerコンテナを実行 ### HTMLのみの場合、HTMLのディレクトリのみホストと共有 $ docker container run -p 8081:80 --name ssi -v `pwd`/htdocs/:/usr/local/apache2/htdocs alpine:python3_httpd24_ssi ### HTML & CGIの場合、HTML & 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
AddOutputFilterを使って、shtmlファイルのみSSIを有効にする
まずは、SSIが動くか試してみます。
そのため、
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>例</title> </head> <body> <h1>SSIサンプル(Echo)</h1> <!--#echo var="DATE_LOCAL" --> </body> </html>
を
- echo.html
- echo.shtml
として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のドキュメントによると、
- AddOutputFilterは、2.0以降
- AddHandlerは、1.3まで
とのことなので、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 # shtmlファイルでSSIを使うための設定を追加 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に.htmlを追加 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にする 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 ドキュメントとして扱われます。
との記載がありました。
そのため、AddType
でshtml
を追加すれば、shtmlでも有効になると考えられたため、試してみました。
httpd.conf
# DocumentRoot DocumentRoot "/usr/local/apache2/htdocs" <Directory "/usr/local/apache2/htdocs"> AllowOverride None Require all granted Options Includes # text/htmlに、.shtmlファイルも追加する 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を使うので、alias・cgidモジュールを追加 LoadModule alias_module modules/mod_alias.so LoadModule cgid_module modules/mod_cgid.so # CGIを使うための設定 # alias_module settings ScriptAlias /cgi-bin/ "/usr/local/apache2/cgi-bin/" # CGI directory <Directory "/usr/local/apache2/cgi-bin"> AllowOverride None Options ExecCGI SetHandler cgi-script Require all granted </Directory>
続いて、標準出力に現在時刻を出すCGI用Pythonスクリプトを作成します。
now.py
#!/usr/bin/python3 import datetime # HTTPヘッダ 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
<!DOCTYPE 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>
$ 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 は使わない方が良い でしょう。
とあったため、試してみます。
httpd.confでXBitHackをfullに修正します。
httpd.conf
DocumentRoot "/usr/local/apache2/htdocs" <Directory "/usr/local/apache2/htdocs"> AllowOverride None Require all granted Options Includes # XBitHackを変更 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
<!DOCTYPE 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
#!/usr/bin/python3 import datetime # HTTPヘッダ # SSIで「include virtual」する時はHTTPヘッダが必要 print('Content-Type: text/plain;charset=utf-8') print('') print(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
witout_content_type.py
#!/usr/bin/python3 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 # SSIを使うための設定 # .htmlファイルでSSIを使えるようにするが、 # include virtualのみ有効にする 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