Current section
Files
Jump to
Current section
Files
README.md
# ExOss
[](https://hex.pm/packages/ex_oss)
[](https://hexdocs.pm/ex_oss)
A unified **S3-compatible and Alibaba Cloud OSS object storage** library for Elixir with **multi-CDN** support.
## Features
- **Native Alibaba Cloud OSS** — OSS V4 signing, STS credentials, multipart uploads, and Aliyun CDN
- **S3 unified storage** — AWS S3, Qiniu S3, MinIO, DigitalOcean Spaces, Cloudflare R2, or any S3-compatible service
- **Multi-CDN** — CloudFront, Qiniu CDN, Aliyun CDN, and extensible via `ExOss.CDN.Behaviour`
- **Multi-client** — configure multiple storage backends and CDNs side by side
- **File transfer** — upload from file, content, remote URL, or cloud-to-cloud copy
- **Presigned URLs** — temporary direct-access upload/download without exposing credentials
## Installation
Add `ex_oss` to your dependencies:
```elixir
def deps do
[
{:ex_oss, "~> 1.2"}
]
end
```
## Quick Start
```elixir
# 1. Define a storage module
defmodule MyApp.Storage do
use ExOss, otp_app: :my_app
end
# 2. Add configuration
config :my_app, MyApp.Storage,
provider: :aws,
access_key_id: "your-access-key",
secret_access_key: "your-secret-key",
region: "us-east-1"
# 3. Use it
MyApp.Storage.upload_credential("bucket", "path/file.jpg", 3600)
MyApp.Storage.authorize_download_url("bucket", "path/file.jpg", 3600)
```
See the [getting started guide](https://hexdocs.pm/ex_oss/getting-started.html) for details.
## Alibaba Cloud and upload headers
See the [Aliyun OSS guide](guides/aliyun-oss.md) and
[Aliyun CDN guide](guides/cdn-aliyun.md) for native configuration.
Both server uploads and presigned PUT credentials accept raw `opts[:headers]`.
Both `opts[:content_type]` and `opts["content_type"]` populate the
`"content-type"` header for all storage providers; an explicit Content-Type header
wins. Send the returned headers unchanged when uploading with a credential:
```elixir
credential = MyApp.Storage.upload_credential("bucket", "photo.png", 3600,
headers: %{"content-type" => "image/png", "cache-control" => "max-age=3600"}
)
Req.put!(credential.presigned_url, body: file_content, headers: credential.headers)
```
Existing calls without options still work. Provider-specific headers are passed
through without translation; consult the provider's API for supported values.
## License
MIT