# Orchardcore Amazon S3 Media

> Skill for configuring Amazon S3 media storage in Orchard Core. Covers bucket setup, AWS credentials, security policies, tenant templating, local S3 emulators, ImageSharp resized-image caches, and CDN use. Use this skill for OrchardCore.Media.AmazonS3, OrchardCore.Media.AmazonS3.ImageSharpImageCache, Amazon S3 Media Storage Configuration, or related implementation, setup, extension, and troubleshooting work. Strong matches include ShellSettings, BucketName, appsettings.json, and AwsImageSharpImageCacheOptions. It also helps with profiles, credential loading, tenant buckets, base folders, emulator settings, recipes, and referenced examples.

- Skill: `crestapps/orchardcore-amazon-s3-media` (Agent Skill)
- Install (CLI): `npx skillmds@latest add crestapps/orchardcore-amazon-s3-media`
- Raw SKILL.md: https://api.skillmd.com/api/skills/crestapps/orchardcore-amazon-s3-media/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: CrestApps (https://skillmd.com/u/crestapps)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/crestapps/orchardcore-amazon-s3-media

---


# Orchard Core Amazon S3 Media Storage - Prompt Templates

## Module Overview

The `OrchardCore.Media.AmazonS3` module enables storing media assets in Amazon S3 Buckets instead of the default `App_Data` file-based store. It provides two features:

- **OrchardCore.Media.AmazonS3** — Replaces the default media store with Amazon S3 storage.
- **OrchardCore.Media.AmazonS3.ImageSharpImageCache** — Stores ImageSharp resized image cache in Amazon S3 instead of the local file system.

Media is still served by the Orchard Core web site. The Media Cache module fetches assets on the fly from S3, enabling image resizing through ImageSharp.Web integration.

## Amazon S3 Media Storage Configuration

### Guidelines

- Enable the `OrchardCore.Media.AmazonS3` feature.
- Only one storage provider can be active at a time (File Storage, Azure Blob Storage, or Amazon S3 Storage).
- When hosting inside AWS (EC2, EKS, etc.), you only need `BucketName`; credentials are resolved via IAM roles.
- When hosting outside AWS, provide credentials via the `Credentials` section, AWS CLI profiles, or environment variables.
- Prefer AWS profiles or environment variables over embedding credentials in `appsettings.json` to avoid accidental source control exposure.
- Set `CreateBucket` to `true` to auto-create the bucket. New buckets are created without ACLs for security.

### Configuration Properties

| Property | Description | Default |
|---|---|---|
| BucketName | AWS S3 bucket name (required). | `""` |
| Region | AWS region endpoint (e.g., `eu-central-1`). | `""` |
| Profile | AWS CLI profile name (e.g., `default`). | `""` |
| ProfilesLocation | Custom location for AWS profiles file. | `""` |
| Credentials.SecretKey | AWS secret key (for hosting outside AWS). | `""` |
| Credentials.AccessKey | AWS access key (for hosting outside AWS). | `""` |
| BasePath | Subdirectory path inside the bucket. | `"/media"` |
| CreateBucket | Auto-create the bucket on startup. | `false` |

### Basic Configuration (Hosted in AWS)

```json
{
  "OrchardCore": {
    "OrchardCore_Media_AmazonS3": {
      "BucketName": "my-orchard-media",
      "BasePath": "/media"
    }
  }
}
```

### Configuration with Explicit Credentials (Hosted Outside AWS)

```json
{
  "OrchardCore": {
    "OrchardCore_Media_AmazonS3": {
      "BucketName": "my-orchard-media",
      "Region": "eu-central-1",
      "Credentials": {
        "SecretKey": "your-secret-key",
        "AccessKey": "your-access-key"
      },
      "BasePath": "/media",
      "CreateBucket": true
    }
  }
}
```

### Configuration with AWS Profile

```json
{
  "OrchardCore": {
    "OrchardCore_Media_AmazonS3": {
      "BucketName": "my-orchard-media",
      "Region": "eu-central-1",
      "Profile": "default",
      "ProfilesLocation": "",
      "BasePath": "/media"
    }
  }
}
```

## AWS Credentials Loading Order

The `OrchardCore_Media_AmazonS3` configuration follows the standard `AWSOptions` loading order:

1. `Credentials` property of `AWSOptions`.
2. Shared Credentials File (custom location) — when both profile and profile location are specified.
3. SDK Store (Windows only) — when only the profile is set.
4. Shared Credentials File (default location) — when only the profile is set.
5. AWS Web Identity Federation Credentials — when an OIDC token file exists in environment variables.
6. `CredentialsProfileStoreChain` — SDK Store (Windows) then Shared Credentials File (default).
7. Environment variables — when `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` are set.
8. ECS Task Credentials or EC2 Instance Credentials — when using IAM roles.

