落書き帖  古事記  いろは歌  日 記

ローカルサーバーを作ってシェルスクリプトでcgi

2016年03月25日
本当はこんな事するつもりじゃ無かったのです。
第一、サーバーなんて今まで興味を持つ事さえ無かったのですから…。
ブラウザのMidoriで使える自分用のテキストエディタを作りたかっただけなのです…。
でも何故かMidoriではローカルにファイルが保存出来なかったのです…。
MidoriのjavascriptさんにはBlobオブジェクトもFileオブジェクトもあるのに、Aタグに仕込んで踏んでもダウンロードしないのです…。
Aタグのhref属性に仕込む値にURLエンコードした値を引っ付けて、Aタグを踏んでもダウンロードしないのです…。
さらにその上、表示されるページは真っ白なのです…。
もう、javascriptさんにはお手上げっぽいのです…。

仕方が無いので、javascriptさんに頼らずとも解決できる方法は無いのか?、とネット上で調べてみました。
そこで、知り会ったのがCGIとか言う御方でした…。
そしてその御方と仲良くなる為には、どうやらサーバーを立ち上げないといけないと言う事が分かりました。
暫くはMidoriを使って行こうと思っていた私ですから、ここはCGIさんと仲良くなる事が得策では無いかと考えたのでした…。
でも事は、そう簡単じゃ無かったのです…。
何故なら私は、CGIと言う単語の存在を知ってはおりましたが、その意味までは知ら無かったのですから…。


初めに取り掛かったのは、php5とapache2のコラボでした。
ネット上で調べていて、簡単そうなコードが書いてありましたので、phpは使った事が無いけれども、とりあえずのテストだけなら問題なく終わるであろうと踏んでおりました。

まずは、一度にapacheとphpを入れるよりも、phpだけ入れコマンドラインで軽くテストしてみる事にしました。
ターミナルを開いて…、

sudo apt-get update
sudo apt-get install php5 php5-cli

phpをコマンドラインで使えるように、php5とphp5−cliをインストールしただけなのですが、何故だかオマケでapache2までついてきました…。
きっと寂しかったのでしょう…。

コマンドラインでのphpのテストはすぐに終わり、apacheの起動とそして、ブラウザとサーバー間の通信テストも滞り無く進みました…。
CGIもapacheもphpも初めての事だらけでしたが、このまま何事も無く終わりそうな、そんな予感さえしておりました。

しかし、私は一つだけ大変な不満を持っておりました。
多分もしかすると他の人には分から無いかもしれないであろう、押さえられ無い不満を…。

このままapacheとphpのコラボで事を進めれば、特に何の問題も無かったのかも知れません…。
phpの書き方さえ知ら無いながらも、ローカルへのファイル保存だけなら見様見真似で何とかなりそうな気もします…。
しかし、どうしてもダメなのです…。
phpと言う響きが…。

…今日はこの書き方で最後まで行こうと思ったけど…
…なんか疲れるわ

phpって響きがカッコ悪いんじゃー
なんだよphpって!
何かの頭文字だけとった様な名前つけやがって!
「今からphpでプログラム書こうかな…」とか…
考えただけで、全然気分が乗らんわい!
男ならシェルスクリプトでしょ!
シェルスクリプト!

と言ってもシェルスクリプトもほとんど分から無いんだけどね…。

今回調子に乗ってシェルスクリプトでCGIやってみようって始めたら…、
ドツボにハマりました…。


apacheを介したphp(サーバー側)とjavascript(クライアント側)間の通信テストは簡単に終わりました。
クライアント側からHttpRequestでサーバー側に送信し、サーバー側は受信後簡単な処理を行った後クライアント側に送信し、それをクライント側で受信して終わり、と言う簡単なテストです。

ところが、いざお目当てのシェルスクリプトでテストしてみると、全くうまく行きません。
phpでテストすると、サーバー側の処理内容を受信出来るのですが…、
シェルスクリプトだと、何の処理もせずただシェルスクリプトのテキストを返してくるだけなのです。

この時点で、apacheどころかサーバーのプログラムを動かすのも初めてだったので、どこが悪いのかさっぱり検討もつかない状態でした。
ネット上で調べた設定方法を、手を替え品を替え試して見るんですが、シェルスクリプトのテキストがそのまま返ってくるか、エラーが出るかどちらかです。
結局最後に分かったのは、シェルスクリプトの書き方が悪かっただけって事だったんですが、この時点では本当何が悪いのか、蜘蛛の巣を掴むようなもんでした。

何度か試している内に、apacheの設定ファイル辺りが煩雑になりそうだったんで、apacheもphpもどちらも一度アンインストールし、仕切り直しする事に…。

sudo apt-get remove apache2 php5 php5-cli
sudo apt-get autoremove

で、大体こんな事やっても設定ファイルや何やかんや思いっきり残ったりしてます。
で、絶対オススメ出来ないんですが…、
おいらは、この設定ファイルとか良く分から無い何やかんやがいっぱい残るのが嫌なので…、

locate apache2 | xargs sudo rm -r
locate php5 | xargs sudo rm -r
locate php5-cli | xargs sudo rm -r

とかやっちゃう訳なんです。
えーもう、該当する物は綺麗に無くなっちゃいますよ…、重要そうな物まで…。
おかげで今回、より深みにハマりました…。
でもその深みがオイラには楽しいんですが…。

綺麗さっぱり、apacheとphpのファイルを消した後、再びインストールし直すと…何か変…。
apacheが全く起動しなくなりました…。
そして起動しようとすると次のようなエラーが該当ファイルのライン番号と共に出ます。

