演習進捗0 / 4未完了
⏱ 約 60 分
Part 4Chapter 01/サーバ構築

nginx を入れて、サービスの入口を公開する

外部へ直接出ない環境で nginx を導入し、プロセス・待受 port・別ノード応答・ログを別々の証拠として確認します。

教材 ✓ 公開中登録不要 実機演習 ― 提供していない読んで学べます
所要時間約 60 分(概念 15 分+演習 45 分)
前提知識Part 1 のパッケージ・ファイル・権限操作、Part 2 の IP・port・経路、Part 3 の systemd・journal と署名付き APT リポジトリの設定(Ch.6)
使用機材入口サーバ front01、操作端末 workstation01、署名済み内部 APT リポジトリ
関連章前: Part 3 / Chapter 7「バックアップとリストア」/後: Part 4 / Chapter 2「PostgreSQL を用意し、残高を安全に更新する」

「入っているものを回す」から「自分で入れて公開する」へ

Part 3 では、すでに導入されているサービスを起動し、状態とログを読み、変更後に復旧しました。Part 4 では一歩進み、必要なソフトウェアを取得して導入し、複数のサーバをつないで、ひとつのサービスを組み立てます。本章で作るのは、その最初の部品となる nginx(Web サーバのソフトウェア)の入口です。

演習環境のサーバは外部へ直接通信できません。そのため、インターネット上の配布元を前提にした素の apt update ではなく、署名済み内部 APT リポジトリを設定して取得経路を先に確認します。導入後は「プロセスが動いている」「port で待っている」「サーバ自身から応答する」「別ノードから届く」を別々に確かめます。

期待される出力
配布サーバ
    │ 公開鍵・InRelease
    │ Packages・.deb
    ▼
署名と hash を検証する APT
    │
    ▼
    front01
    ├─ nginx のプロセス
    ├─ HTTP の待受 port
    └─ access log
        ▲
        │ 別ノードから HTTP
 workstation01

この章のゴール: 外部へ直接出られない環境で nginx を導入し、プロセス・待受 port・ローカル応答・別ノード応答・ログを根拠に、入口が使える状態を説明できる。

この章で入れる nginx は、街の改札サービスの「入口」にあたります。街の全体像と、街の言葉・技術の言葉の対応は Part 0(この教材で作る街)にまとめています。

本章では、次の範囲は扱いません。

この章を終えるとできること

ひとつの HTTP 応答を、取得経路から別ノードの接続まで層ごとに確認できるようになります。本章で身につく 4 動作 は次のとおりです。

01
① 取得経路を確認する
署名済み内部 APT リポジトリを設定し、鍵・署名・取得元を確認する。
02
② nginx を導入する
apt update と apt install を実行し、取得元の証跡を残す。
03
③ プロセスと待受 port を確認する
systemctl status と ss -lntp を使い、動作中のプロセスと socket を対応づける。
04
④ 別ノードから到達を確認する
ローカルの curl と workstation01 からの curl を分けて実行し、access log と照合する。

入口を「動いている」だけで判断しない

1. 外部通信が閉じている環境:先に取得経路を組み立てる

apt は、package の一覧と本体を取得してから導入します。外部への通信が遮断された環境では、公開インターネット上の配布元へ直接つながることを前提にできません。そこで署名済み内部 APT リポジトリから、演習に必要な package を環境内の許可された経路で取得します。

ここで重要なのは、apt install nginx が成功したという結果だけではありません。公開鍵の fingerprint を別経路で照合し、Signed-By で信頼範囲を限定してから、apt update の URI と apt-cache policy で「どこから取得したか」を記録します。取得経路も、構築したサービスを説明する証拠のひとつです。

本章では、演習環境の署名済み内部 APT リポジトリ http://172.16.10.22/ubuntu を使います。公開鍵 fingerprint の正本 089E 07BD FFA2 6DB7 C720 3016 297F AD13 17CA 1DC4 は 教材の HTTPS ページ に掲載しています。

2. プロセスと port:働いている人と受付窓口

systemctl status nginx が示すのは、systemd が nginx のプロセスをどの状態として管理しているかです。一方、ss -lntp が示すのは、どのプロセスがどの TCP port で接続を待っているかです。

プロセスが active でも、期待した port で待っているとは限りません。逆に、目的の port が別のプロセスに使われている場合もあります。次のように、管理状態と通信の入口を分けて読みます。

期待される出力
systemctl status nginx ── プロセスは管理上どう見えるか
ss -lntp              ── どの port で誰が待っているか
curl                  ── HTTP の要求に応答できるか

3. ローカル応答と別ノード応答:確認している経路が違う

front01 上の curl http://localhost/ は、nginx が同じ OS の中からの要求へ応答できることを確認します。この確認は、nginx のプロセス、待受 port、HTTP 応答までを短い経路で調べるのに向いています。

しかし、ローカルで応答しただけでは、別の機械から届くことは証明できません。workstation01 から front01 へ接続すると、名前解決、送信元の経路、受信側 interface、途中の通信制御まで確認範囲が広がります。ローカル成功・別ノード失敗なら、nginx 本体だけでなく、待受アドレスやネットワーク経路を疑う必要があります。

4. ログ:同じ要求を異なる記録から読む

nginx の access log には、HTTP の要求を受けた記録が残ります。journalctl -u nginx には、nginx service の起動、停止、reload、失敗など、systemd が集めた記録が残ります。

同じ「nginx のログ」でも役割が違います。クライアントの要求が届いたかを調べるなら access log、service の起動や設定反映に失敗した理由を調べるなら journal、というように問いに合わせて選びます。

📔 コラム · 成功をひとつの表示だけで決めない

