僕の Apache 初入門(VirtualHost)

超簡単な例で。

http://my-node.com/http://other-node.com で同一の IP である 192.168.33.13 に接続して、別のページを出すだけのお仕事。

/etc/httpd
  /conf
    + httpd.conf
  /conf.d
    + 01-my-node.conf
    + 02-other-node.conf

上記のように httpd.conf に全部かくのではなくて、conf.d の下に書き分けるようにする。

httpd.conf

以下を足す。(conf.d 下に、これだけ書いたファイルを足してもいいかもしれん)

NameVirtualHost *:80

01-my-node.conf

<VirtualHost *:80>
  DocumentRoot /var/www/html/my_node
  ServerName my-node.com
</VirtualHost>

02-other-node.conf

<VirtualHost *:80>
  DocumentRoot /var/www/html/other_node
  ServerName other-node.com
</VirtualHost>

各ノードの HTML 配置

/var/www/html
  /my-node
    + index.html
  /other-node
    + index.html

それぞれの index.html にノード名を書いておく

再起動

$ sudo service httpd restart
Stopping httpd:                                            [OK]
Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
                                                           [  OK  ]

動作確認

ローカルの hosts を書き換え

当方は Mac 環境となります。

sudo vim /private/etc/hosts を開いて以下を足す。

192.168.33.13 my-node.com
192.168.33.13 other-node.com

ブラウザから接続してみます

できた!

ログの場所も変えてみる

<VirtualHost *:80>
  DocumentRoot /var/www/html/my_node
  ServerName my-node.com
  CustomLog logs/my_node_log common
  ErrorLog logs/my_node_error_log
</VirtualHost>

お決まりの再起動をかけると、my-node.com へのアクセスのログが /etc/httpd/logs/my_node_log にログが出るようになりました。

パーミッションの事がよく分からなかった。

僕の Apache 初入門(インストール)

おそらく初めて仕事をした時に JavaStruts のアプリを書いていたころから最終的には Apache/Tomcat で動いていたんだろうけど、(少しは調べたりしてたんだろうけど)、今までろくに勉強してこなかった Apache を今更入門することにした。(というか去年まで IIS の子だったというのもあるが)

環境

CentOS 6 (Vagrant で稼働させてる)

インストールなど

$ sudo yum -y install httpd
...
Complete!
$ sudo service httpd start
Starting httpd: httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
                                                           [  OK  ]

なんかいきなり怒られてる。以下に対処方法が書いてあった、が一端放置。

$ sudo chkconfig httpd on
$ sudo chkconfig --list httpd
httpd           0:off   1:off   2:on    3:on    4:on    5:on    6:off

お決まりの自動起動を ON にする。0 から 6 の数値はランレベルと呼ばれているもので、3 が通常起動を表すらしい。よって、3 が on になっているので問題無い。

$ ps ax | grep httpd
 2405 ?        Ss     0:00 /usr/sbin/httpd
 2407 ?        S      0:00 /usr/sbin/httpd
 2408 ?        S      0:00 /usr/sbin/httpd
 2409 ?        S      0:00 /usr/sbin/httpd
 2410 ?        S      0:00 /usr/sbin/httpd
 2411 ?        S      0:00 /usr/sbin/httpd
 2412 ?        S      0:00 /usr/sbin/httpd
 2413 ?        S      0:00 /usr/sbin/httpd
 2414 ?        S      0:00 /usr/sbin/httpd
 2429 pts/0    S+     0:00 grep httpd

httpd のプロセスが動作してるのが分かる。 ps のオプションの a は「全てのプロセス」、x は「他の端末に結び付けられているプロセスも表示」らしい。

待ち受けポートを調べる

lsof が無いのでいれる。

$ which lsof
/usr/bin/which: no lsof in (/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/vagrant/bin)
$ sudo yum -y install lsof
....
Complete!

関係ないが、lsof を入れる時にたまたまあたったサイトで以下があったが、pgrep で取得して /proc 内を探すの意味がさっぱり分からなかったが、調べてると /proc というディレクトリがあって、確かにそこにはプロセス毎のファイルやディレクトリがあってビックリ。
- lsofの使い方 - プロセスが使用中のファイルを調べる - うまいぼうblog
- /procによるLinuxチューニング [前編]- @IT