Invalid command 'Require', perhaps misspelled or defined by a module not included in the server configuration

で、書いてある事は良く分から無いながら、該当ファイルのライン番号のある該当箇所をたどり、そこをコメントアウト…。
そしてapacheを再起動しようとすると、また同じエラーで今度は違うライン番号が…、
そのライン番号をまたたどり、コメントアウト…。
するとまた同じ繰り返しが…。

そして漸く、「そうだエラーの内容で検索したら答えが出るかも」と気付き…、
googleさんに聞いてみたら…、
「LINUXなら authz_host ってモジュールをロードしたら良いよ」みたいな事が書いてあるっぽい、のを発見…。
で、試してみる…。

sudo a2enmod authz_host

…おぉぉ!エラー出なくなった

でも、いざサーバーにリクエストを出しても全く繋がらない…。
この頃になって漸く、/etc/apache2/modes-enabled 配下のファイルが、初回にインストールした時より少なくなっている事に気付いた。
そう、多分 locate apache2 | xargs sudo rm -r が何か大事な物まで消しちゃったんだよね…。
それから、もっと後で気付いたんだけど…、
locate apache2 | xargs sudo rm -r をやっちゃうと、mods-enabled どころか conf-enabled sites-enabled の設定もインストールの時にされなくなってた。
どのファイルが原因なのか探して見たかったけど、ちょっと良く分から無い。

で、このままではまだまだモジュールが足りない状態。
そこで、別のOS(と言ってもそれもdebian)を立ち上げ、apache2だけをインストールしてロードされてるモジュールを調べてみた。

access_compat alias auth_basic authn_core authn_file authz_core authz_host authz_user autoindex deflate dir env filter mime mpm_event negotiation setenvif status

多分こんな感じ↑だったと思う…。
mpm_event の所が若干自信ない…、mpm_worker だったかも…。
その後、php5をインストールすると mpm_event が mpm_fork に入れ替わったんかな。
繋がらない原因は何なのか?とか思いながら、上のモジュールを1つずつ入れながらテストしてみたけど、結局全部必要だったみたい、最後の一個入れてやっと繋がった…。


apacheが復旧し、漸くCGIのテストに戻れたんだけど…、
その後も、延々とシェルスクリプトが動作しない。
色んなページを参考にしながら、設定を書いて行きながら、良く分から無いながらも、何となく雰囲気もつかめてくると、自分が書いてる設定がまるで間違っている物では無い様な気がしてきた。
でもそれでも、シェルスクリプトは動作しない。
シェルスクリプト自体のテキストを返すか、設定によってエラーを返すかだ。
設定を変えながら変わっていくエラー番号が、ゴールへの道標のようだった。

それから、テストの方法も途中で変わった。
最初は、ブラウザに自作のエディタを表示し、そこからjavascriptの命令をだしていたのだが…、
ネット上で色々調べている内に、もっと良い方法がある事を教わった。
ブラウザがなくても、コマンドラインからテストできるのねん。

curl http://localhost/cgi-bin/test.cgi

こんな感じ。
curl ってただのダウンロードコマンドだと思ってたらこんな所で使えるのね。
いつも wget 使ってたから、今まで見向きもしなかったよ…。

そしてこの curl と関係してくるけど…、
サーバー作るのって本当分かり難いよね。
特にオイラみたいに何の前知識も無いとさ、物凄い混乱する箇所があると思うんだよね…。
どう言う事かと言うと…、

/var/www/html/ をルートにローカルサーバーを立ち上げたとする。
そして同じ /var/www/html/ の配下にhtmlとjavascriptで作った、test.html って言うファイルがあったとする。

/var/www/html/test.html

こんな感じね。
このファイルをブラウザで開く開き方次第で、/var/www/html/ のサーバーとHttpRequestで通信出来るかどうかが変わってくるんだ。

…本当信じらんない

http://localhost/test.html でブラウザからファイルを開くと、そのページから /var/www/html/ のサーバーとHttpRequestを使ってやり取り出来るんだけど…、
file:///var/www/html/test.html でブラウザからファイルを開くと、そのページから /var/www/html/ のサーバーとHttpRequestを使ったやり取りが出来ないんだぜ…。
(Midoriとiceweaselでテスト。他は知らね。)
同一オリジンが何たらかんたらって言う事と、もしかしたら関係あるのかな?、何て一瞬思ったけど…、
(同一オリジンが何たらかんたらはよく理解してない…)
curl コマンドならHttpRequestでやり取り出来るんだぜ…。
ディレクトリの違う curl君には返事してるんだ…。

…もうわけわかんね



何時まで経っても何をやってもシェルスクリプトは動作せず、八方塞がりになってたところ、最後に辿り着いたのが下の記事↓。

bashでCGI (2) CGIのおまじない

…本当助かりました。

「レスポンスは、メッセージヘッダーとメッセージボディで構成されて、空行(blank line)で区切る。」
なんだそうです。
しかも、メッセージは無くても良いけど、ヘッダーは絶対いるんだって。
おいらが、ここまでのテストで使ってたのは↓こんな感じ。

#!/bin/sh
echo "poti"

これだと…、
500 Internal Server Error
なんてエラーが出る。
空行で区切るどころか、ヘッダーさえ書いてなかった…。
いや、echo "poti" がヘッダーだと思われてたみたい…。
そう言えばapacheのエラーログには、ずっとヘッダーがどうだとかこうだとかが出てた…。
↓がapacheの error.log

malformed header from script 'poti.cgi': Bad header

↓こんな感じで書いてたらよかったのねん。

#!/bin/sh
echo "Content-type:text/plain"
echo
echo "tama"

やっと開放されたよ。