Linux & Docker

Linuxファイル権限入門|chmod・chownの使い方

更新: 佐々木 まい
Linux & Docker

Linuxファイル権限入門|chmod・chownの使い方

Linuxの権限は、ls -l の10文字表示と 644・755・777 の意味がつながった瞬間に、一気に見通しがよくなります。この記事は、chmod と chown の違いがまだ曖昧な人や、

Linuxの権限は、ls -l の10文字表示と 644・755・777 の意味がつながった瞬間に、一気に見通しがよくなります。
この記事は、chmodchown の違いがまだ曖昧な人や、Raspberry PiやWebサーバーで Permission denied に何度も止められてきた人に向けて、権限まわりを実例つきで整理する内容です。
筆者もRaspberry Piで Web 公開用ディレクトリを整えたときに、書き込みが必要な uploads だけを 775 にし、所有グループを www-data に変更して運用を安定させました。
何でも 777 にする近道より、owner・group・others の3区分、umask、ACL、SELinux の役割を順に押さえるほうが、原因の切り分けも設定の再現も楽になります。
Red Hatの権限解説や RHEL のドキュメントに沿って、ディレクトリの x 権限の意味と再帰変更の安全な進め方を整理します。
この記事ではさらに、スクリプト実行や Web 公開で詰まりやすいポイントまで順に解説します。
読後は、権限エラーを「とりあえず sudo」や「とりあえず 777」で済ませず、自分で原因を切り分けて直せるようになることを目標にしています。

Linuxファイル権限の基本:まず ls -l の表示を読めるようになる

Linux環境でのDocker開発とターミナルコマンド実行の実践的なセットアップシーン。

ls -lの10文字の読み方

ls -l を実行したとき、まず読めるようになりたいのが先頭の10文字です。
たとえば -rw-r--r--drwxr-xr-x の部分です。
ここには、その項目が何の種類なのかと、誰にどの権限があるのかがまとまって入っています。
10文字の内訳は、先頭1文字がファイル種別、残り9文字が権限です。
権限の9文字は3文字ずつに区切って、owner、group、othersの順に並びます。
それぞれは所有者、所有グループ、その他を表します。
『Linux ファイルのアクセス権について』でも、この3区分で考えるのが基本だと整理されています。
たとえば -rw-r--r-- は、先頭の - が通常ファイル、続く rw- が所有者、次の r-- がグループ、最後の r-- がその他です。
つまり所有者は読み取りと書き込みができ、グループとその他は読み取りだけできます。
これが数値表記の 644 に対応します。
6rw-4r-- です。
drwxr-xr-x なら、先頭の d がディレクトリです。
所有者の rwx は読み取り・書き込み・実行、グループとその他の r-x は読み取りと実行を表します。
これが 755 です。
7rwx5r-x と読めます。
数字だけで見ていたときは暗号に見えても、3文字ずつに分けると急に意味が見えてきます。

Linux ファイルのアクセス権について www.redhat.com

ファイル種別(-, d, l)の意味

先頭1文字は権限そのものではなく、その項目の種別です。
この記事の範囲でまず押さえたいのは -dl の3つです。
- は通常ファイルです。
テキストファイル、設定ファイル、シェルスクリプトなどがここに入ります。
d はディレクトリです。
フォルダと思って差し支えありません。
l はシンボリックリンクで、別のファイルやディレクトリを指す参照です。
たとえば lrwxrwxrwx のような表示を見ると、全部許可されている危険な状態に見えることがあります。
ただ、シンボリックリンクの権限表示は、そのまま通常ファイルと同じ感覚で解釈しないほうがいい場面があります。
リンク自体の扱いは man ページの説明を見ながら判断するのが確実です。
chmod でもシンボリックリンクに対する挙動は通常ファイルと同じとは限らず、再帰処理では無視される動きに出会うことがあります。
ここで大事なのは、先頭が d なら「中に項目を持つ箱」、- なら「中身そのもの」、l なら「参照先を持つ案内板」と認識することです。
この区別を意識すると、同じ 755 でもファイルとディレクトリで意味が少し変わる理由がつかめます。

r/w/xとディレクトリxの違い

r は read、w は write、x は execute です。
数値モードでは r=4w=2x=1 なので、足し算で 644755 を表せます。
たとえば所有者に rw- を与えるなら 4+26rwx なら 4+2+17 です。
通常ファイルでは、r は内容を読む、w は内容を書き換える、x は実行する、という理解でほぼそのまま通ります。
シェルスクリプトに x がないと ./script.sh で直接実行できないのはこのためです。
一方で、ディレクトリの x は「実行」ではありません。
ここが初心者が最初に引っかかる判断材料になります。
『RHEL 9のファイルシステム権限管理』でも、ディレクトリの execute 権限は、そのディレクトリに入るため、たどるための権限として説明されています。
つまり cd できるか、パスを通って目的のファイルに到達できるかに効きます。
この違いを知らないと、「ファイル自体には権限があるのに開けない」「存在しているのに Permission denied になる」という現象が理解できません。
筆者も以前、SSH で入った先で特定の作業ディレクトリにだけ cd できず、最初はそのディレクトリ自身の設定ばかり見ていました。
実際の原因は親ディレクトリのひとつに x がなく、そこを通れなかったことでした。
ディレクトリ権限は目的地だけでなく、そこへ至る途中の階層すべてが関係します。
読み取り権との違いも押さえておきたいところです。
ディレクトリの r は中身の一覧を見る権限、x は中へ入る・名前解決のために通過する権限です。
r があっても x がなければ扱いにくく、x があっても r がなければ一覧表示は制限されます。
ファイルの x とディレクトリの x を同じ「実行」と受け取ると、ここで必ず混乱します。

ℹ️ Note

[!WARNING] 755 がディレクトリでよく使われるのは、所有者は管理でき、グループとその他は中へ入って読めるからです。通常ファイルまで同じ感覚で 755 にすると、設定ファイルや HTML にまで実行権が付くことがあります。

docs.redhat.com

statとnamei -lで深掘り確認

ls -l は入口として優秀ですが、見た目だけでは切り分けきれない場面もあります。
そういうときに便利なのが statnamei -l です。
stat は、シンボリック表記と数値表記を並べて確認したいときに役立ちます。
たとえば次のように見ると、-rw-r--r--0644 が同じ内容だと一度でつながります。

stat file.txt

環境によって表示は少し変わりますが、モードの欄にシンボリック表記と8進数の両方が出ます。
chmod 644 file.txt の結果を確認するときにも、頭の整理に向いています。
パスの途中で詰まっていないかを見るには namei -l が便利です。
これは /a/b/c のようなパスを、階層ごとに分解して権限を表示してくれます。

namei -l /path/to/target

筆者がSSH先で cd できなかったときも、原因特定に効いたのはこれでした。
目的のディレクトリだけを ls -ld しても異常が見えず、namei -l で親を順番に追ったところ、中間のディレクトリに x が欠けていました。
こういうケースは、対象だけ見ていると見落とします。
ls -l は「今見えている1点」を読む道具、stat は「その1点を数値まで含めて確認する」道具、namei -l は「そこへ至る道筋を分解する」道具、と分けて覚えると混乱しません。
権限エラーの切り分けでは、この3つを行き来するだけで見える景色がずいぶん変わります。

chmodとは何か:数値モードとシンボリックモードの使い分け

chmod ファイル権限 数値モード シンボリックモード Linux Unix rwx オクタル表記 所有者 グループ その他 パーミッション設定 コマンドライン

chmod は、ファイルやディレクトリのモード(rwx で表す権限)を変更するコマンドです。
権限は owner、group、others の3区分で管理され、それぞれ所有者、所有グループ、その他を指します。
ここに対して「読む」「書く」「実行する」をどう許可するかを設定します。
Red Hatの『Linux ファイルのアクセス権について』でも、この考え方が Linux 権限の基本として整理されています。
chmod には大きく分けて、数値でまとめて指定する方法と、記号で差分を指定する方法があります。
設定ファイルを 644 にしたい、スクリプトに実行権だけ足したい、といった場面で使い分けると混乱しません。

