Skip to content

Commit 0b9bb2e

Browse files
committed
実行ユーザーの既定を uid 10001 にする
これまでは node イメージが持つ node ユーザー(uid 1000)で動かしていた。 1000 はホストの1人目のユーザーに払い出される番号なので、万一コンテナから 抜け出されたときにそのユーザーのファイルを触れる立場になる。10001 なら ホストの誰でもなく、chown で渡した data/ しか触れない。 - イメージに uid/gid 10001 の app ユーザーを作り、USER をそれに変える - HOME=/home/app を 1777 で用意する。.env で別の uid を指定されたときに /etc/passwd に載らないユーザーになり、HOME が / に落ちて書けなくなる (pihole-monitor で踏んだ) - data/ はホストから見て「知らないユーザー」の持ち物になる。読む(バック アップにコピーする)のはできるが、書き戻しには sudo が要る —— 手元で 直接触りたいホストは .env の TRAVEL_LOG_UID / TRAVEL_LOG_GID を使う Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent edbc7da commit 0b9bb2e

5 files changed

Lines changed: 30 additions & 13 deletions

File tree

.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
# このファイルをコピーして .env.local を作成し、値を設定してください。
55

66
# データの置き場(data/)に書き込むユーザー。docker-compose.yml の app がこの
7-
# ユーザーで動く。`id -u` / `id -g` が 1000 以外のホストでだけ設定すればよい
7+
# ユーザーで動く(既定 10001 = ホストに実在しない番号)。data/ をホストから
8+
# 直接編集・書き戻ししたいときだけ `id -u` / `id -g` を設定する
89
# (合っていないと写真の保存に失敗する)。
910
#TRAVEL_LOG_UID=1000
1011
#TRAVEL_LOG_GID=1000

Dockerfile

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,23 @@ COPY --from=builder /app/db/migrations ./db/migrations
3838
COPY --from=builder /app/scripts/migrate.mjs ./scripts/migrate.mjs
3939
# 写真とエクスポートの置き場。実運用ではホストのディレクトリを bind マウントするが、
4040
# マウントせずに動かしたときも非 root で書けるように用意しておく
41-
RUN mkdir -p /app/photos /app/exports && chown -R node:node /app/photos /app/exports /app/.next
41+
# 実行ユーザーは **ホストに実在しない uid 10001**。node イメージが持つ node ユーザーは
42+
# uid 1000 = ホストの1人目のユーザーの番号で、それで動かすと万一コンテナから
43+
# 抜け出されたときにそのユーザーのファイルを触れる立場になる。10001 ならホストの
44+
# 誰でもなく、chown で渡した data/ しか触れない
45+
RUN addgroup -g 10001 app && adduser -S -D -G app -u 10001 -h /home/app app \
46+
&& mkdir -p /app/photos /app/exports \
47+
&& chown -R 10001:10001 /app/photos /app/exports /app/.next /home/app \
48+
&& chmod 1777 /home/app
4249
# 待ち受けポート。standaloneのserver.jsはPORT環境変数を読む(next dev/start側は
4350
# package.jsonのscriptsで-p 7040を指定していて、ここと両方を揃えて変えること)
4451
ENV PORT=7040
4552
EXPOSE 7040
46-
# root で動かさない。node:24-alpine が持つ node ユーザーは uid/gid とも 1000 で、
47-
# compose の user: の既定 (1000:1000) と一致する
48-
USER node
53+
# root で動かさない。compose の user: の既定 (10001:10001) と一致する。
54+
# HOME を 1777 で用意してあるのは、`.env` で別の uid を指定されたときに
55+
# /etc/passwd に載らないユーザーになり、HOME が / に落ちて書けなくなるため
56+
ENV HOME=/home/app
57+
USER 10001:10001
4958
# マイグレーションが失敗したら待ち受けに進まない(古いスキーマのままアプリが動くのを
5059
# 防ぐ)。exec で server.js を PID 1 にして、シグナルがそのまま届くようにする
5160
CMD ["sh", "-c", "node scripts/migrate.mjs && exec node server.js"]

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,12 @@ docker compose pull && docker compose up -d
170170
`photos/`(添付写真)・`exports/`(エクスポートのZIP)を`init`サービスが起動時に作る。
171171
**バックアップは`data/`をコピーすればよい**(停止してからコピーすること)。
172172
standaloneでもホストに用意するのは親ディレクトリ1つで、YAML冒頭の`x-data-dir`に書く
173-
- **`app`は非rootで動く**`data/`に書かれるファイルはホストのユーザー所有になり、
174-
既定は`1000:1000``id -u`が1000以外のホストでは`.env``TRAVEL_LOG_UID`/`TRAVEL_LOG_GID`
175-
設定する(standaloneはYAML冒頭の`x-run-as`)。所有者合わせは起動前に`init`
173+
- **`app`は非rootで動く**。既定は`10001:10001`で、**ホストに実在しない番号**にしてある
174+
(万一コンテナから抜け出されても、ホストのユーザーのファイルには届かない)。
175+
そのぶん`data/`はホストから見て「知らないユーザー」の持ち物になるので、
176+
**バックアップから書き戻すときやホストで直接編集したいときは**`.env`
177+
`TRAVEL_LOG_UID`/`TRAVEL_LOG_GID``id -u`/`id -g`を設定する
178+
(standaloneはYAML冒頭の`x-run-as`)。所有者合わせは起動前に`init`
176179
自動でやるので、`chown`を手で打つ必要はない
177180
- **置き場を`data/`にまとめる前から動かしているホストは、更新時に1回だけ移すこと。**
178181
`docker compose down`のあと:

