MinIOは、AWSのS3と互換性のあるオブジェクトストレージサーバーです。
開発環境でS3の代替として使用されることが多く、ローカル環境でクラウドストレージのシミュレーションを行うのに適しています。
LaravelのファイルストレージでMinIOを使用する際、公式ドキュメントではtemporaryUrl
メソッドがサポートされていないと記述されています。
MinIOを使用する場合、temporaryUrlメソッドによる一時ストレージURLの生成はサポートされていません。
サポートされていないと書かれていますが、temporaryUrl
メソッド自体は動作します。
ただ、設定によっては、生成されたURLがブラウザからアクセスできない場合があります。
その問題点と解決策について説明します。
問題点
開発環境をDockerで構築した場合、MinIOを使用する際の環境変数は以下のようになると思います。
AWS_ACCESS_KEY_ID=minio_username
AWS_SECRET_ACCESS_KEY=minio_password
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=local
AWS_ENDPOINT=http://minio:9001
AWS_USE_PATH_STYLE_ENDPOINT=true
AWS_ENDPOINT
にはPHPアプリケーション側からアクセスするためのURLを指定します。
ただ、この設定のみだと、url
メソッドを使いURLを生成した場合、http://minio:9001/local/xxx
のようなURLが生成されます。
このURLはPHPアプリケーション側からみたDockerネットワーク内部のURLなので、Docker外部(つまり、ホストマシンのブラウザなど)から直接アクセスすることはできません。
そのため、ドキュメントには次のように書かれています。
MinIOを使用するときに Laravelの統合が適切なURLを生成するには、AWS_URLアプリケーションのローカル URLと一致し、URLパスにバケット名が含まれるように環境変数を定義する必要があります。
なので、環境変数にAWS_URL
を追加します。
AWS_URL=http://localhost:9001/local
この設定を行うことで、url
メソッドでURLを生成した場合、http://localhost:9001/local/xxx
のようなURLが生成されDocker外部からアクセスできるようになります。
ただ、temporaryUrl
メソッドによるURLの生成はAWS_URL
ではなくAWS_ENDPOINT
を元に生成されるため、Docker外部からアクセスできません。
temporaryUrl
メソッド自体は動作するので、AWS_ENDPOINT
のURLをDocker外部からアクセスできる状態になれば問題は解決します。
解決策
上記の状態で一番簡単な解決策は、AWS_URL
の環境変数は使わず、AWS_ENDPOINT
のホスト名をホストマシンの/etc/hosts
に追加することです。
127.0.0.1 minio
少し強引ですが、http://minio:9001/local/xxx
はDocker外部からアクセスできるようになります。
その他の解決策
その他解決策は色々あるのですが、MinIOのURLをhttpsにするパターンでLaravelとMinIOが動く環境をDockerで構築してみます。
Dockerの設定
Docker Composeを使用して環境を構築します。以下はdocker-compose.yml
の例です。
minio.laravel.test
というホスト名でMinIOにアクセスできるようにします。
minio-create-buckets
はMinIOのバケットを作成するためのコンテナです。
services:
app:
build:
context: ./docker/php
volumes:
- .:/var/www
working_dir: /var/www
user: 1000:1000
web:
build:
context: ./docker/nginx
ports:
- 80:80
- 443:443
volumes:
- ./docker/nginx/config:/etc/nginx/conf.d
- ./:/var/www
networks:
default:
aliases:
- minio.laravel.test
minio:
image: minio/minio
environment:
MINIO_ROOT_USER: ${MINIO_USERNAME-minio}
MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD-password}
command: server /data --address :9001 --console-address :8900
volumes:
- minio:/data
ports:
- 9001:9001
- 8900:8900
minio-create-buckets:
image: minio/mc
depends_on:
- minio
entrypoint: >
/bin/sh -c " /usr/bin/mc config host add local http://minio:9001 ${MINIO_USERNAME-minio} ${MINIO_PASSWORD-password}; /usr/bin/mc mb -p local/${MINIO_BUCKET-local}; /usr/bin/mc anonymous set download local/${MINIO_BUCKET-local}; exit 0;"
volumes:
minio:
nginxのDockerfileでは、自己署名証明書を作成しています。
FROM nginx:1.25.4
RUN apt-get update && apt-get -y install openssl \
&& openssl req -newkey rsa:2048 -x509 -nodes -set_serial 1 -days 3650 \
-subj "/C=JP/ST=Tokyo/L=Chiyoda-ku" \
-keyout "/etc/ssl/private/server.key" -out "/etc/ssl/private/server.crt" \
&& chmod 400 /etc/ssl/private/server.*
nginxの設定でminio.*
のホスト名でMinIOにアクセスできるようにします。
server {
listen 80 default_server;
listen 443 ssl default_server;
server_name _;
client_max_body_size 0;
root /var/www/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass app:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 600;
}
ssl_certificate /etc/ssl/private/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
}
server {
listen 80;
listen 443 ssl;
server_name minio.*;
client_max_body_size 0;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://minio:9001/;
}
ssl_certificate /etc/ssl/private/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
}
PHPのDockerfileを作成します。
FROM php:8.2-fpm
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
zip \
unzip
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
ホスト名の設定
ローカルマシンの/etc/hosts
ファイルに以下の行を追加します。
127.0.0.1 laravel.test minio.laravel.test
これにより、ブラウザからhttps://minio.laravel.test
でMinIOにアクセスできるようになります。
環境変数の設定
.env
ファイルに以下の設定をします。
AWS_ACCESS_KEY_ID="minio"
AWS_SECRET_ACCESS_KEY="password"
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET="local"
AWS_ENDPOINT="https://minio.laravel.test"
AWS_USE_PATH_STYLE_ENDPOINT=true
AWS_SSL_VERIFY=false
Laravelの設定
config/filesystems.php
のs3
を以下のように設定します。
自己署名証明書の場合、curlでエラーが発生するので、http=>vaerify
をfalse
に設定します。
そのための.env
にAWS_SSL_VERIFY=false
を設定してあります。
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
'http' => [
'verify' => env('AWS_SSL_VERIFY', true)
],
],
検証
設定が正しく行われたかを確認するために、以下のようなコードを作成し実行します。
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
class TestMinioUrl extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'test-minio-url';
/**
* The console command description.
*
* @var string
*/
protected $description = 'test minio url';
/**
* Execute the console command.
*/
public function handle()
{
$disk = Storage::disk('s3');
// Upload a file
$disk->put('test.txt', 'Hello MinIO!!');
// Get the URL of a file
$url = $disk->url('test.txt');
print "Normal URL: " . $url . PHP_EOL;
// Generate a temporary URL
$tempUrl = $disk->temporaryUrl('test.txt', now()->addMinutes(5));
print "Temporary URL: " . $tempUrl . PHP_EOL;
}
}
docker-compose exec app php artisan test-minio-url
正しく設定されていれば、生成されたURLがブラウザからアクセス可能であることを確認できます。
リポジトリ