Rails ActiveStorage Configuration for Minio
birdy boxcar by b.ug is licensed under CC BY-NC
You are looking at Rails 5.2 and its shiny new ActiveStorage – a built-in abstraction/mechanism to handle file storage. You decide to give it a try and remove a dependency you normally use (i.e., CarrierWave or Paperclip).
For some reason, you decide to use Minio – an Amazon S3 compatible open source project.
Looking through the ActiveStorage documentation and repository’s readme, you figure out how to get everything working locally using ActiveStorage’s local
service.
Now it is time to try running everything, but with Minio as your file storage. Looking at your config/storage.yml
you’ll see the template for Amazon’s S3:
amazon:
service: S3
access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
region: us-east-1
bucket: your_own_bucket
Now it’s time to figure out how to use the S3 service in conjunction with your Minio server…
Your Minio server doesn’t really support regions like Amazon’s S3. Just keep it as us-east-1
or your closest S3 region (although it really could be any string). From what I’ve seen, this is just used at the Amazon S3-level, and for your hosted Minio server it does not matter.
The region
value is simply used to satisfy ActiveStorage and the aws-sdk-s3
gem. If you omit the region
option you get the following exception missing keyword: region (ArgumentError)
. If you use an empty string for region
you will see missing region; use :region option or export region name to ENV['AWS_REGION'] (Aws::Errors::MissingRegionError)
.
Your Minio server is hosted at some URL (i.e., https://minio123.com), so you’ll need to inform ActiveStorage’s S3 service about this endpoint. Luckily, it is just a matter of adding the URL endpoint to your configuration:
endpoint: "https://minio123.com" # Points to your Minio server
You can also use ports on the endpoint (i.e., “http://localhost:9000”).
So you have the endpoint and region all setup from a configuration standpoint. Your Minio server is also up and running, along with a bucket, your_own_bucket
. You try to upload a file and see the following exception:
Aws::Errors::NoSuchEndpointError (Encountered a `SocketError` while attempting to connect to:
https://you_own_bucket.minio123.com/RJioqjrTT4VmFobw5FhXkSby
This is typically the result of an invalid `:region` option or a
poorly formatted `:endpoint` option.
* Avoid configuring the `:endpoint` option directly. Endpoints are constructed
from the `:region`. The `:endpoint` option is reserved for connecting to
non-standard test endpoints.
Hmm… Well that didn’t work out. If we look at the URL (https://your_own_bucket.minio123.com), we can see that it uses a bucket subdomain approach. However, Minio expects the bucket after the domain (i.e., https://minio123.com/your_own_bucket). Again, fortunately there is an configuration option we can add to force this path style:
force_path_style: true # Needed to be compliant with how Minio serves the bucket
At this point we covered all the configuration gotchas to set up ActiveStorage with Minio. Namely, the missing and (mostly undocumented) endpoint
and force_path_style
options. The following is a complete configuration.
minio:
service: S3
access_key_id: <%= Rails.application.credentials.dig(:minio, :access_key_id) %>
secret_access_key: <%= Rails.application.credentials.dig(:minio, :secret_access_key) %>
region: us-east-1
bucket: your_own_bucket
endpoint: "https://minio123.com"
force_path_style: true
It isn’t a bad idea to have the configuration named minio
, just so it is clear that it’s a Minio file storage instead of the typical Amazon S3.