---
name: azion-use-a-bucket-as-an-application-origin
description: >-
  Serve the objects of an Object Storage bucket through an application, with a storage connector and a Rules Engine rule that sends requests to it.
---

# Use a bucket as an application origin

You can serve the objects of an [Object Storage](/en/documentation/platform/object-storage/) bucket through an [application](/en/documentation/platform/applications/) by pairing a [connector](/en/documentation/platform/connectors/) to the bucket with a [Rules Engine](/en/documentation/platform/applications/rules-engine/) rule. A request to the domain of the [workload](/en/documentation/platform/workloads/) that serves the application then returns the object stored under the matching key. To connect an application to an HTTP server instead, refer to [Connect an application to an origin](/en/documentation/guides/application-development/getting-started/work-with-origins/).

An account that [has not migrated to API v4](/en/documentation/guides/application-security/access-and-compliance/verify-account-migration/) builds the same path through the legacy Origins of the application. For more information, refer to [Origins](/en/documentation/platform/connectors/origins/).

> **Tip**
>
> This page carries separate instructions for API v4 and API v3. To find out which apply to your account, refer to [Verify your account migration](/en/documentation/guides/application-security/access-and-compliance/verify-account-migration/).

---

## Prerequisites

### Console

- A bucket whose `workloads_access` is `read_only` or `read_write`. A `restricted` bucket cannot back an application. To create a bucket, refer to [Object Storage quickstart](/en/documentation/platform/object-storage/quickstart/).
- An application served by a workload. To create both, refer to [Applications quickstart](/en/documentation/platform/applications/quickstart/).
- A personal token, sent in the `Authorization` header as `Token [TOKEN VALUE]`, because this page uploads the objects with the API. To create a token, refer to [Manage a personal token](/en/documentation/guides/platform/account-and-billing/personal-tokens/).
- `curl`, or another HTTP client.
- Access to Azion Console. To sign in, refer to [Access Azion Console](/en/documentation/guides/platform/account-and-billing/how-to-access-azion-console/).

### API

- A bucket whose `workloads_access` is `read_only` or `read_write`. A `restricted` bucket cannot back an application. To create a bucket, refer to [Object Storage quickstart](/en/documentation/platform/object-storage/quickstart/).
- An application served by a workload. To create both, refer to [Applications quickstart](/en/documentation/platform/applications/quickstart/).
- A personal token, sent in the `Authorization` header as `Token [TOKEN VALUE]`, because this page uploads the objects with the API. To create a token, refer to [Manage a personal token](/en/documentation/guides/platform/account-and-billing/personal-tokens/).
- `curl`, or another HTTP client.
- The ID of the application. Azion Console shows it in the address of the application's page, after `/applications/edit/`.

> **Caution**
>
> An application that serves a `read_write` bucket lets any request that reaches it modify the bucket, for example by overwriting an object. Serve static content from a `read_only` bucket, and [put a function in front of the bucket](/en/documentation/guides/application-development/data/auth-layer-object-storage-functions/) when a path has to accept writes. For more information, refer to [Object Storage best practices](/en/documentation/platform/object-storage/best-practices/).

---

## Upload the objects to serve

The connector serves what the bucket already holds, so the objects go in first. The example on this page serves a page of two objects, both stored under the `src` prefix of a bucket named `app-origin`:

```text
src/index.html
src/styles/style.css
```

In a local `src` directory, create `index.html`. The page links its stylesheet by a relative path:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="styles/style.css">
</head>
<body>
    <h1>Hello world!</h1>
    <p>I am an object from a bucket.</p>
</body>
</html>
```

In a `styles` directory inside `src`, create `style.css`, the file the page links to:

```css
body {
  background-color: black;
}

h1,
p {
  color: white;
}
```

To upload the HTML file with the API, send a `POST` request with the object key in the path. `Content-Type` sets the type the object is stored and served with:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/storage/buckets/app-origin/objects/src/index.html \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: text/html' \
  --data-binary '@./src/index.html'
```

The API answers `201` with the key the object is stored under:

```json
{
  "state": "executed",
  "data": {
    "object_key": "src/index.html"
  }
}
```

To upload the stylesheet, send the same request with its own key and type:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/storage/buckets/app-origin/objects/src/styles/style.css \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: text/css' \
  --data-binary '@./src/styles/style.css'
