---
title: Setup Scaleway Object Storage for Rails Active Storage
url: https://sxnlabs.com/en/cloud/2025/05/07/setup-scaleway-object-storage-for-active-storage/
lang: en
date: '2025-05-07T15:00:00+02:00'
tags:
- Active Storage
- Scaleway
- Object Storage
- Ruby on Rails
- Infra
---

# Setup Scaleway Object Storage for Rails Active Storage

Scaleway provides an **object storage** service compatible with the S3 API.

Here's how to configure your bucket via **Terraform**, though you can also do it directly through the console.

Table of contents:

1. [IAM Permissions Management](#iam-permissions-management)
2. [Bucket Creation](#bucket-creation)
3. [Ruby on Rails Configuration](#ruby-on-rails-configuration)

Note: the `var.scw_project` variable contains your project UUID, which you can find in the console.

## IAM Permissions Management

First, we’ll create an `application` to which we’ll assign permissions and from which we’ll retrieve the key pair for authentication.

Here, I'm granting full permissions (`ObjectStorageFullAccess`) for the Object Storage API, but you can be more restrictive if you prefer.

```hcl
# iam.tf

resource "scaleway_iam_application" "my_app" {
  name        = "MyApp"
  description = "MyApp application"
}

resource "scaleway_iam_api_key" "my_app" {
  application_id     = scaleway_iam_application.my_app.id
  description        = "MyApp API Key"
  default_project_id = var.scw_project
}

resource "scaleway_iam_policy" "my_app_object_storage" {
  name           = "MyApp Object Storage"
  description    = "Gives MyApp full access to object storage"
  application_id = scaleway_iam_application.my_app.id

  rule {
    project_ids          = [var.scw_project]
    permission_set_names = ["ObjectStorageFullAccess"]
  }
}
```

Add the outputs below to retrieve the authentication key pair:

```hcl
# outputs.tf

output "my_app_access_key" {
  value     = scaleway_iam_api_key.my_app.access_key
  sensitive = true
}

output "my_app_secret_key" {
  value     = scaleway_iam_api_key.my_app.secret_key
  sensitive = true
}
```


## Bucket creation

Let’s move on to creating the bucket. I’ve added rules to migrate objects between storage classes, but you’re not required to use them.
**CORS** rules are important if you want to use [direct uploads](https://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads).

```hcl
# object_storage.tf

resource "scaleway_object_bucket" "my_app" {
  name       = "my_app"
  region     = "fr-par"
  project_id = var.scw_project

  tags = {
    "Application" = "MyApp"
  }

  lifecycle_rule {
    id                                     = "abort_incomplete_multipart_upload"
    enabled                                = true
    abort_incomplete_multipart_upload_days = 7
  }

  lifecycle_rule {
    id      = "onezone_ia"
    enabled = true

    transition {
      days          = 30
      storage_class = "ONEZONE_IA"
    }
  }

  lifecycle_rule {
    id      = "glacier"
    enabled = true

    transition {
      days          = 120
      storage_class = "GLACIER"
    }
  }

  cors_rule {
    allowed_methods = ["GET", "HEAD", "POST", "PUT", "DELETE"]
    allowed_headers = ["*"]
    allowed_origins = [
      "*"
    ]
    expose_headers  = ["ETag"]
    max_age_seconds = 3600
  }
}
```

The last thing we need to configure here is the bucket policy to ensure that the `application` can access it.
Note that I’ve also added a rule for my own user so I can still access the bucket from the console.

```hcl
# object_storage.tf

resource "scaleway_object_bucket_policy" "my_app" {
  bucket = scaleway_object_bucket.my_app.name

  policy = jsonencode({
    Id      = "my_app",
    Version = "2023-04-17",
    Statement = [
      {
        Effect    = "Allow"
        Action    = ["*"]
        Principal = { SCW = "application_id:${scaleway_iam_application.my_app.id}" }
        Resource = [
          scaleway_object_bucket.my_app.name,
          "${scaleway_object_bucket.my_app.name}/*",
        ]
      },
      {
        Effect    = "Allow"
        Action    = ["*"]
        Principal = { SCW = "user_id:${var.scw_my_user}" }
        Resource = [
          scaleway_object_bucket.my_app.name,
          "${scaleway_object_bucket.my_app.name}/*",
        ]
      }
    ]
  })
}
```


## Ruby on Rails Configuration

We can now configure **Active Storage** with our setup.

```yaml
# config/storage.yml

scaleway:
  service: S3
  access_key_id: <%%= Rails.application.credentials.dig(:scaleway, :access_key) %>
  secret_access_key: <%%= Rails.application.credentials.dig(:scaleway, :secret_key) %>
  region: fr-par
  bucket: my_app
  endpoint: https://s3.fr-par.scw.cloud
```

Retrieve the key pair using the commands below:

```bash
tf output my_app_access_key
tf output my_app_secret_key
```

And that’s it!
