Edited at

OSX における Vagrant 80番ポートフォワーディング

More than 3 years have passed since last update.


何がしたいか

OSX 内の Vagrant で動かしてる VM 上で Web サーバーを立てて開発などを行っており、ホストのブラウザから http://localhost/ といった標準80番ポートで確認したいという話。

素直に Vagrantfile 内で


Vagrantfile

config.vm.network "forwarded_port", guest: 80, host: 80


などと書いても、 Windows なら警告つきで起動できますが OSX や Linux の場合は起動できません。

1024以下のポートは各種プロトコルで使用されていることが多いためです。

==> default: You are trying to forward to privileged ports (ports <= 1024). Most

==> default: operating systems restrict this to only privileged process (typically
==> default: processes running as an administrative user). This is a warning in case
==> default: the port forwarding doesn't work. If any problems occur, please try a
==> default: port higher than 1024.

「おいおいそんなポート設定しても知らんぞ。

 何か問題が起きたら1024より大きいポートにしなはれ」

おっしゃるとおりすぎる。


解決方法



  • vagrant-triggers を導入。 OSX のターミナルで vagrant plugin install vagrant-triggers

  • ホストの10080 -> ゲストの80にフォワーディングしておく

  • Vagrantfile の中で pf を呼んでホスト側で80 -> 10080にフィルタリングされるようにする(下記参照)

# ホスト10080 -> ゲスト80

config.vm.network "forwarded_port", guest: 80, host: 10080

# up, reload 時に PF 設定
config.trigger.after [:provision, :up, :reload] do
system('echo "rdr pass on lo0 inet proto tcp from any to 127.0.0.1 port 80 -> 127.0.0.1 port 10080" | sudo pfctl -ef - > /dev/null 2>&1')
system('echo "set packet filter 127.0.0.1:80 -> 127.0.0.1:10080"')
end

# halt, destroy 時に PF をリセット
config.trigger.after [:halt, :destroy] do
system("sudo pfctl -df /etc/pf.conf > /dev/null 2>&1")
system('echo "reset packet filter"')
end

これで、ホスト OSX のブラウザで http://localhost にアクセスすると http://localhost:10080 にアクセスしたことになり、最終的にホスト10080 -> ゲスト80にたどり着きます。

Linux 系でも ipfw や pf を有効にしてれば、同じアプローチでトリガーから呼んでやればできると思います。



おまけ : Vagrantfile の複数 OS 対応

Vagrantfile は Ruby で書くので


Vagrantfile

$is_windows = RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin/i

$is_osx = RbConfig::CONFIG['host_os'] =~ /darwin/i

if $is_windows then
# Win 用の記述
end

if $is_osx then
# OSX 用の記述
end


…とかできます。

例えばチーム内で Win ユーザーと Mac ユーザーが混在しているなら、


Vagrantfile

# Win は普通に80でマッピングし、 OSX は PF を通す。

if $is_windows then
config.vm.network "forwarded_port", guest: 80, host: 80
else
config.vm.network "forwarded_port", guest: 80, host: 10080

config.trigger.after [:provision, :up, :reload] do
system('echo "rdr pass on lo0 inet proto tcp from any to 127.0.0.1 port 80 -> 127.0.0.1 port 10080" | sudo pfctl -ef - > /dev/null 2>&1')
system('echo "set packet filter 127.0.0.1:80 -> 127.0.0.1:10080"')
end

config.trigger.after [:halt, :destroy] do
system("sudo pfctl -df /etc/pf.conf > /dev/null 2>&1")
system('echo "reset packet filter"')
end
end


…とか。


以上です。