```

The response carries the key of the second object:

```json
{
  "state": "executed",
  "data": {
    "object_key": "src/styles/style.css"
  }
}
```

The bucket holds the two objects. The `src/` segment of each key is part of the key, not a folder, and the platform creates it with the object. Without a `Content-Type` header, the platform detects the type of the object. Azion Console and the Azion CLI upload objects too. For more information, refer to [Object Storage quickstart](/en/documentation/platform/object-storage/quickstart/).

---

## Create a connector to the bucket

A connector to a bucket names the bucket an application reads from and the prefix inside it. The prefix sets where the application's paths start. With the prefix `/src`, the object stored under `src/index.html` answers at `/index.html`, and `src/styles/style.css` answers at `/styles/style.css`. The prefix is optional in the API and required in Azion Console.

In Azion Console, you set up connectors in the Connectors menu, not in a tab of the application. For each field of the Console form and of the request body, refer to [Connector settings](/en/documentation/platform/connectors/settings/#storage).

### Console

To create the connector in Azion Console:

1. **Open the Connectors page**

   Access [Azion Console](https://console.azion.com/) > **Connectors**.

2. **Start a new connector**

3. **Name the connector**

   In the **General** section, enter `app-origin-connector` in **Name**.

4. **Select the Object Storage type**

   In the **Connector Type** section, select *Object Storage*.

5. **Select the bucket**

   Select `app-origin` as the bucket the connector reads from.

6. **Set the prefix**

   Enter `/src` in **Prefix**, the prefix the objects were uploaded under.

7. **Select Create**

Azion Console shows `Connector successfully created`.

### API

In the API, the connector's `type` is `storage`, and its `attributes` carry `bucket`, the name of the bucket, and `prefix`. For the example on this page, `bucket` is `app-origin` and `prefix` is `/src`.

Create the connector with a `POST` request to `/v4/workspace/connectors`. Then copy the ID of the connector, which the API returns in `data.id`: the rule that sends requests to the bucket names the connector by this ID.

---

## Send requests to the bucket

A connector receives no request until a rule sets it. The rule in this section runs in the Request Phase of the application. Its criterion matches every path, with the `${uri}` variable, the `starts_with` operator, and `/` as the argument, so the whole application reads from the bucket. Its behavior sets the connector.

The `${uri}` variable works on every application. A criterion on `${request_uri}` needs [Application Accelerator](/en/documentation/platform/applications/application-accelerator/quickstart/) on the application. For every variable and operator, refer to [Rules Engine for Applications](/en/documentation/platform/applications/rules-engine/#criteria).

### Console

To create the rule in Azion Console:

1. **Open the application**

   Access [Azion Console](https://console.azion.com/) > **Applications**, then select your application.

2. **Select the Rules Engine tab**

3. **Start a rule**

   Select **+ Rule**.

4. **Name the rule**

   In the **General** section, enter a **Name**, such as `serve-the-bucket`.

5. **Select the phase**

   In the **Phase** section, select *Request Phase*. A rule keeps the phase it is created in.

6. **Set the criterion**

   In the **Criteria** section, set the variable to `${uri}`, the operator to `starts_with`, and the argument to `/`.

7. **Set the connector**

   In the **Behaviors** section, select *Set Connector*, then select the connector to the bucket in **Connector**.

8. **Save the rule**

   Select **Save**.

The rule appears in the **Rules Engine** tab of the application, under **Request**.

### API

To create the rule with the API, send a `POST` request to the `request_rules` endpoint of the application. Replace `<application-id>` with the ID of your application, and `<connector-id>` with the ID of the connector to the bucket:

```bash
curl --request POST \
  --url https://api.azion.com/v4/workspace/applications/<application-id>/request_rules \
  --header 'Accept: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "serve-the-bucket",
  "active": true,
  "criteria": [
    [
      {
        "variable": "${uri}",
        "conditional": "if",
        "operator": "starts_with",
        "argument": "/"
      }
    ]
  ],
  "behaviors": [
    {
      "type": "set_connector",
      "attributes": {
        "value": <connector-id>
      }
    }
  ]
}'
```

The API answers `202` and returns the rule:

```json
{
  "state": "pending",
  "data": {
    "id": <rule-id>,
    "name": "serve-the-bucket",
    "active": true,
    "criteria": [
      [
        {
          "conditional": "if",
          "variable": "${uri}",
          "operator": "starts_with",
          "argument": "/"
        }
      ]
    ],
    "behaviors": [
      {
        "type": "set_connector",
        "attributes": {
          "value": <connector-id>
        }
      }
    ],
    "description": "",
    "order": 0,
    "last_editor": "user@example.com",
    "last_modified": "2026-01-01T12:00:26.750242Z",
    "created_at": "2026-01-01T12:00:26.750262Z"
  }
}
```

The rule is the first of the application's Request Phase, at `order` `0`.

For the behavior and its attributes, refer to [Set Connector](/en/documentation/platform/applications/rules-engine/#set-connector).

---

## Confirm that the application serves the bucket

The rule takes some time to propagate. Until then, the domain of the workload does not answer with the objects.

To confirm the delivery path, request the page through the domain of your workload, with that domain in place of `<your-workload-domain>`:

```bash
curl https://<your-workload-domain>/index.html
```

The response body is the object stored under `src/index.html`, which the `/src` prefix serves at `/index.html`. It carries the heading `Hello world!` and the paragraph `I am an object from a bucket.` A workload's domain ends in `.map.azionedge.net`, and the API returns it in `workload_domain` when it creates the workload.

Go to the same address in a browser. The browser renders the page with the stylesheet applied, which it loads from `/styles/style.css` under the same prefix.

If the domain does not return the object yet, the rule has not propagated. Send the request again, and look for another cause only after that. For more information, refer to [Troubleshoot Applications](/en/documentation/platform/applications/troubleshooting/).

In the [Deliver an on-demand video library](/en/documentation/use-cases/deliver-media-and-streaming/deliver-an-on-demand-video-library/) use case, expect:

- **The library is served from the bucket with its type.** A request for `https://videos.example.com/course-101/master.m3u8` carries `200` and `content-type: application/vnd.apple.mpegurl`, the type stored at upload.