active、LISTEN、HTTP 応答は、どれも別の事実です。ひとつの表示を「全部正常」の意味に広げず、層ごとの観測を積み上げると、障害時にも同じ順序で切り分けられます。

演習:nginx の入口を導入して別ノードへ公開する

演習環境

項目値
構築対象front01
別ノード確認workstation01
接続方法workstation01 から ssh deployer@front01
必要権限sudo。APT 設定、package 導入、nginx 設定の変更に使う
パッケージ取得署名済み内部 APT リポジトリ(noble / part4)
所要時間約 45 分(STEP 1〜6 の実行)

🛟 失敗しても安全: front01 には変更前 snapshot が用意されている前提です。本章では VM や snapshot 自体を作りません。壊す操作は nginx の設定 1 か所に限定し、観測後に元へ戻します。演習終了時は基盤の手順で変更前 snapshot へ rollback し、導入物を残しません。

コマンド中のアドレスと接続名は、演習環境で受講者が実際に使う値です。

ほかの操作を始める前に、front01 で構築前の manifest(ファイルの場所・権限・更新日時などを一覧にしたもの)を採ります。対象は path・type・mode・uid・gid・size・mtime です。順に、場所・種別・権限・所有ユーザの番号・所有グループの番号・大きさ・更新日時です。章末に同じ条件でもう一度採り、既存の 3 分類の列挙後に差分を確認します。

bash · 構築前 manifest
# front01 で、章のほかの操作より先に実行する
sudo find /etc /var/lib /srv /opt /usr/local "$HOME" \
  -not -path '/var/lib/apt/*' \
  -not -path '/var/lib/dpkg/*' \
  -not -path '/var/lib/systemd/*' \
  -not -path '/var/log/*' \
  -not -path '/var/cache/*' \
  -not -name '.bash_history' \
  -not -path '/etc/passwd-' -not -path '/etc/group-' \
  -not -path '/etc/shadow-' -not -path '/etc/gshadow-' \
  -not -path '/var/lib/fwupd' -not -path '/var/lib/fwupd/*' \
  -not -path '/etc/fwupd' -not -path '/etc/fwupd/*' \
  -not -path '/var/lib/ucf' -not -path '/var/lib/ucf/*' \
  -not -path '/var/lib/landscape' -not -path '/var/lib/landscape/*' \
  -not -path '/etc/ld.so.cache' \
  -not -path '/var/lib/ubuntu-release-upgrader/release-upgrade-available' \
  -not -path '/var/lib/snapd/state.json' \
  -not -path '/var/lib/snapd/maintenance.json' \
  -not -path '/var/lib/logrotate/status' \
  -printf '%p\t%y\t%m\t%U\t%G\t%s\t%T@\n' 2>/dev/null \
  | LC_ALL=C sort \
  | sudo tee /tmp/part4-manifest-before.tsv >/dev/null

配布リポジトリを設定し、取得経路を確認する

Part 3 で学んだ署名付き内部 APT リポジトリの設定を、新しいサーバへ適用します。まず front01 へ接続し、配布サーバから公開鍵を取得します。鍵の取得元と信頼する根拠は分けます。

bash · コマンド
ssh deployer@front01
REPO_URI='http://172.16.10.22/ubuntu'
curl --fail --show-error --head "$REPO_URI/dists/noble/InRelease"
curl --fail --show-error "$REPO_URI/infra-study-archive-keyring.asc" \
  -o /tmp/infra-study-archive-keyring.asc
期待される出力
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Date: Sun, 16 Aug 2026 03:52:36 GMT
Content-Type: application/octet-stream
Content-Length: 2699
Last-Modified: Sun, 16 Aug 2026 01:35:52 GMT
Connection: keep-alive
ETag: "6a8113f8-a8b"
Accept-Ranges: bytes

curl の成功は HTTP で到達できたことだけを示し、署名の正しさは示しません。取得した鍵の fingerprint を表示し、教材の HTTPS ページに掲載された値と空白を除いた全桁で照合します。

bash · コマンド
GPG_HOME="$(mktemp -d)"
chmod 700 "$GPG_HOME"
gpg --homedir "$GPG_HOME" --show-keys --with-fingerprint --keyid-format long \
  /tmp/infra-study-archive-keyring.asc

EXPECTED_FINGERPRINT='089E07BDFFA26DB7C7203016297FAD1317CA1DC4'
ACTUAL_FINGERPRINT="$(gpg --homedir "$GPG_HOME" --show-keys --with-colons \
  /tmp/infra-study-archive-keyring.asc | awk -F: '$1=="fpr" {print $10; exit}')"
test "$ACTUAL_FINGERPRINT" = "$EXPECTED_FINGERPRINT"
fingerprint_status=$?
rm -rf -- "$GPG_HOME"
echo "fingerprint match=$fingerprint_status"
test "$fingerprint_status" -eq 0
期待される出力
gpg: directory '/home/deployer/.gnupg' created
gpg: keybox '/home/deployer/.gnupg/pubring.kbx' created
pub   ed25519/297FAD1317CA1DC4 2026-08-05 [SC] [expires: 2027-08-05]
      Key fingerprint = 089E 07BD FFA2 6DB7 C720  3016 297F AD13 17CA 1DC4
uid                            infra-study lab archive <archive@lab.invalid>

fingerprint match=0

小 STEP · 既存の取得先を確認し、変更せずに作業範囲を分ける

① 確認する。 配布リポジトリを追加する前に、現在有効な取得先を確認します。旧形式の /etc/apt/sources.list と、deb822 形式などを置く /etc/apt/sources.list.d/ の両方を見てください。片方だけでは設定を見落とします。

