LinuxのOpenSSHでSFTPユーザーをChrootDirectoryに制限する方法|シェルアクセスなしのファイル転送サーバーを構築する

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Linuxtips > セキュリティ > LinuxのOpenSSHでSFTPユーザーをChrootDirectoryに制限する方法|シェルアクセスなしのファイル転送サーバーを構築する
「WebサイトのファイルをSFTPで更新してほしいが、サーバーのシェルには入らせたくない」
こういった要件はLinuxサーバーの運用で必ずと言っていいほど出てくる。ところがOpenSSHをデフォルト設定のまま使うと、SFTPアクセスを許可した瞬間にシェル接続も可能になってしまう。

この記事では、OpenSSHの ChrootDirectory ディレクティブと Match Group ブロックを使って、SFTP専用ユーザーを特定のディレクトリだけに封じ込め、通常のSSHシェルアクセスを完全に禁止する設定手順を解説する。RHEL 9.4 / Rocky Linux 9.4 / Ubuntu 24.04 LTS で動作確認済みの実機手順をベースに説明する。

この記事のポイント

・sshd_configのChrootDirectoryで、SFTPユーザーを特定ディレクトリに封じ込められる
・ChrootDirectory本体はroot所有・パーミッション755でなければ「Bad ownership or modes」エラーが出る
・ForceCommand internal-sftpで通常のSSHシェル接続を完全に拒否できる
・Match Groupブロックを使えばSFTP専用グループのみに制限を適用でき、他のSSHユーザーに影響しない


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

なぜSFTPにChrootDirectoryが必要なのか

OpenSSHのデフォルト設定でSFTPを許可すると、次の2つの問題が生まれる。

・シェルも使える: 通常のSSH接続も可能なため、シェルコマンドが自由に実行できる
・他のディレクトリも見える: SFTPでホームディレクトリ以外のパスへ cd することもできる

ChrootDirectory は、SSH接続後にユーザーのルートを指定のディレクトリに切り替える(chroot)仕組みだ。ユーザーはそのディレクトリの外が見えなくなる。さらに ForceCommand internal-sftp を組み合わせることで、SFTPプロトコルしか使えなくし、シェルの起動を完全に拒否できる。

設定の全体像と実行環境

設定は大きく3つのステップに分かれる。

・ステップ1 ユーザー・グループ作成: SFTP専用グループを作り、そのグループのユーザーのみを制限する
・ステップ2 ディレクトリ作成: ChrootDirectoryには所有者root・パーミッション755のディレクトリが必要
・ステップ3 sshd_config設定: Match Groupブロックを末尾に追加し、ChrootDirectoryとForceCommandを指定する

実行環境は以下で確認した。
・RHEL 9.4 / Rocky Linux 9.4(OpenSSH 8.7p1)
・Ubuntu 24.04 LTS(OpenSSH 9.6p1)

手順1:SFTPグループとユーザーを作成する

1. sftpusersグループを作成する

# SFTPアクセス専用グループを作成する groupadd sftpusers

2. SFTP専用ユーザーを作成する

以下の例では webdev というユーザーを作成し、sftpusers グループに所属させる。-s /sbin/nologin でシェルログインを無効にし、-M でホームディレクトリを作成しない(ChrootDirectory配下に別途作るため)。

# ユーザー作成(シェルはnologin・ホームディレクトリは作らない) useradd -M -s /sbin/nologin -g sftpusers webdev # パスワードを設定する passwd webdev

既存ユーザーをsftpusersグループに追加するだけでよい場合は usermod を使う。

# 既存ユーザーをsftpusersグループに追加する(-aで既存グループは維持) usermod -aG sftpusers 既存ユーザー名

手順2:ChrootDirectory用のディレクトリ構造を作る

1. ディレクトリ階層のルール

ChrootDirectory には必ず守らなければならないルールがある。

・ChrootDirectory本体の所有者はrootでなければならない
・ChrootDirectory本体のパーミッションは755以下(他ユーザーへの書き込みビットがあるとエラー)
・ユーザーが書き込む場所は、ChrootDirectory配下のサブディレクトリとして別途作る

