> ## Documentation Index
>
> Fetch the complete documentation index at: https://chat.sh/help/llms.txt
> Use this file to discover all available pages before exploring further.

# Serve the help center in a folder

> Put your help center at an address like acme.com/help.

Serve your help center from a path on a site you already run, like acme.com/help. There is no DNS change and no certificate to wait for. Your site forwards the requests to chat.sh.

## Set it up

1. Open **Help center**, then **Domain**.
2. Under **Inside a folder on your site**, enter **Your domain**, like `acme.com`, and the **Folder**, like `/help`.
3. Select **Save**.
4. Choose what sits in front of your site: **Cloudflare Worker**, **Vercel**, **Next.js**, or **nginx**.
5. Copy the snippet into that setup and deploy it.

## What gets forwarded

Your site forwards two paths to chat.sh, unchanged:

- The folder and everything under it, like `/help` and `/help/...`.
- `/chat-assets/...`, which carries the help center's styles and scripts.

The snippet already does both.

## The snippets

These are the snippets the Domain page gives you, for a help center at `acme.chat.sh` served from `acme.com/help`. The Domain page fills in your own address and folder, so copy from there when you set yours up.

### Cloudflare Worker

Create a Worker with this script:

```javascript
// Everything this Worker needs is in these three lines. If you change
// the folder in the dashboard, change PREFIX here too.
const ORIGIN = "acme.chat.sh";
const PREFIX = "/help";
const ASSETS = "/chat-assets";

export default {
  async fetch(request) {
    const url = new URL(request.url);

    const mine =
      url.pathname === PREFIX ||
      url.pathname.startsWith(PREFIX + "/") ||
      url.pathname.startsWith(ASSETS + "/");

    // Everything else is your site, untouched.
    if (!mine) return fetch(request);

    // One address per page: /x/ and /x are the same page.
    if (url.pathname.endsWith("/") && url.pathname !== "/") {
      url.pathname = url.pathname.slice(0, -1);
      return Response.redirect(url.toString(), 301);
    }

    const upstream = new URL(url);
    upstream.hostname = ORIGIN;

    const proxied = new Request(upstream, request);
    proxied.headers.set("Host", ORIGIN);
    proxied.headers.set("X-Forwarded-Host", url.host);

    // Redirects are handled here rather than followed. A renamed article
    // redirects to the help center's own host; visitors should stay on yours.
    const response = await fetch(proxied, { redirect: "manual" });
    if (response.status < 300 || response.status >= 400) return response;

    const location = response.headers.get("location");
    if (!location) return response;

    const target = new URL(location, "https://" + ORIGIN);
    if (target.hostname !== ORIGIN) return response;
    target.protocol = url.protocol;
    target.host = url.host;

    const rewritten = new Response(response.body, response);
    rewritten.headers.set("location", target.toString());
    return rewritten;
  },
};
```

Then add three routes to it: `acme.com/help`, `acme.com/help/*`, and `acme.com/chat-assets/*`. The `/help/*` route alone does not match `/help` itself, so without the first one every page works except the home page.

Requests outside those paths go straight to your site, untouched. If you change the folder later, change `PREFIX` in the script too.

### Vercel

Add the rewrites to `vercel.json` at the root of your project:

```json
{
  "rewrites": [
    { "source": "/help", "destination": "https://acme.chat.sh/help" },
    { "source": "/help/:path*", "destination": "https://acme.chat.sh/help/:path*" },
    { "source": "/chat-assets/:path*", "destination": "https://acme.chat.sh/chat-assets/:path*" }
  ]
}
```

These are rewrites, not redirects: the address in the browser stays yours.

### Next.js

Add the rewrites to `next.config.js`:

```javascript
// next.config.js
module.exports = {
  async rewrites() {
    return [
      { source: "/help", destination: "https://acme.chat.sh/help" },
      { source: "/help/:path*", destination: "https://acme.chat.sh/help/:path*" },
      { source: "/chat-assets/:path*", destination: "https://acme.chat.sh/chat-assets/:path*" },
    ];
  },
};
```

Use this instead of `vercel.json` when your own Next.js app owns the routing.

### nginx

Add both locations to the `server` block for your domain:

```nginx
location /help {
  proxy_pass https://acme.chat.sh;
  proxy_set_header Host acme.chat.sh;
  proxy_set_header X-Forwarded-Proto https;
  proxy_ssl_server_name on;
}

location /chat-assets/ {
  proxy_pass https://acme.chat.sh;
  proxy_set_header Host acme.chat.sh;
  proxy_ssl_server_name on;
}
```

- Keep `proxy_ssl_server_name on`. Without it, chat.sh cannot tell which help center to serve.
- Do not add a trailing slash to `proxy_pass`. That would rewrite the path.

## Once it is live

Links, the sitemap, and search engines use the folder address. Your chat.sh address keeps working too.
