> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ibee.co.in/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ibee.co.in/docs/_mcp/server.

# Hosting Static Sites and SPAs on Object Storage

> Complete guide to hosting static websites and single-page applications (React, Vue, Angular) on IBEE Object Storage with CDN, custom domains, and HTTPS.

IBEE Object Storage can serve static websites and single-page applications (SPAs) directly from a bucket. Combined with the CDN and a custom domain, you get global delivery, automatic HTTPS, and zero-server hosting for frontends built with React, Vue, Angular, Svelte, or plain HTML.

## Before you begin

* An active IBEE Solutions organization ([Create an organization](/docs/getting-started/account-setup/create-a-project))
* A built static site or SPA (output folder containing `index.html`)
* An S3 credential for the bucket's workspace ([API Credentials](/docs/infrastructure/object-storage/api-tokens))
* AWS CLI or any S3-compatible tool installed locally

### 1. Build your site

Generate the production build for your framework. The output folder is what you'll upload.

| Framework               | Build command                         | Output folder      |
| ----------------------- | ------------------------------------- | ------------------ |
| React (CRA)             | `npm run build`                       | `build/`           |
| React (Vite)            | `npm run build`                       | `dist/`            |
| Next.js (static export) | `next build && next export`           | `out/`             |
| Vue                     | `npm run build`                       | `dist/`            |
| Angular                 | `ng build --configuration production` | `dist/<project>/`  |
| Svelte / SvelteKit      | `npm run build`                       | `build/`           |
| Plain HTML              | —                                     | your source folder |

### 2. Create a bucket

[Create a bucket](/docs/infrastructure/object-storage/buckets#create-a-bucket). Keep **Automatic location**, or click **Need a specific location? click here** to pick one of the available sites.

New buckets are private. After creating it, open the bucket → **Settings** → **General** and turn on **Public Access** ([Bucket policies → Public access](/docs/infrastructure/object-storage/buckets/bucket-policies#public-access)).

> **Info**
>
> **Bucket name tip:** match the bucket name to your domain (e.g., `app.ibee.ai`) for clarity. It does not affect functionality.

### 3. Configure the AWS CLI

Set up a profile pointing at IBEE Object Storage:

```bash
aws configure --profile ibee
# AWS Access Key ID: <your access key>
# AWS Secret Access Key: <your secret>
# Default region: us-east-1
# Default output format: json
```

### 4. Upload your build output

Sync the build folder to your bucket. Replace `<bucket>`, `<workspace-id>`, and `./dist` with your values — the full endpoint is the **S3 Endpoint** shown when you created the credential:

```bash
aws s3 sync ./dist s3://<bucket>/ \
  --endpoint-url https://<workspace-id>.blob.ibeestorage.com \
  --profile ibee \
  --acl public-read \
  --delete
```

The `--delete` flag removes files from the bucket that no longer exist locally — useful for clean redeploys.

### 5. Set correct cache headers

SPAs and static sites benefit from aggressive caching for hashed assets and no caching for `index.html`. Re-upload `index.html` with a short TTL after the sync:

```bash
aws s3 cp ./dist/index.html s3://<bucket>/index.html \
  --endpoint-url https://<workspace-id>.blob.ibeestorage.com \
  --profile ibee \
  --acl public-read \
  --cache-control "no-cache, no-store, must-revalidate" \
  --content-type "text/html"
```

This ensures users always get the latest `index.html` (which references new hashed asset filenames), while the hashed assets themselves can be cached for a year by the CDN.

### 6. Create a CDN distribution

Put a CDN in front of the bucket for HTTPS, custom domains, and global edge caching ([CDN integration](/docs/infrastructure/object-storage/cdn-integration)).

* **Origin Type:** Object Storage Bucket → select your bucket
* **Cache Policy:** Static Assets (1 year)

You'll get a CDN URL like `dl-abc123.cdn.ibee.ai`.

> **Warning**
>
> **SPA deep links:** the portal doesn't currently offer a default-root-object or SPA-fallback (error page) setting for CDN distributions. A direct request for a client-side route such as `/dashboard/settings` doesn't match any object key and can return 404. Use hash-based routing (for example `/#/dashboard/settings`) so every route loads from `index.html`.

### 7. Add a custom domain

Add your domain (e.g., `app.ibee.ai`) to the CDN distribution ([CDN integration](/docs/infrastructure/object-storage/cdn-integration)). Then create a CNAME at your DNS provider:

| Type  | Name  | Value                   |
| ----- | ----- | ----------------------- |
| CNAME | `app` | `dl-abc123.cdn.ibee.ai` |

SSL is auto-provisioned within a few minutes of DNS propagating.

## Verify

Visit your custom domain — you should see your site over HTTPS. For SPAs, open a few routes directly (with hash routing, e.g. `/#/about`) to confirm they load.

```bash
curl -I https://app.ibee.ai
# HTTP/2 200
# content-type: text/html
# cache-control: no-cache, no-store, must-revalidate
```

## Redeploying

Each deploy is a fresh sync:

```bash
npm run build
aws s3 sync ./dist s3://<bucket>/ \
  --endpoint-url https://<workspace-id>.blob.ibeestorage.com \
  --profile ibee --acl public-read --delete

aws s3 cp ./dist/index.html s3://<bucket>/index.html \
  --endpoint-url https://<workspace-id>.blob.ibeestorage.com \
  --profile ibee --acl public-read \
  --cache-control "no-cache" --content-type "text/html"
```

If hashed asset filenames changed, the CDN serves the new `index.html` immediately (because of `no-cache`), which then references the new assets — no manual cache invalidation needed.

## Troubleshooting

**Site loads on CDN URL but not on custom domain**
DNS hasn't propagated yet, or the CNAME points at the bucket instead of the CDN URL. Use `dig app.ibee.ai CNAME +short` to confirm it resolves to `dl-*.cdn.ibee.ai`.

**SPA returns 404 on refresh of nested routes**
There's no `index.html` fallback setting for CDN distributions in the portal. Switch the app to hash-based routing (see the SPA note under Step 6).

**Stale content after redeploy**
Hashed asset filenames should bust caches automatically. If you're seeing the old `index.html`, confirm the `Cache-Control: no-cache` header is set on it (Step 5).

**Mixed content / blocked HTTP requests**
Ensure all internal API calls and asset URLs use HTTPS. Browsers block HTTP subresources on HTTPS pages.

**CORS errors when calling APIs from the site**
Configure CORS on the API or the bucket ([CORS](/docs/infrastructure/object-storage/buckets/cors)).

## Related pages

* [Create a bucket](/docs/infrastructure/object-storage/buckets)
* [Upload and download objects](/docs/infrastructure/object-storage/objects)
* [CDN integration](/docs/infrastructure/object-storage/cdn-integration)
* [Custom domains](/docs/infrastructure/object-storage/buckets/custom-domains)
* [CORS](/docs/infrastructure/object-storage/buckets/cors)