# SSHなしレンタルサーバーへのLaravel本番反映手順【サブディレクトリ配置編】

対象環境：SSHログイン不可、FTP + ファイルマネージャーのみ使用可能なレンタルサーバー

**既存の静的ホームページが公開済みの状態を維持したまま、`/reservation/`以下にLaravelアプリを追加する**構成です。

サーバー上でコマンドを実行できないため、ローカルで本番用に完成させたファイル一式を作り、それをアップロードします。

---

# 完成後のディレクトリ構成

```
public_html/
├── index.html          ← 既存サイト（そのまま）
├── css/                ← 既存サイト（そのまま）
├── js/                 ← 既存サイト（そのまま）
├── images/             ← 既存サイト（そのまま）
│
└── reservation/        ← ここから下がLaravel
    ├── index.php       ← public/index.php（要パス修正）
    ├── .htaccess       ← public/.htaccess（要RewriteBase追加）
    ├── build/          ← public/build
    ├── favicon.ico     ← public配下のその他ファイル
    └── laravel_app/    ← public以外のLaravel本体一式
        ├── .htaccess   ← 外部アクセス遮断用（新規作成）
        ├── app/
        ├── bootstrap/
        ├── config/
        ├── database/
        ├── resources/
        ├── routes/
        ├── storage/
        ├── vendor/
        ├── artisan
        ├── composer.json
        └── .env
```

アクセスURLは `https://example.com/reservation/` になります。

---

# パートA：ローカルでの作業

## A-1. 本番用に依存パッケージをビルド

```bash
composer install --optimize-autoloader --no-dev
npm install
npm run build
```

- `--no-dev`：開発用パッケージ（PHPUnit・Faker等）を除外
- `npm run build`：`public/build`にCSS・JSを生成

> `vendor`はそのままアップロードします。ローカルと本番でPHPバージョンや拡張構成が大きく異なると動作しないため、可能な限り本番と同じPHP環境でComposerを実行してください。

## A-2. 本番用 `.env` を作成

サブディレクトリ配置では`APP_URL`にパスまで含める点が重要です。

```env
APP_NAME=YourApp
APP_ENV=production
APP_DEBUG=false
APP_URL=https://example.com/reservation

DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=xxxx
DB_USERNAME=xxxx
DB_PASSWORD=xxxx

SESSION_PATH=/reservation
```

- `APP_URL`：末尾スラッシュなしで`/reservation`まで指定します。ここが間違っているとCSSやJSのパスがずれます
- `SESSION_PATH`：セッションCookieの有効範囲を`/reservation`配下に限定します。既存サイト側にCookieが漏れず、将来同じドメインに別アプリを置く場合の衝突も防げます
- `APP_DEBUG=false`は必須です。`true`のままだとエラー内容やサーバー情報が外部に漏れます

## A-3. APP_KEYを生成

```bash
php artisan key:generate --show
```

出力されたキーを本番用`.env`の`APP_KEY`に設定します。

```env
APP_KEY=base64:Jf6QjL2mYj4lVqv7v0gYQ1eW5gF7Q8mM2nP8Xc9KkL0=
```

## A-4. `config:cache` は実行しない

`php artisan config:cache`を実行すると、その時の`.env`の値が`bootstrap/cache/config.php`に焼き込まれます。ローカルで実行したものをアップロードすると、ローカルのDB接続先やURLで本番が動いてしまうため**実行しないでください**。

`view:cache`・`route:cache`は環境依存の値を含まないため理論上は問題ありませんが、SSHが無い環境ではキャッシュのクリアが手作業になります。ルートやBladeを変更するたびに該当ファイルの削除が必要になるので、こちらも生成しない運用が無難です。

なお`bootstrap/cache/packages.php`・`services.php`はComposerが自動生成するファイルなので、そのままアップロードして問題ありません。

## A-5. `reservation/index.php` のパスを修正

`public/index.php`をコピーし、Laravel本体を参照している**すべてのパス**を`laravel_app/`配下に向けて書き換えます。バージョンによって記述は異なりますが、対象は次の3箇所です。

```php
// メンテナンスモードのチェック
if (file_exists($maintenance = __DIR__.'/laravel_app/storage/framework/maintenance.php')) {

// オートローダー
require __DIR__.'/laravel_app/vendor/autoload.php';

// アプリケーション本体
$app = require_once __DIR__.'/laravel_app/bootstrap/app.php';
```

元は`__DIR__.'/../'`（1階層上）になっている箇所を、`__DIR__.'/laravel_app/'`（同階層のサブフォルダ）に変える形です。`vendor/autoload.php`だけ直して他を直し忘れるとエラーになるので、`__DIR__`を含む行をすべて確認してください。

## A-6. `reservation/.htaccess` を用意

`public/.htaccess`をベースに、**`RewriteBase /reservation/`の1行を追加**します。これが無いとサブディレクトリでのURL書き換えが正しく動かず、404やリダイレクトループが起きます。

