When it comes to using S3 with Rails, a quick Google search can line up lots of awesome resources and posts that discuss the process in full. I wanted to add to this list and highlight navigating S3 for the typical Rails configuration.

So let’s dive in!

Make sure you’re logged in to your AWS Console and are in a region you’d prefer. I use us-west-1, but any should do! Just remember which one you pick because sometimes the AWS Console will default back to us-east-1 and leave you panicked about why all your AWS services disappeared! 🙉

aws-s3-select-region.png

AWS Setup

Before we make our bucket, you’ll need a user with permissions set up first. Navigate to the IAM dashboard and then to the Users section. From here click Create user. At the time of writing this (2025), the process seems mostly unchanged except that Access Keys aren’t auto-generated at creation anymore for security reasons.

IAM: Create a User with the S3 Policy

  1. Add a User name.
  2. Attach the AmazonS3FullAccess policy.

    1. You can select Attach policies directly and type s3 into the search since there are A LOT of policies you can attach 🫣 This will allow us to keep the S3 bucket completely private and provide access to just this user.
    aws-s3-attach-policies.png
  3. Review and create. Nothing special here, just click Create user.

  4. You’ll be redirected back to the Users page, from here click on your new User.

  5. In the Summary section click Create access key to generate credentials for your User.

  6. Select Local code. Again, a lot of options here! But because we will be encrypting these in Rails, they hopefully won’t need to be rotated! Don’t forget to check the Confirmation box.

  7. Add a Description tag if you want. You could call it s3-access if ya want!

  8. Now you’ve got some credentials! You can either copy the values or download the .csv.

    🧩 Note: This is your only opportunity to save or copy these keys, make sure you grab em. If you don’t, or you lose them, you have to make a new set!

S3: Create your S3 bucket

It’s bucket time! 🪣 BUCKET TIME!!! 🪣🪣🪣🪣!!!

BUCKET TIME!

Navigate to the S3 dashboard and click Create bucket. Creating a bucket for this use case is literally one step: Add a name (and preferably something unique/specific. Maybe not my-bucket) all the other options are good to go as their defaults. I know it may be overkill, but I like to use a Passphrase generator to make an extra-long name for the bucket, which requires minimal inspiration when thinking of a name. If you use the one I linked, uncheck Capitals as all S3 names need to be lowercase.

  • Object Ownership: ACLs disabled (default)
  • Block Public Access settings for this bucket: Block all public access (default)
  • Bucket Versioning: Disabled (default)
  • Default encryption: Server-side encryption with Amazon S3 managed keys (SSE-S3) (default)
  • Bucket Key: Enabled (default)

Rails: Configure for Direct S3 Uploads

To start, in your Rails app, we need to initialize ActiveStorage. This will put together all the pieces needed for image attachment & upload. More info in the docs.

bash
rails active_storage:install
rails db:migrate

Now is a good time to install the required AWS S3 SDK as well. It's the library that allows ActiveStorage to just work out of the box with S3 by enabling Rails to communicate with S3 for uploading, downloading, and managing files. Neat-o!

yaml
bundle add aws-sdk-s3

Before getting to associating attachments and images in the Model of your choice, let's add our IAM User credentials. We will use Rails encrypted credentials. In the command, I have my IDE alias for VSCode passed to the EDITOR variable, but you can add yours in its place.

bash
'EDITOR="code --wait" rails credentials:edit'

In the credentials.yml it opened, we can fill in our secrets and some other related variables in this format and close the file to save and encrypt.

yaml
aws:
  access_key_id: <Your access key>
  secret_access_key: <Your secret access key>
  bucket_name: <Your bucket name>
  region: <Your region>

Now in our config/storage.yml, we can declare our S3 credentials for ActiveStorage. And I gotta say, Rails encrypted credentials are nice vs. dealing with a .env file! ⭐️ Those secrets are an easy call away.

yaml
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: <%= Rails.application.credentials.dig(:aws, :region) %>
  bucket: <%= Rails.application.credentials.dig(:aws, :bucket_name) %>

One more step. In the environment config files for Rails, we need to point ActiveStorage towards AWS instead. You can point development towards AWS too to test out uploads.

In your config/environments/production.rb and config/environments/development.rb (if you’d like to test it out locally) change the service from :local to :amazon

ruby
config.active_storage.service = :amazon

Now we are ready to get photos uploaded however you might like! There are lots of ways to do this, have at thee!

You earned it!

Thanks for reading, remember to commit early and often! 🏁