macOS 起動時に autossh を実行したい
autossh という ssh のラッパーソフトがあり、sshが切れたら自動的に繋ぎ直してくれるという便利なやつです。
autossh は homebrew で入れられます。
これを ターミナル起動時 ではなく、macOS の起動時に自動実行させたいという要望です。
まずは普通にターミナルから実行できるか試す
うちの場合はこんな感じでした。
$ ssh -L 127.0.0.1:${LOCAL_PORT}:${SERVER_IP}:${SERVICE_PORT} -i ~/ssh/id_rsa -l ${LOGIN_NAME} -p ${SERVER_PORT} ${SERVER_ID}
ローカルポートにアクセスすると、サーバーの特定のサービスポートにつながる、いわゆるトンネルを掘るというやつです。
これを autossh に書き直すとこんな感じ。
${LOCAL_PORT}
とかは 実際には 22 などのポート番号、${LOGIN_NAME}
には sironekotoro とかの文字列が入っております。
$ autossh -M 0 -f -N -L 127.0.0.1:${LOCAL_PORT}:${SERVER_IP}:${SERVICE_PORT} -i ~/ssh/id_rsa -l ${USERNAME} -p ${SERVER_PORT} ${SERVER_ID}
これをターミナルから実行して、ちゃんとトンネルが掘れたことを確認。
これを launchd の作法で書くだけで大丈夫なはず!
launchd で動かせない
大丈夫じゃなかった。ダメでした。
もう、何がダメかわからないレベル。
これが動かなかった 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>local.mxcl.autossh</string> <key>EnvironmentVariables</key> <dict> <key>PATH</key> <string>/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin</string> </dict> <key>ProgramArguments</key> <array> <string>/usr/local/bin/autossh</string> <string>-M</string> <string>0</string> <string>-f</string> <string>-N</string> <string>-p</string> <string>${SERVER_PORT}</string> <string>-l</string> <string>${LOGIN_NAME}</string> <string>-i</string> <string>/Users/${USERNAME}/.ssh/id_rsa</string> <string>-L</string> <string>127.0.0.1:${LOCAL_PORT}:${SERVER_IP}:${SERVICE_PORT}</string> <string>${SERVER_IP}</string> </array> <key>RunAtLoad</key> <true/> <key>StandardOutPath</key> <string>/Users/${USERNAME}/Desktop/standard_out.txt</string> <key>StandardErrorPath</key> <string>/Users/${USERNAME}/Desktop/standard_error.txt</string> </dict> </plist>
エラーを吐き出すようにしてるけど、standard_error.txt
には、autossh を引数なし(あるいは不正な引数)時の usage が出力されてるのみ。
で、最小限の引数でってことでバージョンを表示する -V
オプションだけを入れると、ちゃんと standard_out.txt
にバージョン番号が追記される。
ぐぐぐぐ。
<array> <string>-V</string> </array>
なお、launchd ではシェル変数とかホームディレクトリを表す ~
とかが展開されないってことに気づくのにえらい時間がかかった。
基本に立ち返る
いやいや、俺は致命的な勘違いをしているのかも。
よくやるじゃん致命的な勘違い。
ってことで、ファイルを作るだけの簡単なやつで試してみる。
$ cd ~/Library/LaunchAgents $ touch local.test.touch.plist
作った local.test.touch.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>local.test.touch</string> <key>ProgramArguments</key> <array> <string>/usr/bin/touch</string> <string>/Users/sironekotoro/Desktop/test.txt</string> </array> <key>RunAtLoad</key> <true/> <key>StandardOutPath</key> <string>/Users/sironekotoro/Desktop/standard_out.txt</string> <key>StandardErrorPath</key> <string>/Users/sironekotoro/Desktop/standard_error.txt</string> </dict> </plist>
作ったら、文法に間違いないか確認する
$ plutil -lint local.test.touch.plist local.test.touch.plist: OK
ではいざ実行!
$ launchctl load local.test.touch.plist
これでうまく動いて、デスクトップ上に text.txt という空のファイルができた。
うん、間違ってない・・・となると何故 autossh は動かないのか。
とりあえず、後片付け。
$ launchctl unload local.test.touch.plist $ rm local.test.touch.plist
ワークアラウンド
いいかげん、あれこれ試すのも飽きてきたので、諦めてワークアラウンド(回避策)さがす。
Autometer でコマンド実行するやつを作って、それを 環境設定 → ユーザとグループ のログイン項目に入れる
Autometer 単体ではちゃんと動いた。
でも、macOS 起動時になぜか、なぜか、Xcode が立ち上がる。なんで???
没
autossh のコマンド入れたシェルクスリプト作って、それを launchd から呼ぶ
これはうまくいきました。
autossh.sh というファイルを以下の内容で作って
#!/bin/bash /usr/local/bin/autossh -M 0 -f -N -L 127.0.0.1:${LOCAL_PORT}:${SERVER_IP}:${SERVICE_PORT} -i ~/ssh/id_rsa -l ${LOGIN_NAME} -p ${SERVER_PORT} ${SERVER_ID}
実行権限つけておきます。
$ chmod +x autossh.sh
このファイルを起動する 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>local.mxcl.autossh</string> <key>EnvironmentVariables</key> <dict> <key>PATH</key> <string>/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin</string> </dict> <key>ProgramArguments</key> <array> <string>/Users/${USERNAME}/autossh.sh</string> </array> <key>RunAtLoad</key> <true/> <key>StandardOutPath</key> <string>/Users/sironekotoro/Desktop/standard_out.txt</string> <key>StandardErrorPath</key> <string>/Users/sironekotoro/Desktop/standard_error.txt</string> </dict> </plist>
あとはさっきの touch の時のように起動時のリストに登録・・・これで動きました。
本当は、シェルスクリプト通さずに plist の中身だけで autossh を実行したかったんですが、今はこれが精一杯ってことで。
お疲れ様でした。