```apache
<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On
    RewriteBase /reservation/

    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>
```

### 既存サイト側の.htaccessとの関係

`public_html`直下に既存サイトの`.htaccess`がある場合、その内容によっては`/reservation/`へのアクセスが横取りされることがあります。以下のような**全リクエストを書き換えるルール**が既存サイト側にある場合は要注意です。

```apache
RewriteRule ^(.*)$ /index.html [L]
```

この場合、既存サイト側の`.htaccess`に除外条件を追加する必要があります。

```apache
RewriteCond %{REQUEST_URI} !^/reservation/
```

既存サイトが静的HTMLを置いているだけで`.htaccess`が無い、あるいは書き換えルールが無いのであれば、変更は不要です。**まず既存の`.htaccess`の中身を確認し、必要な場合のみ手を入れてください。**（変更前にバックアップを取ることを推奨します）

## A-7. `laravel_app/.htaccess` を新規作成

`laravel_app/`は公開ディレクトリ配下にあるため、そのままだと`.env`やソースコードにURL直打ちでアクセスできてしまう可能性があります。以下の内容の`.htaccess`を`laravel_app/`直下に置き、外部アクセスを遮断してください。

```apache
# Apache 2.4系
<IfModule mod_authz_core.c>
    Require all denied
</IfModule>

# Apache 2.2系
<IfModule !mod_authz_core.c>
    Order deny,allow
    Deny from all
</IfModule>
```

配置後、`https://example.com/reservation/laravel_app/.env`にアクセスして403が返ることを必ず確認してください。

## A-8. DBのSQLを用意

サーバー上で`artisan migrate`が打てないため、事前にSQLを作っておきます。

**初回構築時**：ローカルで`php artisan migrate`を実行し、スキーマのみをエクスポート

```bash
mysqldump -u ユーザー名 -p --no-data データベース名 > schema.sql
```

**更新時**：スキーマ全体ではなく、`ALTER TABLE`・`CREATE INDEX`など変更差分のSQLだけを作成

## A-9. アップロード対象を整理

`.git/`と`node_modules/`は除外します（`node_modules`はビルド済みの`public/build`があれば不要）。

ローカル用`.env`をアップロードしないよう注意し、A-2で作った本番用`.env`のみを対象にしてください。

`vendor`は数千ファイルになるためFTPだと非常に時間がかかります。ファイルマネージャーにZIP解凍機能があれば、圧縮してアップロード→サーバー側で展開すると大幅に短縮できます。

---

# パートB：本番サーバーでの作業

## B-1. `reservation/` ディレクトリを作成してアップロード

`public_html`直下に`reservation`フォルダを作成し、その中にパートAで準備した一式をアップロードします。**既存サイトのファイルには触れません。**

`vendor`をZIPで送った場合はサーバー側で展開してください。

## B-2. DBにSQLを反映

A-8で用意したSQLを、コントロールパネルのphpMyAdmin等からインポートします。

サーバーが外部からのMySQL接続を許可している場合は、ローカルの`.env`の`DB_HOST`を本番のホスト名に一時的に切り替えて、ローカルから直接`php artisan migrate`を実行することもできます。

## B-3. storage:linkの代替対応

`php artisan storage:link`はシンボリックリンクを作るコマンドですが、SSHが無いと実行できません。画像アップロード機能などで使用している場合は次のいずれかで対応します。

- レンタルサーバーのシンボリックリンク作成機能を利用する
- ファイルマネージャーで手動コピーする（`laravel_app/storage/app/public`の中身を`reservation/storage/`へ）
- 保存方法自体を変更する

## B-4. 権限を確認

`laravel_app/storage/`と`laravel_app/bootstrap/cache/`はPHPから書き込み可能である必要があります。サーバーのマニュアルや管理画面で推奨されている権限設定を確認し、必要以上に緩めないようにしてください。

## B-5. 動作確認

**既存サイト側（デグレしていないことの確認）**

- トップページが今まで通り表示されるか
- 既存の各ページ・フォームが正常に動くか

**Laravel側**

- `https://example.com/reservation/`が表示されるか
- CSS・JSが適用されているか（適用されていない場合は`APP_URL`のパス指定を確認）
- 下層ページのURLが動くか（`.htaccess`と`RewriteBase`が効いているかの確認）
- ログイン・フォーム送信・画像アップロード（該当機能があれば）

**セキュリティ**

- `https://example.com/reservation/laravel_app/.env` が403になるか

500エラーが出る場合は`laravel_app/storage/logs/laravel.log`を確認します。原因の多くは`storage/framework`配下の権限不足です。

---

# 更新時の運用（2回目以降）

- 変更したファイルのみアップロード（FTPクライアントの差分同期機能が便利）
- `.env`は上書きしない
- DB変更は差分SQLのみ反映
- 必要な場合のみ`vendor`も更新
- 作業範囲は`reservation/`配下に限定する（既存サイトへの影響を避ける）
