# Serve a bucket publicly

> Turn on a bucket's public URL so anyone with the link can read its objects, purge the cached copies, and learn what visitors can and cannot do.

Source: https://www.coritan.com/docs/object-storage/public-access/

In the dashboard:

- /dashboard/storage/…/buckets/…/public: https://www.coritan.com/dashboard/storage

Every bucket starts private: each request needs a signature from one of your access keys, or a presigned URL. When you want anyone to read a bucket's objects without either, serve it publicly. A bucket can be served on its *public URL*, an address we give it, and on [custom domains](/docs/object-storage/custom-domains/) of your own. Both go through our edge, which caches the objects and holds the certificates.

Serving a bucket publicly lets anyone read every object in it. Nobody can list the bucket, upload to it or delete from it without a key.

## Before you begin

- Sign in to the [dashboard](https://www.coritan.com/dashboard/storage) and open the service. The service must be `active`.
- Your role on the account must be Admin or Technical. Other roles can see the **Public access** tab and cannot change it.
- The account needs a saved payment method, credit or a paid invoice ([Payment methods](/docs/billing/payment-methods/)). Without one, the dashboard shows **Add a payment method to serve this bucket publicly** and the switch stays off.

## Turn on the public URL

1. Open the service, select the **Buckets** tab, then select the bucket.
2. Select the **Public access** tab.
3. On the **Public URL** card, turn the switch on.
4. Type the bucket's name to confirm, then select **Turn on public URL**.

A message confirms it: `Public URL on.`

## Result

The **Public URL** card shows the address, such as `https://6f1c2a9e8b3d4f70a5e1c9d2b7f30a48.pub.example.net` (these pages use `pub.example.net` for the platform's domain for public buckets). Add an object's key after it to read the object:

```text
https://6f1c2a9e8b3d4f70a5e1c9d2b7f30a48.pub.example.net/images/logo.png
```

Select **Open** to try it in a new tab. The name in front of the domain is random, and it stays the same when you turn the public URL off and on again.

If the card says `Public URLs are not available yet. You can still serve the bucket on a custom domain.`, we do not offer public URLs on this platform yet. [Serve a bucket on your own domain](/docs/object-storage/custom-domains/) instead.

## What visitors can do {#what-visitors-can-do}

- Read an object with `GET`, or its headers with `HEAD`. Range requests (`Range: bytes=0-1023`) and conditional requests (`If-None-Match`, `If-Modified-Since`) work. `OPTIONS` answers a browser's CORS check, and every other method answers `405`.
- Read nothing else. A key with no object answers `404`, and so do `/` and any path that ends in `/`, until you [serve the bucket as a website](/docs/object-storage/static-websites/). Listing the bucket is never public.
- The query string does not change what is read: `?versionId=`, `?acl` and the like are ignored.
- Each answer carries the object's own `Content-Type`, `Cache-Control`, `Content-Disposition` and `ETag`, as you set them at upload.
- On the public URL, each visitor's address can make a set number of requests a minute, and the **Public URL** card says how many. Past it, the address answers `429`. Custom domains have no such limit.
- The public URL asks search engines not to index it (`X-Robots-Tag: noindex`). To have a site found, serve it on a custom domain.
- A browser on another website can show an image or play a video from the bucket, but it cannot read an object with `fetch` until a [CORS rule](/docs/object-storage/cors/) allows that website.

## The cache {#cache}

Our edge keeps a copy of each object of up to 10 MB that it serves. It keeps the copy for an hour, or for as long as the object's `Cache-Control` allows (`max-age` or `s-maxage`), up to a day. It does not keep an object whose `Cache-Control` says `no-store`, `no-cache` or `private`.

A copy can be older than the object. After you replace an object, purge its copy so visitors get the new one at once:

1. On the bucket's **Public access** tab, select **Purge cache…** on the **Cache** card.
2. In **Paths**, type each path to purge on a line of its own, such as `/images/logo.png`. Leave it empty to purge everything.
3. Select the button. It says how many paths it purges, or **Purge everything**.

A purge clears the copies on the public URL and on every custom domain. You can name up to 100 paths at once. **Purge cache…** is greyed out while nothing serves the bucket.

Changing the bucket's website settings purges everything for you.

## How it is billed {#billing}

Each read that our edge cannot answer from its copy counts as a Class B operation on the bucket's service, the same as a signed `GET`. A request for a key that does not exist counts too. On a [website](/docs/object-storage/static-websites/) such a request can count up to three times: once for the key, once for the folder's index document, and once for the error document, or for the index document of a single page app. Reads answered from the copy are free, and so is the data sent to visitors ([How Object Storage is billed](/docs/object-storage/usage-and-billing/)).

## Turn the public URL off

On the **Public URL** card, turn the switch off, then select **Turn off public URL**. Links to the public URL stop working, and its cached copies are purged. Custom domains keep serving the bucket.

## When our staff turn public access off {#turned-off}

Our staff can turn public access off for a bucket that breaks our terms, such as one that serves malware or phishing pages. The **Public access** tab then shows **Our staff turned off public access for this bucket**, with the reason. The public URL and every custom domain stop serving, and you cannot turn either back on. The objects stay in the bucket, and your access keys still work.

Select **Contact support** to ask for it to be turned back on. When it is, the public URL stays off until you turn it on again, and your verified custom domains serve again.

## Troubleshooting

`To serve a bucket publicly, your account needs a saved payment method, credit, or a paid invoice. Add one in Billing, then try again.`
: Add a payment method or credit in [Billing](https://www.coritan.com/dashboard/billing), then turn the switch on again.

`Our staff turned off public access for this bucket. Contact support to have it turned back on.`
: See [When our staff turn public access off](#turned-off).

The public URL answers `404` for every path
: Check the key, including its case and any folder in front of it. `/` answers `404` unless the bucket is a [website](/docs/object-storage/static-websites/). A suspended service serves nothing until you pay its overdue invoice ([Failed payments and suspended services](/docs/billing/failed-payments/)).

Visitors still get the old file
: Purge its path ([The cache](#cache)). A visitor's browser can keep its own copy too, for as long as the object's `Cache-Control` allows.

`Too many requests for this action. Try again later.`
: Your account made 60 public access changes, 60 purges or 120 domain checks in the last hour. Wait, then try again.

## Related

- [Serve a bucket on your own domain](/docs/object-storage/custom-domains/)
- [Host a static website in a bucket](/docs/object-storage/static-websites/)
- [Let websites use a bucket with CORS rules](/docs/object-storage/cors/)
- [Share a file with a presigned URL](/docs/object-storage/objects/#share-a-file-with-a-presigned-url)

## With the API

Each request takes the service ID and the bucket ID, from [`GET /api/v1/client/object-storage/{service_id}/buckets`](/docs/api/reference/client/object-storage/object-storage-buckets/#op-get-api-v1-client-object-storage-service-id-buckets). A service that is not Object Storage on your account answers `404` with `Object storage service not found`, and a bucket that is not on the service answers `404` with `Bucket not found`.

### Read the bucket's public access

[`GET /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/public`](/docs/api/reference/client/object-storage/object-storage-buckets/#op-get-api-v1-client-object-storage-service-id-buckets-bucket-id-public) returns everything the **Public access** tab shows:

```bash
curl https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/public \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

```json
{
  "bucket_id": 31,
  "bucket_name": "u7-assets",
  "public_url": "https://6f1c2a9e8b3d4f70a5e1c9d2b7f30a48.pub.example.net",
  "public_url_enabled": true,
  "public_url_available": true,
  "disabled": null,
  "good_standing": true,
  "website": {"enabled": false, "index": "index.html", "error": null, "spa": false},
  "domains": [],
  "max_domains": 10,
  "cname_target": "6f1c2a9e8b3d4f70a5e1c9d2b7f30a48.pub.example.net",
  "rate_limit_per_minute": 1200
}
```

`public_url` is `null` while the public URL is off. `public_url_available` is `false` when the platform offers no public URLs. `disabled` holds `at` and `reason` when our staff turned public access off. `good_standing` says whether the account can turn public access on. `domains` is described in [Serve a bucket on your own domain](/docs/object-storage/custom-domains/#with-the-api), and `website` in [Host a static website in a bucket](/docs/object-storage/static-websites/#with-the-api).

### Turn the public URL on or off

[`PUT /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/public`](/docs/api/reference/client/object-storage/object-storage-buckets/#op-put-api-v1-client-object-storage-service-id-buckets-bucket-id-public) takes `enabled`:

```bash
curl -X PUT https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/public \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true}'
```

It answers `200` with the shape above.

### Purge the cache

[`POST /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/public/purge`](/docs/api/reference/client/object-storage/object-storage-buckets/#op-post-api-v1-client-object-storage-service-id-buckets-bucket-id-public-purge) takes up to 100 `paths`, or no body to purge everything:

```bash
curl -X POST https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/public/purge \
  -H "Authorization: Bearer $CORITAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"paths": ["/images/logo.png", "/css/site.css"]}'
```

```json
{"hosts": ["6f1c2a9e8b3d4f70a5e1c9d2b7f30a48.pub.example.net", "cdn.example.com"], "paths": ["/images/logo.png", "/css/site.css"]}
```

`hosts` lists every address the purge cleared, and `paths` is empty when it cleared everything.

### Errors

| Status | `detail` | Cause |
| --- | --- | --- |
| `403` | `To serve a bucket publicly, your account needs a saved payment method, credit, or a paid invoice. Add one in Billing, then try again.` | The account has no payment method, no credit and no paid invoice. |
| `403` | `Our staff turned off public access for this bucket. Contact support to have it turned back on.` | [Our staff turned public access off](#turned-off). |
| `409` | `This service is pending; it can be changed once it is active` | The service is not `active`. The message names its status. |
| `409` | `Public URLs are not available yet. Link a custom domain to serve this bucket instead.` | The platform offers no public URLs. |
| `409` | `Nothing serves this bucket publicly, so there is no cache to purge.` | A purge of a bucket with no public URL and no verified domain. |
| `422` | `Purge at most 100 paths at once, or purge everything.` | A purge named more than 100 paths. |
| `429` | An object with `"error": "rate_limited"` and `retry_after_seconds` | Your account made 60 changes, or 60 purges, in the last hour. The `Retry-After` header says how long to wait. |

## API

- `GET /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/public`: Get public access (https://www.coritan.com/docs/api/reference/client/object-storage/object-storage-buckets/#op-get-api-v1-client-object-storage-service-id-buckets-bucket-id-public)
- `PUT /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/public`: Turn the bucket's public URL on or off (https://www.coritan.com/docs/api/reference/client/object-storage/object-storage-buckets/#op-put-api-v1-client-object-storage-service-id-buckets-bucket-id-public)
- `POST /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/public/purge`: Purge cache (https://www.coritan.com/docs/api/reference/client/object-storage/object-storage-buckets/#op-post-api-v1-client-object-storage-service-id-buckets-bucket-id-public-purge)