数値モードの考え方

数値モードは、r=4w=2x=1 を足し算して、owner / group / others の3桁で表します。
まずはこの対応だけ押さえると、644755 が文字列ではなく意味のある数として読めるようになります。

権限
r4
w2
x1

たとえば owner に読み書きを許可するなら 4 + 2 = 6、読み書き実行を全部許可するなら 4 + 2 + 1 = 7 です。
これを3区分ぶん並べるので、644 は owner が 6、group が 4、others が 4 という意味になります。
代表的な2つを文字列に直すと次の対応です。

数値文字列表記よくある用途
644rw-r--r--設定ファイル、テキスト、公開読み取りだけの通常ファイル
755rwxr-xr-x実行スクリプト、公開ディレクトリ

実際のコマンドはこう書きます。

chmod 644 file
chmod 755 dir

chmod 644 file は、所有者だけ書き込み可能で、グループとその他は読み取りのみです。
設定ファイルやソースコードなど、実行する必要がない通常ファイルによく使います。
反対に chmod 755 dir は、所有者がフル権限、他のユーザーは読み取りと通過が可能な状態です。
ディレクトリでは x が「中へ入る・たどる」権限として働くので、公開用ディレクトリで見かけることが多い値です。
ここで引っかかりやすいのが、ファイルとディレクトリに同じ 755 を付ければよいわけではないことです。
ディレクトリに 755 は自然でも、設定ファイルまで 755 にすると不要な実行権が付きます。
ラズパイで Web アプリやシェルスクリプトを触っていると、配下をまとめて chmod -R 755 して動いたものの、あとで「設定ファイルにも x が付いていた」と気づくことがよくあります。
数値モードは一括で揃える力が強いぶん、対象の種類を見て使い分ける必要があります。
なお、新規作成ファイルが 644、新規ディレクトリが 755 になる場面をよく見かけます。
これは基準値と umask の組み合わせによるものです。
Red Hatの『RHEL 9 ファイルシステム権限管理』でも、umask 022 なら新規ファイルが 644、新規ディレクトリが 755 になると説明されています。

シンボリックモード

symbolic mode chmod 記号表記 ファイル権限 Linux rwx ugoa 所有者 グループ その他 パーミッション設定 シェルコマンド

シンボリックモードは、今ある権限に対して誰に、何を、どう変更するかを記号で書く方法です。
全部を数値で上書きするのではなく、「実行権だけ足す」「group と others の書き込みだけ外す」といった差分操作に向いています。
基本の記号は次の通りです。

  • u は user(所有者)
  • g は group(所有グループ)
  • o は others(その他)
  • a は all(u, g, o すべて)
  • + は追加
  • - は削除
  • = はその権限に置き換え

たとえば chmod u+x script.sh は、所有者に対して実行権を追加します。

chmod u+x script.sh

これは「owner にだけ x を足す」という意味です。
元の読み書き権はそのままで、実行権だけが増えます。
シェルスクリプトを作った直後に実行可能にしたいとき、数値で全部書き換えるより意図が見えやすい書き方です。
chmod go-w config は、group と others から書き込み権を外します。

chmod go-w config

go を並べて書けるので、まとめて操作できます。
設定ファイルを共有環境で扱うときに「所有者以外は書き換え不可」に寄せたい、という場面で役立ちます。
a の意味もここで押さえておくと便利です。
a は all の略で、owner / group / others 全員をまとめて指します。
たとえば次のように書けます。

chmod a+r file

これは全員に読み取り権を追加する指定です。
u+r,g+r,o+r をまとめた形と考えるとつながります。
ただし、a+x のような指定はファイル種別を見ずに実行権を広げるので、通常ファイルへ雑に使うと意図しない権限になります。
シンボリックモードのよいところは、今ある権限を壊さず、必要な差分だけ触れることです。
数値モードは完成形を一気に作るのに向き、シンボリックモードは微調整に向きます。
たとえば 644755 に変えるのではなく、「このスクリプトだけ owner に x を足す」なら chmod u+x のほうが意図が明確です。

特殊ビット(setuid/setgid/sticky)の基礎

chmod は 3 桁だけでなく、最大 4 桁の 8 進数でも指定できます。
先頭の 1 桁は通常の rwx ではなく、特殊ビットを表します。
対応は setuid=4setgid=2sticky=1 です。
たとえば 4755 なら、先頭の 4 が setuid、後ろの 755 が通常の権限です。

特殊ビット役割の概要
setuid4実行時にファイル所有者の権限で動く
setgid2実行時にグループ権限を引き継ぐ、またはディレクトリでグループ継承に使う
sticky1ディレクトリ内で所有者以外の削除を制限する

初心者のうちは、まず 1777 のような sticky bit を見かけることが多いはずです。
典型例は /tmp で、全員が書き込めても、他人のファイルを勝手に消せないようにするために使われます。
一方、setuid と setgid は「普通の rwx より一段強い意味」を持つので、意味を知らないまま付ける対象ではありません。
ラズパイや自宅サーバーで権限エラーに遭遇すると、検索結果の断片だけ見て特殊ビットを足したくなることがありますが、そこに進むのは通常の owner / group / others と rwx を整理してからで十分です。
普段のファイル操作では 644755u+xgo-w を正しく使えるだけで、ほとんどの場面に対応できます。
一方、setuid と setgid は「普通の rwx より一段強い意味」を持ちます。
意味を知らないまま付ける対象にするべきではありません。
ラズパイや自宅サーバーで権限エラーに遭遇したとき、検索結果の断片だけを頼りに特殊ビットを付けるのは避けたほうがよく、まずは owner / group / others と rwx を整理することを優先してください。
setuid と setgid は通常の rwx より強い意味を持ちます。
意味を知らないまま付けるとセキュリティや動作に影響が出るため、用途と影響を理解してから使ってください。
chmod u+x script.sh で実行権を付けたのに動かない、というのは初心者が最初に戸惑う判断材料になります。
原因は「x が無い」以外にもいくつかあります。
権限だけ見て止まらず、実行経路全体を切り分けると答えに近づきます。

  1. シバン(shebang)が正しいか

スクリプトの先頭行が #!/bin/bash#!/usr/bin/env bash になっていないと、直接実行で失敗することがあります。
単なるテキストとして保存されているだけでは、カーネルはどのインタプリタで実行するか判断できません。

  1. PATH にあるコマンドとして呼んでいないか

カレントディレクトリの script.sh は、通常 script.sh だけでは実行されません。
./script.sh のように ./ を付けて呼ぶ必要があります。
PATH にカレントディレクトリが入っていないためです。
ここで「実行権を付けたのに command not found」となることがあります。

  1. 親ディレクトリをたどれるか

ファイル自体に x があっても、途中のディレクトリに x がないと到達できません。
前のセクションで触れた通り、ディレクトリの x は通行権です。
namei -l でパスを分解すると、どこで止まっているか見えます。

  1. マウントが noexec になっていないか

ファイルシステムが noexec でマウントされていると、x が付いていても直接実行できません。
CI 環境で作業ディレクトリがこの状態になっていて、./script.sh は失敗するのに bash script.sh なら通る、という場面を筆者も何度か見ました。
ファイルを「実行ファイルとして起動」するのではなく、bash が「入力ファイルとして読む」形に変わるためです。

  1. 改行コードが CRLF になっていないか

筆者もこのパターンで詰まりました。
見た目は普通の #!/bin/bash なのに、実際には行末に \r が入っていて、Linux 側が /bin/bash\r を探してしまうからです。
そのときは dos2unix script.sh で LF に変換したらそのまま動きました。
注意点として、dos2unix は環境によってはプリインストールされていないことがあります。
Debian/Ubuntu 系なら sudo apt install dos2unix、RHEL/CentOS 系なら sudo yum install dos2unix(または dnf)で導入できます。
インストールできない環境や軽微な変換なら tr -d '\r' < script.sh > script.lf && mv script.lf script.sh のような代替手段も使えます。

