LAN/WANでhostsを切り替える(MacOS)

# 自宅サーバーにLAN内外からドメイン名でアクセスしたい
ファイルサーバーとかを自宅に建てて，httpsで自宅外(例えば仕事場)からアクセスできるようにしている人は結構いると思います．
MacBookを持ち歩くようなタイプの人間は，自宅の内外問わずMacBookを膝の上で使うと思います．
そんな時，自宅サーバーに対して**外出先ではhogehoge.comでアクセスして，自宅ではサーバーのローカルIPでアクセスする**なんていうめんどくさいことをしないといけないシチュエーションがあります．
**自宅でも外出先でも，hogehoge.comでアクセスしたい！** という人向けの記事です．
（[こちら](https://oiio.jp/entries/1256)の方法が理想的だったのですが，できなかったので妥協案として．やりたいことは基本同じです．）

# 解決法：接続されたWi-FiのSSIDを検出して，自宅内外に応じたhostsファイルを切り替える
です．自宅のWi-Fiにつながっている(=サーバーと同一ネットワーク内にいる)時は，サーバーのローカルIPとドメイン名hogehoge.comを結びつけたhostsファイルを適用して，それ以外の時はその結びつきのないhostsファイルを適用することで，「自宅外からhogehoge.comでアクセスしようとしたときにローカルIPに向かってしまって正しくサーバーにアクセスできない」という事態を回避します．

MacOSでの方法を備忘録としてメモしておきます．

ざっくりした流れは下記の通り．
1. hosts.local, hosts.externalを用意する（それぞれ自宅内外用）
2. SSIDをに応じてhostsファイルを切り替えるシェルスクリプトを作る
3. Wi-Fi接続が切り替わったタイミングで作動するlaunchdジョブを作る
です．

## 1. hosts.local, hosts.externalの作成
通常のhostsファイルをまずはhosts.localとhosts.externalに複製して，.localのほうののみ，下の通りサーバーのローカルIPとドメインの対応付けを追記します．
```hosts.local
xxx.xxx.xx.xx(サーバーのローカルIP) hogehoge.com（ドメイン)
```

## 2. SSIDに応じてhostsファイルを切り替えるシェルスクリプト
airportというコマンドでSSIDを取得する方法があるみたいですが，2025年時点では非推奨っぽいので，別の方法．
[こちら](https://discussions.apple.com/thread/255761216?sortBy=rank)を使いました．

やってることとしては，**「SSIDを取得して，自宅Wi-FiのSSIDだったら，hostsをhosts.localで置き換えて，自宅外のネットワークだったらhosts.externalで置き換える」** という処理です．
```sh:switch_hosts.sh
#!/bin/bash

TARGET_SSID="aterm-xxxxx(自宅のルーターのSSID)"
INTERFACE="en0(MacBookでWi-Fiなら大体これだと思います)"

#system_profilerを使った，現在接続されているWi-FiのSSID取得．
CURRENT_SSID=$(system_profiler SPAirPortDataType | awk '/Current Network/ {getline;$1=$1;print $0 | "tr -d ':'";exit}')

#SSIDに応じたhostsファイル切り替え
if [ "$CURRENT_SSID" = "$TARGET_SSID" ]; then
    echo "Connected to LAN ($CURRENT_SSID): applying hosts.local"
    sudo cp /etc/hosts.local /etc/hosts #<-hostsファイルの置き場．hosts.localは別の場所でもいいと思います．
else
    echo "Connected to external ($CURRENT_SSID): applying hosts.external"
    sudo cp /etc/hosts.external /etc/hosts #<-hosts.externalは上と同じくどこでもいいと思います．
fi
```
作成したshファイルには実行権限を与えておきましょう．

また，パスワードなしでこの処理ができるようにしておきます．
```shell
sudo visudo
```
で，
```shell
yourusername ALL=(ALL) NOPASSWD: /bin/cp /etc/hosts.local /etc/hosts, /bin/cp /etc/hosts.external /etc/hosts
```
と追記．yourusernameは自身のユーザー名に置き換えましょう．hosts.local, hosts.externalのパスも自分が配置した場所に

## 3. Wi-Fi接続が切り替わったタイミングで作動するlaunchdジョブ
MacOSでは，Wi-Fiが切り替わると，~/Library/Preferences/SystemConfiguration/内のファイルが更新されるみたいなので，それをトリガーとして利用します．

/Users/username/Library/LaunchAgents/に，次のようにジョブを作ります．
```html:com.user.switchhosts.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.switchhosts</string>
    <key>ProgramArguments</key>
    <array>
        <!-- switch_hosts.shの場所 -->
        <string>/path/to/switch_hosts.sh</string> 
    </array>
    <key>RunAtLoad</key>
    <true/>
    <!-- SystemConfiguration/の変化検出　-->
    <key>WatchPaths</key>
    <array>
        <string>/Library/Preferences/SystemConfiguration</string>
    </array>

    <!-- ログの出力 -->
    <key>StandardOutPath</key>
    <string>/tmp/switchhosts.out</string>

    <key>StandardErrorPath</key>
    <string>/tmp/switchhosts.err</string>
</dict>
</plist>
```
そしたら
```shell:terminal
launchctl load ~/Library/LaunchAgents/com.user.switchhosts.plist
```
でジョブをロードします．
これで，Wi-Fiが切り替わったタイミングでジョブが実行され，ジョブに記載されたshが実行されることでhostsファイルが切り替わります．

**以上**

# おわりに
多分，サーバーと同じネットワーク内に，DNSサーバーを建てたりするのが普通のやり方だと思うのですが，別にこれで困らないならそれでいいと思います．そんなにめんどくさくもなかったし．