$ sudo lsof -i -n -P | grep httpd
httpd     2405    root    4u  IPv6  14312      0t0  TCP *:80 (LISTEN)
httpd     2407  apache    4u  IPv6  14312      0t0  TCP *:80 (LISTEN)
httpd     2408  apache    4u  IPv6  14312      0t0  TCP *:80 (LISTEN)
httpd     2409  apache    4u  IPv6  14312      0t0  TCP *:80 (LISTEN)
httpd     2410  apache    4u  IPv6  14312      0t0  TCP *:80 (LISTEN)
httpd     2411  apache    4u  IPv6  14312      0t0  TCP *:80 (LISTEN)
httpd     2412  apache    4u  IPv6  14312      0t0  TCP *:80 (LISTEN)
httpd     2413  apache    4u  IPv6  14312      0t0  TCP *:80 (LISTEN)
httpd     2414  apache    4u  IPv6  14312      0t0  TCP *:80 (LISTEN)

確かに 80 で待ち受けていることが分かる。

IPv6 のみの待受にみえるが、実際は IPv4 互換であるらしい。 現状 ssh の 443 で待ち受けていないのは、その設定をしていないから。

iptables の設定

正直何度見てもよく分からない。AWS の INBOUND, OUTBOUND が INPUT, OUTPUT みたいなものだろうか。