⚠️ Warning

dos2unix は便利なツールですが、ディストリビューションやイメージによってはプリインストールされていないことがあります。Debian/Ubuntu 系なら sudo apt install dos2unix、RHEL/CentOS 系なら sudo yum install dos2unix(または dnf)で導入してください。導入できない環境や軽微な変換には tr -d '\r' < script.sh > script.lf && mv script.lf script.sh のような代替手段もあります。 [!TIP] +x を付けたのに実行できないときは、「ファイルに x があるか」だけでなく、「先頭行のシバン」「./ を付けているか」「親ディレクトリに x があるか」「noexec ではないか」「CRLF ではないか」を順に見ると、詰まりどころを切り分けやすくなります。

このチェックが頭に入ると、chmod を「魔法の解決コマンド」として扱わなくなります。
権限を足すだけで動くケースもありますが、実際には実行形式、パス、ディレクトリ権限、マウント設定、改行コードまで含めて初めて「実行できる状態」になります。

chownとは何か:権限変更と所有者変更の違い

chown コマンド ファイル所有者変更 所有権 Linux Unix ユーザー グループ chmod 権限管理 difference 違い

chmod が「誰にどこまで許すか」を変えるコマンドなら、chown は「そのファイルを誰の持ち物として扱うか」を変えるコマンドです。
ここを混同すると、書き込みできない原因がモードなのか、所有者なのかを見誤ります。
Red Hatの『Linux ファイルのアクセス権について』でも、権限モデルは owner・group・others の区分で考えるのが基本だと整理されています。
chmod はその区分ごとの rwx を調整し、chown は owner と group そのものを入れ替える、という役割分担です。
たとえば、あるファイルが alice 所有で rw- を持っているとき、chmod では「alice に実行権を足す」「group の書き込みを外す」といった変更を行います。
一方で chown は「このファイルの所有者を bob にする」「所有グループを www-data にする」といった変更です。
見た目はどちらも“権限を直している”ように感じますが、触っているレイヤーが違います。
chmod 775chown www-data は置き換え関係ではありません。

基本構文とバリエーション

chown の基本形は、所有者だけを変える chown user file です。
たとえば chown alice app.log なら、app.log の owner を alice に変更します。
グループも同時に変えるなら chown user:group file を使います。
chown alice:www-data app.log なら、owner は alice、group は www-data です。
グループだけ変えたいときは chown :group file という書き方もできます。
chown :www-data uploads のように、ユーザー名を空にしてコロンから始める形です。
これは「所有者はそのまま、所有グループだけ差し替える」という意味で、構文を覚えると chgrp と近い感覚で使えます。
chgrp との関係もここで押さえておくと混乱しません。
chgrp はグループだけを変更する専用コマンドで、役割は chown :group file とほぼ同じです。
つまり、owner も group も触れる汎用版が chown、group のみを扱う専用版が chgrp と考えると整理できます。
グループ変更だけなら chgrp www-data uploads と書いても同じ方向の操作です。
筆者は /var/www にアプリを配布するとき、この違いを意識して構成を分けています。
コード本体は開発者所有のまま読み取り中心に置き、アプリが書き込む uploads だけを www-data グループに寄せる運用です。
このとき、コード全体を www-data 所有にしてしまうと、Web サーバープロセスが広い範囲を書ける状態になります。
そこで owner は開発者側に残し、uploads だけ chown :www-data でグループを切り替え、775 を組み合わせるほうが事故の範囲を狭められました。
所有者変更とモード変更を別々に考えると、この判断がしやすくなります。

いつchownが必要か

chown が必要になるのは、「読める・書けるの設定」ではなく「そもそも誰のファイルとして扱うべきか」を直したい場面です。
典型例は、管理者権限で作ってしまったファイルを通常ユーザーに戻すとき、デプロイ後に Web サーバーが扱うディレクトリの owner/group を整えるとき、バックアップ復元後に所有者が崩れたときです。
Web サーバー運用では、www-data を owner にするか、group にとどめるかの判断がよく出てきます。
アプリ全体を www-data 所有にすると、Web サーバー経由で更新される前提の CMS では扱いやすい一方、コードまで書き換え可能になります。
静的ファイルやアプリ本体を守りたいなら、コードは開発者所有のままにして、書き込みが必要な場所だけ www-data グループを付けるほうが筋が通ります。
筆者が /var/www 配下で運用したときも、ソースコードは開発者所有で読み取り専用に寄せ、画像アップロード先だけ www-data グループ所有にして分離しました。
こうすると、更新責任のある人と、実行時に書き込むプロセスの境界がはっきりします。
逆に、chmod だけで解決しようとして 777 に寄せるのは、所有者設計を飛ばしてしまう典型です。
本当の問題が「owner が root のまま」「group がアプリ実行ユーザーに合っていない」なら、まず chownchgrp で持ち主を整えるべきです。
そのうえで必要なビットだけ chmod で足す、という順序のほうが意図を保てます。

sudoが必要な理由と注意点

chownchmod と違って戸惑いやすいのは、所有者変更は多くの環境で root 権限が必要な点です。
特に owner を別ユーザーへ変更する操作は一般ユーザーには許されないことが多く、監査や責任の境界を保つために sudo が必要になります。
ただし例外もあります。
自分が現在の所有者であり、かつ変更先のグループに自分が所属している場合は、chgrpchown :group file が sudo なしで通ることがあります。
要は「ほとんどのケースで sudo が必要だが、自分が所有者かつ変更先グループに入っている場合などは sudo を要しないことがある」という点を押さえておくと誤解を避けられます。

よく使う権限パターン:644・755・700・775・777の意味と選び方

ファイル用途別の推奨(要点)

通常ファイルはまず 644 を基準に考え、実行が必要なスクリプトや配布用コマンドだけ 755 にするのが安全です。
用途ごとに理由を明確にして権限を決めると、あとで見直すときに意図が残ります。

ファイル用途別の推奨

現場で頻出する数値は、まず「そのファイルを読むだけなのか、実行するのか、秘密にしたいのか」で切り分けると迷いません。
Red Hatの権限解説でも、通常の新規ファイルは基準値に umask が反映され、umask 022 なら 644 に落ち着く流れが説明されています。
つまり、特別な理由がない通常ファイルは、最初から 644 に寄る場面が多いということです。
設定ファイルや静的な HTML、CSS、画像、テキストのように「内容を読ませたいが、実行は不要」という通常ファイルなら、まずは 644 が基準になります。
owner は読み書きでき、group と others は読み取りだけです。
筆者が実務や自宅の公開ディレクトリを見ていて頻繁に出会うのが、静的 HTML や設定ファイルまで 755 にしてしまう過剰権限です。
たしかに 755 でも読めますが、ファイルに実行権を付ける理由がないなら 644 で足ります。
実際、配布した HTML 一式が全部 755 になっていた案件で、実害は出ていなくても「どれが本当に実行対象なのか」が見えにくくなり、後で点検するときに手間が増えました。
シェルスクリプトや自作コマンドのように「読むだけではなく実行したい」ファイルには 755 がよく使われます。
owner が編集でき、group と others は読み取りと実行だけという形なので、配布用スクリプトや運用コマンドに向いています。
ここでのポイントは、755 は「便利な万能値」ではなく、「実行権を付ける理由があるファイルに限定して使う値」だということです。
個人用の秘密ファイルや、ホームディレクトリ配下に置く個人スクリプト、鍵や認証情報を含む設定には 700 が候補になります。
owner 以外は一切読めないため、個人専用のバックアップスクリプトや、API トークンを含む補助ファイルを他ユーザーから切り離したいときに合います。
共有前提のサーバーでは、この差がそのまま漏えい防止につながります。
チームで同じグループに所属するメンバーが編集するファイルでは 775 よりも、ファイル単体なら 664 が自然なこともありますが、運用上「同一グループで触るもの一式」をディレクトリ単位で管理する流れでは 775 と組み合わせて登場します。
nixCraftなどで説明される umask 002 の環境では、新規ディレクトリが 775 になりやすく、グループ共有と相性が合います。
ファイルそのものに実行権が不要なら、むやみに 775 を付けず、必要なものだけに絞るのが筋です。

