SSH 接続先でサーバを立ち上げっぱなしにしてログアウトするための Bash の書き方

自端末から、SSH で Linux (CentOS) サーバに接続し、その Linux サーバ上で Express サーバを立ち上げ、SSH 接続を切断したかった。

Express サーバは、$ npm install 後、$ node main.js と叩くと起動するようになっているのだが、ターミナルを閉じたり、ログアウトしたりした時に、このプロセスを生かし続ける方法が分からず調べた。

結論からいうと、Linux の nohup というコマンドを使うと実現できた。

HUP シグナルを無視しつつバックグラウンドプロセスで起動する

nohup を使って、SSH 切断後もプロセスを動かし続けるには、nohup 【コマンド】 & というイディオムを使う。

nohup コマンド自体は、SSH ログアウトなどを行った時に送信される HUP (ハングアップ) シグナルを無視するだけ。そのコマンドをバックグラウンドで動かすには、末尾に & を与える。

というワケで、以下のように叩けば良い。

# Linux サーバに SSH 接続する
$ ssh -p 22 hogeuser@linux-host

# Linux サーバにて以下のように実行する
$$ nohup node main.js > /dev/null 2>&1 </dev/null &

# プロンプトが戻るので、このまま exit したりして良い
$$ exit

標準出力、エラー出力などを無視するため、リダイレクトと /dev/null の記述を追加してはいるが、nohup node main.js & ということだ。

バックグラウンドで起動しているプロセスを停止させるには

最初の目的はこれで果たせたが、今度はこの Express サーバを止めたくなった時にどうするか、ということである。普通プロンプトを奪われたままだったら、Ctrl + C で終了できたのに…というところ。

具体的な手法がいくつかあるのでこれから紹介するが、やろうとしていることは プロセスを特定して終了させる、ということだ。

方法1 : ps でプロセス ID を調べて kill する

最も原始的なやり方は、ps コマンドで node main.js が動作している PID (プロセス ID) を取得して、コレを指定して kill コマンドを叩く、というモノ。

$ ps aux | grep [n]ode
Neo        4954   0.0  0.5  5226356  39428 s000  S     1:32PM   0:00.72 node main.js

# コレでプロセス ID が「4954」と分かったので、以下のように叩く
$ kill -9 4954

$ ps aux | grep [n]ode
# 何も出なくなる = プロセスが終了できた

grep コマンドの検索文字列に [n]ode と書いているが、先頭の文字列を [] で囲むと、grep コマンド自身のプロセスを除外できるという小技だ。

# 「[n]」と書かないと、以下のように grep コマンド自身も表示されてしまう
$ ps aux | grep node
Neo        4980   0.0  0.0  4267768    896 s000  S+    1:32PM   0:00.00 grep --color node
Neo        4954   0.0  0.5  5226356  39428 s000  S     1:32PM   0:00.72 node main.js

方法2 : pgrep でプロセス ID を取得して kill する

pgrep という便利なコマンドがある。ps | grep を一気にやってくれるようなコマンドだ。このコマンドはプロセス ID だけを返すので、コレを直接 kill コマンドに渡してしまえば終了できる。

# 比較のため、「方法1」のやり方でプロセスを確認しておく
$ ps aux | grep [n]ode
Neo        5046   0.0  0.5  5226868  39796 s000  S     1:36PM   0:00.62 node main.js

# pgrep を使うと、検索対象のコマンドを指定して、PID のみ取得できる
$ pgrep -f 'node main.js'
5046

# 「$()」構文を利用して、kill コマンドに PID を渡して終了させる
$ kill -9 $(pgrep -f 'node main.js')

# 以下いずれのコマンドも結果が表示されなく鳴った = 停止できた
$ ps aux | grep [n]ode
$ pgrep -f 'node main.js'

方法3 : pkill で対象のコマンドを指定して直接 Kill してもらう

「方法2」のようなことをしなくとも、同等のことをやってくれるコマンドとして、pkill というコマンドが用意されている。最初からコレでよかった…。

# コレだけでプロセスを終了できる
$ pkill -f 'node main.js'

以上。コレで Express サーバを立ち上げっぱなしにできるぞ〜