この記事は生活コーディングのLinux講義を受講しながら、別途気になった部分を調査・追記してまとめた学習ノートです。
Linuxシステムの構造を理解し、ターミナルで自由にコマンドを扱うための基礎学習資料です。
1. Linuxファイルシステムの構造(Directory Structure)#
Linuxはウィンドウと異なりドライブ(C:、D:)の概念がなく、ルート(/)という最上位ディレクトリからすべてが始まるツリー(Tree)構造を持ちます。
| ディレクトリ | 説明・用途 |
|---|---|
/(Root) | ファイルシステムの最上位の起点です。 |
/bin | User Binaries. 必須の基本コマンドが位置します。最新システムでは /usr/bin へのリンクである場合が多いです。 |
/sbin | System Binaries. システム管理用の必須コマンドが位置します。最新システムでは /usr/sbin へのリンクである場合が多いです。 |
/lib | Libraries. システムやプログラムの実行に必要な共有ライブラリファイルが位置します。 |
/home | ユーザーホームディレクトリ。 ウィンドウの C:\Users\ に似ています。cd ~ コマンドですぐに移動できます。 |
/etc | 設定ファイル(Configuration)。 プログラムやシステム全般の設定ファイルが集まっています。 |
/var | 可変データ(Variable)。 ログファイル(log)、データベースなど内容が変化し続けるファイルが格納されます。 |
/tmp | 一時ファイル(Temporary)。 多くのディストリビューションでは起動時または定期的に整理されますが、常に保証されるわけではないため機密データを置かないでください。 |
/usr | User System Resources. ディストリビューションが提供するほとんどのユーザー用プログラムとライブラリがインストールされます。手動インストールは通常 /usr/local(または /opt)に置きます。 |
2. 必須基本コマンド(Navigation & File Operation)#
ターミナルで現在地を把握しファイル/フォルダを操作するコマンドです。
位置確認と移動#
pwd(Print Working Directory): 現在どのパスにいるかを表示します。pwd # 出力例: /home/ubuntucd(Change Directory): ディレクトリを移動します。cd ~: 自分のホームディレクトリに即座に移動。cd ..: 上位(親)ディレクトリに移動。- Tip: パスを入力するとき
Tabキーを押すと自動補完されます。(タイプミス防止・速度向上)
ファイルとディレクトリの操作#
ls(List): 現在のディレクトリのファイル一覧を表示します。ls -a: 隠しファイル(ドットで始まるファイル)もすべて表示。ls -l: ファイルの権限、所有者、サイズなど詳細情報をリスト形式で表示。ls -al: 上記2つのオプションを合わせて、隠しファイルを含むすべてのファイルの詳細情報を表示。
mkdir(Make Directory): 新しいディレクトリを作成します。mkdir -p dir1/dir2: 親ディレクトリまで一度に作成します。(-pはparents)
cp(Copy): ファイルやディレクトリをコピーします。cp [元] [対象] cp -r [元_ディレクトリ] [対象_ディレクトリ] # ディレクトリのコピーには -r オプションが必須mv(Move): ファイルを移動したり名前を変更するときに使用します。mv old_name.txt new_name.txt # 名前変更 mv file.txt /home/user/docs/ # ファイル移動rm(Remove): ファイルを削除します。rm -r [ディレクトリ]: ディレクトリを削除します。(内部ファイルを含む)rm -f [ファイル]: 確認メッセージなしに強制削除します。(-fはforce)- 非常に危険:
rm -rf /のようなコマンドはシステム全体を削除する可能性があるため絶対に使用してはいけません。
ファイル内容の確認と作成#
touch: 空の新ファイルを作成したり、既存ファイルの最終修正時刻を現在の時刻に変更します。touch new_file.txtcat: ファイルの全内容をターミナルに一度に出力します。短いファイルに便利です。less:catと異なり、長いファイルの内容をページ単位で快適に確認できます。(移動:方向キー、終了:q)less large_log_file.loghead/tail: ファイルの前部または後部の10行をデフォルトで出力します。head -n 5 log.txt: 前部5行だけ見るtail -f log.txt: ファイルに内容が追加されるたびにリアルタイムで表示し続ける(-fはfollow)
file: ファイルの種類(テキスト、画像、実行ファイルなど)を教えてくれます。file my_script.sh->Bourne-Again shell script, ASCII text executable
3. システム権限とパッケージ管理#
権限(Permissions)#
sudo(SuperUser Do): 管理者(Root)権限でコマンドを実行します。システム設定の変更やプログラムのインストール時に必須です。なぜ権限が必要かについては14章で詳しく説明します。
パッケージマネージャー(Package Manager)#
アプリストアのようにプログラムを簡単にインストール、アップデート、削除してくれるツールです。OS別でコマンドが異なります。
| 系統 | 代表OS | パッケージマネージャー | 主要コマンド |
|---|---|---|---|
| Debian | Ubuntu, Debian, Mint | apt | sudo apt updatesudo apt install [パッケージ]( apt-get も広く使われる) |
| Red Hat | RHEL, Fedora, CentOS | dnf | sudo dnf install [パッケージ](旧システムでは yum を使用) |
| Arch | Arch Linux, Manjaro | pacman | sudo pacman -Syusudo pacman -S [パッケージ] |
| macOS | - | Homebrew(brew) | brew install [パッケージ]brew upgrade |
Java 開発者 Tip: JDK のインストール Java(JDK)はパッケージマネージャーで簡単にインストールできます。
# Ubuntu で OpenJDK 17 をインストール sudo apt install openjdk-17-jdk # 複数の Java バージョンがインストールされている場合、使用するバージョンを選択 sudo update-alternatives --config java別の方法: SDKMAN! 複数の JDK バージョンを頻繁に切り替える必要がある場合は
sdkmanが便利です。# インストール curl -s "https://get.sdkman.io" | bash # 例) Temurin 21 のインストールとデフォルト設定 sdk install java 21-tem sdk default java 21-tem企業/セキュリティ環境ではインストールスクリプトの内容を先に確認し、社内ポリシーを遵守してください。
ファイルのダウンロードとAPIテスト#
wget#
wget はURLを通じてファイルをダウンロードするシンプルで直感的なツールです。
wget [URL]: URLのファイルを現在のディレクトリに元のファイル名そのままダウンロードします。wget -O [保存するファイル名] [URL]: ダウンロードしたファイルの名前を指定して保存します。
curl(Web開発者の必需品)#
curl(cURL)はHTTP、HTTPS、FTPなど多様なプロトコルを使ってデータを転送する強力なツールです。単純なファイルダウンロードだけでなく、Web開発時にAPIとやり取りするほぼすべての状況を模倣できるため「ターミナル界のPostman/Insomnia」と呼ばれます。
基本GETリクエスト(APIエンドポイントの確認) APIが正常に動作しているかを最も簡単に確認するときに使います。
# 特定のユーザー情報をリクエストするAPIをターミナルからすぐにテスト curl https://jsonplaceholder.typicode.com/users/1ヘッダー情報の確認(
-i、-I) HTTPステータスコード(200 OK、404 Not Foundなど)やレスポンスヘッダー(Content-Type、Cache-Controlなど)を確認するときに非常に便利です。# レスポンス本文とヘッダーを一緒に見る curl -i https://example.com # ヘッダー情報だけを見る(HEADリクエスト) curl -I https://example.comPOSTリクエスト(APIにデータを送信) ログイン、会員登録、データ作成などクライアントがサーバーにデータを送る際の状況をテストします。
# JSONデータをAPIサーバーに送信する例 curl -X POST \ -H "Content-Type: application/json" \ -d '{"title": "foo", "body": "bar", "userId": 1}' \ https://jsonplaceholder.typicode.com/posts-X POST: HTTPリクエストメソッドを「POST」に指定します。(-X GET、-X PUT、-X DELETEなども可能)-H "Content-Type: ...": リクエストヘッダーを設定します。REST APIは大抵JSONを使うため必須のオプションです。-d '{"json": "data"}': リクエストに含めて送るデータ(Request Body)を指定します。
リダイレクトを追う(
-L) リクエストしたURLが別のアドレスにリダイレクトされるとき、その最終目的地まで追って内容を取得します。# http://t.co/... のような短縮URLの実際の内容を見るときに使用 curl -L http://t.co/I5YYd9dDA
4. 入出力制御とパイプライン(I/O Redirection)#
コマンドの結果(出力)を画面ではなくファイルに保存したり、ファイルの内容をコマンドの入力として使う際に使います。
核心概念:標準ストリーム#
- Standard Input(stdin、0): 入力(主にキーボード)
- Standard Output(stdout、1): 出力(主にモニター)
- Standard Error(stderr、2): エラーメッセージ
コマンドは実行時にこの3つの入出力通路を持ってスタートします。OSはこれらの通路に 0、1、2 という番号を付けて管理しますが、これを**ファイルディスクリプター(file descriptor、fd)**と呼びます。
ここで「file」という言葉があるため実際のファイルだけを指しているように見えますが、必ずしもそうではありません。ターミナル、ファイル、パイプ、ソケットのような入出力対象全体を指す番号札に近いです。
そのためシェルのリダイレクション文法は次のように読めます。
0= 入力通路(stdin)1= 一般出力通路(stdout)2= エラー出力通路(stderr)
つまり 2> のような文法は**「2番通路(stderr)を別の場所に送れ」**という意味です。
なぜ数字と > が一緒に付くか#
シェルは**「何番の通路をどこに送るか」**を数字と記号で表現します。
>は実は1>の省略形です。 つまりls > result.txtはls 1> result.txtと同じ意味です。2>は**2番通路(stderr)**をファイルに送ります。<はファイルの内容を**0番通路(stdin)**に接続します。
例えば:
ls > result.txt # stdout(1) -> result.txt
rm nofile.txt 2> error.log # stderr(2) -> error.log
sort < list.txt # list.txt -> stdin(0)& とは何か?なぜ 2>&1 のように使うか#
初心者が最も混乱するのがここです。
まずコマンドの末尾に付く & と 2>&1 の中の & は同じ形ですが文脈が異なります。
sleep 100 &の&はバックグラウンド実行を意味します。2>&1の&は**「ファイル名ではなく、別のファイルディスクリプターを指す」**という意味です。
つまり 2>&1 はこのように読めます。
2>: 2番通路(stderr)を対象にする&1: ファイル名1ではなく、1番通路(stdout)が現在向かっている場所を指す
そのため 2>&1 の意味は:
「stderr(2)もstdout(1)が現在行く場所に送れ」
です。
この違いを必ず区別する必要があります。
rm nofile.txt 2>1上のコマンドはエラーを 1 という名前のファイルに保存します。
つまり 1 をファイル名として見たわけです。
一方:
rm nofile.txt 2>&1このコマンドはエラー(stderr)をstdoutと同じ場所に送ります。
ここで &1 はファイルではなく1番出力通路を意味します。
リダイレクション記号#
>: 実行結果(stdout)をファイルに上書き保存します。(1>の省略形)ls -l > result.txt>>: 実行結果をファイルの末尾に追加します。ls -al >> result.txt<: ファイルの内容をコマンドの入力(stdin)として使います。sort < list.txt # list.txtの内容を並べ替えて画面に出力2>: エラー(stderr)だけ別途ファイルに保存します。rm nofile.txt 2> error.log&>または> ... 2>&1: 出力(stdout)とエラー(stderr)をすべて同じ場所に送ります。自動化スクリプトでログを残すときによく使います。# コマンドのすべての結果(出力+エラー)をall.logに上書き # &> all.logは > all.log 2>&1の短縮表現(Bash/Zsh専用)です。 ls -l /nonexistent &> all.log # POSIX互換も考慮するならこの形がより汎用的です。 ls -l /nonexistent > all.log 2>&1 # コマンドのすべての結果をall.logに追加 ls -l /nonexistent >> all.log 2>&1
ここで重要なポイントがもう1つあります。2>&1 は**「stderrをstdoutと同じ場所に送れ」という意味であり、ファイルを直接指定する文法ではありません。そのため通常は > ファイル名 または >> ファイル名 と合わせて**使います。
例えば:
command > all.log 2>&1この文はこのように読みます。
- stdout(1)をまず
all.logに送る。 - stderr(2)も**stdoutが現在行く場所(all.log)**に送る。
つまり最終的にstdoutとstderrがどちらも all.log に入ります。
逆に順序を変えると結果が変わる場合があります。
command 2>&1 > all.logこの場合、まずstderrが現在stdoutが向かっている場所(通常ターミナル)を追い、その後でstdoutだけ all.log に変わります。
つまり初心者としては> all.log 2>&1 の順序を覚えておくのが安全です。
パイプライン(Pipeline、|)#
あるプログラムの**出力(stdout)を別のプログラムの入力(stdin)**に接続するコンベアベルトです。
- 活用例:
ps aux | grep apache: 現在実行中のすべてのプロセス(ps)の中から「apache」だけをフィルタリングして見ます。ls -l | wc -l: ファイル一覧の行数を数えて現在のディレクトリのファイル/フォルダ数を確認します。
grep(フィルタリング)#
パイプラインとよく一緒に使われ、目的の文字列が含まれる行(Line)だけを検索する強力なツールです。
- よく使うオプション:
-i(Ignore case): 大文字小文字を区別せずに検索します。-r(Recursive): 下位ディレクトリまですべて検索します。-n(Line number): 結果が何行目にあるかも一緒に出力します。-w(Word): 正確にその単語だけを検索します。(例:grep -w "is"は「this」を除外)-v(Invert): その単語が含まれない行だけを出力します。
5. シェル(Shell)とカーネル(Kernel)#
ユーザーが入力したコマンドがハードウェアまで伝達される過程です。
- User: コマンドを入力(例:
ls) - Shell: ユーザーのコマンドを解釈してカーネルに伝達(翻訳家の役割)
- Kernel: ハードウェアを制御して実際の作業を実行
- Hardware: 物理的な演算を実行
シェルの種類#
bash: ほとんどのLinuxシステムにデフォルトでインストールされている最も大衆的なシェル。zsh:bashと互換性を持ちながら、強力なプラグイン(oh-my-zsh)とテーマ、自動補完機能で生産性を大きく向上させるシェル。fish: 「Friendly Interactive SHell」の略で、別途設定なしでも便利な機能(自動サジェスト、文法ハイライトなど)をすぐ使えて初心者に親しみやすいシェル。echo $0またはps -p $$: 現在使用中のシェルを確認するコマンド。
シェルスクリプト(Shell Script)#
繰り返しの作業を自動化するためにコマンドをファイルにまとめて一度に実行する「台本」です。
- Shebang(
#!): スクリプトファイルの最初の行に書き、このファイルをどのシェルで解釈するかを指定します。#!/bin/bash # 上のコードは以下の内容を /bin/bash シェルで実行するという意味 echo "Hello Shell Script!"
シェルスクリプトの実行#
- 実行権限の付与:
chmod +x my_script.sh - スクリプトの実行:
./my_script.sh
6. Linuxファイル検索コマンドのまとめ#
1. locate(データベースベースの高速検索)#
あらかじめ作られたファイル目録データベース(DB)を検索するため非常に速いですが、直前に作成したファイルは見つからない場合があります。
- 使い方:
locate [ファイル名] - DBの更新(必要時):
sudo updatedb
2. find(リアルタイム精密検索)#
遅いですが現在のファイルシステムを直接探索して、名前、種類、サイズ、時間など非常に多様な条件で検索できます。
- 基本構造:
find [パス] [オプション] [式]- パス:
/(全体)、.(現在のディレクトリ)、~(ホームディレクトリ)
- パス:
- 主要オプション:
- 名前:
-name "*.log"(大文字小文字区別)、-iname "*.log"(大文字小文字無視) - タイプ:
-type f(ファイル)、-type d(ディレクトリ) - サイズ:
-size +100M(100MB超)、-size -10k(10KB未満) - 時間:
-mtime -7(7日以内に修正)、-mtime +7(7日以前に修正)
- 名前:
- 検索後に作業を実行(
-exec、-delete):-execは検索されたファイルに対して別のコマンドを実行する強力な機能です。{}は検索されたファイルを意味し、\;はコマンドの終わりを知らせます。
# .tmpファイルを見つけて削除前に確認メッセージを表示(安全) find . -name "*.tmp" -exec rm -i {} \; # .tmpファイルをそのまま削除(効率的) find . -name "*.tmp" -delete
7. ファイルの位置と実行の仕組み#
7.1. コマンドの実際の位置を見つける(which、whereis)#
which [コマンド]:$PATH環境変数に設定されたパスだけを検索して、実行されるコマンドの絶対パスを見つけてくれます。$ which ls /bin/lswhereis [コマンド]: 実行ファイルだけでなく、ソースコード、マニュアルファイルの位置まで教えてくれます。
7.2. コマンド実行の仕組み($PATH)#
ls や java のように短く入力するだけでコマンドが実行される理由は、シェルが $PATH という環境変数に登録されたディレクトリを順番に検索して実行ファイルを見つけてくれるからです。
- 確認方法:
echo $PATH
Java 開発者 Tip: JAVA_HOME と PATH Java インストール後に
JAVA_HOME環境変数を設定し、この変数を使って$PATHに JDK のbinディレクトリを追加するのが標準的な方法です。こうすることでjava、javac、jpsなど JDK のすべてのコマンドをどこからでも使えます。# ~/.bashrc または ~/.zshrc に追加 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 export PATH=$JAVA_HOME/bin:$PATH
8. コンピューターの構造とプロセスの理解#
8.1. プログラム vs プロセス#
- プログラム(Program): ストレージ(HDD、SSD)に保存された、実行される前の静的なコードの塊です。(例:
/bin/ls実行ファイル) - プロセス(Process): プログラムが実行されてメモリに上がり、CPUによって処理されている動的な状態です。すべてのプロセスは固有のID(PID)を持ちます。
8.2. 親と子のプロセス(Parent-Child Process)#
Linuxのすべてのプロセスは「家族関係」のように階層構造を形成します。この概念を理解すると export がなぜ重要かが完璧に理解できます。
比喩:「たい焼き型とたい焼き」
- 親プロセス(Parent Process): 現在実行中のプロセスです。(例:コマンドを入力するターミナル(シェル))
- 子プロセス(Child Process): 親プロセスが生成した新しいプロセスです。
どのように作られるか?(Fork & Exec)
ターミナル(親)で java -jar my-app.jar というコマンドを実行すると、内部的に2つのことが瞬時に起こります。
Fork(複製): ターミナル(親)が自分自身とほぼ同じコピー、つまり「子」を作ります。まるでたい焼き型で同じ形を型抜きするようなものです。この時点の子は親とほぼすべてを共有します。(特に環境変数!)Exec(実行): 複製された「子」が自分自身を捨てて、javaという新しいプログラムに変わります。今この子はJVMプロセスとなってmy-app.jarを実行し始めます。型から出た生地にあんこを入れて本当のたい焼きとして完成させる過程と同じです。
Java 開発者にとってなぜ重要か? まさにこの**
Fork(複製)の段階で親の「環境変数」が子(JVM)に継承**されるからです。 ターミナル(親)でexport SPRING_PROFILES_ACTIVE=prodのように設定すると、子のjavaプロセスはこの値をそのまま受け継ぎます。 Spring Boot アプリケーションはSystem.getenv()を通じてこの環境変数を読み取り、prodプロファイル用のapplication-prod.yml設定をロードします。exportを使わない「シェル変数」は親の部屋でだけ使われる秘密なので子に継承されません。
プロセスの関係を確認する#
ps コマンドにオプションを付けると親子関係を直接確認できます。PPID がまさに親プロセスのIDです。
# 現在自分が実行したプロセスのID(PID)と親ID(PPID)を一緒に見る
ps -o pid,ppid,comm
# PID PPID COMMAND
# 12345 1234 bash (自分のターミナル、親)
# 54321 12345 ps (psコマンドを実行した子)pstree コマンドを使うとこの関係をツリー構造でよりわかりやすく見ることができます。(インストールが必要:sudo apt install psmisc)
pstreeこの親子関係と継承の概念はLinuxシステムの動作方式の核心の1つです。
9. プロセスのモニタリングと管理#
9.1. プロセス一覧の確認(ps)#
ps -ef: システムのすべてのプロセスを標準フォーマットで詳しく照会します。ps auxと類似していますが、System V系(多くのLinuxディストリビューション)でより標準として使われます。ps -ef | grep java: システムで実行中のすべてのjavaプロセスをフィルタリングして確認します。
9.2. リアルタイムモニタリング(top & htop)#
top: 従来のリアルタイムプロセスモニタリングツール。htop:topより視覚的に見やすく使いやすいアップグレード版。(インストールが必要:sudo apt install htop)- Load Average: システム負荷平均。CPUコア数より高ければ過負荷状態と見なせます。
Java 開発者 Tip: JDK 内蔵モニタリングツール
psの他に JDK が提供するツールを使うと JVM に特化した情報が得られます。
jps: 現在実行中の Java プロセスの PID と Main クラス名を表示します。ps -ef | grep javaよりずっとすっきりしています。jstat -gc [PID] 1000: 該当 PID の Java プロセスに対して GC(Garbage Collection)状態を1秒ごとに表示します。メモリリークや GC チューニング時に有用です。
10. マルチタスキングとバックグラウンド実行#
10.1. フォアグラウンド vs バックグラウンド#
- フォアグラウンド(Foreground): コマンドを実行するとターミナルの制御権を持ってユーザーの入力を待っている状態。
- バックグラウンド(Background): ターミナルの制御権なしに裏で静かに実行されている状態。
10.2. 作業制御#
- プロセスの中断(
Ctrl+C): フォアグラウンドで実行中のプロセスに**終了シグナル(SIGINT)**を送って中断させます。 - プロセスの一時停止(
Ctrl+Z): 実行中のプロセスを停止してバックグラウンドに送ります。(終了ではありません) - バックグラウンド作業の確認(
jobs): バックグラウンドにある作業の一覧と番号(Job ID)を確認します。 - バックグラウンドで実行(
&): コマンドの後に&を付けると最初からバックグラウンドで実行されます。# ターミナルを閉じてもプロセスが終わらないように nohup と一緒に使う nohup java -jar my-app.jar &- Tip:
&だけ使うとターミナルセッションが切れるときプロセスも一緒に終了します。nohup(No Hang Up)コマンドと合わせて使うことでターミナル接続が切れてもプロセスを実行し続けられます。出力とエラーはnohup.outファイルに自動保存されます。 - より安定した運用のためには
nohupより11章で学ぶsystemdを使うのが良いです。
- Tip:
- 作業の切り替え(
fg、bg):fg %[作業番号]: バックグラウンドの作業を再びフォアグラウンドに持ってきます。(Foreground)bg %[作業番号]: 一時停止した作業をバックグラウンドで実行し続けます。(Background)
10.3. プロセスの終了:kill の技術#
kill は単にプロセスを「殺す」だけでなく、特定の**「シグナル(Signal)」**を送る繊細なコマンドです。
ステップ1:PIDを見つける(feat. jps、pgrep)#
プロセスを制御するにはまず固有番号である**PID(Process ID)**を知る必要があります。
# 1. jps できれいに見つける(推奨)
jps
# 2. pgrep で名前で見つける
pgrep -f "my-app.jar"
# 出力例: 12345ステップ2:シグナルを送る(状況に合わせて)#
kill -15 [PID]またはkill [PID](最も一般的で安全な終了)SIGTERM(15) シグナルを送ります。これは「アプリよ、もう準備して丁寧に終了してください」という礼儀正しいリクエストです。- Java 開発者 Tip: よく作られた Spring Boot アプリはこのシグナルを受け取ると、進行中のHTTPリクエストを安全に終わらせ、DBコネクションプールを閉じ、メッセージキューリスナーを停止するなど**グレースフルシャットダウン(Graceful Shutdown)**を実行します。常にこの方法を先に試すべきです。
kill -9 [PID](最後の手段、強制終了)SIGKILL(9) シグナルを送ります。これはプロセスが無視できない強制終了命令です。「今すぐすべてを止めて消えろ!」という意味です。- Java 開発者 Tip:
kill -15でも終了しない応答不能(Hang)プロセスを片付けるときだけ使用してください。すでに終了した後に親が回収できなかったゾンビプロセスはkill -9でも消えないため、親プロセスを終了するかsystemdが回収するように処理する必要があります。JVMが後処理(Shutdown Hook)をする時間すら与えずに即座に消えるため、データが破損したり不完全な状態で残る場合があります。
kill -1 [PID](設定のリロード)SIGHUP(1) シグナルを送ります。多くのサーバープログラムはこのシグナルを受け取ると設定ファイルを再読み込みします(reload)。- Web 開発者 Tip: Nginx のようなWebサーバーの設定を変更した後、サーバーを中断させずに変更内容を適用したいときに使います。(Javaアプリ自体はこのシグナルを直接処理しないことが多いため、Javaアプリの再起動が不要なNginxの再設定に主に使われます。)
ステップ3:名前で一度に制御(pkill)#
PIDをいちいち探すのが面倒なとき、プロセス名を使ってシグナルを送ります。
# "my-app.jar" を実行しているすべての java プロセスに丁寧な終了シグナルを送る
pkill -f "my-app.jar"
# "hung-app.jar" のように応答しないプロセスに強制終了シグナルを送る
pkill -9 -f "hung-app.jar"11. デーモン(Daemon)とサービス管理(systemd)#
11.1. デーモンの概念と systemd#
- デーモン(Daemon): システムバックグラウンドで常に実行されて特定のリクエストを処理するために待機するプログラム。(例:Webサーバー、DBサーバー)
systemd: 現代のLinuxディストリビューションの標準システム・サービスマネージャーです。過去のinit.dスクリプトやserviceコマンドに代わってデーモン(サービス)を管理します。
11.2. サービスの制御(systemctl)#
systemctl は systemd を制御する核心コマンドです。(大抵 sudo が必要)
- サービスの開始/停止:
sudo systemctl start apache2.service sudo systemctl stop apache2.service - サービスの再起動/状態確認:(
sudo systemctl restart apache2.service sudo systemctl status apache2.service.service拡張子は省略可能)
11.3. 起動時の自動実行設定#
- 自動実行の有効化:
sudo systemctl enable apache2 - 自動実行の無効化:
sudo systemctl disable apache2 - 有効化の確認:これらのコマンドは過去に
sudo systemctl is-enabled apache2/etc/rc.d/ディレクトリにシンボリックリンクを作る複雑な過程に代わります。
11.4. Javaアプリケーションのためのsystemdサービス登録(実務の核心)#
nohup はシンプルですが、サーバーが再起動するとアプリが自動で実行されず、ログ管理も不便です。現代のLinuxでは systemd を使ってJavaアプリケーションを安定した「サービス」として登録・管理します。
サービスファイルの作成:
/etc/systemd/system/パスに[サービス名].serviceファイルを作成します。(例:my-app.service)sudo vim /etc/systemd/system/my-app.serviceサービスファイルの作成:
[Unit] Description=My Spring Boot Application After=network.target [Service] User=myuser Group=mygroup ExecStart=/usr/bin/java -jar /home/myuser/app/my-app-0.0.1.jar --spring.profiles.active=prod SuccessExitStatus=143 Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.targetDescription: サービスの説明。User/Group: サービスを実行するユーザーとグループ。セキュリティのためにrootではなく専用アカウントを作るのが良いです。ExecStart: アプリケーションを実行するコマンド。必ず絶対パスを使う必要があります。SuccessExitStatus=143:kill -15(SIGTERM)で正常終了したときの終了コード(143)を成功とみなします。Restart=on-failure: サービスが異常終了すると10秒後に自動的に再起動します。WantedBy=multi-user.target: システムが起動するときにこのサービスを開始するように設定します。- 環境変数管理のTip: サービスファイルに
Environment="SPRING_PROFILES_ACTIVE=prod"を追加するかEnvironmentFile=/etc/default/my-appで外部ファイルを読み込むようにすると、コードと秘密の値を分離して運用できます。(systemctl edit my-appでドロップインファイルを作るのが更新時に衝突を減らす安全な方法です。)
サービスの適用と開始:
sudo systemctl daemon-reload: 新たに作ったサービスファイルをsystemdが認識するようにリロードします。sudo systemctl start my-app: サービスを開始します。sudo systemctl status my-app: サービスの状態を確認します。(緑色のactive (running)を確認)sudo journalctl -u my-app -f:my-appサービスのログをリアルタイムで確認します。(tail -fと類似)
起動時の自動実行設定:
sudo systemctl enable my-app: システムが起動するときに自動的にサービスが開始されるよう有効化します。sudo systemctl disable my-app: 自動起動を無効化します。
12. 定期的な作業のスケジューリング(Cron)#
12.1. Cronの概念と設定#
定期的に繰り返される作業(バックアップ、ログ整理など)を自動化するツールです。
- 設定ファイルの編集:
crontab -e - 設定一覧の確認:
crontab -l - Tip:
crontab -e実行時にデフォルトのエディターが不便であればexport EDITOR=nanoコマンドでエディターを変更してから使ってみてください。
12.2. 作成文法#
形式: 分 時 日 月 曜日 コマンド(左から順番に)
| フィールド | 意味 | 範囲 |
|---|---|---|
| 分 | 何分に | 0-59 |
| 時 | 何時に | 0-23 |
| 日 | 毎月何日に | 1-31 |
| 月 | 何月に | 1-12 |
| 曜日 | 何曜日に | 0-7(0と7が日曜日) |
*: 「毎回」を意味します。- 例:
# 毎日深夜2時10分にバックアップスクリプトを実行 10 2 * * * /home/user/backup.sh > /var/log/backup.log 2>&1
13. シェル設定の自動化:自分だけの開発環境を構築する#
開発をしているとき git status を頻繁に入力したり、cd ~/projects/my-awesome-project のような長いパスに移動し続けたりと、毎回繰り返す作業が多くあります。また DATABASE_URL や API_KEY のような情報をターミナルに一時的に入力することもあります。
ターミナルを開くたびにこのような環境が自動的に設定されると非常に便利ですね。その役割をするのが「シェル起動スクリプト」を利用した設定の自動化です。
13.1. シェル設定の核心:起動ファイル、変数、そしてエイリアス#
1)シェル起動ファイル:.bashrc と .zshrc(設定レシピ)#
新しいターミナルを実行すると、シェル(料理人)は ~/.bashrc や ~/.zshrc のような「レシピノート」を読んで書かれたコマンドを実行しながら作業環境を構成します。
.bashrc: BASHシェルが起動するたびに読む個人のカスタム設定集です。.zshrc: ZSHシェルが起動するたびに読む個人のカスタム設定集です。
両者の用途はまったく同じであり、どのシェルを使うかによって使う「設定集」の名前だけが異なります。以下のコマンドで現在使用中のシェルを確認できます。
# 今自分が使っているシェルを確認(「bash」または「zsh」などが出力される)
echo $02)変数の2種類:シェル変数 vs 環境変数(自分の部屋 vs 家全体)#
export はシェル設定で最も重要で分かりにくい概念です。**「家全体」と「自分の部屋」**の比喩で確実に理解しましょう。
- ターミナル(シェル) = 「自分」
- シェル変数 (
API_KEY="12345") = 「自分の部屋」だけで使う秘密の暗号。「自分」(現在のターミナル)だけが知っていて、「自分」が実行する他のプログラム(子プロセス)は知ることができません。 - 環境変数 (
export API_KEY="12345") = 「家」のすべての家族が知っている共有Wi-Fiのパスワード。「自分」と「自分」が実行するすべての子(プログラム)が一緒に使えるように継承されます。 exportコマンド = 「自分の部屋のパスワード」を「家族共有のパスワード」に昇格させて全員に知らせる拡声器の役割。
ここで初心者が最も多くする質問がこれです。
「
~/.bashrcに単にMY_VAR=helloと書いても、シェルが子を作るときforkするから子もその値をコピーしてもらえるのではないか?」
混乱しやすい質問ですが、核心は**fork だけでなく実際の外部コマンドの実行は通常 fork + exec と続く**という点です。
もう少し正確に説明すると:
- 現在のシェルが子プロセスを作るときまず
fork()を行う。 - その次に子は
exec()でjava、python、envのような別のプログラムに切り替わる。 - このとき新しいプログラムに渡されるのはシェル内部の状態全体ではなく、exportされた環境変数のリストです。
つまり MY_VAR=hello のようにexport なしで作ったシェル変数は現在のシェル内では見えますが、exec() で実行された外部プログラムには基本的に渡されません。
そのため以下の2行はまったく異なる動作をします。
MY_VAR=hello
export OTHER_VAR=worldMY_VARは現在のシェル内部でのみ知っている値OTHER_VARは現在のシェル + 以降に実行する子プロセスも知っている値
つまり違いは単純に「変数か環境変数か」で正しいです。ただし実務ではこの違いが子プロセスに渡されるかどうかを決めるため非常に重要です。
Java 開発者に
exportが必須な理由 ターミナルでjava -jar my-app.jarで Spring Boot アプリを実行すると、このjavaプロセスはターミナルの「子」プロセスになります。Spring Boot コードのapplication.ymlで${MY_API_KEY}のように環境変数を使ったり、コード内でSystem.getenv("MY_API_KEY")を通じて値を読み込もうとするとき、親のターミナルがexportでMY_API_KEYを設定していなければ子の Java プロセスはこの値を絶対に知ることができません。そのため「API キーが定義されていません」のようなエラーが発生したり設定値が空になります。外部の子プロセスに値を渡すには必ずexportを使う必要があります。
3)変数の永続性:一時変数 vs 永久変数(付箋 vs レシピ)#
ターミナルで設定した変数はなぜウィンドウを閉じると消えるのでしょう?一時記憶(メモリ)と永久記憶(ファイル)の違いだからです。
ターミナルで直接
export(一時、付箋)export MY_VAR="hello"をターミナルに入力するのは、現在のターミナルのメモリ(RAM)に内容を一時的に記録することです。モニターに付箋を貼るのと同じで、ターミナルを閉じると一緒に消えます。設定ファイルに
exportを書く(永久、レシピ) 変数を永久に保存するにはexport MY_VAR="hello"というコマンド自体を~/.bashrcのような設定ファイルに記録する必要があります。このファイルは「シェルが起動するたびにこれらのコマンドを実行して環境を再構成せよ」と教えてくれる**「設定レシピ」**です。新しいターミナルが開くたびにシェルはこのレシピを読んで再び「付箋を貼って」くれます。
ここでも重要な違いがあります。
# ~/.bashrc
MY_VAR="hello"このように書くだけでは、新しいターミナルが開くたびにそのシェル自身は MY_VAR を知るようになります。
つまりターミナル内で echo "$MY_VAR" は正常に動作する場合があります。
しかしそのターミナルで実行した外部プログラムは異なります。
python3 -c 'import os; print(os.getenv("MY_VAR"))'このようなプログラムは MY_VAR を見えない場合があります。なぜなら MY_VAR はまだシェル変数にすぎず、環境変数としてexportされていないからです。
逆に:
# ~/.bashrc
export MY_VAR="hello"このように書いておくと:
- 新しいターミナルが開くとシェルが
MY_VARを作る。 - 同時にこの値を環境変数として登録する。
- その後このシェルが実行する
java、python、node、envのような子プロセスもその値を受け取れる。
つまり ~/.bashrc に書くという事実だけで子プロセスへの伝達が保証されるわけではありません。
**「設定ファイルに書いたか?」と「export したか?」**は別の問題です。
まとめると:
~/.bashrcにMY_VAR=helloを書く 新たに開いたシェル自身がその値を使用可能~/.bashrcにexport MY_VAR=helloを書く 新たに開いたシェル + そのシェルが実行する子プロセスも使用可能
もう1つよく混乱する点があります。新しいターミナルが MY_VAR を知っている理由は、親シェルが無条件にその値を渡したからではなく、新しいシェルが自分の起動ファイル(~/.bashrc)を再度読んで実行したからかもしれません。
つまり「新しいターミナルでも見える」と「外部の子プロセスに渡される」は同じ話ではありません。
4)自分だけのコマンド:エイリアス(Alias)を作る#
よく使う長くて複雑なコマンドを簡単なショートカットキーのように作れます。
# エイリアス(alias)設定の例
alias gs="git status"
alias ll="ls -alF"
alias bootRun="./gradlew bootRun"このような alias 設定を ~/.bashrc や ~/.zshrc ファイルに追加しておくと、新しいターミナルからすぐに使えます。
5)現在設定されている変数を確認する#
「それで今自分のターミナル(メモリ)にどんな「付箋」が貼られているか?」が気になるときに使うコマンドです。
envまたはprintenv: 現在のシェルの環境変数(「家族共有のパスワード」)だけを選んで表示します。set: 環境変数とシェル変数(「家族共有のパスワード」と「自分の部屋のパスワード」)をすべて表示します。
13.2. 発展:ログインシェルとインタラクティブシェル(.bash_profile vs .bashrc)#
シェルは起動方式によって異なる設定ファイルを読みます。この微妙な違いを知っておくと良いです。
.bash_profile(ログインシェル)- いつ?: システムにログインするとき一度だけ実行されます。(例:
sshでリモートサーバーに初めて接続するとき) - 何を?: 一度設定すれば良い重要な環境変数(
JAVA_HOMEなど)を主に設定します。
- いつ?: システムにログインするとき一度だけ実行されます。(例:
.bashrc(インタラクティブシェル)- いつ?: ログインではなく、新しいターミナルウィンドウを開くたびに実行されます。
- 何を?: ターミナルを便利に使うための設定(
alias、プロンプトの形など)を主に設定します。
ベストプラクティス(これだけ使えばOK!)#
上の区別が分かりにくいなら、ほとんどのLinuxシステムで使われるベストプラクティスは以下の通りです。
すべての設定を
.bashrcにまとめます。(alias、exportなど).bash_profileでは.bashrcを読み込むだけにします。 以下のコードを~/.bash_profileに追加するか、すでにあればコメントを外してください。# ~/.bash_profile if [ -f ~/.bashrc ]; then source ~/.bashrc fi理由: こうすると
sshでログインするとき(.bash_profileが実行)も、新しいターミナルを開くとき(.bashrcが実行)も常に同一で一貫した環境で作業できるようになります。
13.3. 設定の適用:source コマンド(更新)#
.bashrc ファイルを修正しても、すでに開いているターミナルウィンドウには変更が適用されません。ターミナルは起動時だけ設定ファイルを読むからです。
source は**現在のシェルにスクリプトファイルの内容をすぐに適用(更新)**せよというコマンドです。
# 1. ~/.bashrc に新しいエイリアスを追加(例: alias gp="git push")
# 2. ターミナルを再起動しなくても、以下のコマンドですぐに適用!
source ~/.bashrc
# 新しいエイリアス 'gp' をすぐに使えます。source はターミナルを再起動せずに設定をすぐに反映できる非常に便利なコマンドです。
14. マルチユーザーと権限管理#
Linuxは複数のユーザーが同時に接続して使う「マルチユーザーシステム」です。そのため誰がどのファイルにアクセスして修正できるかを制御する「権限」の概念が非常に重要です。
14.1. ユーザーの確認と切り替え#
id: **自分(現在のユーザー)**のシステム情報(UID、GID、所属グループ)を確認します。who: 現在システムにログインしているすべてのユーザーの一覧を表示します。su - [ID]: そのユーザーへ完全に切り替え(ログイン)します。(-はそのユーザーの環境設定もすべて読み込む重要なオプション)
14.2. ユーザーの追加と管理#
sudo useradd -m [ID]: 新しいユーザーを追加します。(-mはホームディレクトリ作成オプション)sudo passwd [ID]: ユーザーのパスワードを設定または変更します。sudo usermod -aG [グループ名] [ID]: ユーザーを特定のグループに追加します。(例:sudo usermod -aG sudo myuserはmyuserに管理者権限を付与)sudo userdel -r [ID]: ユーザーを削除します。(-rはホームディレクトリまですべて削除)
14.3. ファイル権限(Permission)の完全理解#
ファイル権限とは、特定のファイルやディレクトリを誰が読み、書き、実行できるかを指定するルールです。権限は3種類のユーザーに対して定義されます。
- Owner(User): ファイルの所有者。
- Group: 所有者が属するグループ。(例:開発チーム、管理者グループなど)
- Other: 所有者でもなくグループにも属していない第三者(その他のすべてのユーザー)。
権限情報の解読(ls -l)#
ls -l コマンドはファイルとディレクトリの詳細情報を表示し、このうち権限情報が最も重要です。
drwxr-x--- 8 keonhongkoo staff 256 1 15 2023 .android
ファイルタイプ(最初の文字)
d: ディレクトリ(Directory)-: 一般ファイル(File)l: シンボリックリンク(Symbolic Link)
権限モード(次の9文字列:
rwxr-x---)rwx(Owner): 最初の3文字は所有者の権限です。読み取り(r)、書き込み(w)、実行(x)がすべて可能です。r-x(Group): 中間の3文字はグループの権限です。読み取り(r)と実行(x)のみ可能です。---(Other): 最後の3文字はその他のユーザーの権限です。何の権限もありません。
その他の項目
8: ハードリンク数keonhongkoo: 所有者名staff: グループ名256: ファイルサイズ(Byte)1 15 2023: 最終修正日.android: ファイルまたはディレクトリ名
権限の意味:ファイル vs ディレクトリ#
r、w、x 権限は対象がファイルかディレクトリかによって意味が異なります。
| 権限 | 記号 | ファイル(File)での意味 | ディレクトリ(Directory)での意味 |
|---|---|---|---|
| 読み取り | r | ファイルの内容を見る(cat、vim) | ディレクトリ内部のファイル一覧を参照(ls) |
| 書き込み | w | ファイルの内容を修正/保存 | ディレクトリ内のファイル作成、削除、名前変更(touch、rm、mv) |
| 実行 | x | ファイルをプログラムとして実行 | ディレクトリ内部への進入(アクセス)(cd) |
- 注意: ディレクトリに
x権限がないとcdで入ることができません。また自分のファイルでも、そのファイルが含まれているディレクトリにw権限がなければファイルを削除したり名前を変えることができません。
権限の変更:chmod(Change Mode)#
chmod はファイルやディレクトリの権限を変更するコマンドです。2つの方式(Symbolic、Octal)があります。
1)シンボリック(Symbolic)方式:直感的な文字を使用
chmod [対象][演算子][権限] [ファイル名] の形で使います。
- 対象:
u(user)、g(group)、o(other)、a(all) - 演算子:
+(追加)、-(除去)、=(指定) - 権限:
r(read)、w(write)、x(execute)
# my_script.shファイルに対して...
# 所有者(u)に実行(x)権限を追加(+)
chmod u+x my_script.sh
# グループ(g)に書き込み(w)権限を除去(-)
chmod g-w my_script.sh
# すべてのユーザー(a)に読み取り(r)権限だけになるよう指定(=)
chmod a=r my_script.sh2)数字(Octal)方式:素早く正確な数字を使用
権限を数字で表現して組み合わせます。
r(Read) = 4w(Write) = 2x(Execute) = 1
3桁の数字を 所有者-グループ-その他 の順序で指定します。
rwx= 4+2+1 = 7rw-= 4+2 = 6r-x= 4+1 = 5r--= 4
# 所有者はrwx(7)、グループはr-x(5)、その他のユーザーはr-x(5)の権限を付与
# 一般的な実行ファイルやWebディレクトリの権限としてよく使われる
chmod 755 my_script.sh
# 所有者はrw-(6)、グループはr--(4)、その他のユーザーはr--(4)の権限を付与
# 一般的なファイルの権限としてよく使われる
chmod 644 my_document.txt
# すべてのユーザーにすべての権限を付与(セキュリティ上注意が必要)
chmod 777 shared_folder- 再帰的変更(
-R): ディレクトリとその中のすべてのサブファイル/フォルダの権限を一度に変えるには-Rオプションを使います。# my_dir内部のすべてのファイルとフォルダに755の権限を適用 chmod -R 755 my_dir
所有権の変更:chown(Change Owner)#
chown はファイルやディレクトリの所有者と所有グループを変更するコマンドです。(主に sudo が必要)
# my_file.txtの所有者をnew_userに変更
sudo chown new_user my_file.txt
# my_file.txtの所有グループをnew_groupに変更
sudo chown :new_group my_file.txt
# my_file.txtの所有者とグループを一度に変更
sudo chown new_user:new_group my_file.txt
# my_dirディレクトリとその中のすべての内容(-R)の所有者をnew_userに変更
sudo chown -R new_user my_dir15. ネットワークの基礎とインターネットの仕組み(Network Basics)#
サーバーを扱うためには、インターネットがどのように接続されているか、自分のコンピューターのアドレスは何かを知ることが必須です。
15.1. クライアントとサーバー(Client & Server)#
インターネットは巨大な対話です。この対話は情報をリクエストして応答する2つの主体で構成されています。
- クライアント(Client、お客様): Webブラウザ(Chromeなど)やモバイルアプリ。情報を**リクエスト(Request)**します。
- サーバー(Server、提供者): Linuxシステム上で動いているWebサーバープログラム(Apache、Nginx、Node.jsなど)。リクエストされた情報を探して**レスポンス(Response)**します。
- 動作過程:
- クライアント:
google.comを入力(リクエスト) - サーバー:
index.htmlファイルを探して送信(レスポンス) - クライアント:コードを解釈して画面に描画
- クライアント:
15.2. アドレス体系:IPとドメイン、そしてDNS#
- IPアドレス(IP Address): コンピューターが通信のために持つ実際の数字アドレス(例:
172.217.25.78)。電話番号に例えられます。 - ドメイン名(Domain Name): 人が覚えやすい文字アドレス(例:
google.com)。電話帳の名前に例えられます。 - DNS(Domain Name System): ドメイン名をIPアドレスに変換するシステムです。
- Tip: ターミナルで
ping google.comと入力するとそのドメインの実際のIPを確認できます。
- Tip: ターミナルで
15.3. 公開IP vs プライベートIP(重要)#
サーバー開発者が最も混乱する部分です。ip addr で確認した自分のIPと外部から見た自分のIPが異なる場合があります。
- 確認方法:
- 内部IP:
ip addr(結果の中のinetの後の数字、例:10.0.x.x、192.168.x.x) - 外部IP:
curl ipinfo.io/ip(外部インターネットから自分を見るときに見えるIP)
- 内部IP:
| 種類 | 説明 | 比喩 | 特徴 |
|---|---|---|---|
| 公開IP(Public IP) | 通信会社が付与した世界で唯一のアドレス | 会社の代表電話番号 | 外部から直接アクセス可能 |
| プライベートIP(Private IP) | ルーターが内部機器に付与したアドレス | 会社の内線番号 | 外部から直接アクセス不可 |
バックエンド開発者 Tip: クラウド(AWS)環境では? AWS EC2 などのクラウドサーバーも同じです。インスタンスを作成すると Public IP(外部アクセス用)と Private IP(VPC内部通信用)がそれぞれ割り当てられます。DBサーバーはセキュリティのためにPrivate IPでのみ通信するように設定するのが一般的です。
16. Webサーバーの構築と運営(Web Server)#
自分のLinuxコンピューターを世界中に情報を提供するサーバーにする過程です。従来のApacheサーバーを基準に説明しますが、原理はNginxなど他のサーバーも同じです。
16.1. インストールと実行(Apache2)#
Ubuntu基準のコマンドです。
- インストール:
sudo apt update && sudo apt install apache2 - サービス管理(
systemctl):- 実行:
sudo systemctl start apache2 - 状態確認:
sudo systemctl status apache2(緑色のactive (running)が表示されれば正常)
- 実行:
- 接続テスト:
- ブラウザのアドレスバーに
http://localhostまたはhttp://127.0.0.1を入力。 - 「Apache2 Default Page」が見えれば成功です。
- ブラウザのアドレスバーに
16.2. 設定ファイルと DocumentRoot#
Webサーバーが「どこにあるファイルを見せるか」を決める設定です。
- 設定ファイルの位置:
/etc/apache2/sites-enabled/000-default.conf - DocumentRoot: ユーザーが接続したときに見せるWebページファイル(
index.html)が位置する最上位ディレクトリです。(デフォルト:/var/www/html) - 実習:
/var/www/html/index.htmlファイルをsudo nanoで開いて内容を修正してみてください。更新すると内容が変わります。
16.3. ログ(Log)の分析:サーバーのブラックボックス#
サーバーに問題が発生したときや不正アクセスが疑われるときに最初に確認する場所です。
- 位置:
/var/log/apache2/ access.log: 誰が(IP)、いつ、何をリクエストしたかが記録されます。error.log: サーバー内部のエラーや実行失敗の原因が記録されます。- リアルタイムモニタリング:
tail -f /var/log/apache2/access.log
Java 開発者 Tip: Apache vs Nginx(Reverse Proxy) 最近の実務では Apache より Nginx をより多く使う傾向があり、特に Java 陣営ではほぼ標準のように使われます。
- Nginx の役割: Nginx は軽量で大容量トラフィック処理に非常に効率的な Web サーバーです。ユーザーのリクエスト(80、443ポート)を直接受ける「ドアマン」の役割をし、内部で実際のビジネスロジックを処理する Spring Boot アプリケーション(8080ポート)にリクエストを安全に転送する**リバースプロキシ(Reverse Proxy)**として主に活躍します。
- なぜ必要か?:
- 性能と負荷分散: 静的ファイル(画像、CSS など)は Nginx が高速に処理し、動的な API リクエストだけを Spring Boot サーバーに渡して負荷を軽減します。複数の Spring Boot サーバーにリクエストを分散(ロードバランシング)することもできます。
- セキュリティ: アプリケーションサーバー(WAS)を外部に直接露出しないためセキュリティが向上します。
- 無停止デプロイ: デプロイ時に Nginx がトラフィックを旧バージョンのアプリから新バージョンのアプリへ段階的に切り替えることでサービスを中断せずにデプロイが可能です。
17. リモートアクセスとセキュリティ(SSH)#
サーバールーム(データセンター)に直接行かなくても、自宅やカフェからサーバーコンピューターを制御する技術です。
17.1. SSH(Secure Shell)の概念#
- Linuxサーバー管理の標準です。すべてのデータが暗号化されて送信されるため安全です。
- SSH Server: 制御されるコンピューター(サーバー)にインストール(
openssh-server)。 - SSH Client: 制御するコンピューター(自分のMacBook/ノートPC)にインストール。
17.2. 接続方法#
- 基本コマンド:
ssh [ユーザーID]@[サーバーIP]ssh ubuntu@192.168.0.65 - ポート指定: セキュリティのためにデフォルトポート(22)を別の番号に変えた場合は
-pオプションを使います。ssh -p 2222 ubuntu@192.168.0.65
バックエンド開発者 Tip: パスワードの代わりに「キーファイル(.pem)」を使用 実務(AWSなど)ではセキュリティ上パスワードログインを無効にして、**SSH キーファイル(Key Pair)**を使います。
# -i オプションでキーファイルを指定 ssh -i my-key.pem ubuntu@3.12.34.56このときキーファイルの権限は必ず
400(chmod 400 my-key.pem)である必要があります。(あまりにも公開された権限だとSSHが接続を拒否する)
18. ポート、ファイアウォールと外部アクセス#
「サーバーを起動したのに外部からアクセスできません!」という問題の99%はこの部分の設定問題です。
18.1. ポート(Port)とは?#
IPがコンピューター(建物)を見つけるアドレスなら、ポートはその中の**プログラム(部屋番号)**を見つけるアドレスです。(0〜65535番)
主要ポート(Well-Known Ports):
- 22: SSH(リモートアクセス)
- 80: HTTP(Web)
- 443: HTTPS(セキュアWeb)
- 3306: MySQL / MariaDB
- 5432: PostgreSQL
- 6379: Redis
- 8080: Tomcat、Spring Boot などWASの代替/開発用ポート
1つのポートは1つのプログラムだけが使用できます。(すでに80番をApacheが使っていればNginxは80番を使えない)
ポート使用確認: 特定のポート(例:8080)を誰が使っているか知りたい場合は
sudo ss -ltnp | grep 8080またはsudo lsof -i :8080で確認します。Spring Bootサーバーが立ち上がらなかったりポートの衝突が起きるときに最初に確認してください。
18.2. ファイアウォール(Firewall)#
サーバーへのネットワークトラフィックを制御するセキュリティシステムで、許可されたポート以外はすべてのアクセスをブロックします。外部アクセス問題のもう1つの主な原因です。
ufw(Ubuntu基本ファイアウォール)コマンド:# ファイアウォールを有効化 sudo ufw enable # ファイアウォールの状態を確認 sudo ufw status # 特定のポートを許可(Nginx、SSH、Spring Boot App) sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 22/tcp sudo ufw allow 8080/tcp # ルールの削除 sudo ufw delete allow 8080/tcp
18.3. ポートフォワーディング(Port Forwarding)#
ルーターを使う環境(自宅、オフィス)で外部アクセスを可能にする技術です。
- 問題: 外部からはルーターの公開IPまでしかアクセスできず、自分のコンピューターのプライベートIP(
192.168...)には入ってこれません。 - 解決: ルーターに道標を立てます。
- 「外部から公開IPの9000番ポートに入ってきたら -> 自分のコンピューター(192.168.0.65)の8080番ポートに接続してください!」
18.4. 設定とテストの手順#
- ファイアウォールの確認: サーバー自体のファイアウォール(
ufwなど)が望むポート(例:80、8080)を許可しているか確認します。 - ルーターの設定ページへアクセス: 通常
192.168.0.1などのアドレスで接続(Default Gatewayを確認)。 - NAT/ポートフォワーディングの設定:
- 内部IP: サーバーコンピューターのプライベートIP
- 外部ポート:
9000(外部に公開する番号) - 内部ポート:
8080(実際のサーバープログラムのポート)
- 接続テスト: スマートフォン(LTE/5Gモード)で
http://[自分の公開IP]:9000にアクセスを試みる。(Wi-Fi環境ではテストがうまくできない場合がある)
バックエンド開発者 Tip: クラウドとDocker
- クラウド(AWS、GCP、Azureなど): クラウド環境ではルーターの代わりに**「セキュリティグループ(Security Group)」や「ファイアウォールルール(Firewall Rules)」でインバウンド(Inbound)ルール**を設定してあげることで外部アクセスが可能になります。(例:80、443、22、8080ポートを許可)
- Docker:
docker run -p 8080:8080 my-appでの-pオプションがまさにポートフォワーディングの概念です。「ホスト(Linux)サーバーの8080番ポートに入ったリクエストを -> コンテナ内部の8080番ポートに接続せよ」という意味です。