ディレクトリ用途別の推奨

ディレクトリはファイルと見方が少し違います。
前述の通り、ディレクトリでの x は「中に入る、名前解決できる」という意味を持つので、ファイルと同じ感覚で数値だけ合わせると意図がずれます。
RHEL 9の権限管理ドキュメントでも、新規ディレクトリの基準は 777 で、umask 022 なら 755 になると整理されています。
公開用ディレクトリで 755 が定番なのはこの流れとも一致します。
Web 公開ディレクトリや、一般ユーザーが参照するコマンド置き場には 755 がよく合います。
owner は作業でき、group と others は中をたどって読めます。
/var/www/html のような公開ディレクトリや、/usr/local/bin のようなコマンド置き場が典型です。
公開する静的サイトのディレクトリに 755、そこに入る HTML や画像には 644 という組み合わせは、最も素直で崩れにくい形です。
同じグループで共同編集するディレクトリなら 775 が実務向きです。
たとえば開発チーム全員を同じグループに入れ、共有ディレクトリの group をそのグループにそろえる運用です。
これなら owner だけでなく group も書き込めるので、担当者が変わっても作業が止まりません。
Web 運用でもこの考え方は有効で、コード本体は 644/755 を基本に据えつつ、uploadscache のような書込先だけを www-data グループ所有にして 775 に分ける構成は、権限の境界が明確です。
個人専用ディレクトリや秘密情報を含む保管場所には 700 が向きます。
たとえば SSH 関連、個人用スクリプト置き場、秘密設定を含むディレクトリです。
他ユーザーが同居するサーバーでホーム配下を整理するとき、この値にしておくと「自分しか入れない場所」がはっきりします。

777を避ける理由と代替

chmod 777 セキュリティリスク ファイル権限 全員読み書き実行 Linux Unix 権限設定 755 644 代替方法 最小権限原則 umask

777 は owner・group・others の全員に読み書き実行を許す状態です。
ファイルでもディレクトリでも「誰でも触れる」ため、動かないものをその場で動かすには手っ取り早く見えますが、運用では事故の入口になりがちです。
特にディレクトリで 777 にすると、想定していないユーザーやプロセスまで書き込み可能になり、改ざんや不正配置の余地が広がります。
初心者が 777 に寄せたくなる場面の多くは、本当は chmod の問題ではなく、owner や group の設計がずれているケースです。
Web サーバーが書けないなら、コード全体を 777 にするのではなく、書き込みが必要な uploadscache だけを www-data グループに寄せ、775 にするほうが意図に合います。
さらに細かく制御したいなら、chmod だけで押し切らず、必要な相手にだけ権限を足せる ACL も候補です。
setfacl が出てくるのはこの文脈で、共有相手が複数いて owner/group/others の三分割だけでは足りないときに効きます。
筆者が 777 を見て警戒するのは、あとから「なぜそこまで開けたのか」が追えなくなるからです。
障害対応の最中に一時しのぎで付けた 777 が、そのまま本番に残ることは珍しくありません。
しかも表面上は動くので、見直しが後回しになります。
権限で詰まったときほど、誰に書かせたいのかを owner と group で表現し、それでも足りない部分だけ ACL で補うという順序のほうが、構成の意味が残ります。

💡 Tip

Web 運用では、コード本体を 644 と 755 に保ち、書込先の uploadscache だけを www-data グループ所有にして 775 に分けると、公開範囲と更新範囲を切り離せます。動かないから 777 にするのではなく、書ける場所を限定する発想のほうが後から点検しやすくなります。

3つの具体例:Raspberry Pi・Webサーバー・スクリプト

1つ目はRaspberry Piです。
GPIO を叩く補助スクリプトを毎回フルパスで実行するのが面倒で、筆者は /usr/local/bin に置いて使うことがあります。
ファイルは 755 にして実行可能にすると扱いやすくなります。
/usr/local/bin が PATH に含まれている事例は多く見られますが、これはディストリビューションやユーザー設定で差が出る点です。
確実にコマンドとして呼び出せるかは、実際に echo $PATH を実行して確認してください。
環境によっては別のディレクトリを PATH に追加する必要があります。
2つ目は Web サーバーです。
静的 HTML、CSS、JavaScript、設定ファイルといったコード本体は 644、公開ディレクトリは 755 が基本線です。
筆者がよく修正するのは「ファイルもディレクトリも全部 755」に揃えてしまうケースです。
ディレクトリに 755 が要るのは理解できますが、HTML や設定ファイルまで実行可能にする理由は通常ありません。
書き込みが必要な uploadscache だけを www-data グループ所有にして 775 に分けると、公開部分と更新部分の役割がはっきりします。
3つ目はスクリプト全般です。
たとえば配布用のメンテナンススクリプトや、手元で使う自作コマンドは 755、自分だけが使うバックアップ用や秘密鍵を扱う補助スクリプトは 700、設定を読むだけの .conf.env に近いファイルは内容に応じて 644 か、秘匿が必要なら 600 系に寄せる、という考え方です。
ここでも「実行するから 755」「読むだけだから 644」「他人に見せたくないから 700」と用途で切ると、数字の丸暗記から抜け出せます。
1つ目はRaspberry Piです。
GPIO を叩く補助スクリプトを毎回フルパスで実行するのが面倒で、筆者は /usr/local/bin に置いて使うことがあります。
ただし /usr/local/bin が PATH に含まれているかはディストリビューションやユーザー設定で差があるため、確実にコマンドとして呼び出せるかは実際に echo $PATH を実行して確認してください。
必要なら PATH を追加するか、フルパスで実行する運用にしてください。
この見方が定着すると、644・755・700・775・777 は単なる丸暗記ではなく、用途に基づく設計判断になります。
静的 HTML と設定ファイルは 644、公開ディレクトリと実行スクリプトは 755、個人秘密ファイルは 700、グループ共有は 775、そして 777 は原則避ける、という基準で考えられるようになります。

再帰変更の注意点:chmod -R / chown -R で事故を防ぐ

chmod chown recursive -R ファイル権限 注意点 事故防止 Linux コマンド ディレクトリ パーミッション 所有者 グループ セキュリティリスク

ありがちな事故パターン

-R を付けた chmodchown は、一気にそろえたい場面では便利です。
ただ、この便利さに引っ張られて、ファイルとディレクトリへ同じ設定をまとめて当てると崩れます。
前のセクションで触れた通り、通常ファイルとディレクトリでは役割が違うので、同じ数値をそのまま流し込む発想が事故の入口になります。
筆者も大規模リポジトリで chmod -R を雑に使って失敗したことがあります。
実行可能であるべきスクリプトまで一緒にそろえてしまい、逆に必要な実行ビットが剥がれてCIが落ちました。
見た目には「権限を整えた」つもりでも、実際には bin/ 配下のスクリプトやフックだけ別扱いにすべきでした。
この手の失敗は、権限そのものの理解不足というより、対象を分けずに再帰したことが原因です。
chown でも似た混乱が起きます。
chmod は rwx などのモードを変えるコマンドで、chown は所有者と所有グループを変えるコマンドです。
たとえば chown user file は所有者だけを user に変え、chown user:group file は所有者を user、所有グループを group に変えます。
chown :group file と書けば、所有者はそのままでグループだけを変えられます。
グループだけを変えたいなら chgrp group file でも同じ方向の作業ができ、こちらは「グループ所有権だけを変える」という意図が名前から伝わります。
ただし、所有者変更は誰でもできる操作ではありません。
所有者を変える処理は多くの環境で root 権限が必要で、sudo chown ... が出てくるのはこのためです。
chgrp は自分が所有するファイルに対して自分が属するグループへ変更できる場面がありますが、任意の所有者や任意のグループに変える話になると、やはり権限の壁に当たります。
ここを曖昧なまま sudo-R を同時に使うと、被害範囲が一気に広がります。
危険例として象徴的なのが sudo chmod -R 777 / です。
これは単なる「強引な解決策」ではなく、システム全体のセキュリティと動作を壊しにいく操作です。
OS 配下のコマンド、設定、サービス関連ファイルまで全開放されるので、権限モデルそのものが崩れます。
再帰変更は便利ですが、ルートディレクトリやサービス配下へ無造作に当てるものではありません。