**Best practice**: Use profiles or environment variables instead of embedding credentials directly in configuration files.

## S3 Bucket Access

### Guidelines

- Buckets created with `CreateBucket: true` are created without ACLs for security.
- **Private bucket (recommended)**: Media is served through Orchard Core, so the application identity needs bucket access but the bucket does not need public reads.
- **Public bucket**: Use only when clients or a CDN must retrieve media directly from S3. Configure an explicit read policy and review the effect of public-access-block settings.
- Do not combine a public read policy with a public-access block that prevents public policies from taking effect.

### Public Read Bucket Policy (Direct S3 Delivery Only)

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AddPerm",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/YOUR-BASE-PATH/*"
    }
  ]
}
```

## Multi-Tenant Bucket Templating

### Guidelines

- Use Liquid templating in `BucketName` and `BasePath` for multi-tenant setups.
- The `ShellSettings` object is available in the Liquid template context.
- `{{ ShellSettings.Name }}` is automatically lowercased; ensure the full `BucketName` conforms to [S3 naming rules](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html).
- Only default Liquid filters and tags are available.

### Bucket per Tenant

```json
{
  "OrchardCore": {
    "OrchardCore_Media_AmazonS3": {
      "BucketName": "{{ ShellSettings.Name }}-media",
      "Region": "eu-central-1",
      "Credentials": {
        "SecretKey": "",
        "AccessKey": ""
      },
      "BasePath": "/media",
      "Profile": "",
      "ProfilesLocation": ""
    }
  }
}
```

### Single Bucket with Base Folder per Tenant

```json
{
  "OrchardCore": {
    "OrchardCore_Media_AmazonS3": {
      "BucketName": "shared-media",
      "Region": "eu-central-1",
      "Credentials": {
        "SecretKey": "",
        "AccessKey": ""
      },
      "BasePath": "{{ ShellSettings.Name }}/Media",
      "Profile": "",
      "ProfilesLocation": ""
    }
  }
}
```

## Local S3 Emulator Setup (Docker)

### Guidelines

- Use a local emulator for development to avoid shared online storage conflicts.
- Set `ServiceURL` instead of `Region` when using an emulator.
- Enable `ForcePathStyle: true` for all emulators (uses `http://localhost/mybucket` instead of `http://mybucket.localhost`).
- Credentials are required but not validated by emulators; use dummy values.

### Emulator Configuration

```json
{
  "OrchardCore": {
    "OrchardCore_Media_AmazonS3": {
      "ServiceURL": "http://localhost:9444/",
      "Profile": "default",
      "ProfilesLocation": "",
      "Credentials": {
        "SecretKey": "dummy",
        "AccessKey": "dummy"
      },
      "BasePath": "/media",
      "CreateBucket": true,
      "RemoveBucket": true,
      "BucketName": "media",
      "ForcePathStyle": true
    }
  }
}
```

### Docker Commands for S3 Emulators

**S3Mock** (Adobe):

```bash
docker run -p 9444:9090 -t adobe/s3mock:latest
```

**LocalS3** (Robothy):

```bash
docker run -d -e MODE=IN_MEMORY -p 9444:80 luofuxiang/local-s3:latest
```

## Amazon S3 ImageSharp Image Cache

### Guidelines

- Enable the `OrchardCore.Media.AmazonS3.ImageSharpImageCache` feature.
- The options type is `AwsImageSharpImageCacheOptions`.
- Custom startup registration uses the `ImageSharpCache` configure order.
- Useful for ephemeral file systems (containers, clean deployments).
- Reduces pressure on local disk IO.
- Cache files are only removed per tenant when using a separate bucket per tenant.
- Templating and emulator settings work the same as for the main S3 media storage.

### ImageSharp Cache Configuration

```json
{
  "OrchardCore": {
    "OrchardCore_Media_AmazonS3_ImageSharp_Cache": {
      "Region": "eu-central-1",
      "Profile": "default",
      "ProfilesLocation": "",
      "Credentials": {
        "SecretKey": "",
        "AccessKey": ""
      },
      "BasePath": "/cache",
      "CreateBucket": true,
      "RemoveBucket": false,
      "BucketName": "media-cache"
    }
  }
}
```

## CDN Caching Strategy

- When fronting media with a CDN, allow sufficient time for CDN PoPs to cache assets before purging the local Media Cache.
- Each CDN PoP maintains its own cache independently.
- The Media Cache will re-fetch assets from S3 on demand when a CDN PoP requests an uncached item.
- CDN providers clear caches on their own schedules; the S3 source must always remain accessible.
- The Media Cache feature is automatically enabled with Amazon S3 storage and supports purging via the admin dashboard.
- Local remote-media files use the `wwwroot/{tenant}/ms-cache` folder.