docker-compose.standalone.example.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ x-data-volume: &data-volume "/path/to/travel-log/data:/data"
4444
# 上のディレクトリをホスト側で読み書きするユーザーの `id -u`:`id -g`。
4545
# app はこのユーザーで動くので、ここが合っていないと写真の保存に失敗する。
4646
# db は関係ない(postgresのエントリポイントが自分で所有者を揃える)
47-
x-run-as: &run-as "1000:1000"
47+
# **イメージ内の既定は 10001:10001**(ホストに実在しない番号)。data/ をホストから
48+
# 直接編集・書き戻ししたいときだけ `id -u`:`id -g` に書き換える
49+
x-run-as: &run-as "10001:10001"
4850

4951
# ---- ここだけ編集: アプリの設定(.env の代わり) ----
5052
# セッションCookieの署名鍵(必須)。32バイト程度のランダム文字列を入れる

docker-compose.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ services:
1515
- sh
1616
- -c
1717
- mkdir -p /data/db /data/photos /data/exports && chown -R "$$0" /data/photos /data/exports
18-
- ${TRAVEL_LOG_UID:-1000}:${TRAVEL_LOG_GID:-1000}
18+
- ${TRAVEL_LOG_UID:-10001}:${TRAVEL_LOG_GID:-10001}
1919
restart: "no"
2020

2121
db:
@@ -80,9 +80,11 @@ services:
8080
# db/も見えるが、postgresがPGDATAを0700で作るのでappのユーザーからは読めない
8181
- ./data:/data
8282
# data/に書かれるファイルをホストのユーザー所有にする。イメージの既定は
83-
# node(uid/gidとも1000)で、ホスト側の所有者と合わないとbindマウントに書けない。
84-
# id -u が1000以外のホストでは.envのTRAVEL_LOG_UID/GIDで合わせる
85-
user: "${TRAVEL_LOG_UID:-1000}:${TRAVEL_LOG_GID:-1000}"
83+
# 実行ユーザー。既定は 10001 = ホストに実在しない番号(抜け出されてもホストの
84+
# ユーザーのファイルに届かない)。そのぶん data/ はホストから見て「知らない
85+
# ユーザー」の持ち物になるので、手元で直接編集・書き戻ししたいホストでは
86+
# .env の TRAVEL_LOG_UID/GID に `id -u`/`id -g` を入れる
87+
user: "${TRAVEL_LOG_UID:-10001}:${TRAVEL_LOG_GID:-10001}"
8688
ports:
8789
- "7040:7040"
8890
restart: unless-stopped

0 commit comments

Comments
 (0)