Rails 7 Active Storage with Tigris on Fly.io
It's so easy to use Tigris as an ActiveStorage backend
My site is built with Rails. I'm using ActiveStorage to handle file uploads, and ActionText to create posts with rich text content. The default active storage configuration file is as follows:
test: service: Disk root: <%= Rails.root.join("tmp/storage") %> local: service: Disk root: <%= Rails.root.join("storage") %>
Now that my site is in production, I want my images stored in the cloud so that they don't take up space on my server. Amazon S3 is the obvious choice, they're fast and reliable, but their Identity and Access Management system is complex and confusing. I need a simpler solution. Enter Tigris.
In their own words:
Tigris is a globally distributed S3-compatible object storage service that provides low latency anywhere in the world, enabling developers to store and access any amount of data for a wide range of use cases.
Sounds good to me. Let's see how to use Tigris as a backend for ActiveStorage attachments on Fly.io. It only took me 10 minutes to get it all working.
Step 1: Create a Tigris project
Run the following command from the root of your application:
fly storage create --public
Fly.io will do the heavy lifting for you, and when the process is complete they will set the following ENV variables on your server:
- AWS_ACCESS_KEY_ID
- AWS_ENDPOINT_URL_S3
- AWS_REGION
- AWS_SECRET_ACCESS_KEY
- BUCKET_NAME
Step 2: Create a Tigris adapter for ActiveStorage
Add the following code to the ActiveStorage configuration file found at config/storage.yml:
tigris: service: S3 endpoint: <%= ENV["AWS_ENDPOINT_URL_S3"] %> access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %> secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %> bucket: <%= ENV["BUCKET_NAME"] %> region: <%= ENV["AWS_REGION"] %>
Step 3: Tell Rails to use Tigris in production
Update the ActiveStorage service in config/environments/production.rb to the following:
config.active_storage.service = :tigris
Step 4: Add the S3 gem to your Gemfile
group :production do gem "aws-sdk-s3", require: false end
Don't forget to run bundle install
bundle install git add . git commit -m 'Panthera Tigris'
We're almost done, but if you're using ActionText then you will need to configure CORS on your Tigris bucket so that direct uploads via the Trix editor will work.
Step 5: Install the AWS CLI
If you already have AWS CLI installed and configured, then you might want to back-up your existing settings (found at ~/.aws on MacOS) before doing the following.
I'm on a Mac so I installed the AWS CLI using homebrew, and then I configured it to use the ENV variables from step 1:
brew install awscli aws configure
Note that I had to SSH into my server to get the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY as the values displayed in the Fly.io UI are merely digests.
When finished you should have the following in ~/.aws/config
[default] region = auto output = json
And you should have the following in ~/.aws/credentials
[default] aws_access_key_id = your_aws_access_key_id aws_secret_access_key = your_aws_secret_access_key
Step 6 - Create a CORS file
We need to create a json file containing the following CORS rules if we want direct uploads to work via the Trix editor:
{ "CORSRules" : [ { "AllowedHeaders":["*"], "AllowedMethods":["PUT", "POST", "DELETE"], "AllowedOrigins":["https://your_domain.com"], "MaxAgeSeconds":3000 }, { "AllowedHeaders":["*"], "AllowedMethods":["GET"], "AllowedOrigins":["*"], "MaxAgeSeconds":3000 } ] }
Save the file as cors.json somewhere on your local machine, and make sure you put your own domain name in there where it says "your_domain.com".
You can now register your cors file with your Tigris project by running the following command:
aws s3api put-bucket-cors --endpoint-url https://fly.storage.tigris.dev --bucket put_your_bucket_name_here --cors-configuration file:///path/to/cors.json
Make sure to use your own bucket name when running the above command.
Step 7 - Deploy your code
We just need to deploy our code now:
fly deploy
And that's it. ActiveStorage will now use Tigris, and the CORS rules we added will allow direct uploads via the Trix editor if you're using ActionText.
Remember you can skip the CORS stuff from steps 5 and 6 if you're not using direct uploads or Trix.
Good luck.