OSX
vagrant

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

…とか。


以上です。