Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?

【Laravel×Heroku】シンボリックリンクが上手くいかない時の対処法

"laravel シンボリックリンク" を検索すると、多くの関連記事が出てくると思います。
自分も、今回laravelアプリを開発していて、本番環境でシンボリックリンクが効いておらずハマったのですが、全く同じ境遇という方が見受けられなかったため、記事を書いています。

対象者

・Laravelでstorageディレクトリを使った画像表示、ファイルの操作を行う方

前提

・Laravelアプリを、Herokuにデプロイする方

ローカル環境でシンボリックリンクが上手くいっていない方は
Laravelでpublicフォルダ配下に保存したファイルにアクセスできないを参考にしてみてください。

まずはこれを試してみる

今回の解決策を述べる前に、まずまだ何も試していない方は、以下を確認してみてください。

そもそも本番環境にシンボリックリンクが無い。

laravelで普通に開発をしている場合、ローカル環境で設定したシンボリックリンクはGitにpushされません。本番環境にGitと連携してpushする場合、Gitに無いものはpushされないのは当然のことです。
これを解消するには、アプリのホームディレクトリ上にある.gitignoreから、public/storageを削除してください。これで、ローカル環境で作成したシンボリックリンクはGitで管理されるようになるため、pushして、本番環境にデプロイしてみてください。

.gitignore
/node_modules
/public/hot
/public/storage  #削除
/storage/*.key
/vendor
.env
.env.backup
.phpunit.result.cache
docker-compose.override.yml
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log

heroku run php artisan storage:linkを実行すれば良いんじゃないの?
と思うかも知れません。自分もそう考えてHerokuにpushした後に実行してみましたが、効果はありませんでした。試しに、Herokuにssh接続してみた結果、シンボリックリンクが作成されて無いことに気が付きました。

さらに、ssh接続したHeroku上で、php artisan storage:linkを実行します。この瞬間では、public/storageとしてシンボリックリンクが作成されます。しかし、一度ssh接続を終了し、再度接続した時にはもう消えています。

Heroku上で直接行うのは意味がない
Heroku上で、直接ファイル操作をするのは、意味がなかったようです。
Herokuはマルチテナントであるが故に、インスタンスの切り替えが発生するらしいです。
以下のタイミングでその切り替えが発生し、直接アップ(Git以外から操作)したファイルなどが消えてしまいます。

  • Git Push時
  • Heroku config変更時
  • おおむね1日1度、自動的に再起動

Heroku初心者がつまづいたこと3つ

それでも動かない

・ローカル環境ではシンボリックリンクで正常に動作する
・本番環境では動作しないが、シンボリックリンクは存在する
この2点が重なった場合、考えられる可能性は、以下の2つです。

・権限の問題でアクセスできない
・シンボリックリンクのパスが環境の差異による影響を受けている

権限が無い場合

当方は、こちらに遭遇したことはないのですが、一応載せておきます。一応。
app/storageディレクトリのパーミッションの設定~Laravel初期設定~

シンボリックリンクのパスが環境の差異による影響を受けている

当方の場合、こちらでした。
Docker環境で開発しており、Herokuにはアプリ本体だけをデプロイしていたために発生しました。

ローカル環境のシンボリックリンクのパスを確認

% cd public
% ls -l

...省略
lrwxr-xr-x ... storage -> /workspace/[アプリのディレクトリ]/storage/app/public
...省略

Herokuのシンボリックリンクのパスの確認

% heroku run bash

[~ $ cd public
[~/public $ ls -l

lrwxrwxrwx ... dyno ... storage -> /workspace/[アプリのディレクトリ]/storage/app/public

ローカル環境で作成したシンボリックリンクがそのままです。
しかし、Heroku環境はこのようなディレクトリ構造になっていないため、リンク切れになっていると想定できます。

Heroku上の正しいシンボリックリンクのリンクを確認

Herokuで正常に動作させるには、Heroku上のディレクトリ構造に合わせてあげなければなりません。
ただ、Heroku上で直接変更しても意味がないのは前述の通りです。
なので、Heroku上の正しいパスを確認し、それをローカル環境で設定し、pushし直します。

heroku
[ ~ $ cd public
[ ~/public $ rm storage
[ ~/public $ ls -l #storageが無いことを確認してください。

[ ~/public $ cd
[ ~ $ php artisan storage:link
[ ~ $ cd public
[ ~/public $ ls -l

lrwxrwxrwx ... dyno ... storage -> /app/storage/app/public

このように、Heroku上の正しいパスでシンボリックリンクが作成されます。
このパスで再設定してあげます。

ローカル
% cd public
% rm storage #既存のシンボリックリンクを削除します。
% ln -s /app/storage/app/public storage
$ ln -s リンク元 登録名

リンク元に設定するリンク、登録名にシンボリックリンクの名前を設定します。
php artisan storage:linkはlaravelのコマンドですが、lnはlinuxコマンドです。
windowsの場合はmklinkコマンドがあります。

確認します。

% ls -l

...
lrwxr-xr-x ... storage -> /app/storage/app/public
...

これで、Heroku上のディレクトリ構造に合わせることができました。
ただし、ローカル環境で正常に動作しなくなるので、再設定が必要です。

再デプロイ

以上が設定し終わったら、Herokuにデプロイします。
正常に動作するはずです。

最後に

対処療法的なものだと思うので、もしよりベターな方法があればアドバイスいただけるとありがたいです。

参考にした記事
シンボリックリンクの作成, 確認, 削除
Laravel シンボリックリンクで少しハマった話
Heroku初心者がつまづいたこと3つ
lnコマンドについて詳しくまとめました 【Linuxコマンド集】
app/storageディレクトリのパーミッションの設定~Laravel初期設定~
Laravelでpublicフォルダ配下に保存したファイルにアクセスできない
Windows 10でシンボリックリンクを作成する
Mklink - DOS コマンド一覧
herokuでアプリを指定してsshログイン

大変参考になりました。有難うございます!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?