ChrootDirectory を /srv/sftp/webdev に設定する場合、ディレクトリ階層は次のようになる。

/srv/sftp/webdev/ ← root所有・755(ChrootDirectory本体)
/srv/sftp/webdev/upload/ ← webdev所有・755(ユーザーが実際に書き込む場所)

2. ディレクトリを作成して所有者・パーミッションを設定する

# ChrootDirectory本体(root所有・755が必須) mkdir -p /srv/sftp/webdev chown root:root /srv/sftp/webdev chmod 755 /srv/sftp/webdev # ユーザーが実際にファイルを置くサブディレクトリ(webdev所有) mkdir /srv/sftp/webdev/upload chown webdev:sftpusers /srv/sftp/webdev/upload chmod 755 /srv/sftp/webdev/upload

ls -la で確認する。

$ ls -la /srv/sftp/webdev/ total 0 drwxr-xr-x. 3 root root 20 Oct 6 09:23 . drwxr-xr-x. 3 root root 19 Oct 6 09:23 .. drwxr-xr-x. 2 webdev sftpusers 20 Oct 6 09:23 upload

webdev/ の所有者が root root でパーミッションが drwxr-xr-x(755)になっている。これが正しい状態だ。

手順3:sshd_configにMatch Groupブロックを追加する

1. 設定ファイルに追記する内容

/etc/ssh/sshd_config の末尾に以下のブロックを追加する。Match ブロックは必ずファイルの末尾に置くこと(Match以降の設定は前のグローバル設定をオーバーライドする仕組みのため、Matchブロックの後にグローバル設定を書くとMatchブロック配下に取り込まれる)。

# /etc/ssh/sshd_config の末尾に追加する Match Group sftpusers ChrootDirectory /srv/sftp/%u ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no

各ディレクティブの意味を補足する。

・Match Group sftpusers: sftpusersグループに所属するユーザーにのみ、以下の設定を適用する
・ChrootDirectory /srv/sftp/%u: %uはユーザー名に展開される。webdevなら /srv/sftp/webdev にchrootされる
・ForceCommand internal-sftp: ログイン後に必ず internal-sftp だけを実行させ、シェルを起動させない
・AllowTcpForwarding no: ポートフォワーディングも禁止する(セキュリティ強化)

ForceCommand internal-sftp は一見地味な設定だが強力だ。SFTPプロトコルだけに限定することで、ポートフォワーディングや exec など SSHの全機能を封じ込められる。このようなLinuxサーバーのアクセス制御設計は、現場での必須スキルの一つだ。

2. 設定構文テストとsshdの再起動

設定ミスでSSH接続ができなくなると取り返しがつかない。必ず sshd -t で構文テストを通してから再起動する。

# sshd_configの構文テスト(エラーがなければ終了コード0で何も表示されない) sshd -t # 問題なければsshdを再起動する systemctl restart sshd # 再起動後のステータス確認 systemctl status sshd

* sshd.service - OpenSSH server daemon Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; preset: enabled) Active: active (running) since Mon 2026-10-06 09:30:12 JST; 5s ago Main PID: 12345 (sshd)

動作テスト:SFTPで接続し通常SSHが拒否されることを確認する

1. SFTP接続テスト

別のPCから webdev ユーザーでSFTP接続する。

$ sftp webdev@192.168.1.xx webdev@192.168.1.xx's password: Connected to 192.168.1.xx. sftp> pwd Remote working directory: / sftp> ls upload sftp> cd upload sftp> put test.txt Uploading test.txt to /upload/test.txt test.txt 100% 5 0.0KB/s 00:00 sftp> cd .. sftp> cd /etc Couldn't canonicalize: No such file or directory

pwd の結果が / と表示されているのは、/srv/sftp/webdev にchrootされているためだ(本当のルートの /srv/sftp/webdev が / に見える)。/etc に移動しようとするとエラーになる。これが ChrootDirectory の効果だ。

2. 通常SSH接続が拒否されることを確認する