---

## Serve the bucket from a v3 application

An account that runs on API v3 has no connectors. The bucket is an origin of the application, of the **Object Storage** type, and a rule points the application at it. To find out which model your account runs on, refer to [Verify your account migration](/en/documentation/guides/application-security/access-and-compliance/verify-account-migration/).

**Console**

The objects you uploaded need no change. To serve them from a v3 application in Azion Console:

1. **Open the application**

   Access [Azion Console](https://console.azion.com/) > **Applications** > **your application**.

2. **Add the origin**

   In the **Origins** tab, select **+ Origin** and name it.

3. **Choose the Object Storage type**

   In **Origin Type**, select **Object Storage**.

4. **Name the bucket and the prefix**

   In **Bucket Name**, enter the name of your bucket. In **Prefix**, enter the prefix of the object keys you want to serve, such as `/src`. Leave it empty to serve the whole bucket.

5. **Save the origin**

   Select **Save**.

6. **Point the application at the origin**

   In the **Rules Engine** tab, select **Default Rule**. Under **Behaviors**, in the **Set Origin** behavior, replace **Default Origin** with the origin you created, and select **Save**.

**API v3**

To serve the bucket with API v3, create the origin on the application and then point its default rule at it. Both requests carry the header `Accept: application/json; version=3`.

Create the origin:

```bash
curl --request POST \
  --url https://api.azionapi.net/edge_applications/<application-id>/origins \
  --header 'Accept: application/json; version=3' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --data '{
  "name": "object storage origin",
  "origin_type": "object_storage",
  "bucket": "my-bucket",
  "prefix": "/src"
}'
```

The response carries the `origin_id` of the new origin:

```json
{
  "results": {
    "origin_id": 123456,
    "origin_key": "bdcd7003-ba53-4ed8-8ca0-05b1357cdafd",
    "name": "object storage origin",
    "origin_type": "object_storage",
    "bucket": "my-bucket",
    "prefix": "/src"
  }
}
```

Then read the rules of the request phase to find the ID of the default rule:

```bash
curl --request GET \
  --url https://api.azionapi.net/edge_applications/<application-id>/rules_engine/request/rules \
  --header 'Accept: application/json; version=3' \
  --header 'Authorization: Token [TOKEN VALUE]'
```

The default rule carries `"phase": "default"` and its current behaviors:

```json
{
  "results": [
    {
      "id": 987654,
      "name": "Default Rule",
      "phase": "default",
      "behaviors": [
        { "name": "set_origin", "target": "<origin-id>" },
        { "name": "set_cache_policy", "target": "<cache-setting-id>" }
      ]
    }
  ]
}
```

Finally, send a `PATCH` to that rule with the `set_origin` behavior. Keep the `set_cache_policy` behavior as the response returned it, or the rule loses its cache setting:

```bash
curl --request PATCH \
  --url https://api.azionapi.net/edge_applications/<application-id>/rules_engine/request/rules/<rule-id> \
  --header 'Accept: application/json; version=3' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Token [TOKEN VALUE]' \
  --data '{
  "behaviors": [
    { "name": "set_origin", "target": "<origin-id>" },
    { "name": "set_cache_policy", "target": "<cache-setting-id>" }
  ]
}'
```

| Key           | What it carries                                                                  |
| ------------- | -------------------------------------------------------------------------------- |
| `origin_type` | `object_storage` for a bucket origin                                             |
| `bucket`      | The name of the bucket                                                           |
| `prefix`      | The prefix of the object keys to serve. `/` serves the whole bucket              |
| `set_origin`  | The v3 behavior that **Set Connector** replaced. Its `target` is the `origin_id` |

**Set Origin** is the v3 behavior that **Set Connector** replaced. For every field of the origin, refer to [Origins](/en/documentation/platform/connectors/origins/).

---

## Next steps

- [Cache settings](/en/documentation/platform/applications/cache/cache-settings.md): Set how long the objects the application serves stay cached.
- [Connectors](/en/documentation/platform/connectors.md): Every field of a connector to a bucket, and the other connector types.
- [How Object Storage works](/en/documentation/platform/object-storage/how-it-works.md): What the access level changes, and the path a request takes to an object.
- [Buckets and objects](/en/documentation/platform/object-storage/buckets-and-objects.md): Bucket names, access levels, object keys, and prefixes.
- [Deliver an on-demand video library](/en/documentation/use-cases/deliver-media-and-streaming/deliver-an-on-demand-video-library.md): An HLS library stored in Object Storage and served through an application with Cache and Tiered Cache.