とりあえずここまでやると、403 ページまでは見れるようになる。(今回は http://192.168.33.13/)

telnet でおしゃべり

% telnet 192.168.33.13 80
Trying 192.168.33.13...
Connected to 192.168.33.13.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.1 403 Forbidden
Date: Mon, 10 Nov 2014 06:00:28 GMT
Server: Apache/2.2.15 (CentOS)
Accept-Ranges: bytes
Content-Length: 4954
Connection: close
Content-Type: text/html; charset=UTF-8

しゃべれた!

ついでに curl

% curl http://192.168.33.13/
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <head>
...

% curl -I http://192.168.33.13/
HTTP/1.1 403 Forbidden
Date: Mon, 10 Nov 2014 10:46:28 GMT
Server: Apache/2.2.15 (CentOS)
Accept-Ranges: bytes
Content-Length: 4954
Connection: close
Content-Type: text/html; charset=UTF-8

Ruby の next, break でよく分かってなかったこと

繰り返し (for とか while とか)や case とかで使うためだけかと思ってた。C#continue, break と同じイメージ。

ブロック内での挙動

よく考えると、each とかでも渡したブロック内で next って書くことあったけど、なんで使えるか分かってなかった。

def display_method
  puts yield

  puts 'after yield'
end

display_method do
  123
end

# 実行結果
123
=> nil

display_method do
  next 10

  123
end

# 実行結果
10
=> nil

display_method do
  break 10

  123
end

# 実行結果
=> 10

ブロック内での next は呼び出し元(ここでは yield)に処理を戻す事ができる。よって、puts に戻り値が渡っている。

ブロック内での break は呼び出しているメソッド自体の処理を中断する。よって、puts に戻り値は渡らないが、変わりにメソッドの戻り値になる。

なので each を考えた時も、nexteach に渡されたブロックの処理を each に戻すだけなので、次の要素のブロック実行に移るだけだが、breakeach そのものを中断する。

たぶん用途は無いが、map のように戻り値を使うような場合だと以下のような事もできるみたい。

%w(a b c).map {|i|
  break '$' if i == 'b'
  i + '@'
}

# 実行結果
=> "$"

実はそもそも next が戻り値をもたせられる事を知らなかったのですよね。。

ゆるふわ.rb に参加してきた

f:id:dany1468:20140802140754j:plain

いきなり名前間違えてるあたりが素敵です。(初回からこうらしい)

イベント概要

ゆるふわ.rb in 大洲 〜魚のさばき方勉強会やります〜 - Doorkeeper

特に説明いりませんね、ガチで魚を捌いて、ガチで魚を食べて酒を飲む会でした!

Ruby 成分無しが宣言されてる事をいいことに、Ruby イベントに夫婦参戦(嫁は Web デザイナです)してきました。キッチンで酒飲むなんていつもやってる!

遅れて到着したのですが、到着早々に朝水揚げされたばかりの鯵を一人一匹渡され、当日に誕生した経験 2 時間の先生に導かれながら、なかなかまともに三枚おろしが完成、そのままビールを注がれて飲み始めました。

見てください、主催者様自ら捌いた鯛も並んで、とにかく美味しかったです!!

f:id:dany1468:20140802144321j:plain

主催者の ogino さんのブログでさらに詳しくレポートされております。(捌き方も詳しく解説されております!)

そしてなぜか懇親会の居酒屋でも鯵の刺し身を注文し、自分たちとの diff を取って「プリプリ感は負けたが味は勝った」という素材勝負の発言をした結果、「鯵は骨の唐揚げが旨い」という結論に達しましたw

f:id:dany1468:20140802181646j:plain

感じたこと

元々は Agile Japan の神山サテライトに愛媛 Agile459 の方々を中心に神山に来てくださったのが縁の始まりでした。その時にお会いしたことがある方もいらっしゃいましたし、それ以外にも愛媛で IT の仕事に従事されている方と会うことができました。

同じように東京の会社のリモートワークを愛媛でやっておられる方もおり、いろいろとお話できて有意義な時間でした。

半農エンジニア

半農というと大げさですが、ちょっと大きめの家庭菜園をしている自分と似たようなエンジニアさんに出会えました。家庭菜園あるある(例: 雨の後の野菜の成長半端ないなど)で一緒に笑う事ができて、東京のエンジニアと話すのとは全く違う刺激があってホント面白かったですw

その中でも、ハック可能なデバイスで家庭菜園のルーチンをちょっと自動化できたらいいねーとかエンジニアぽいトークもできて、ちょうど考えていたことだったのですごく盛り上がれました。

他にも

懇親会の帰りにホテルまで送っていただいたのですが(ホントに感謝です><)、その車内でも愛媛のコミュニティの現状などお話を聞けてまた徳島に帰って何かできるかなと考えたりしました。なにより ゆるふわ.rb のゆるふわの突き抜け感は地方コミュニティの一種のモデルケースなのではと強く感じました。(まじめに)

最後に

外の看板は何回目かで、ちゃんと正式名に直したそうです!

f:id:dany1468:20140802140414j:plain

今回は台風の影響で四国は大雨で、愛媛から徳島に帰れなかったというアクシデントもありましたが、また次回も行きたいでーす。

Mobile Safari で戻るボタンを使えなくする (iOS 7)

戻るボタン対応

これ自体はいろんな 対応方法 があると思うのですが、今回は 戻らせない を目的としています。(戻っても大丈夫とか、戻るボタンを効かなくするとかではありません)

PC や Android Chrome の場合

よくある対応として以下のようなものがありますね。PC 、Android 4.1.2 Chrome ではこの対応である程度要件を満たす事ができました。

<script type="text/javascript">
  window.onunload = function() {};
  history.forward();
</script>

参考

Mobile Safari の場合

Mobile Safari に限った話しではないかもしれませんが、上記の対応では普通に戻れてしまいます。Webインスペクト機能でデバッグしてみると、どうもキャッシュ画面が使われてしまっています。onunload の対応もしているのに何故?というところなのですが、どうやら back forward cache が効いているようです。

以降では、上記の中から今回対応した内容を中心に記述します。上記はあくまで調査過程の参考リンクということで。

onpageshow イベントでの実装

back forward cache に対する対策として、よく使われているのが onpageshow イベント時にリロードするというものでした。

window.onpageshow = function(event) {
  if (event.persisted) {
    window.location.reload();
  }
};

event.persisted が重要で、これが true になった場合には、キャッシュが使われたページという事になります。この対応では、キャッシュされたページでは onload などのイベントが発火しないので、リロードすることでそれを回避しています。

つまり以下のようにすると、戻らせない対応を可能のように思えます。

window.onpageshow = function() {
  history.forward();
};

onpageshow の課題

onpageshow一度しか発火しない 事が分かりました。よって、一度は戻れない事が実現できても、さらにもう一度「戻るボタン」を押されると戻れてしまいます。

一度というのは、キャッシュされたページに対してという事であり、リロードしていれば大丈夫です。よって、以下のようにすると大丈夫なように思えます。

window.onpageshow = function(event) {
  if (event.persisted) {
    window.location.reload();
  }
};
history.forward();

ある程度は上手くいきますが、この対応の問題点は「リロードできないページがある場合にエラーとなる」事です。Rails のルーティング設定で GET を受け付けないようになっている URL をリロードした場合を想像してもらうと良いかもしれません。

popState イベントでの対応

onpageshow は一度しか発火しない、ではキャッシュされたページであっても必ず発火するイベントがあればいいわけです。

History API が実装されたブラウザであれば popState イベントが利用できます。popState は履歴の変化があった場合に発火されるため、キャッシュされたページでも大丈夫なようです。

window.onpopstate = function() {
  history.forward();
};

この対応は onpageshow と違いリロードの問題も起きないため比較的安定します。

ただ、戻る連打すると変になることがあり、やはりネットワーク環境も、そもそも性能も低いモバイル環境で history.forward での戻るボタン制御は難しいのかなと。

pushState で開いたページと同じ URL を積む

window.onpopstate = function() {
  history.pushState(); // 引数無しだと state 無しで、開いているページの URL が履歴に積まれる
};

以下に履歴がどうなっているかのイメージを書いてみました。(これでいいのか。。)

ページA [A]
onpopstate [A, A]
↓
(ページBに遷移)
↓
ページB [A, A, B]
onpopstate [A, A, B, B]
↓
(戻る) => 履歴が積まれているため戻るのは [A, A, *B, B] の * の部分。よって同じページ。
↓
ページB [A, A, B]
onpopstate [A, A, B, B]

ちょっとトリック的なのですが、戻るボタン連打にも耐えてくれたため、そこそこ良い対応方法なのではと思います。

問題点

Mobile Safari には過去の履歴に飛べる機能があるため、それを実行されるとどうにもなりません。そこが history.forward 対応との違いですね。history.forward の場合は、強制的に元のページまで遷移させてくれるので。

まとめ

今回の要件的に最終的には popState イベント時に同じURLを積むという対応を採用しました。記載したようなリスクもありますが、そこを許容すれば良いバランスではなかったかと。

逆に、戻った画面で操作できる事を目的にするのであれば、onpageshowevent.persisted == true 時にリロードするが良い対応なのかなと思いました。

onpageshow と popstate の書き方が最後まで統一できてないな。。。どうして片方だけ on が付いたし。。

Chrome Extension を更新した (GMail Address Checker)

GMail Address Checker

GMail Address Checker - Chrome ウェブストア

特定のドメインを利用する企業利用を想定したツールです。(というか、もともとは社内で利用してもらおうと作ったもの) 予めドメインを登録しておくと、GMail の宛先に指定されたメールアドレスの中にそのドメイン以外のものがあると宛先欄の背景を警告色に変更するというものです。

f:id:dany1468:20140303233415p:plain

変更点

リポジトリ公開してるので以下の diff をどうぞ。なんというか変わり過ぎで見れないですが。。

https://bitbucket.org/dany1468/gmail_address_checker/branches/compare/v0.3..v0.1

Manifest のバージョンアップ

最初に作ったのが 2 年前だったので、まず manifest.json がまともに動かず。。以下参考にしつつ解決しました。 JavaScript の外部ファイル化が主でした。

GMail の新インターフェースへの対応

新と言っても変わってから一年ぐらい経つんじゃないかという所ですが、GMail の宛先の表示方法が最初の Extension 作成当初とは変わっておりそれに追随させました。

何しろ GMail の class や id の命名は推測しにくいため、どうやって背景を警告色に変更するかは悩みました。。結局かなり妥協した実装になってしまっております。

ちょこちょこリファクタ

2 年前とはいえ、いろいろ酷い状態だったので少しだけマシになった、、、ような。。

実は更新失敗

更新用の秘密鍵を消失しており、一度 Chrome ウェブストアから削除して上げ直しました。まあ、一年ぐらい使えてなかったので継続して利用してくださっていた方は居ないと思いますが、ちょっと残念。

更新したきっかけ

昨年の後半に bitbucket から fork された事をメールで通知され、fork された方のリポジトリを見ると修正を試みてくださっており、当時は忙しく修正する気になれなかったのですが、ようやく修正できました。

http://hiro99ma.blogspot.com/2013/11/gmail-address-checker.html

ブログにも書いてくださっており感謝です。(そして、分かりにくいコードでホントごめんなさいでした><)

同じようなツール

当時は調べなかったのですが、今見ると結構ありますね。なんというか、このツールは本来削除がが適当だったのではないかと思うほどに。。

これとか同じ名前のツールですが、結構良さそうなので使ってみようかと思います。 https://chrome.google.com/webstore/detail/gmail-address-checker/fodmjhcedhancmmfclhjjdfofnahppnd

GitHub の issue に画面キャプチャを貼り付ける (Skitch を使って)

GitHub の issue にできるだけ早く画像を貼り付けたいというのが動機です。

Windows 環境で Redmine 使ってた時は ChromeAwesome Screenshot でキャプチャした画像をクリップボードに保存し、それを Redmineクリップボードから画像添付するプラグイン (名前忘れた。。) 使うとかなりスムーズに添付できました。

Mac 版だと Awesome Screenshotクリップボードに添付できないんですよね。

Skitch 初めて使ってみた

評判いいのは聞いてたのですが使ったことないので、この機に使ってみようかなと。

画面キャプチャからいろいろできて便利ですねー(小並感

GitHub の issue に貼り付ける方法

クリップボード連携でもできるかなーと思ったのですが、それよりもっと簡単でした。

Skitch 最下部のつまみをドラッグして、GitHub の issue の画面にドロップするだけで OK 。これは便利!

解像度が高すぎると感じたら

Skitch の 拡大・切り取り から縮小できるので、そこで調整すると良いかなと。