bash · コマンド
sudo grep -HnE '^[[:space:]]*(deb |Types:|URIs:)' \
  /etc/apt/sources.list \
  /etc/apt/sources.list.d/*.list \
  /etc/apt/sources.list.d/*.sources 2>/dev/null || true

② 作業範囲を分ける。 表示された source は OS や管理者が所有する既存設定です。本章では削除も改名もせず、章専用ディレクトリ /etc/apt/sources.list.d.part4/ に自分の source を作ります。後続の apt-get と apt-cache には、そのディレクトリだけを参照する指定を毎回渡します。

③ 変更していないことを確かめる。 既存 source はこの時点でも有効なままです。章末の manifest 差分で、既存の /etc/apt/sources.list と /etc/apt/sources.list.d/ が変更されていないことまで確認します。

期待される出力
/etc/apt/sources.list.d/ubuntu.sources:43:Types: deb
/etc/apt/sources.list.d/ubuntu.sources:44:URIs: http://archive.ubuntu.com/ubuntu
/etc/apt/sources.list.d/ubuntu.sources:51:Types: deb
/etc/apt/sources.list.d/ubuntu.sources:52:URIs: http://security.ubuntu.com/ubuntu

なぜ既存 source を無効化しないのか

これらはサーバを作ったときに設定された、OS や管理者が所有する取得先です。演習環境から外部へ直接通信できなくても、他者管理の設定を一時的に改名すると、その設定に依存する索引や cache を壊す可能性があります。本章の取得処理だけを章専用 source に限定すれば、既存設定に触れずに内部リポジトリを使えます。

ただし source を限定するだけでは不十分です。apt-get update は参照対象から外れた索引を掃除し、それに連動する AppStream の swcatalog も消します。そこで APT::Get::List-Cleanup=0 を同時に指定し、既存の索引を壊さないようにします。現場では、作業対象を限定するだけでなく、限定による副作用まで止めることが非干渉の条件です。

一致した鍵だけを keyring へ置き、deb822 形式の source を作ります。Signed-By は、このリポジトリに使う鍵を指定して信頼範囲を限定します。

bash · コマンド
sudo install -d -m 0755 /etc/apt/keyrings
sudo install -o root -g root -m 0644 \
  /tmp/infra-study-archive-keyring.asc \
  /etc/apt/keyrings/infra-study-archive-keyring.asc

sudo install -d -m 0755 /etc/apt/sources.list.d.part4
sudo tee /etc/apt/sources.list.d.part4/infra-study.sources > /dev/null <<EOF
Types: deb
URIs: $REPO_URI
Suites: noble
Components: part4
Architectures: amd64
Signed-By: /etc/apt/keyrings/infra-study-archive-keyring.asc
EOF

sudo chmod 0644 /etc/apt/sources.list.d.part4/infra-study.sources
cat /etc/apt/sources.list.d.part4/infra-study.sources

# 章専用 source だけを見る。既存の取得先と索引には触れない
APT_ONLY_PART4=(
  -o Dir::Etc::sourcelist=/dev/null
  -o Dir::Etc::sourceparts=/etc/apt/sources.list.d.part4
  -o APT::Get::List-Cleanup=0
)

sudo apt-get "${APT_ONLY_PART4[@]}" update
apt-cache "${APT_ONLY_PART4[@]}" policy nginx
期待される出力
-rw-r--r-- 1 root root 425 Aug 16 03:52 /etc/apt/keyrings/infra-study-archive-keyring.asc
Types: deb
URIs: http://172.16.10.22/ubuntu
Suites: noble
Components: part4
Architectures: amd64
Signed-By: /etc/apt/keyrings/infra-study-archive-keyring.asc

Get:1 http://172.16.10.22/ubuntu noble InRelease [2699 B]
Get:2 http://172.16.10.22/ubuntu noble/part4 amd64 Packages [14.5 kB]
Fetched 17.2 kB in 0s (117 kB/s)
Reading package lists...
Building dependency tree...
Reading state information...
All packages are up to date.
nginx:
  Installed: (none)
  Candidate: 1.24.0-2ubuntu7.15
  Version table:
     1.24.0-2ubuntu7.15 500
        500 http://172.16.10.22/ubuntu noble/part4 amd64 Packages

curl は HTTP 到達性、fingerprint の照合は鍵の同一性、APT は InRelease の署名、apt-cache policy は package の選択元を確認します。ひとつの成功表示を別の検査の代わりにせず、apt update が内部リポジトリの InRelease と Packages を取得し、署名 warning が無いことまで記録します。

nginx を取得して導入する

STEP 01 で確認した候補版の nginx を導入します。表示を流さず、exact version と取得元の component を記録してください。

bash · コマンド
APT_ONLY_PART4=(
  -o Dir::Etc::sourcelist=/dev/null
  -o Dir::Etc::sourceparts=/etc/apt/sources.list.d.part4
  -o APT::Get::List-Cleanup=0
)
sudo apt-get "${APT_ONLY_PART4[@]}" install nginx
期待される出力
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
  nginx-common
Suggested packages:
  fcgiwrap nginx-doc ssl-cert
The following NEW packages will be installed:
  nginx nginx-common
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 568 kB of archives.
After this operation, 1602 kB of additional disk space will be used.
Do you want to continue? [Y/n] Get:1 http://172.16.10.22/ubuntu noble/part4 amd64 nginx-common all 1.24.0-2ubuntu7.15 [44.9 kB]
Get:2 http://172.16.10.22/ubuntu noble/part4 amd64 nginx amd64 1.24.0-2ubuntu7.15 [523 kB]
debconf: unable to initialize frontend: Dialog
debconf: (Dialog frontend will not work on a dumb terminal, an emacs shell buffer, or without a controlling terminal.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (This frontend requires a controlling tty.)
debconf: falling back to frontend: Teletype
dpkg-preconfigure: unable to re-open stdin:
Fetched 568 kB in 0s (53.1 MB/s)
Selecting previously unselected package nginx-common.
(Reading database ...

(Reading database ... 106672 files and directories currently installed.)
Preparing to unpack .../nginx-common_1.24.0-2ubuntu7.15_all.deb ...
Unpacking nginx-common (1.24.0-2ubuntu7.15) ...
Selecting previously unselected package nginx.
Preparing to unpack .../nginx_1.24.0-2ubuntu7.15_amd64.deb ...
Unpacking nginx (1.24.0-2ubuntu7.15) ...
Setting up nginx-common (1.24.0-2ubuntu7.15) ...
debconf: unable to initialize frontend: Dialog
debconf: (Dialog frontend will not work on a dumb terminal, an emacs shell buffer, or without a controlling terminal.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (This frontend requires a controlling tty.)
debconf: falling back to frontend: Teletype
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.

Setting up nginx (1.24.0-2ubuntu7.15) ...
 * Upgrading binary nginx
   ...done.
Processing triggers for man-db (2.12.0-4build2) ...
Processing triggers for ufw (0.36.2-6) ...
debconf: unable to initialize frontend: Dialog
debconf: (Dialog frontend will not work on a dumb terminal, an emacs shell buffer, or without a controlling terminal.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (This frontend requires a controlling tty.)
debconf: falling back to frontend: Teletype

Running kernel seems to be up-to-date.

No services need to be restarted.

No containers need to be restarted.

No user sessions are running outdated binaries.

No VM guests are running outdated hypervisor (qemu) binaries on this host.

導入された package と候補版の情報も確認します。

bash · コマンド
APT_ONLY_PART4=(
  -o Dir::Etc::sourcelist=/dev/null
  -o Dir::Etc::sourceparts=/etc/apt/sources.list.d.part4
  -o APT::Get::List-Cleanup=0
)
dpkg-query -W -f='${Package}\t${Status}\t${Version}\n' nginx
apt-cache "${APT_ONLY_PART4[@]}" policy nginx
期待される出力
nginx	install ok installed	1.24.0-2ubuntu7.15
nginx:
  Installed: 1.24.0-2ubuntu7.15
  Candidate: 1.24.0-2ubuntu7.15
  Version table:
 *** 1.24.0-2ubuntu7.15 500
        500 http://172.16.10.22/ubuntu noble/part4 amd64 Packages
        100 /var/lib/dpkg/status

ここでの証拠は「コマンドが終了した」だけではありません。nginx が導入済みであることと、どの取得経路が選ばれたかの両方です。

systemd からプロセスの状態を読む

nginx package の導入後、systemd が service をどの状態として認識しているかを確認します。

bash · コマンド
systemctl status nginx --no-pager
systemctl is-active nginx
systemctl is-enabled nginx
期待される出力
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Sun 2026-08-16 03:52:39 UTC; 2s ago
       Docs: man:nginx(8)
    Process: 1636 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 1638 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 1664 (nginx)
      Tasks: 2 (limit: 2315)
     Memory: 1.7M (peak: 3.7M)
        CPU: 12ms
     CGroup: /system.slice/nginx.service
             ├─1664 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             └─1667 "nginx: worker process"
active
enabled

status は原因調査に使える詳細、is-active は現在動作中か、is-enabled は OS 起動時の自動起動設定を短く返します。同じ systemd の確認でも問いが違います。

service の起動記録も保存します。

bash · コマンド
sudo journalctl -u nginx --no-pager -n 30
期待される出力
Aug 16 03:52:39 front01 systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...
Aug 16 03:52:39 front01 systemd[1]: Started nginx.service - A high performance web server and a reverse proxy server.

ss -lntp で待受 port を確認する

次に、nginx のプロセスが TCP の待受 socket を持っているかを確認します。

bash · コマンド
sudo ss -lntp | grep nginx
期待される出力
LISTEN 0      511          0.0.0.0:80        0.0.0.0:*    users:(("nginx",pid=1667,fd=5),("nginx",pid=1664,fd=5))
LISTEN 0      511             [::]:80           [::]:*    users:(("nginx",pid=1667,fd=6),("nginx",pid=1664,fd=6))

systemctl status が active でも、この確認は省けません。Local Address:Port と users: を対応づけ、期待する HTTP port を nginx が使っていることを読み取ります。

ローカルと別ノードから同じ入口へ接続する

最初に front01 自身から HTTP 応答を確認します。

bash · コマンド
curl --fail --show-error --include http://localhost/
期待される出力
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Date: Sun, 16 Aug 2026 03:52:42 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Sun, 16 Aug 2026 03:52:38 GMT
Connection: keep-alive
ETag: "6a813406-267"
Accept-Ranges: bytes

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

この成功が示すのは、同じ OS 内で nginx まで届き、HTTP 応答を返せたことです。別ノードの経路はまだ通っていません。

別のターミナルで workstation01 を操作し、front01 の接続名へ要求を送ります。

bash · コマンド
curl --fail --show-error --include "http://front01/"
期待される出力
Server: nginx/1.24.0 (Ubuntu)
Date: Sun, 16 Aug 2026 03:53:03 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Sun, 16 Aug 2026 03:52:38 GMT
Connection: keep-alive
ETag: "6a813406-267"
Accept-Ranges: bytes

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

この要求は workstation01 からネットワークを通って front01 へ届きます。ローカルでは成功し、別ノードでは失敗する場合、nginx のプロセスだけでなく、名前解決、経路、待受アドレス、通信制御を調べる必要があります。

front01 に戻り、直前の要求がどこへ記録されたかを確認します。

bash · コマンド
sudo tail -n 20 /var/log/nginx/access.log
sudo journalctl -u nginx --no-pager -n 30
期待される出力
::1 - - [16/Aug/2026:03:52:42 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.5.0"
172.16.10.22 - - [16/Aug/2026:03:53:03 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/8.5.0"
Aug 16 03:52:39 front01 systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...
Aug 16 03:52:39 front01 systemd[1]: Started nginx.service - A high performance web server and a reverse proxy server.

HTTP 要求の記録は access log、service の起動や reload の記録は journal で確認します。両方を並べると、「要求が届かなかった」のか「service 自体が起動できなかった」のかを分けられます。

待受 port を誤らせて切り分ける + GOAL 🎯

待受 port を一時的に変更し、構文検査・service 状態・HTTP 接続がそれぞれ何を教えるかを比べます。 この STEP では、狙ったとおりに壊れないところから始めます。 そこが本題です。

まず、変更の対象になる行を探します。「listen 80 を含む行」を全部探してください。

bash · コマンド
grep -nE 'listen .*80 default_server;' /etc/nginx/sites-available/default
期待される出力
22:	listen 80 default_server;
23:	listen [::]:80 default_server;

見つかった行数を数えてください。 1 行だと思っていたなら、その思い込みがこの STEP の主題です。

変更前の構文検査を行い、ファイルを退避してから、まず 1 行だけを変えます。

bash · コマンド
sudo nginx -t
sudo cp /etc/nginx/sites-available/default /tmp/ch1-nginx-default.before
sudo sed -i 's/listen 80 default_server;/listen 8080 default_server;/' /etc/nginx/sites-available/default
sudo nginx -t
sudo systemctl reload nginx
期待される出力
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

入口を 8080 へ移したのだから、80 番への接続は失敗するはずです。確かめます。

bash · コマンド
curl --fail --show-error --include http://127.0.0.1/
期待される出力
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Date: Sun, 16 Aug 2026 03:53:06 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Sun, 16 Aug 2026 03:52:38 GMT
Connection: keep-alive
ETag: "6a813406-267"
Accept-Ranges: bytes

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

🔴 接続できてしまったら、そこから追う

失敗を期待した操作が成功したときは、期待のほうが間違っています。 設定を疑う前に、 いま実際に何番で待ち受けているかを見ます。

bash · コマンド
sudo ss -lntp | grep nginx
期待される出力
LISTEN 0      511          0.0.0.0:80        0.0.0.0:*    users:(("nginx",pid=1667,fd=5))
LISTEN 0      511          0.0.0.0:8080      0.0.0.0:*    users:(("nginx",pid=1973,fd=11),("nginx",pid=1664,fd=11))
LISTEN 0      511             [::]:80           [::]:*    users:(("nginx",pid=1973,fd=6),("nginx",pid=1667,fd=6),("nginx",pid=1664,fd=6))

待受の一覧には、まだ 80 番を持っている行が残っているはずです。理由は 2 つあります。

残っている理由内容性質
IPv6 の行を変えていない既定の設定には listen 80 の行が IPv4 用と IPv6 用の 2 つある。変えたのは片方だけ🔴 設定を直さない限り消えない
古いワーカーがまだ生きている設定の再読み込みは、処理中の接続を抱えたワーカーをその場で終わらせない一時的(やがて消える)

「1 か所直したから塞がった」と考えるのは危険です。 同じ役割の設定が複数の場所に書かれていれば、 片方だけ直しても効きません。そして片方を直したことで直した気持ちになるぶん、 最初から何もしていないより見つけにくくなります。

もう 1 行も変えて、今度こそ 80 番が閉じることを確かめます。

bash · コマンド
sudo sed -i 's/listen \[::\]:80 default_server;/listen [::]:8080 default_server;/' /etc/nginx/sites-available/default
sudo nginx -t
sudo systemctl reload nginx
sudo ss -lntp | grep nginx
curl --fail --show-error http://127.0.0.1/
期待される出力
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
LISTEN 0      511          0.0.0.0:8080      0.0.0.0:*    users:(("nginx",pid=1988,fd=11),("nginx",pid=1664,fd=11))
LISTEN 0      511             [::]:8080         [::]:*    users:(("nginx",pid=1988,fd=13),("nginx",pid=1664,fd=13))

curl: (7) Failed to connect to 127.0.0.1 port 80 after 0 ms: Couldn't connect to server

ここで 3 つの検査が何を示すかを比べます。

検査分かること分からないこと
nginx -t設定の文法が読めることその設定が意図どおりかどうか
systemctl statusプロセスが動いていること期待する port で応答するかどうか
curl実際に応答が返るかどうかなぜ返らないのか
ss -lntp実際に開いている port設定ファイルのどの行が原因か

どれか 1 つでは足りません。 構文が正しく、service が active でも、接続できないことがあります。

退避したファイルを戻し、修正後にも同じ確認をします。

bash · コマンド
sudo cp /tmp/ch1-nginx-default.before /etc/nginx/sites-available/default
sudo nginx -t
sudo systemctl reload nginx
systemctl status nginx --no-pager
curl --fail --show-error http://127.0.0.1/
sudo ss -lntp | grep nginx
sudo rm /tmp/ch1-nginx-default.before
期待される出力
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Sun 2026-08-16 03:52:39 UTC; 30s ago
       Docs: man:nginx(8)
    Process: 1636 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 1638 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 1999 ExecReload=/usr/sbin/nginx -g daemon on; master_process on; -s reload (code=exited, status=0/SUCCESS)
   Main PID: 1664 (nginx)
      Tasks: 3 (limit: 2315)
     Memory: 2.7M (peak: 3.9M)
        CPU: 29ms
     CGroup: /system.slice/nginx.service
             ├─1664 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             ├─1988 "nginx: worker process"
             └─2000 "nginx: worker process"

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
LISTEN 0      511          0.0.0.0:80        0.0.0.0:*    users:(("nginx",pid=2000,fd=7),("nginx",pid=1664,fd=7))
LISTEN 0      511          0.0.0.0:8080      0.0.0.0:*    users:(("nginx",pid=1988,fd=11))
LISTEN 0      511             [::]:80           [::]:*    users:(("nginx",pid=2000,fd=8),("nginx",pid=1664,fd=8))
LISTEN 0      511             [::]:8080         [::]:*    users:(("nginx",pid=1988,fd=13))

ゴール到達 ✓ ① LAN 内の取得経路を確認した / ② nginx を導入してプロセスと待受 port を対応づけた / ③ ローカルと別ノードの応答を分けて確認した / ④ 構文・service 状態・接続の 3 点で誤設定を切り分けて元へ戻した。

演習の証跡を保存したら、自分で追加した構築物を削除します。本章で導入した nginx と、依存で導入された nginx-common を名指しで purge します。apt autoremove は、章の外で auto 扱いになった package まで対象になり、clean snapshot の状態によって削除範囲が変わるため使いません。章専用 source ディレクトリ、keyring、一時取得ファイルも消します。既存の source は最初から変更していないため、復元処理や終了時の apt update は不要です。

purge の確認待ちに注意

apt purge は -y を付けないと [Y/n] の確認で止まり、その間は package 管理の lock を保持します。ここでは削除対象を nginx と nginx-common に名指ししたうえで -y を付け、確認待ちを発生させません。

bash · コマンド
sudo DEBIAN_FRONTEND=noninteractive apt purge -y nginx nginx-common
sudo rm -rf /etc/apt/sources.list.d.part4
sudo rm -f /etc/apt/keyrings/infra-study-archive-keyring.asc
rm -f /tmp/infra-study-archive-keyring.asc
分類検査すること合格条件
package本章で導入した nginx と nginx-commoninstall ok installed の package が残っていない
servicenginx service の状態演習用 service が稼働していない
socket本章で開いた待受 port演習用 port の待受がない
設定ファイル/etc/nginx など nginx が配置した設定本章で追加された path が残っていない
取得設定章専用 source と keyring本章で追加した取得設定が残っていない

3 分類の外を manifest 差分で確認する

package・service・socket の 3 分類を自分で列挙して検査したあと、その外側に残る変更を、構築前後の sorted manifest で確認します。差分は 3 分類を置き換えるものではなく、列挙から漏れた残留候補を見つける安全網です。全差分は /var/tmp/part4-chapter-manifest.diff に一時保存し、「残留候補」と「更新日時だけ変わった通常ファイル」に分けて全件を画面に表示してから削除します。途中で切りません。表示に失敗したときは、構築前・章末の manifest と差分ファイルを消さずに残し、理由を表示します。表示された理由を確かめるまで、後片付けへ進まないでください。

次の除外には、それぞれ理由があります。

  • /var/lib/apt/ は apt が索引を更新する場所で、章の作業とは無関係に必ず変わります。
  • /var/lib/dpkg/ は package 操作で更新される管理情報で、package 差分として別に判定します。
  • /var/lib/systemd/ は service の状態管理で更新される場所で、service・unit の分類として別に判定します。
  • /var/log/ は操作の証跡そのもので、コマンドを実行するだけでも変わります。
  • /var/cache/ は再生成できる一時的な cache で、章の構築物とは分けて扱います。
  • .bash_history は操作履歴として更新されるため、章が配置したファイルとは分けて扱います。
  • /var/lib/snapd/state.json・/var/lib/snapd/maintenance.json と /var/lib/logrotate/status は、snapd と logrotate が章と無関係に定期的に書き換える状態ファイルです。親ディレクトリは除外しません。

/var/lib/swcatalog/ は除外しません。限定した apt-get update に APT::Get::List-Cleanup=0 を付け、既存カタログを壊していないことを manifest 差分で確認します。

bash · manifest 差分
sudo find /etc /var/lib /srv /opt /usr/local "$HOME" \
  -not -path '/var/lib/apt/*' \
  -not -path '/var/lib/dpkg/*' \
  -not -path '/var/lib/systemd/*' \
  -not -path '/var/log/*' \
  -not -path '/var/cache/*' \
  -not -name '.bash_history' \
  -not -path '/etc/passwd-' -not -path '/etc/group-' \
  -not -path '/etc/shadow-' -not -path '/etc/gshadow-' \
  -not -path '/var/lib/fwupd' -not -path '/var/lib/fwupd/*' \
  -not -path '/etc/fwupd' -not -path '/etc/fwupd/*' \
  -not -path '/var/lib/ucf' -not -path '/var/lib/ucf/*' \
  -not -path '/var/lib/landscape' -not -path '/var/lib/landscape/*' \
  -not -path '/etc/ld.so.cache' \
  -not -path '/var/lib/ubuntu-release-upgrader/release-upgrade-available' \
  -not -path '/var/lib/snapd/state.json' \
  -not -path '/var/lib/snapd/maintenance.json' \
  -not -path '/var/lib/logrotate/status' \
  -printf '%p\t%y\t%m\t%U\t%G\t%s\t%T@\n' 2>/dev/null \
  | LC_ALL=C sort \
  | sudo tee /tmp/part4-manifest-after.tsv >/dev/null
sudo diff -u /tmp/part4-manifest-before.tsv /tmp/part4-manifest-after.tsv > /var/tmp/part4-chapter-manifest.diff
diff_rc=$?
if [ "$diff_rc" -le 1 ]; then
  if awk 'BEGIN { FS = "\t"; c = "LC_ALL=C sort" }
      /^\+\+\+|^---|^@@/ { next }
      /^[+-]/ {
        if (NF != 7) { printf "manifest の列数が 7 ではありません: %s\n", $0 > "/dev/stderr"; bad = 1; exit 2 }
        t++; s = substr($1, 1, 1); p = substr($1, 2)
        k = $2 " " $3 " " $4 " " $5 " " ($2 == "d" ? "-" : $6)
        if (s == "-") { if (p in b) { dup = p; exit 2 } b[p] = k; bm[p] = $7; bt[p] = $2 }
        else          { if (p in a) { dup = p; exit 2 } a[p] = k; am[p] = $7 }
      }
      END {
        if (bad) exit 2
        if (dup != "") { printf "同じパスが重複しています: %s\n", dup > "/dev/stderr"; exit 2 }
        print "== 残留候補(0 件で合格)=="
        n = 0
        for (p in b) {
          if (!(p in a)) { print "消えた   " p | c; n++ }
          else if (a[p] != b[p]) { print "変わった " p "  (" b[p] " -> " a[p] ")" | c; n++ }
        }
        for (p in a) if (!(p in b)) { print "増えた   " p | c; n++ }
        fflush(); close(c)
        print "残留候補: " n " 件"
        print "== 更新日時だけ変わった通常ファイル(1 件ずつ理由を説明できること)=="
        m = 0; d = 0
        for (p in b) if ((p in a) && a[p] == b[p] && am[p] != bm[p]) { if (bt[p] == "d") d++; else { print p | c; m++ } }
        fflush(); close(c)
        print "更新日時だけ変わった通常ファイル: " m " 件 / ディレクトリ: " d " 件"
        print "差分行総数: " (t + 0)
      }' /var/tmp/part4-chapter-manifest.diff; then
    sudo rm -f /tmp/part4-manifest-before.tsv /tmp/part4-manifest-after.tsv
  else
    echo "差分の表示に失敗しました。構築前・章末の manifest と /var/tmp/part4-chapter-manifest.diff は残してあります。表示された理由を確認してください" >&2
  fi
else
  echo "差分を採れませんでした(diff の終了コード $diff_rc)。構築前 manifest /tmp/part4-manifest-before.tsv があるか確認してください" >&2
fi
bash · 差分証跡の後片付け
sudo rm -f /var/tmp/part4-chapter-manifest.diff
test ! -e /var/tmp/part4-chapter-manifest.diff

表示は 2 つの節に分かれます。合格の条件は、1 つ目の「残留候補」が 0 件であることです。残留候補は、構築前になかったパスが増えた、あったパスが消えた、種別・権限・所有者・サイズが変わった、のいずれかです(ディレクトリのサイズは比べません)。

2 つ目の「更新日時だけ変わった通常ファイル」は、中身の属性は同じで更新日時だけが違うファイルです。ここに出る行は 1 件ずつ、次のどちらかで説明できなければ完了にしません。

  • OS の自動処理(package 索引の更新、通知用の記録など)が書いたもの。
  • 章の操作の跡で、中身は戻っているもの。

どちらでも説明できない行が 1 件でもあれば、それは自分が挙げた 3 分類の外側にある残留です。何の分類にあたるかを考えて「4 番目の分類」を自分の後片付け手順へ足し、解消後に再確認してください。

期待される出力
(形の例です。M・K・T には実行したときの件数が入ります。更新日時だけ変わった通常ファイルの行と件数は、台・章によって変わります。合格の条件は「残留候補: 0 件」です)
== 残留候補(0 件で合格)==
残留候補: 0 件
== 更新日時だけ変わった通常ファイル(1 件ずつ理由を説明できること)==
(該当するパスが 1 行ずつ並びます)
更新日時だけ変わった通常ファイル: M 件 / ディレクトリ: K 件
差分行総数: T
bash · コマンド
if dpkg-query -W -f='${db:Status-Abbrev}\t${binary:Package}\n' nginx nginx-common 2>/dev/null | grep -q '^ii'; then
  echo "対象 package が残っています"
else
  echo "対象 package なし"
fi
if systemctl is-active --quiet nginx; then
  echo "nginx service 稼働中"
else
  echo "nginx service は非稼働"
fi
if sudo ss -lntp | grep -q ':80 '; then
  echo "80 番の待受あり"
else
  echo "80 番の待受なし"
fi
nginx_paths=(/etc/nginx /etc/default/nginx /etc/init.d/nginx /etc/logrotate.d/nginx)
nginx_path_left=0
for path in "${nginx_paths[@]}"; do
  if sudo test -e "$path"; then
    echo "残留 path: $path"
    nginx_path_left=1
  fi
done
[ "$nginx_path_left" -eq 0 ] && echo "nginx 設定 path なし"
test ! -e /etc/apt/sources.list.d.part4
test ! -e /etc/apt/keyrings/infra-study-archive-keyring.asc
test ! -e /tmp/infra-study-archive-keyring.asc
合格時に確認する表示(実機出力は要再採取)
対象 package なし
nginx service は非稼働
80 番の待受なし
nginx 設定 path なし

この演習環境は、セッションが終わると基盤側の手順で初期状態へ戻ります。ただし、戻ることを当てにして消さずに終えるのではなく、自分が作ったものを自分で消し、消えたことを確認するところまでが演習です。

つまずきポイント

原因を探すときは、最初に nginx -t、次に systemctl status nginx、最後に curl と ss -lntp で接続経路を確認します。この順序なら、設定の文法、service の状態、通信の入口を混ぜずに調べられます。

ハマり #1 · nginx -t が構文エラーになる

設定変更後に構文検査が失敗した状態です。この段階では reload を続けません。

bash · コマンド
sudo nginx -t
期待される出力
2026/08/16 03:53:09 [emerg] 2014#2014: invalid parameter "listen" in /etc/nginx/sites-enabled/default:23
nginx: configuration file /etc/nginx/nginx.conf test failed
  • 原因: ディレクティブ名、区切り、波括弧など、nginx が設定を解釈できない箇所があります。
  • 対処: エラーに表示されたファイルと行を確認し、直前に変更した 1 か所を元へ戻します。再度 sudo nginx -t が成功するまで reload しません。
ハマり #2 · service は active なのに接続できない

systemctl status nginx はプロセスの管理状態を示しますが、期待する port で待っていることや、別ノードから到達できることまでは示しません。

bash · コマンド
sudo nginx -t
systemctl status nginx --no-pager
sudo ss -lntp | grep nginx
curl --fail --show-error http://127.0.0.1/
期待される出力
curl: (7) Failed to connect to 127.0.0.1 port 80 after 0 ms: Couldn't connect to server
LISTEN 0      511          0.0.0.0:8080      0.0.0.0:*    users:(("nginx",pid=2028,fd=11),("nginx",pid=1664,fd=11))
LISTEN 0      511             [::]:8080         [::]:*    users:(("nginx",pid=2028,fd=12),("nginx",pid=1664,fd=12))
  • 原因: listen の port またはアドレスが、クライアントが接続する入口と一致していない可能性があります。
  • 対処: ss -lntp で nginx の待受を確認し、クライアントが指定した接続先と照合します。設定を修正したら nginx -t、reload、curl の順で再確認します。
ハマり #3 · ローカルでは成功するが workstation01 から失敗する

nginx 自体は HTTP 応答を返せています。失敗しているのは、別ノードから front01 までの追加経路です。

  • 原因: 名前解決、経路、受信側の待受アドレス、途中の通信制御のどこかがローカル確認と異なります。
  • 対処: front01 の ss -lntp、workstation01 側の名前解決と接続先、access log に要求が残ったかを順に確認します。access log に記録がなければ、HTTP 要求は nginx まで届いていません。

AI に相談

AInginx の導入と接続確認の詰まりを質問できます
この章の APT・systemd・待受 port・curl・ログを前提に答えます

修了確認

問 1 · なぜ取得経路を先に確認するのか

外部へ直接通信できない演習環境で、apt install nginx より前に HTTP 到達性、fingerprint、署名、選択元を分けて確認する理由を説明してください。

問 2 · systemctl status と ss -lntp は何が違うか

systemctl status nginx が active なら、なぜ ss -lntp も確認する必要があるのでしょうか。

問 3 · ローカル成功だけでは足りない理由

front01 上の curl http://localhost/ が成功しました。それでも workstation01 からの curl を行う理由を、確認する経路の違いから説明してください。

問 4 · 3 点で原因を切り分ける

nginx -t は成功し、systemctl status nginx は active ですが、curl http://127.0.0.1/ は失敗しました。最初に何を確認し、どのような原因を疑いますか。

段階ヒント(問 1〜問 4)

問 1 のヒントと答え

ヒント 1 段 · 軽く方向だけ

package を「入れられるか」だけでなく、「どこから取るか」に注目してください。

ヒント 2 段 · 確認する表示

curl --head は配布リポジトリまでの HTTP 到達性、fingerprint は鍵の同一性、APT は InRelease の署名、apt-cache policy は package の選択元を確認します。

答えを見る

外部の配布元へ直接通信できないため、署名済み内部リポジトリへ到達でき、別経路で照合した鍵による署名検証が成功し、APT がそのリポジトリの part4 component を選んだことを先に確認します。導入が成功したかだけでなく、信頼した取得元から選んだことを証跡に残すためです。

問 2 のヒントと答え

ヒント 1 段 · 軽く方向だけ

「プロセスの管理状態」と「通信を待つ窓口」は同じ情報ではありません。

ヒント 2 段 · 具体的なコマンド

systemctl status nginx の Active: と、sudo ss -lntp | grep nginx の待受 port・プロセス名を対応づけます。

答えを見る

systemctl status は systemd が nginx のプロセスをどう管理しているかを示します。ss -lntp は nginx がどのアドレスと TCP port で接続を待っているかを示します。active でも期待する port にいない可能性があるため、両方が必要です。

問 3 のヒントと答え

ヒント 1 段 · 軽く方向だけ

localhost の要求は front01 の外へ出ません。

ヒント 2 段 · 比べる観測点

別ノード確認では、名前解決、送信経路、受信 interface、通信制御、access log まで確認範囲に入ります。

答えを見る

ローカルの成功は、同じ OS 内で nginx が応答できることだけを示します。workstation01 からの要求はネットワークを通るため、別ノードから入口までの経路も成立していることを確認できます。ローカル成功だけでは外部のクライアントから届くことを証明できません。

問 4 のヒントと答え

ヒント 1 段 · 軽く方向だけ

構文とプロセスが正常なら、次は接続先と実際の待受を比べます。

ヒント 2 段 · 具体的なコマンド

sudo ss -lntp | grep nginx を実行し、curl が接続した IPv4 の HTTP port と一致するか確認します。

答えを見る

最初に ss -lntp で nginx の待受アドレスと port を確認します。nginx -t の成功は構文が正しいこと、active はプロセスが動いていることしか示しません。期待する IPv4 の HTTP port と listen 設定がずれている、または別のアドレスだけで待っている可能性を疑います。

データを持つサービスへ

本章で HTTP の入口はできましたが、まだ要求に応じて読み書きするデータを持っていません。次章では PostgreSQL(データベース管理システム)と共有領域を用意し、入口の先に置くサービスが残高を安全に更新するためのデータ層を組み立てます。

Chapter 2: PostgreSQL と共有領域を用意し、残高を安全に更新する

  • transaction(複数の更新を一体として確定する仕組み)で残高更新をまとめる
  • 同じ処理の再送と競合を安全に扱う
  • DB と共有ファイルの役割を分ける

参考資料