Mac上のVagrantで立ち上げた仮想環境の上で建てたWebサーバーに実機のiPhoneのブラウザからアクセスしてフロントエンドをデバッグする

この記事は、[岩手県立大学 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/ipu)の17日目の記事です。
タイトルが冗長の割に難しいことはしていません。Web開発のフロントエンド部分のデバッグが少し楽になるTipsをご紹介します。

# はじめに

Web開発をやっていく上で、スマートフォンからのアクセスを想定して画面を作っていくことは、よくあることだと思います。そうすると、開発中にスマートフォンから閲覧したときにどのように見えるか、目的を達成するための動作に問題ないかを確認していく必要が出てきます。

自分は[Vagrant](https://www.vagrantup.com/)と[Ansible](https://www.ansible.com/)を組み合わせて仮想環境の[VirtualBox](https://www.virtualbox.org/)（CentOS）を立ち上げて、その上にRuby on Railsの開発環境を構築して、開発をやっていくことが多いのですが、このRailsで開発中のアプリに実機のiPhoneやAndroid端末でアクセスしてデバッグがしたいことがよくあります。

また、今回はWebアプリの開発環境が仮想環境上に乗っかっている状況での説明ですが、そうでない場合はVagrantの設定部分などを飛ばして読んで頂けると良いかと思います。

# 実機からアクセスしたい理由

というのも、PC版Safariのレスポンシブモードを使ってアクセスした際の表示と、実機のiOS版Safariでアクセスした表示が微妙に違っているときがあるためです。ステージング環境に追加機能をデプロイした後で実機でアクセスしたときにはじめて「アイコンの位置が微妙にズレてる・・・」「JSで実装したフロント部分が動かない・・・」というようなフロントエンド部分の差異に気づくことがあります。

たとえば、以下は最近実際にあった「お気に入りボタンのアイコンが実機だと右にズレている」例です。（こういう類の差異は、CSS力が足りなく、厳密にCSSを定義していないために起きていることがほとんどです:sob:）

|![差異のある事例.png](https://qiita-image-store.s3.amazonaws.com/0/66682/4e61d0ba-8639-beec-4f28-2a3136a9d1b6.png)|
|:---:|
|図：差異がある例|

このように、ステージング環境にデプロイしてから、[Webインスペクタ](https://qiita.com/gctoyo/items/8b3b6a5b9816e69f97bd)機能を使って問題がないか確認しつつ、問題があればローカルに戻って修正し、再びデプロイする・・・という一連の作業は、CI環境が整っていたとしても結構手間になります。（一時期、そうやっていました:scream:）

そんなこともあり、開発環境の段階からモバイル端末の実機からフロントエンドをデバッグできればいいのに、と思いました。調べると色々方法がありますが、今回はその一つをご紹介します。


# 実機でデバッグする方法

ここからは、順を追ってアクセスする手順を説明していきます。
簡単にまとめると以下のような流れになります。

1. Vagrantfileで`private_network`を設定
1. `vagrant up`して、Railsアプリのサーバーを立ち上げる
1. Webデバッグプロキシ Charlesを導入
1. Charlesを起動して`Proxy Settings`を行う
1. Macに割り当てられたIPアドレスの確認
1. iPhone／Android側のWi-Fi設定（HTTPプロキシ）
1. 実機のSafariまたはChromeでアクセスしてみる
1. Mac側で各Webインスペクタで検証作業

手数が多いですが、初期設定ができれば2回目以降は時間はかかりません。

### 前提条件

次の前提の上で説明していきます。

- 既にVagrantで立ち上げた仮想環境の上で動くRailsアプリにプライベートアドレスでアクセスできる
- デバッグで用いるiPhone/Android端末とMac（OSX）が同一のWi-Fiに接続している

### 動作を確認している環境

今回動作を確認している環境の各種バージョンは以下です。

- ホスト側
  - macOS Sierra 10.12.6
  - Vagrant 1.9.5
  - VirtualBox 5.1.18
  - Charles 4.2.1
- クライアント（実機）
  - iOS 11.2 - Safari 11.0 Mobile
  - Android 7.0 - Chrome 63.0.3239

## 1. Vagrantfileで`private_network`を設定

検証したいWebアプリが載っているVagrantの設定ファイルを以下のように設定します。
`vagrant init`した際のデフォルトで`private_network`が既に設定されているかと思います。ない場合は以下のように追加します。今回は`192.168.33.10`に割り当て、諸事情でポート番号も`3000`で指定しています。

こうすることで`localhost:3000`ではなく、`192.168.33.10:3000`でサーバーにアクセスが可能になります。

```:Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.box = 'centos7'

  # 以下の :private_network 設定を追加
  config.vm.network :private_network, ip: "192.168.33.10"
  config.vm.network 'forwarded_port', guest: 3000, host: 3000

  config.vm.synced_folder './', '/your_app_path'

  config.vm.provider 'virtualbox' do |vb|
    vb.memory = '1024'
  end

  config.vm.provision :ansible do |ansible|
    ansible.playbook = 'provision/playbook.yml'
  end
end
```

## 2. `vagrant up`して、Railsアプリのサーバーを立ち上げる

Vagrantが既に立ち上がっている場合は`vagrant reload`、まだ立ち上がっていない場合は`vagrant up`します。

```:bash
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 3000 (guest) => 3000 (host) (adapter 1)
    default: 22 (guest) => 2222 (host) (adapter 1)
...

==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.
$
```

立ち上がったようなので、SSH接続して、Railsアプリのサーバーを立ち上げます。

```:bash
$ vagrant ssh
Last login: Thu Dec 14 12:47:08 2017 from 10.0.2.2
Welcome to your Vagrant-built virtual machine.

[vagrant@localhost ~]$ cd /vagrant
[vagrant@localhost vagrant]$ ls
Gemfile  Gemfile.lock  README.md  Rakefile  Vagrantfile  app  bin  config  config.ru  db  lib  log  package.json  provision  public  spec  tmp  vendor

[vagrant@localhost vagrant]$ rails s -b 0.0.0.0
=> Booting Puma
=> Rails 5.1.4 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.10.0 (ruby 2.4.1-p111), codename: Russell's Teapot
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
```


この時点で、ゲスト側（vagrant上ではなくMacのターミナル等）からcurlで`http://192.168.33.20:3000/`にアクセスできることを確認します。

```:bash
$ curl -LI http://192.168.33.10:3000/ -o /dev/null -w '%{http_code}\n' -s
200
```

ゲストからホストに立てたサーバーにアクセスできることが確認できました。


## 3. Webデバッグプロキシ Charlesを導入

Charlesは、通信系のデバッグに便利に使えるものでHTTPプロキシを立てることで端末の通信をキャプチャを可能とし、WebAPI等のやりとりのパケット情報（リクエストやレスポンス）を覗いたり、任意に変更することができるものです。

以下からCharlesを導入します。
[Download a Free Trial of Charles • Charles Web Debugging Proxy](https://www.charlesproxy.com/latest-release/download.do)

インストールは特に変わった点はありません。
Free Trial版は30分までの利用で、それ以降は再起動する必要があります。有料版を購入すれば、不自由なく使用できます。

## 4. Charlesを起動して`Proxy Settings`を行う

初回起動時は、以下のように「自動的にプロキシ設定をするために権限を与えるか」という旨のダイアログが出ますが、特段の理由がない限り`Grant Privileges`を選択します。

<img width="780" alt="charles.png" src="https://qiita-image-store.s3.amazonaws.com/0/66682/23543620-468d-21c1-d152-63ffcbe2b8f7.png">



起動が完了したら、メニューの`Proxy -> Proxy Settings` を選択します。


<img width="631" alt="charles画面" src="https://qiita-image-store.s3.amazonaws.com/0/66682/3dbe5132-3900-82b0-1ff5-d073b47358d3.png">

ここでは、HTTP Proxyのポート番号を指定できます。デフォルトで`8888`に設定されていますが、他のポートと競合しないように[1024〜65535](https://ja.wikipedia.org/wiki/%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7)の範囲で指定することもできます。今回は、デフォルトのまま進めます。

<img width="598" alt="プロキシ設定" src="https://qiita-image-store.s3.amazonaws.com/0/66682/102db5b8-8d7e-fe06-03d4-559e466de85b.png">




## 5. Wi-Fiに接続中のMacに割り当てられたIPアドレスの確認

Macのシステム環境設定を開き、`ネットワーク`を選択します。
左のメニューで`Wi-Fi`を選択されている状態を確認し、IPアドレスを控えます。

![IPアドレス確認.png](https://qiita-image-store.s3.amazonaws.com/0/66682/0e903910-6ed6-edd4-ccc2-a350f41362a3.png)

今回の場合は、`192.168.55.1`となります。


## 6. iPhone／Android側のWi-Fi設定（HTTPプロキシ）

### iPhone（iOS）の設定方法

Wi-Fiの設定画面からMacと同一のWi-Fiに接続します。

![iPhoneのWifi設定.png](https://qiita-image-store.s3.amazonaws.com/0/66682/f5d5f755-6874-a3a5-e32d-e05a6b8426f8.png)


1. Wi-Fiの設定画面から、Macと同一のWi-Fiを確認する
2. ①のアイコンを選択
3. Wi-Fiの詳細設定画面の一番の「HTTPプロキシ -> プロキシを構成（手動）」を選択
4. 先ほど控えたMacのIPアドレスを入力し、ポート番号はCharlesで設定した番号を入力。保存。

以上でiPhone側でのWi-Fiのプロキシ設定は完了です。

### Androidの設定方法

iPhoneの場合と、設定する項目と手順は同じです。

![AndroidのWifi設定.png](https://qiita-image-store.s3.amazonaws.com/0/66682/a33dbc74-5c29-1384-0028-700c425c59d8.png)

1. Wi-Fiの設定画面から、Macと同一のWi-Fiを確認する
2. ①の項目を選択する
3. ダイアログの「プロキシ -> 手動」を選択
4. 先ほど控えたMacのIPアドレスを「プロキシホスト名」に、Charlesに設定したポート番号を「プロキシポート」に入力。保存

以上でAndroid側でのWi-Fiのプロキシ設定は完了です。

## 7. 実機のSafariまたはChromeでアクセスしてみる

いよいよ、実機から開発環境に立ち上がったWebサーバーにアクセスできる準備が整ったので、アクセスしてみます。手順2の最後にMacのターミナルからcurlで`http://192.168.33.10:3000/`にアクセスしましたが、各スマートフォンはプロキシを経由して同様のアドレスにアクセスが可能になっているかと思います。また、実機からのプロキシサーバへのアクセス時にCharlesから**アクセス許可を求めるダイアログが出てくることがありますが、`Allow`を選択**します。

iPhoneからはSafariで、AndroidからはChromeで`http://192.168.33.10:3000/`にアクセスした結果が以下です。

![実機からアクセス.png](https://qiita-image-store.s3.amazonaws.com/0/66682/86c426b7-dda4-9b75-07dd-4925bd0d2ed4.png)

AndroidのChromeからだと問題無さそうですが、iPhoneのSafariだと、ハートの位置が少しズレているのが分かります。
こうして、開発環境の時点から実機のブラウザアプリからアクセスすることで、期待していない表示に気づくことができます。

## 8. Mac側で各Webインスペクタで検証作業

では、さっそくなぜズレているのかを検証してみます。今回はMac版SafariからiPhoneのSafariに対してWebインスペクタで接続します。

![safari.png](https://qiita-image-store.s3.amazonaws.com/0/66682/3dd9aee9-b04e-f155-87aa-1f1f86088e78.png)

1. デバッグ中のiPhoneで検証したいアプリのURLにアクセスする
1. デバッグ中のiPhoneをMacにUSBで接続する
1. Mac版Safariを立ち上げて、`開発 > [デバッグ中のiPhone名] > [Safari > iPhoneでアクセスしているURL]`を選択

すると、以下のようにWebインスペクタが立ち上がります。デベロッパーツールをよく使う方であれば見慣れたインタフェースです。

![Webインスペクタ.png](https://qiita-image-store.s3.amazonaws.com/0/66682/f4e80666-6134-0417-170a-3afd90f1af5c.png)

このWebインスペクタはデバッグ中のiPhoneのSafariと同期しているので、任意のDOMを選択するとプロパティなどを変更し、即座に変更を確認できます。以下のような使用感です。

![web_inspector_gif](https://media.giphy.com/media/l3mZj7znsueFZ70VW/giphy.gif)

アイコンがズレてしまっていた原因は、**paddingの指定が明示的にされていなかったため**だったようです:sweat_smile:

Android端末でChromeのWebインスペクタと繋げてデバッグしたい場合はこちらが参考になります。
[ASCII.jp：Android実機のデバッグが激しく捗る「Webインスペクタ」｜Web制作が3倍速くなるChromeデベロッパーツールの使い方](http://ascii.jp/elem/000/001/006/1006268/)

# さいごに

各ブラウザ（Chrome、Safari、FireFox、Edgeなど）で、各要素のデフォルトで指定されているスタイルの違いによって、ブラウザごとに表示が少し違ってくる場合があります。そういった事情に対してここ数年間、「できるだけ元々持っているデフォルトスタイルの良さや癖を残しつつ、ブラウザ間のスタイルの差異を解消していこう」という試みがされてきた中でリセットCSSフレームワークがいくつも登場しました。

自分は体系的にCSSを学んだ経験もなく、そういったフレームワークをありがたく利用させてもらいつつ、正直なところ雰囲気でCSSを書きがちです。そういった現状なので、できるだけ意図しないスタイルが表示されないよう防ぐために、スマホ表示の確認のためには今後も実機でのデバッグを行っていきたいと思います。:mag:

# 参考

- [ローカル開発環境の Web サイトにスマホからアクセスする方法 (Vagrant もOK) - Qiita](https://qiita.com/noraworld/items/264d944f3ac8074e454d)
- [cURLでHTTPステータスコードだけを取得する - Qiita](https://qiita.com/mazgi/items/585348b6cdff3e320726)
- [iPhoneのSafariで開いているページをWebインスペクタでPCからデバックする方法 - Qiita](https://qiita.com/gctoyo/items/8b3b6a5b9816e69f97bd)
- [ASCII.jp：Android実機のデバッグが激しく捗る「Webインスペクタ」｜Web制作が3倍速くなるChromeデベロッパーツールの使い方](http://ascii.jp/elem/000/001/006/1006268/)