技術別対策
レンタルサーバーで .env を公開しないための配置と設定
共用レンタルサーバーにLaravel等のアプリを置くとき、.env・.git・vendor を外から読めなくする実践ガイド。本命は『アプリ本体を公開ルートの外に置き、public/ だけを見せる』構造。配置の正誤を図解し、すぐできる .htaccess の止血、恒久対策の手順、ITDが実戦で学んだ罠(symlinkより bootstrap-redirect)、そして自己点検の方法までまとめます。
対象:共用レンタルサーバー(Apache/.htaccess が使える環境)に Laravel など「public/ だけ公開する前提」のアプリを置いている人。実際の事故(→ .env全公開の話)から抽出した、自分の環境を守るための手順です。
ITDの視点:これは“個人のミス”ではない
レンタルサーバー黎明期の「public_html 直下に全部置く」文化に、public/ だけを晒す前提のLaravelが流入した結果、危険な配置が事実上の標準になってしまいました。各社の公式ドキュメントすら public_html 内にプロジェクトを置く例ばかりです。だから対策は個人の注意力ではなく“仕組み”にするのが正解——デプロイ手順のデフォルトを変えるのです。
正しい配置を図で押さえる
✗ 危険(本体を公開ルート直下)
public_html/ ├─ .env ← 読める! ├─ .git/ vendor/ └─ public/
✓ 安全(本体は外、public だけ)
app-laravel/ ← 公開ルート外 ├─ .env .git/ ← 到達不能 └─ public/ → public_html から require
Step 1:止血(すぐできる・可逆)
公開ルートの .htaccess 冒頭に、機密ファイルを拒否するブロックを追記します(防御目的の設定例)。通常表示には影響しません。
# === SECURITY BLOCK ===
RedirectMatch 404 (?i)/\.(env|git)(\..*)?(/|$)
<FilesMatch "(?i)\.(sql|sql\.gz|bak|old|swp|save|orig|tgz)$|^credentials\.json$|\.bk[._]">
Require all denied
</FilesMatch>
<FilesMatch "(?i)^(phpinfo|info)\.php$">
Require all denied
</FilesMatch>
# /<app>/storage 等の内部ディレクトリが見えている場合
RedirectMatch 403 (?i)^/[^/]+/(storage|bootstrap/cache|config|database|resources|routes|tests|vendor)(/|$)
# === END ===止血はゴールではない
ブラックリストは composer.lock や .gitignore など『塞ぎ忘れ』が必ず出るモグラ叩きです。あくまで Step 2 までの時間稼ぎと考えます。
Step 2:構造改修(恒久対策)
アプリ本体を公開ルートの外へ移し、公開ルートには「読み込むだけの小さな入口」を置きます。
# 1. 本体を公開ルートの外へ(同一ファイルシステムなら mv は一瞬・atomic)
mv ~/example/public_html/app ~/example/app-laravel
# 2. 公開ルートに最小の入口だけ作る
mkdir -p ~/example/public_html/sub
cat > ~/example/public_html/sub/index.php <<'PHP'
<?php require __DIR__ . '/../../app-laravel/public/index.php';
PHP
# 3. Laravel public/.htaccess をコピー、静的アセットを symlink
# 4. 設定キャッシュをクリア
rm -f ~/example/app-laravel/bootstrap/cache/{config,services,packages,routes-v7}.phpITDが実戦で学んだ罠:symlinkより bootstrap-redirect
「public_html 自体を public/ へのsymlinkにする」やり方は、登録済みサブドメインのdocrootだと追従せず500になる環境があります。docrootは実ディレクトリのまま、中の小さな index.php から絶対パスで require する「bootstrap-redirect型」のほうが、スコープ制約のある共用環境で安定します。さらに opcache が壊れたロードを記憶して500を返し続けることがあり、最終手段は入口ファイル名を変える(entry.php 等)です。
Step 3:鍵ローテーション(漏れていた前提で)
公開されていた期間があるなら、.env の鍵は見られた前提で入れ替えます。優先順は「外部API・OAuthシークレット → 暗号鍵 → メール → DB」。.env の項も参照。OAuthのシークレット再発行は refresh_token を無効化することがあるので、再認可フローを用意してから実施します。
Step 4:自己点検(習慣化)
最後に、自分のサイトで実際に漏れていないか確認します(自分の所有ドメインに対してのみ)。
# 200 で本文が返ったら公開されている。403/404 なら一旦OK
curl -sI https://あなたのドメイン/.env | head -1
curl -sI https://あなたのドメイン/.git/config | head -1これを公開のたびに確認する癖をつけると、配置ミスを早期に発見できます。
次に読む
よくある質問
Qとりあえず今すぐできる対策は?
公開ルートの .htaccess に『.env・.git・SQLダンプ・credentials.json などを拒否する』ブロックを追記する止血です。可逆で通常表示に影響しません。ただしこれは応急処置で、本命は構造改修です。
Qなぜ .htaccess だけだと不十分なの?
ブラックリストは新しい名前のファイルを足すたびに穴が増えるモグラ叩きだからです。アプリ本体を公開ルートの外に出せば、.env がそもそも到達不能になり、ルールに頼らず安全になります。
Qsymlink で public/ を晒すのではダメ?
環境によっては、登録済みサブドメインのdocrootを後からsymlinkで別ツリーに向けると追従せず500になります。ITDの経験では、docrootは実ディレクトリのまま、中の小さな index.php から絶対パスで require する『bootstrap-redirect型』のほうが安定します。