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

# Reverse proxy

> Configure a reverse proxy to serve Obvlo Microsite content through your own domain, consolidating SEO authority and providing a seamless user experience.

Serving Obvlo content through your primary domain consolidates SEO authority and ensures a seamless user experience. This guide covers configuration for Cloudflare Workers, NGINX, Apache, IIS, and Caddy.

A typical Obvlo content URL follows this pattern:

```text theme={null}
https://content.obvlo.com/live/orgs/{orgId}/sites/{siteId}/live/
```

## SEO benefits

* **Consolidated authority** — link equity and domain authority accrue to your primary domain rather than being split across subdomains.
* **Consistent URLs** — search engine crawlers index a single URL structure, eliminating duplicate content risks.
* **Improved engagement signals** — a unified domain reduces bounce rates and increases session duration.
* **Simplified analytics** — all traffic flows through one domain, making attribution straightforward.
* **Performance control** — edge caching improves page speed, a direct ranking factor.

## General principles

These principles apply regardless of which reverse proxy you use.

**Path-based proxying** — configure your proxy to forward requests from a specific URL path (e.g. `/travel-guides/`) to your Obvlo content URL.

**Host header** — the `Host` header sent to the Obvlo backend must be `content.obvlo.com`.

**Forwarded headers** — include the following so the backend can identify the original client:

| Header              | Value                                 |
| ------------------- | ------------------------------------- |
| `X-Forwarded-For`   | Client IP address                     |
| `X-Forwarded-Proto` | Original protocol (`http` or `https`) |
| `X-Forwarded-Host`  | The visitor's requested domain        |

**SSL/TLS** — the connection between your proxy and the Obvlo backend must use HTTPS.

***

## Cloudflare Workers (recommended)

Cloudflare Workers run JavaScript at the edge. Cloudflare handles SSL certificate provisioning and renewal automatically — no origin servers, load balancers, or certificate managers required.

**Request flow:** Visitor → Cloudflare Edge (SSL + Worker) → Obvlo CDN

### Prerequisites

* A Cloudflare account (free tier is sufficient)
* Your domain's DNS managed by Cloudflare (nameservers pointed to Cloudflare)
* Your Obvlo content URL (provided during onboarding)

### Setup

1. **Add your domain to Cloudflare.** Update your domain registrar's nameservers to the Cloudflare nameservers shown in the dashboard.
2. **Create a DNS A record.** Point your domain to `192.0.2.1` (a dummy address — the Worker intercepts traffic before it reaches any origin). Set proxy status to enabled (orange cloud icon).
3. **Create the Worker.** Go to **Workers & Pages → Create → Create Worker**, select "Start with Hello World!", deploy, then click **Edit Code** and replace the contents with the worker code below.
4. **Configure routes.** Go to your domain → **Workers Routes → Add Route**. Add a route matching your specific path, e.g., `yourdomain.com/local-guides*`, pointing to your worker.
5. **Verify.** Visit your domain — Obvlo content should load with your domain in the browser address bar.

### Worker code

Replace `ORIGIN_BASE` with your actual Obvlo content URL and `PROXY_PATH` with the path on your domain where the content should live.

```javascript theme={null}

const ORIGIN_BASE = "https://content.obvlo.com/live/orgs/{orgId}/sites/{siteId}/live";
const PROXY_PATH = "/local-guides";

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


    if (!url.pathname.startsWith(PROXY_PATH)) {
      return fetch(request);
    }

    let targetPath = url.pathname.replace(PROXY_PATH, "");
    if (targetPath === "" || targetPath === "/") targetPath = "/";
    
    const originUrl = `${ORIGIN_BASE}${targetPath}${url.search}`; 

    const headers = new Headers(request.headers);
    headers.set("Host", "content.obvlo.com"); 
    headers.set("X-Forwarded-Host", url.hostname); 
    headers.set("X-Forwarded-Proto", "https"); 

    try {
      const response = await fetch(originUrl, {
        method: request.method,
        headers,
        redirect: "follow", 
      });

      const contentType = response.headers.get("Content-Type") || "";

      if (contentType.includes("text/html")) {
        return new HTMLRewriter()
          .on("link, script, img, source, a", {
            element(element) {
              const attrs = ["href", "src", "srcset"];
              attrs.forEach(attr => {
                if (element.hasAttribute(attr)) {
                  let val = element.getAttribute(attr);

                  // Only prefix relative paths (starting with / but not //)
                  if (val.startsWith("/") && !val.startsWith("//")) {
                    element.setAttribute(attr, `${PROXY_PATH}${val}`);
                  }
                }
              });
            }
          })
          .transform(response);
      }

      const finalResponse = new Response(response.body, response);
      finalResponse.headers.delete("x-served-by");
      finalResponse.headers.delete("x-cache"); 
      
      return finalResponse;

    } catch (err) {
      return new Response(`Proxy error: ${err.message}`, { status: 502 });
    }
  },
};
```

### Important Considerations

* **Trailing Slashes:** In the Worker code, ensure `ORIGIN_BASE` does not end with a slash.
* **Path Stripping:** The code above strips the `PROXY_PATH` before forwarding to Obvlo. This is necessary because the Obvlo backend expects requests relative to its own root, not your domain's sub-folder.