findでの分離適用レシピ

典型例は次の形です。
まずはディレクトリとファイルを分けて適用します。
具体的には次のコマンド例のように、ディレクトリには 755、ファイルには 644 を適用するのが安全です。
再帰変更で事故を減らす基本は、対象を型で分けることです。
ファイルとディレクトリを別コマンドで扱えば、「全部まとめて同じ権限」の罠から抜けられます。
筆者がリポジトリ事故のあとに定着させたのも、この分離でした。
典型例は次の形です。
再帰変更で事故を減らす基本は、対象を型で分けることです。
ファイルとディレクトリを別コマンドで扱えば「全部まとめて同じ権限」の罠から抜けられます。
筆者もリポジトリ事故のあと、この分離を定着させました。
find . -type d -exec chmod 755 {} + find . -type f -exec chmod 644 {} +

これならディレクトリにはディレクトリ向け、ファイルにはファイル向けの設定を分けて適用できます。Red Hatの権限解説でも、新規作成時の基準はファイルが 666、ディレクトリが 777 で、そこへ umask が掛かる前提になっています。たとえば umask 022 なら、新規ファイルは 644、新規ディレクトリは 755 になります。権限の考え方を整理するなら、Red Hatの『Linux ファイルのアクセス権について』や『RHEL 9 ファイルシステム権限管理』の説明が土台になります。
必要なら、その上に「実行すべきものだけ追加で立てる」という順番にします。たとえば `scripts/` や `bin/` の中だけ別途 `chmod u+x` を足す、という流れです。筆者はこの手順に変えてから、スクリプト実行権の消し忘れや付けすぎを追いかける時間が減りました。最初に全体を安全側へ寄せ、あとから役割のある一部だけを持ち上げるほうが、差分の意味が読み取れます。
所有者変更でも同じ考え方が使えます。たとえばプロジェクト配下をアプリ実行ユーザーへそろえるなら `chown -R user:group project/` という形になりますが、本当に全体を変えるべきかを先に分解したほうが事故が減ります。ログやアップロードだけグループを寄せたいなら、所有者まで巻き込まず `chown :group path` や `chgrp group path` のほうが意図に合います。`chown user file`、`chown user:group file`、`chown :group file` は見た目が似ていますが、変える対象が違うので、ここを明確に使い分けるだけでも混同が減ります。
> [!NOTE]
> 再帰変更を始める前に、まず `find . -type d -print` や `find . -type f -print` で対象一覧を出すと、どこまで触るのかを目で確認できます。`--dry-run` 相当がないコマンドでは、このひと手間がそのまま保険になります。
### リンク・広すぎる対象指定への注意
> [!NOTE]
> 再帰変更を始める前に、まず `find . -type d -print` や `find . -type f -print` で対象一覧を出すと、どこまで触るのかを目で確認できます。`--dry-run` 相当がないコマンドでは、このひと手間がそのまま保険になります。
対象指定が広すぎるケースも厄介です。カレントディレクトリが想定と違うまま `chmod -R .` を実行したり、補完ミスでひとつ上の階層まで含めたりすると、原因追跡が一気に難しくなります。`/var/www/app` を触るつもりが `/var/www` 全体を変えてしまう、ホーム配下だけのつもりがマウント済みボリュームまで巻き込む、といった失敗は現場で珍しくありません。特にDockerのバインドマウントやNFS配下では、ローカルだけのつもりで触った変更が共有先にもそのまま見えるので、被害の切り分けに時間を取られます。
筆者は広い範囲へ当てる前に、必ずテスト用ディレクトリで同じコマンドを一度流して挙動を確かめます。`--dry-run` がないなら、検証用に数個のファイルとディレクトリを作って結果を見るほうが早いです。再帰変更は一発で片付く反面、間違えたときの巻き戻しが面倒です。だからこそ、`chmod` と `chown` の違いを整理したうえで、対象を絞り、型を分け、一覧を見てから当てる、という順番が効いてきます。
## 新規ファイルの権限はなぜ644/755になるのか:umaskの仕組み
### 基準パーミッションとumaskの計算
新規ファイルや新規ディレクトリが、作った瞬間から毎回同じ権限になるのは偶然ではありません。ここで効いているのが **umask** です。Red Hatの『RHEL 9 ファイルシステム権限管理』でもその点は説明されています。基準になる値は**ファイルが 666、ディレクトリが 777**です。そこから umask で許可しない分を差し引いて、実際の初期権限が決まります。
たとえば umask が 022 なら、ファイルは 666 から引かれて 644、ディレクトリは 777 から引かれて 755 になります。ここで引っかかりやすいのが、「なぜ新規ファイルは最初から実行可能にならないのか」という点です。理由は単純で、ファイルの基準値そのものが 666 だからです。つまり x は最初から立っていません。実行したいスクリプトは、作成後に `chmod +x` で明示的に付ける前提です。
この考え方を持つと、現場でよく見る権限の意味が用途と結びつきます。たとえば設定ファイルや個人用のメモ、一般的な HTML ファイルのように「読めればよく、実行はしない」ものが 644 で始まるのは自然です。公開ディレクトリが 755 で作られるのも、所有者は編集でき、他のユーザーや Web サーバープロセスは中をたどって読める、という使い方に合っています。一方でシェルスクリプトは、新規作成直後は 644 のままなので、そのままでは実行されません。これは不便ではなく、安全側の初期値です。実行権が必要なものだけ後から足すほうが、意図しない実行を防げます。
個人秘密ファイルはこの流れとは別で、作成直後の 644 のまま置かないほうがよい場面があります。たとえば秘密鍵や API トークンを書いたファイルは、あとから 600 や 700 に絞る運用が合います。umask は初期値を決める仕組みであって、すべての用途にそのまま最適化してくれるわけではありません。
### 022と002の違い
umask で実務上よく出てくるのが **022** と **002** です。違いは、グループにどこまで権限を残すかにあります。022 なら新規ファイルは 644、新規ディレクトリは 755 です。002 なら新規ファイルは 664、新規ディレクトリは 775 になります。差はグループの書き込み権だけですが、この 1 ビットで運用のしやすさが変わります。
022 は個人用途と相性がよく、自分だけが更新し、他の人は読むだけという前提に合います。設定ファイルや HTML、個人管理のスクリプトを置くなら、まず困りません。対して 002 はチーム共有の作業ディレクトリで効きます。同じグループに所属するメンバーがファイルを共同編集する前提なら、664 や 775 で始まるほうが手戻りが減ります。共有リポジトリの作業領域や、複数人で触る公開ディレクトリ配下の素材置き場などでは、この差がそのまま運用コストに出ます。
筆者の開発環境では umask を 002 にしていることが多く、新規ファイルが 664、ディレクトリが 775 で作られる状態にしています。チームで同じグループを使っていると、あとから毎回 `chmod g+w` を足す必要がなく、共有作業が止まりません。反対に、個人用途の作業や秘密情報を含むファイルを触る場面では 022 に切り替えます。たとえば個人用の設定ファイルや認証情報まわりは、最初からグループ書き込み不要の状態にしておくほうが意図に合います。umask は「どちらが正しいか」ではなく、「この作業場所を誰と共有するのか」で選ぶ値です。
ここで 777 を安易に使わない理由も見えてきます。共同編集したいからといって、所有者・グループ・その他の全員に読み書き実行を開けると、関係ないユーザーまで変更できる状態になります。公開ディレクトリやアップロード先で権限エラーが出たときに 777 で押し切ると、その場では動いても、誰が書き換えられるのかという境界が消えます。多くのケースでは、所有者やグループの見直し、あるいは 775 や 664 への調整で足ります。権限不足の原因を飛ばして 777 にすると、あとで「なぜこのファイルが書き換わったのか」が追えなくなります。
### umaskの確認と設定ポイント
今の umask を確認するには、まず `umask` を実行します。数値で表示されるので、022 なのか 002 なのかをすぐ確認できます。記号表記で見たいときは `umask -S` が便利です。こちらは `u=rwx,g=rx,o=rx` のように、どの権限が落とされるのかを読み取りやすい形で出してくれます。
> [!WARNING]
実務では、まず umask で初期値を整え、それでも足りない部分だけ個別に追加する流れが安定します。公開ディレクトリは 755、通常の HTML や設定ファイルは 644、実行が必要なスクリプトだけ `chmod +x`、個人秘密ファイルは 600 へ絞る、という順番です。この順番にしておくと、権限エラーが起きたときも「初期値の問題なのか、用途に応じた追加設定の問題なのか」を切り分けやすくなります。
## 標準権限で足りないとき:ACLとSELinuxを知っておく
### ACLの基本とsetfacl -m
`chmod` と `chown` で大半の場面は片付きますが、それでも「この人にだけ書き込みを足したい」「所有グループは変えたくないけれど、特定ユーザーだけ更新できるようにしたい」という場面が残ります。そこで出てくるのが ACL(Access Control Lists)です。ACL は、owner / group / others の3区分だけでは表現しきれない例外ルールを足すための仕組みです。
たとえば `project` ディレクトリは従来どおりの所有者とグループで運用しつつ、ユーザー `alice` にだけ読み書き実行を追加したいなら、`setfacl -m u:alice:rX project` のように設定します。`-m` は既存 ACL に対して追加・修正を行う指定で、いきなり全部を置き換えるものではありません。ここでの `X` は、大文字の実行権で、ディレクトリや、もともと実行権を持つファイルにだけ実行を付ける書き方です。共有ディレクトリに対して使うと、通常ファイルまで無差別に実行可能へしてしまう事故を避けやすくなります。
設定後の確認は `getfacl project` です。`ls -l` だけでは ACL の中身までは読み取れず、末尾に `+` が付いて「追加ルールがある」と分かる程度です。実際に誰へ何が付いているかは `getfacl` で見るほうが確実です。ここでつまずきやすいのが **ACL mask** です。たとえば `alice` に `rwx` を付けたつもりでも、mask が `r-x` なら実効権限はそこまでに制限されます。`setfacl` を触っているのに期待どおり書けないときは、個別エントリだけでなく mask まで一緒に見ると原因が見つかります。
筆者は、共同編集の対象が少人数だけ増える場面では、所有グループをむやみに増やすより ACL を足すほうをよく使います。グループ設計まで変えると影響範囲が広がりますが、ACL なら「この人だけ例外」という意図をそのまま設定に落とし込めます。`chmod` が全体ルール、ACL が個別の上書きに近い、と捉えると整理しやすくなります。
### default ACLでの継承設定
ACL を理解した直後に出やすいのが、「親ディレクトリには設定したのに、新しく作ったファイルには効いていない」という疑問です。これは普通の ACL と default ACL が別物だからです。既存のディレクトリに ACL を追加しても、その時点であるファイルやディレクトリに権限を与えるだけで、新規作成物への継承ルールにはなりません。新しく作られるものにも同じ方針を引き継ぎたいなら、default ACL を設定します。
共有ディレクトリなら、`setfacl -m d:u:alice:rwx shared` のように `d:` を付けた default エントリを使います。これで `shared` の下に新しく作られるファイルやサブディレクトリに対して、`alice` 向けの ACL が初期値として付きます。`getfacl shared` を見ると、通常エントリとは別に `default:` で始まる行が出るので、そこを見れば継承設定の有無が分かります。
default ACL にも mask は影響します。設定したつもりの権限が弱く見える場合、親ディレクトリの default mask が上限になっていることがあります。共有ディレクトリの運用で ACL を使うなら、通常 ACL と default ACL を分けて考えること、そして `getfacl` で実際のエントリを確認すること、この2つが効きます。
> [!TIP]
> `chmod` で全体ルールを決め、足りない相手だけ ACL を追加し、新規作成物の統一には default ACL を使う、という順番にすると設定の意図が崩れません。
### SELinuxのls -Z/chcon/restorecon
`chmod` したのに読めない、`chown` も合っているのに Web サーバーからアクセスできない、というときは SELinux も候補に入ります。**通常の権限と SELinux コンテキストは別物** だという点です。前者は owner / group / others と ACL の世界で、後者は「このファイルをこのサービスが読んでよいか」というラベル付けの世界です。モードが正しくても、コンテキストが合っていなければ拒否されます。
確認には `ls -Z` を使います。`ls -l` が rwx を見るコマンドだとすると、`ls -Z` は SELinux ラベルを見るコマンドです。Red Hatの SELinux ドキュメントでも、ファイルラベルの確認と復元が基本手順として整理されています。たとえば Web サーバー向けの静的コンテンツなら `httpd_sys_content_t` のようなタイプが付きますが、手動で別の場所へコピーしたファイルや、ラベルが崩れたファイルではここがずれていることがあります。
一時的にラベルを変えるなら `chcon` を使えます。たとえば検証中にタイプを付け替えて挙動を見るには便利です。ただし、`chcon` は恒久設定ではありません。`restorecon` を実行したり、再ラベリングが走ったりすると、既定ポリシーに基づく本来のラベルへ戻ります。ここを知らないと、「直ったと思ったのに後日また戻った」という現象に見えます。恒久的に運用するなら、既定ポリシー側に沿った設定と `restorecon` の組み合わせで整えるのが筋です。
筆者も SELinux が有効な本番環境で、`chmod` してもNginxがファイルを読めず、権限の数値ばかり見直して遠回りしたことがあります。`ls -Z` でラベルを見たら Web 配信用のコンテキストになっておらず、`restorecon` をかけたらその場で解消しました。こういうケースでは「権限が合っているのに動かない」のではなく、「権限は合っているがラベルが違う」が正確です。
SELinux は無効な環境では当然この問題は出ませんし、ディストリビューションによって前提も変わります。とはいえ、RHEL 系やその周辺環境では、`chmod` と `chown` だけでは説明しきれない拒否の原因として頻出します。`Permission denied` を見たとき、rwx と所有者だけでなく `ls -Z` も一度眺める。この視点が入ると、原因の切り分けが一段深くなります。
## よくあるトラブルと対処法
### Permission deniedの切り分け
`Permission denied` はひとつのエラー文に見えても、実際には「どこで拒否されたか」で原因が変わります。まず対象が**ファイルなのか、ディレクトリなのか**を分けて考えると、遠回りが減ります。ファイルを実行したいのに拒否されるなら、そのファイル自体に `x` がないのが第一候補です。いっぽう `cd` できない、あるいはその下のファイルにたどり着けないなら、見ているディレクトリだけでなく**親ディレクトリを含めた経路上のどこかに `x` がない**ことがよくあります。
たとえば `cat file.txt` が失敗したとき、つい `file.txt` の `r` だけを見がちですが、実際には親ディレクトリを通過するための `x` も必要です。`cd` できないケースではこの性質がもっとはっきり出ます。対象ディレクトリに `x` が必要なのはもちろん、そのひとつ上、さらにその上と、パスに含まれる各ディレクトリを順番に通れなければ到達できません。こういうときに役立つのが `namei -l /path/to/target` です。途中のどの階層で `x` が欠けているかを一列に展開して見せてくれるので、`ls -l` を何度も打ち直すより原因が早く見えます。
権限ビットに問題がなさそうなら、次は**所有者とグループの不一致**を見ます。自分が思っていたユーザーで実行していない、サービスが別ユーザーで動いている、グループに入っているつもりで入っていない、というのは定番です。`id` や `groups` で実行中ユーザーの所属を確認し、`stat` で対象ファイルやディレクトリの owner と group を見ると、見えている前提のズレが分かります。特にDockerのバインドマウントでは、ホストとコンテナで UID/GID の数値がずれていて、見た目は同じ名前でも実体は別という場面が起きます。
そこまで見ても `chmod` が効いていないように見えるなら、通常の rwx 以外を疑う段階です。ACL を使っている環境では、追加権限だけでなく **mask が上限になっている** ことがあります。`getfacl` で ACL と mask を見ると、「付けたはずの権限が実際にはマスクで削られていた」という状況を拾えます。Red Hat系で Web サーバーやミドルウェアを動かしているなら、Red Hatの SELinux ドキュメントが整理している通り、`ls -Z` でコンテキストを見る流れも外せません。さらにスクリプトや実行ファイルが置かれている場所が `noexec` マウントになっていると、実行権を付けても起動できません。`mount | grep noexec` で該当マウントを確認すると、`chmod +x` では解けない理由が見えてきます。
確認用のコマンドは多く見えますが、実際の順番は単純です。`stat` で基本情報、`namei -l` で経路、`id` と `groups` で実行主体、`getfacl` で ACL、`ls -Z` で SELinux、必要なら `setfacl` で修正、という流れで追うと、`Permission denied` をひとつずつ分解できます。
> [!TIP]
> `chmod` したのに効かないときは、権限ビットが間違っているのではなく、ACL の mask、SELinux、`noexec` のいずれかが後ろから止めていることが多いです。
### スクリプト実行時のチェック
シェルスクリプトが動かないときは、まず「**実行しているつもりの方法**」を疑うと切り分けが進みます。`./script.sh` で起動したいなら、そのファイル自体に実行権が必要です。ここで `chmod +x script.sh` を付け忘れているケースはまだ分かりやすいのですが、権限を付けても動かないなら、次に見るべきはシバンです。先頭行が `#!/bin/bash` や `#!/usr/bin/env bash` になっているか、存在しないインタプリタを指していないかで結果が変わります。
加えて、コマンド名だけで `script.sh` を打っている場合は、カレントディレクトリが `PATH` に入っていなければ見つかりません。その場合は `./script.sh` のように明示して起動します。`Permission denied` と `command not found` は別の失敗ですが、現場では混ざって認識されがちです。前者は実行できない、後者はそこにたどり着けていない、という違いがあります。
Ubuntu系の man ページで説明されているdos2unixは、この CRLF を LF に直す定番ツールです。筆者も自宅のRaspberry Piで自動化スクリプトを試していたとき、権限もシバンも合っているのに起動せず、原因を追ったらエディタ由来の CRLF だったことがありました。`dos2unix script.sh` でその場で直り、以後は「実行権」「シバン」「改行コード」を最初の3点として見る癖が付きました。前述の通り `dos2unix` が未インストールの環境もあるため、必要なら `sudo apt install dos2unix` 等で導入するか、`tr` コマンド等で CR を取り除く方法を案内してください。
それでも動かない場合は、ファイルを置いている場所そのものに目を向けます。USB メモリや一時領域、共有ストレージなどが `noexec` でマウントされていると、ファイルに `x` があってもカーネル側で実行を拒否します。このときは「スクリプトが実行できない」のではなく、「その場所からの実行が禁止されている」が正確です。`bash script.sh` のようにインタプリタを明示すると動くのに、`./script.sh` だけ失敗するなら、この筋が濃くなります。
`chmod` を足したのに効かない場面では、ここでも ACL と SELinux が絡みます。`getfacl` で mask を確認し、`ls -Z` でコンテキストを見れば、「ファイルには x があるのに拒否される」理由が通常権限の外側にあると分かります。スクリプト実行のトラブルは一見ばらばらですが、実際には **実行権、起動方法、インタプリタ、改行コード、マウント属性** のどこかに集約されます。
### Web公開時の権限チェック
前述のように、改行コードが CRLF だと `/bin/bash^M: bad interpreter` のようなエラーになります。`dos2unix` が無い環境では導入(Debian/Ubuntu 系: `sudo apt install dos2unix`、RHEL 系: `sudo yum install dos2unix` または `dnf`)するか、`tr -d '\r'` のような代替手段で CR を取り除いてください。
Web サーバーが読めないケースでは、ローカルユーザーとして `cat` できることと、NginxやApacheが読めることを分けて考える必要があります。Web サーバーは専用ユーザーで動いているので、ドキュメントルート配下の所有者・所有グループがその実行ユーザーとかみ合っていなければ、ブラウザでは 403 なのにシェルでは普通に見える、という状態が起きます。静的公開の基本形では、ディレクトリに 755、ファイルに 644 が揃っているかを見ると整理しやすく、`stat` で owner と group を確認すると数字の見落としが減ります。
とくに `uploads` のような書き込みが絡む場所は、静的ファイル置き場と同じ感覚で全部そろえると詰まりやすくなります。読むだけの場所と、アプリや Web サーバーが書く場所では、所有者やグループの設計を分けたほうが筋が通ります。前のセクションで触れた ACL を併用する構成でも、まず通常の owner / group / mode が素直に読める状態になっているかを押さえると、例外設定の意味が見えやすくなります。
ここで強く意識したいのが SELinux です。筆者はNginxの静的配信で 403 に遭遇したとき、最初は owner と mode ばかり見直していました。`ls -l` では不自然な点が見えず、`chmod` をやり直しても変化がありませんでした。そこで `ls -Z` を見たところ、配置したファイルのコンテキストが Web 配信用のものと一致していませんでした。`restorecon` をかけたらその場で配信が復旧し、原因は SELinux のコンテキスト不一致だったと分かりました。`chmod` したのに効かない、と感じる典型例です。
Web 公開では、静的コンテンツ向けの `httpd_sys_content_t` が付いているかが読み取り可否に直結します。新しく作ったディレクトリに手でファイルをコピーした場合や、別の場所から持ってきたコンテンツをそのまま置いた場合は、ラベルだけがずれていることがあります。そのときに `chcon` で一時的に直す方法もありますが、運用では `restorecon` で既定ラベルへ戻すほうが再現性があります。`ls -Z` で type を見て、Web サーバー向けのコンテキストになっているかを確認すると、403 の原因を通常権限と分離して考えられます。
「Web サーバーが読めない」「chmod したのに効かない」という相談では、実際には **owner/group の不一致、経路上のディレクトリに x がない、ACL の mask、SELinux コンテキスト、`noexec`** が混ざっています。`namei -l` で経路、`getfacl` で ACL、`ls -Z` で SELinux、`mount | grep noexec` でマウント属性を見る流れにしておくと、403 や `Permission denied` を感覚ではなく根拠で切り分けられます。
## 実践演習:手元で安全に試して身につける
まずは演習用の作業場を切り分けます。筆者はこの種の確認をするとき、普段から `/tmp` 配下に自分専用のサンドボックスを作ります。たとえば作業ディレクトリを1つ切って、その中だけで `chmod` や `find` を試す形です。権限操作は打ち間違いがそのまま広がるので、本番用のホームディレクトリや Web 公開用ディレクトリで始めるより、捨てても困らない場所で手を動かしたほうが理解が早く進みます。コマンドの意味を読むだけでは曖昧だったところも、自分で作ったファイルの表示が変わる様子を見ると、一気につながります。
### ls -lとstatの読み比べ
最初の演習では、通常ファイルとディレクトリを1つずつ用意して、`ls -l` と `stat` の表示を見比べます。`ls -l` は一覧性が高く、どの項目をざっと確認するかに向いています。一方の `stat` は、その1個に対して mode、owner、group をきっちり読む場面で力を発揮します。
たとえば空のファイルとディレクトリを作ってから `ls -l` を実行すると、先頭の1文字がファイル種別を表し、通常ファイルなら `-`、ディレクトリなら `d` になります。続く9文字で owner、group、others の権限を読みます。ここで `ls -l` だけ見て終わるのではなく、同じ対象に `stat` を当てると、「一覧表示の記号」と「モードの実体」が頭の中で結び付きます。新規ファイルの基準パーミッションは 666、ディレクトリは 777 で、そこに umask が差し引かれるので、作成直後の見え方が違う理由も後の演習で納得できます。
`stat` は「見た目では同じに見えるけれど、所有者やグループが違う」といった場面でも役立ちます。筆者は Web サーバー周りの確認で `ls -l` だけだと流してしまうことがあるので、owner と group を見たいときは `stat` を併用する癖を付けています。1ファイルずつ丁寧に観察すると、後で `chmod` や `chown` を実行した結果も追いやすくなります。
### chmod +xと644の違いを体験
次は `test.sh` を作って、実行権の有無で何が変わるのかを体験します。中身は短いもので十分で、シバン付きのシェルスクリプトにしておくと挙動の差がはっきり出ます。作成した直後は、umask が 022 なら新規ファイルは 644 になるので、そのまま `./test.sh` を実行すると拒否されます。ここで `chmod +x test.sh` を付けると、同じファイルが実行対象として扱われます。逆に `chmod 644 test.sh` に戻すと、読み取りはできても直接実行は止まります。
この演習では「読める」と「実行できる」が別物だと体感できます。`cat test.sh` はできるのに `./test.sh` は失敗する、という差がまさにそれです。さらに `bash test.sh` の形でも試すと、ファイル自体に実行権がなくても、インタプリタを明示して読ませれば動くケースが見えてきます。前のセクションで触れた「実行権」「起動方法」「インタプリタ」の切り分けが、ここで手触りを持って理解できます。
シバンも同時に試すと効果的です。先頭行を `#!/bin/bash` にして動かしたあと、わざとシバンを消した状態でも `bash test.sh` なら通ることがあります。一方で `./test.sh` はシバンに依存するので、同じスクリプトでも起動方法で結果が変わります。`PATH` の確認も入れるなら、カレントディレクトリの `./test.sh` と、`PATH` に入っている場所へ置いたスクリプトでは呼び出し方が変わることも見ておくと整理しやすくなります。Raspberry Pi OS系では `/usr/local/bin` が `PATH` に含まれている例がよく見られるので、名前だけで起動できる理由の理解につながります。
改行コードもここで試せます。`test.sh` を Windows 由来の CRLF にすると、シバン行の末尾に CR が紛れ込み、`/bin/bash^M: bad interpreter` のような典型的な失敗が起きます。Ubuntu系の man ページで説明されている dos2unix は、この CRLF を LF に直す定番ツールです。筆者もラズパイ用の小さな自動化スクリプトで一度ここに引っかかってから、実行権を付けた後は必ず改行コードも疑うようになりました。`chmod +x` だけでは直らない不具合があると、権限の見方が一段深くなります。
{{product:0}}
### findで安全に再帰変更
再帰変更の演習は、ワークディレクトリの中だけで完結させるのが前提です。ディレクトリとファイルを混在させた木を作って、`find` で対象を分けて設定します。ここでの狙いは、ディレクトリには 755、通常ファイルには 644 を分けて適用する感覚をつかむことです。前述の通り、両者を同じ数値でまとめてそろえると、実行不要なファイルまで `x` が付いたり、逆にディレクトリの通過権が落ちたりします。
`find` を使うときは、いきなり `-exec chmod ...` に進まず、まず対象一覧だけを表示する流れが安全です。筆者は `find . -type d` と `find . -type f` で対象が想定通りかを見てから、変更コマンドに進みます。これを挟むだけで、作業場所を取り違えたときの被害が抑えられます。サンドボックスを `/tmp` に置いているのも、この確認を気楽に繰り返せるからです。
たとえばディレクトリだけを拾って 755、ファイルだけを拾って 644 にすると、`ls -lR` で見たときに並びがきれいに整います。Web 公開ディレクトリの初期整備でもこの考え方はそのまま使えますが、演習ではまず「なぜ分けるのか」を自分の目で確認するのが先です。`find` は強力なので、`-R` より安全に対象を絞れるという実感をここで持っておくと、その後の実運用でも無理のない手順になります。
### umaskの確認と検証
次は `umask` を見て、新規作成時の初期権限と突き合わせます。シェルで `umask` を表示したあと、空ファイルとディレクトリを新規作成して `ls -l` で確認すると、数値の説明がそのまま画面に現れます。基準はファイルが 666、ディレクトリが 777 で、umask が 022 なら新規ファイルは 644、ディレクトリは 755 になります。普段よく見る数値が、実は「最初から固定で与えられる値」ではなく、「基準値から差し引かれた結果」だとわかる瞬間です。
ここでは umask を一時的に変えて差も比べられます。たとえば 002 にすると、新規ファイルは 664、ディレクトリは 775 になります。グループ共同編集を前提にした作業領域でこの差が効いてくるので、owner だけでなく group の振る舞いを読む練習にもなります。`touch` と `mkdir` の結果を並べると、同じ umask でもファイルとディレクトリで初期値が異なる理由が腑に落ちます。
筆者は初心者向けの説明でも、この演習を入れると理解の速度が上がると感じています。644 や 755 を暗記するだけだと、なぜその値になるのかが残りません。自分のシェルで `umask` を見て、直後に作ったファイルの mode が一致すると、「普段見ていた数値」と「作成時のルール」がつながります。
> [!TIP]
> `umask` の確認は、既存ファイルに `chmod` を当てる演習と並べると理解が定着します。新規作成時の初期値を決めるのが umask で、既存ファイルの状態を変えるのが `chmod` だと切り分けると、役割が混ざりません。
### ACL/SELinuxの入門演習
標準の owner / group / others だけで足りない場面を軽く触るなら、ここはオプション課題として進めるのがちょうどいいところです。ACL では `getfacl` で現状を読み、`setfacl` で特定ユーザーやグループに追加権限を付けます。たとえば通常の mode では表せない「このユーザーだけ読み取りを許す」といった例外を作ると、`ls -l` だけでは見えない権限層があることがわかります。前のセクションで触れた mask の存在も、実際に `getfacl` の出力を見ると理解しやすくなります。
SELinux の入門演習では、`ls -Z` でラベルを表示し、`restorecon` で既定のコンテキストへ戻す流れを試します。Red Hat系の環境で Web 配信用ディレクトリを触った経験があると、この確認の意味がよくわかります。筆者もNginxの配信確認で mode と owner に問題が見当たらず、`ls -Z` を見て初めて原因にたどり着いたことがありました。通常権限が正しく見えても、SELinux の文脈で拒否されることがあるので、`chmod` の外側にもう1層あると意識できるだけで切り分けの質が上がります。
`restorecon` は、手で変えてしまったラベルを既定ルールに沿って戻す場面で役立ちます。静的コンテンツ向けの `httpd_sys_content_t` を持つべき場所でそれ以外のラベルになっていると、Web サーバーが読めずに止まることがあります。ここまで来ると初心者向けの基礎を一歩超えますが、`ls -l`、`stat`、`getfacl`、`ls -Z` を順番に見る流れを一度体験しておくと、「権限の数字は合っているのに拒否される」場面でも迷いにくくなります。
{{related:ubuntu-install-guide}}
## 次のステップ
権限まわりは、数字を覚えて終わりではなく、**どの層を触っているのかを切り分けられること**が次の成長につながります。この記事で `chmod` と `chown` の違いが腹落ちしたら、次はファイル操作やプロセス管理まで基礎を広げる段階です。身近な用途で小さく試し、失敗した理由を `ls -l` や関連コマンドで追う流れを何度か回すと、知識が実務の判断に変わっていきます。筆者も新規プロジェクトでは、`uploads` のような書き込み先だけを 775 にし、グループを先に整える運用を定型化しており、このひと手間で不要な開放や後戻りを減らしています。

この記事をシェア

佐々木 まい

IT企業でのシステムエンジニア経験を経て、スマートホーム導入のコンサルティングに転身。Home AssistantやESPHomeを使った自宅オートメーションを日々研究中。