同じユーザーで通常のSSH接続を試みると、即座に切断される。

$ ssh webdev@192.168.1.xx webdev@192.168.1.xx's password: This service allows sftp connections only. Connection to 192.168.1.xx closed.

ForceCommand internal-sftp が有効なため、シェルの代わりにinternal-sftpが起動し、SSH接続はすぐに閉じられる。セミナーの実習でこの設定を確認してもらうと「シェルが起動しない=設定ミスかと焦る」受講生が必ず出るが、この動作は正しい。

トラブルシュート

「Bad ownership or modes for chroot directory」が出る

ChrootDirectory本体の所有者またはパーミッションが誤っている場合に発生する。/var/log/secure または journalctl -u sshd に記録される。

# エラーの例(journalctl -u sshd または /var/log/secure で確認) Oct 6 09:45:12 server1 sshd[12678]: fatal: bad ownership or modes for chroot directory "/srv/sftp/webdev"

対処法は以下の通りだ。

# ChrootDirectory本体の所有者をrootに修正する chown root:root /srv/sftp/webdev # パーミッションを755にする(他グループへの書き込みビットは不可) chmod 755 /srv/sftp/webdev

よくある間違いは「webdev ユーザーが /srv/sftp/webdev に直接書き込みたいので webdev に chown する」というパターンだ。ChrootDirectory本体はrootが所有し、書き込みはサブディレクトリに限定するという設計を守ること。

SFTPで接続できるがディレクトリが見えない・書けない

ChrootDirectory 直下に書き込み権限のあるサブディレクトリ(upload/ 等)を作り忘れている場合が多い。ls で upload/ の所有者を確認し、webdev になっていなければ修正する。

# サブディレクトリの所有者確認 ls -la /srv/sftp/webdev/ total 0 drwxr-xr-x. 3 root root 20 Oct 6 09:23 . drwxr-xr-x. 3 root root 19 Oct 6 09:23 .. drwxr-xr-x. 2 root root 20 Oct 6 09:23 upload ← 誤り: rootのまま # 修正する chown webdev:sftpusers /srv/sftp/webdev/upload

SELinuxのためPermission deniedになる(RHEL/Rocky Linux)

RHEL / Rocky Linux 環境では SELinux が有効な場合、/srv 配下のディレクトリのデフォルトラベルが var_t になっており、sshd_t ドメインのSFTP操作を拒否することがある。

# SELinuxラベルを確認する ls -laZ /srv/sftp/ drwxr-xr-x. 3 root root unconfined_u:object_r:var_t:s0 19 Oct 6 09:23 webdev # SFTP用のSELinuxラベルを設定して適用する semanage fcontext -a -t ssh_home_t "/srv/sftp(/.*)?" restorecon -Rv /srv/sftp

設定後、ls -laZ /srv/sftp/ で ssh_home_t ラベルが付与されたことを確認してから再度SFTP接続テストを行う。

本記事のまとめ

やりたいこと 設定内容
SFTPユーザーを特定ディレクトリに閉じ込める ChrootDirectory /srv/sftp/%u
通常のSSHシェルを完全に無効化する ForceCommand internal-sftp
特定グループのユーザーにのみ制限を適用する Match Group sftpusers
ChrootDirectory本体の所有者とパーミッション root所有・パーミッション755
ユーザーが書き込む場所 ChrootDirectory配下のサブディレクトリ(ユーザー所有)
Bad ownershipエラーの原因 ChrootDirectory本体がroot以外の所有 / 書き込みビットあり
OpenSSHのChrootDirectory設定は、ディレクトリ構造のルールとSELinuxラベルさえ押さえれば難しくない。一度設定しておけばWebサーバーのSFTPアクセスを安全に外部に開放でき、シェルアクセスのリスクをゼロにできる。

現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、

SSH設定・SELinux・firewalldを含むサーバーセキュリティ設計を、現役のサーバー管理者が2日間ハンズオンで指導するセミナーを開催しています。3,100名以上の受講実績を持つ実践的な内容です。

>> Linux Master Pro Seminar の詳細はこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。