SSHでサーバーに接続し、時間のかかる処理(大量データの変換、バックアップ、ビルドなど)を実行しているとき、SSH接続が切れると実行中のコマンドも一緒に終了してしまう——これは多くの人が一度は経験する現象です。原因は、SSHセッションが切れると実行中のプロセスにSIGHUP(ハングアップ信号)が送られ、多くのコマンドはこれを受け取ると終了するためです。nohup(no hang up)は、このSIGHUPを無視させることで、SSHを切断しても処理を継続させるための定番コマンドです。
この記事では、実際のレンタルサーバーへのSSH接続を使い、本当にSSH切断でプロセスが死ぬのか、nohupを付けると生き残るのかを実際に確かめます。あわせて、似たような目的で使われるdisownとの違いについても、実際に検証した結果を紹介します。
- SSHが切れると、実行中のプロセスに
SIGHUPが送られ、通常は終了します。 nohup コマンド &にすると、SIGHUPを無視してSSH切断後も処理を継続できます。- 出力は既定で
nohup.outというファイルに自動で保存されます。 disownは「シェルの管理下から外す」機能で、SSHセッション終了時の挙動に対してはnohupほど確実ではありません(実際に検証済み)。setsid コマンドも、新しいセッションを作ることでSSH切断から独立させられます。- 長時間の処理をSSH越しに実行するときは、最初から
nohupを付けて起動するのが安全です。
実行中のプロセスを確認・終了する方法はps・kill、SSH接続の基本はscpコマンドや~/.ssh/configもあわせて参考になります。
【実証】SSH切断でコマンドが本当に死ぬのか
まず、nohupを使わずに実際のサーバー上でバックグラウンドジョブを起動し、SSH接続を切ってから改めて確認してみます。
# SSH接続してバックグラウンドでコマンドを起動し、そのまま切断する ssh user@server "sleep 30 &" # (コマンドが返ってきた時点でSSH接続は終わる) # 少し待ってから、別のSSH接続でプロセスを確認 ssh user@server "ps aux | grep sleep" # → 何も表示されない(プロセスが消えている)
実際のレンタルサーバーで、sleep 30 &を実行してすぐにSSH接続を終了し、数秒後に別のSSH接続からps auxで確認したところ、そのプロセスは跡形もなく消えていました。ssh user@server "コマンド"という形でコマンドを実行すると、コマンドの終了と同時にSSHのセッションも終了し、そこで実行していたプロセスにSIGHUPが送られます。sleepのような多くのコマンドはSIGHUPを受け取ると、途中であっても終了してしまいます。「バックグラウンドで&を付けたのに、SSHを切ったら止まっていた」という現象は、まさにこれが原因です。
【実証】nohupを付けると生き残る
同じ操作を、今度はnohupを付けて行います。書き方はnohup コマンド &です(&でバックグラウンド実行にするのも忘れずに)。
# nohup を付けてバックグラウンドで起動 ssh user@server "nohup sleep 30 > nohup.out 2>&1 &" # (コマンドが返ってきた時点でSSH接続は終わる) # 別のSSH接続でプロセスを確認 ssh user@server "ps aux | grep sleep" # user 3492607 0.0 0.0 107972 724 ? S 08:36 0:00 sleep 30 # ↑ TTY欄が「?」=制御端末なしで、ちゃんと生きている
実際のサーバーで、nohup sleep 30 > nohup.out 2>&1 &としてから同様にSSH接続を切り、別接続から確認したところ、今度はsleep 30プロセスがちゃんと生きたままps auxに表示されました。TTY列が?になっているのは、制御端末(元のSSHセッション)から完全に切り離されていることを示しています。さらに、出力先を指定しなくてもnohup.outというファイルが自動生成され、標準出力・標準エラーがそこに書き込まれることも確認しました。長時間かかる処理をSSH越しに実行するときは、最初からnohupを付けて起動するのが鉄則です。
【重要な発見】disownだけでは不十分だった
nohupと似た目的で紹介されることが多いのがdisownです。disownは「バックグラウンドジョブをシェルの管理下(ジョブテーブル)から外す」コマンドで、通常のログアウト時にシェルがジョブへSIGHUPを送るのを防ぎます。しかし、実際に検証したところ、SSHの非対話的なコマンド実行では、disownだけでは生き残りませんでした。
# disown -h でジョブをシェルの管理下から外してから切断 ssh user@server "set -m; sleep 25 & disown -h %1" # 別接続で確認すると… ssh user@server "ps aux | grep sleep" # → 何も表示されない(disownしても消えてしまった)
実際にset -mでジョブ制御を有効にしたうえでdisown -h %1を実行し、SSH接続を切って確認したところ、プロセスは生き残りませんでした。これは、disownが防げるのは「シェル自身が終了時に子ジョブへSIGHUPを送る」経路だけであり、SSHサーバー(sshd)がセッション終了時にそのセッションのプロセスへ直接SIGHUPを送る経路までは防げないためだと考えられます。一方nohupは、プロセス自身がSIGHUPを「無視する」よう設定されるため、信号がどこから送られてきても影響を受けません。この違いから、「SSH越しにコマンドを実行して切断後も残したい」という目的には、disownよりnohupのほうが確実だと言えます(対話的なターミナルでジョブをバックグラウンド化してからexitする、という異なる場面ではdisownが有効なこともあります)。
setsidという選択肢
setsidは、コマンドを新しいセッションのリーダーとして起動するコマンドです。元のセッション(SSH接続)から完全に独立するため、こちらもSSH切断後の生存に使えます。
# setsid でコマンドを新しいセッションとして起動 ssh user@server "setsid sleep 25 < /dev/null > /dev/null 2>&1 &" # 別接続で確認 ssh user@server "ps aux | grep sleep" # user 3510364 0.0 0.0 107972 628 ? Ss 08:40 0:00 sleep 25 # ↑ 生きている(Ssはセッションリーダーであることを示す)
実際のサーバーでも、setsid sleep 25 < /dev/null > /dev/null 2>&1 &としたプロセスは、SSH切断後も生き残ることを確認しました(STAT列のSsは、独立したセッションのリーダーであることを示します)。nohupとsetsidはアプローチが異なりますが(nohupは信号を無視、setsidはセッションごと独立させる)、どちらも実務では有効です。迷ったらnohupを使うのが、最もシンプルで広く知られた方法です。
主な書き方一覧
SSH切断からプロセスを守る方法をまとめます。
| 書き方 | SSH切断後の生存 |
|---|---|
コマンド &(何もなし) |
× 死ぬ(実証) |
nohup コマンド & |
○ 生存(実証) |
コマンド & disown -h |
× 死ぬ場合がある(実証) |
setsid コマンド & |
○ 生存(実証) |
nohup.out |
nohupの既定の出力先 |
よくある失敗
SSHを切ったら処理が止まっていた
&だけではSIGHUPを防げません。nohupを付けて起動し直します。
disownを付けたのに切断で死んでしまう
SSHの非対話実行では、disownだけでは不十分なことがあります。nohupのほうが確実です。
nohup.outが肥大化する
出力先を明示的に指定(nohup コマンド > ログファイル 2>&1 &)すれば、場所や内容を管理しやすくなります。
ジョブが生きているか確認しない
ps aux | grep コマンド名で、実際に生きているか必ず確認します。
長時間処理を対話シェルで実行してしまう
最初からnohupを付けて起動する習慣をつけると、切断事故を防げます。
よくある質問
SIGHUP(ハングアップ信号)が送られるためです。多くのコマンドは、この信号を受け取ると途中であっても終了します。実際に検証したところ、nohupを付けずにバックグラウンド実行したプロセスは、SSH切断後すぐに消えていることを確認しています。nohup コマンド &のように、コマンドの前にnohupを付けてバックグラウンド実行します。実際にサーバー上で試したところ、SSHを切断してもプロセスが生き残り、標準出力・標準エラーは既定でnohup.outというファイルに自動保存されることを確認しています。disownはジョブをシェルの管理下から外し、シェル自身が終了時に送るSIGHUPを防ぎます。一方nohupはプロセス自身がSIGHUPを無視するよう設定します。実際に検証したところ、SSHの非対話的なコマンド実行ではdisownだけでは生き残らないケースがあり、SSH越しの長時間処理にはnohupのほうが確実だと分かりました。nohupコマンド自体は起動時に付けるものなので、あとから同じようには付けられません。既に実行中のジョブをSIGHUPから守りたい場合はdisownを試す方法がありますが、この記事の検証結果のとおりSSH切断に対しては確実とは言えません。長時間の処理は、最初からnohupを付けて起動するのが安全です。nohupはSIGHUPを無視する仕組み、setsidは新しいセッションとして独立させる仕組みで、アプローチは異なりますが目的は同じです。広く知られていて書き方もシンプルなnohupを基本の選択肢にするとよいでしょう。まとめ
- SSH切断はプロセスに
SIGHUPを送り、多くのコマンドはそれで終了します。 nohup コマンド &で、SIGHUPを無視してSSH切断後も処理を継続できます(実証済み)。- 出力は既定で
nohup.outに保存されます。 disownだけではSSH切断時に不十分な場合があります(実証済み)。setsidも有効な代替手段です。迷ったらnohupを使いましょう。
SSH越しの長時間処理は、「切断=処理が止まる」と考えて、最初からnohupを付けて起動するのが最も安全な習慣です。ps・killと組み合わせて、実行中のジョブの状態も定期的に確認しておきましょう。
- grep(文字列検索)
- find(ファイル検索)
- sed(置換・行編集)
- awk(列抽出・集計)
- chmod(パーミッション)
- tar(圧縮・解凍)
- リダイレクトとパイプ
- ps・kill(プロセス管理)
- 環境変数とPATH
- ln(シンボリックリンク)
- cp・mv・rm(コピー/移動/削除)
- history(コマンド履歴)
- curl(HTTP通信・API)
- jq(JSON処理)
- vim(基本操作・終了方法)
- cron・crontab(定期実行)
- sort・uniq・wc(並べ替え/集計)
- xargs(一括処理)
- chown・chgrp(所有者/グループ変更)
- diff(ファイル比較)
- du・df(ディスク使用量)
- head・tail(先頭/末尾・ログ監視)
- alias(コマンドの別名)
- nohup(SSH切断対策)
- tmux(セッション管理)
- よく使うコマンドまとめ
- cd(ディレクトリ移動)