### What this gives you

* Automatic SSL certificate management — zero configuration
* No servers or infrastructure to maintain
* Edge execution with sub-millisecond cold starts globally
* 100,000 free requests per day on the free tier
* Built-in DDoS protection and CDN caching

***

## Web server configurations

Traditional web server setups require you to manage SSL certificates, server infrastructure, and updates yourself. For most use cases, the Cloudflare Workers approach above is simpler to operate.

### NGINX

Add the following to your server block. Replace the placeholder paths with your actual Obvlo content URL.

```nginx theme={null}
server {
    listen 443 ssl;
    server_name customer-domain.com;

    ssl_certificate /etc/nginx/ssl/customer-domain.com.crt;
    ssl_certificate_key /etc/nginx/ssl/customer-domain.com.key;

    location / {
        proxy_pass https://content.obvlo.com/live/orgs/{orgId}/sites/{siteId}/live/;
        proxy_set_header Host content.obvlo.com;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_redirect off;

        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}
```

The trailing slash on both `location` and `proxy_pass` strips the location prefix and appends the remainder to the backend URL. The `Host` header must be `content.obvlo.com`.

### Apache HTTP Server

Enable `mod_proxy` and `mod_proxy_http`, then configure your virtual host:

```apache theme={null}
<VirtualHost *:443>
    ServerName customer-domain.com
    SSLEngine on
    SSLCertificateFile /path/to/certificate.crt
    SSLCertificateKeyFile /path/to/private.key

    ProxyPass "/" "https://content.obvlo.com/live/orgs/{orgId}/sites/{siteId}/live/"
    ProxyPassReverse "/" "https://content.obvlo.com/live/orgs/{orgId}/sites/{siteId}/live/"

    ProxyPreserveHost Off
    RequestHeader set Host "content.obvlo.com"
    RequestHeader set X-Forwarded-Proto "https"
    RequestHeader set X-Forwarded-Host "customer-domain.com"
</VirtualHost>
```

`ProxyPassReverse` rewrites response `Location` headers so redirects use your domain. Set `ProxyPreserveHost Off` and explicitly set `Host` to `content.obvlo.com`.

### IIS (Internet Information Services)

IIS requires the Application Request Routing (ARR) module and URL Rewrite module. On Azure App Service, these are pre-installed.

**Enable the proxy:**

1. Open IIS Manager and select your server in the Connections pane.
2. Double-click **Application Request Routing Cache**.
3. Click **Server Proxy Settings** and check **Enable proxy**.

**web.config** — place this in your site's root directory:

```xml theme={null}
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="ObvloProxy" stopProcessing="true">
          <match url="(.*)" />
          <action type="Rewrite"
            url="https://content.obvlo.com/live/orgs/{orgId}/sites/{siteId}/live/{R:1}" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>
```

ARR automatically adds `X-Forwarded-For`, `X-Forwarded-Proto`, and `X-Forwarded-Host` headers. Proxy timeouts are configured in the ARR server-level settings.

### Caddy

Caddy handles SSL automatically via Let's Encrypt:

```caddy theme={null}
customer-domain.com {
    reverse_proxy /* https://content.obvlo.com/live/orgs/{orgId}/sites/{siteId}/live/ {
        header_up Host content.obvlo.com
        header_up X-Forwarded-Host {host}
    }
}
```

Caddy automatically sets `X-Forwarded-For` and `X-Forwarded-Proto`.

***

## CDN / edge providers

If you already use a CDN or edge platform, it can likely serve as your reverse proxy. The key requirements are the same across all providers: correct `Host` header, forwarded headers, and HTTPS to the origin.

| Provider          | Notes                                       |
| ----------------- | ------------------------------------------- |
| Cloudflare        | Workers (see above) or Page Rules           |
| Amazon CloudFront | Origin configuration with custom headers    |
| Google Cloud CDN  | URL maps with backend services              |
| Azure Front Door  | Routing rules with backend pools            |
| Fastly            | VCL configuration or Compute\@Edge          |
| Akamai            | Property configuration with origin settings |

***

## Troubleshooting

### Content not loading

* Verify the `Host` header is set to `content.obvlo.com` — this is the most common configuration error.
* Confirm the full Obvlo content URL is correct, including the trailing path.
* Test the origin URL directly:
  ```bash theme={null}
  curl -I https://content.obvlo.com/live/orgs/{orgId}/sites/{siteId}/live/
  ```

### SSL certificate errors

* **Cloudflare Workers** — ensure DNS records are proxied (orange cloud icon). Cloudflare manages certificates automatically.
* **Web servers** — verify certificate paths and renewal configuration (e.g. Certbot cron jobs).
* **CDN providers** — check origin SSL settings match your backend configuration.

### Cloudflare Worker not executing

* Confirm the DNS A record has proxy status enabled (orange cloud, not grey).
* Check **Workers Routes** — ensure the correct worker is assigned to your domain pattern.
* Purge the Cloudflare cache: **Caching → Configuration → Purge Everything**.
* Verify the worker was deployed by checking real-time logs in the Workers dashboard.

## Related pages

* [Developers overview](/developer-docs/overview)
* [Microsite overview](/microsite/overview)
* [Language reference](/reference/language-reference)
