{"Status":true,"Message":"","Response":{"post":{"postuid":"3aaaa21c-8cce-40cb-adad-8655d2493aae","tenantuid":"d8b744fc-2e70-4089-bb80-dd1d08f6c7b2","projectuid":"fc6490ac-7527-4f49-b06e-46f701280e85","title":"Setup Reverse Proxy","slug":"article/setup-reverse-proxy","html":"\u003Cp\u003EHelpGuides supports serving your content through a reverse proxy, for advanced setups where your documentation or blog needs to live under a path on your main website.\u003C/p\u003E\u003Ch2 id=\u0022what_is_reverse_proxy\u0022\u003EWhat is Reverse Proxy?\u003C/h2\u003E\u003Cp\u003EFor the sake of example, let\u0027s say you own a domain \u003Ccode class=\u0022inline-code\u0022\u003Eexample.com\u003C/code\u003E. You have an existing website using that domain running WordPress where you host a blog: \u003Ccode class=\u0022inline-code\u0022\u003Eexample.com/blog/example-name\u003C/code\u003E.\u003C/p\u003E\u003Cp\u003EYou then create a HelpGuides project at \u003Ccode\u003Emyproject.helpguides.io\u003C/code\u003E, and want to move your blog from WordPress to HelpGuides while keeping WordPress for your main website. A reverse proxy makes this possible.\u003C/p\u003E\u003Ch3 id=\u0022how_it_works\u0022\u003EHow it works\u003C/h3\u003E\u003Cp\u003ERequests sent to \u003Ccode\u003Eexample.com/blog/example-name\u003C/code\u003E are proxied to \u003Ccode\u003Emyproject.helpguides.io/example-name\u003C/code\u003E. The content is hosted at \u003Ccode\u003Emyproject.helpguides.io\u003C/code\u003E, but the browser URL and canonical URL remain \u003Ccode\u003Eexample.com/blog/example-name\u003C/code\u003E.\u003C/p\u003E\u003Ch3 id=\u0022why_use_a_reverse_proxy\u0022\u003EWhy use a reverse proxy?\u003C/h3\u003E\u003Cp\u003EA reverse proxy lets you:\u003C/p\u003E\u003Cul\u003E\u003Cli\u003EMove content to HelpGuides (search, APIs, AI tools and more) without moving your whole website.\u003C/li\u003E\u003Cli\u003EKeep existing, published URLs working.\u003C/li\u003E\u003Cli\u003EKeep content on your root domain instead of a subdomain, which is better for SEO.\u003C/li\u003E\u003C/ul\u003E\u003Ch2 id=\u0022setting_up_a_reverse_proxy\u0022\u003ESetting up a Reverse Proxy\u003C/h2\u003E\u003Cp\u003ESetting up a reverse proxy is an advanced task, but platforms such as Cloudflare make it relatively simple.\u003C/p\u003E\u003Ccite class=\u0022recommended\u0022\u003E\u003Cspan class=\u0022title\u0022\u003ERecommended\u003C/span\u003E\u003Cp\u003EIf you want to support a reverse proxy for your HelpGuides content, please contact support. Reverse proxy configuration is only available in our enterprise plans.\u003C/p\u003E\u003C/cite\u003E\u003Ch2 id=\u0022reverse_proxy_with_cloudflare\u0022\u003EReverse proxy with Cloudflare\u003C/h2\u003E\u003Ccite class=\u0022important\u0022\u003E\u003Cspan class=\u0022title\u0022\u003EImportant\u003C/span\u003E\u003Cp\u003ESetting up a reverse proxy with Cloudflare requires your domain\u0027s DNS to be managed by Cloudflare. If you can\u0027t move your DNS to Cloudflare, you can\u0027t use Cloudflare as your reverse proxy.\u003C/p\u003E\u003C/cite\u003E\u003Ch3 id=\u0022step_1__get_your_application_domain\u0022\u003EStep 1 - Get your application domain\u003C/h3\u003E\u003Cp\u003EYour \u003Cb\u003EApplication Domain\u003C/b\u003E is in \u003Cb\u003ESettings\u003C/b\u003E \u2192 \u003Cb\u003EGeneral\u003C/b\u003E:\u003C/p\u003E\u003Cimg class=\u0022lazy-load\u0022 data-width=\u0022870\u0022 data-height=\u0022480\u0022 data-src=\u0022https://graffiti-auf7e6dwhxhcbwek.z03.azurefd.net/d8b744fc-2e70-4089-bb80-dd1d08f6c7b2/fc6490ac-7527-4f49-b06e-46f701280e85/f2a558c7-713a-4aea-9738-109f4039dbdc.png?v=690928257\u0022 style=\u0022\u0022 alt=\u0022\u0022/\u003E\u003Cp\u003EWithout a reverse proxy, this is the address where your content is served. HelpGuides also supports custom subdomains.\u003C/p\u003E\u003Ch3 id=\u0022step_2__get_your_canonical_path\u0022\u003EStep 2 - Get your canonical path\u003C/h3\u003E\u003Cp\u003EYour canonical path is configured by the HelpGuides team. Once it\u0027s set up, you\u0027ll see it in \u003Cb\u003ESettings\u003C/b\u003E \u2192 \u003Cb\u003EAdvanced\u003C/b\u003E \u2192 \u003Cb\u003ECanonical Path\u003C/b\u003E:\u003C/p\u003E\u003Cimg class=\u0022lazy-load\u0022 data-width=\u00221207\u0022 data-height=\u0022481\u0022 data-src=\u0022https://graffiti-auf7e6dwhxhcbwek.z03.azurefd.net/d8b744fc-2e70-4089-bb80-dd1d08f6c7b2/fc6490ac-7527-4f49-b06e-46f701280e85/71372a38-d720-445f-8867-66ed15db84a4.png?v=2082973682\u0022 style=\u0022\u0022 alt=\u0022\u0022/\u003E\u003Cp\u003EIn this example, requests to \u003Ccode\u003Ehttps://helpguides.io/blog\u003C/code\u003E are mapped to the application domain \u003Ccode\u003Ehttps://vszh13.helpguides.io\u003C/code\u003E. Your setup would map, for example, \u003Ccode\u003Ehttps://yourdomain.com/blog\u003C/code\u003E to \u003Ccode\u003Ehttps://[your subdomain].helpguides.io\u003C/code\u003E. Once a canonical path is set, HelpGuides uses it for canonical URLs, sitemaps and feeds, and redirects visitors who go straight to the application domain.\u003C/p\u003E\u003Ch3 id=\u0022step_3__create_a_cloudflare_worker\u0022\u003EStep 3 - Create a Cloudflare worker\u003C/h3\u003E\u003Cp\u003ECreate a Cloudflare worker that forwards requests from your domain to your HelpGuides project. You\u0027ll need your \u003Cb\u003EApplication Domain\u003C/b\u003E. The script below forwards any request whose path starts with \u003Ccode\u003E/blog\u003C/code\u003E.\u003C/p\u003E\u003Cp\u003EFor example, a request to:\u003C/p\u003E\u003Cdiv class=\u0022code_wrapper\u0022\u003E\u003Cdiv class=\u0022code\u0022 data-language=\u0022plaintext\u0022\u003Ehttps://helpguides.io/blog/helpguidesio-now-supports-model-context-protocol-mcp\u003C/div\u003E\u003C/div\u003E\u003Cp\u003Eis reverse proxied to:\u003C/p\u003E\u003Cdiv class=\u0022code_wrapper\u0022\u003E\u003Cdiv class=\u0022code\u0022 data-language=\u0022plaintext\u0022\u003Ehttps://vszh13.helpguides.io/helpguidesio-now-supports-model-context-protocol-mcp\u003C/div\u003E\u003C/div\u003E\u003Cp\u003EReplace the \u003Ccode\u003Eapp_domain\u003C/code\u003E value with your own \u003Cb\u003EApplication Domain\u003C/b\u003E, with no trailing slash. If you use a path other than \u003Ccode\u003E/blog\u003C/code\u003E, change it throughout the script.\u003C/p\u003E\u003Cdiv class=\u0022code_wrapper\u0022\u003E\u003Cdiv class=\u0022code\u0022 data-language=\u0022javascript\u0022\u003E// Your HelpGuides Application Domain, with no trailing slash\nconst app_domain = \u0026quot;https://vszh13.helpguides.io\u0026quot;;\n\nexport default {\n  async fetch(request, env, ctx) {\n    const incomingUrl = new URL(request.url);\n\n    // The blog home page: /blog or /blog/\n    if (incomingUrl.pathname === \u0026quot;/blog\u0026quot; || incomingUrl.pathname === \u0026quot;/blog/\u0026quot;) {\n      return fetchAndProcess(\u0060${app_domain}/${incomingUrl.search}\u0060, request, incomingUrl);\n    }\n\n    // All other blog paths, such as /blog/hello-world or /blog/site.json\n    if (incomingUrl.pathname.startsWith(\u0026quot;/blog/\u0026quot;)) {\n      const targetPath = incomingUrl.pathname.replace(\u0026quot;/blog\u0026quot;, \u0026quot;\u0026quot;);\n      const targetUrl = \u0060${app_domain}${targetPath}${incomingUrl.search}\u0060;\n      return fetchAndProcess(targetUrl, request, incomingUrl);\n    }\n\n    return new Response(\u0026quot;Not Found\u0026quot;, { status: 404 });\n  }\n};\n\n// Forwards the request to HelpGuides and returns the response\nasync function fetchAndProcess(targetUrl, originalRequest, incomingUrl) {\n  const proxyRequest = new Request(targetUrl, {\n    method: originalRequest.method,\n    headers: new Headers({\n      ...Object.fromEntries(originalRequest.headers),\n      \u0026quot;X-Forwarded-Host\u0026quot;: incomingUrl.hostname // passes the root domain\n    }),\n    body: originalRequest.body,\n    redirect: \u0026quot;manual\u0026quot;\n  });\n\n  const originResponse = await fetch(proxyRequest);\n  const contentType = originResponse.headers.get(\u0026quot;Content-Type\u0026quot;) || \u0026quot;\u0026quot;;\n\n  // HTML: rewrite root-relative paths so assets load from HelpGuides\n  if (contentType.includes(\u0026quot;text/html\u0026quot;)) {\n    let html = await originResponse.text();\n\n    html = html.replace(/(href|src)=[\u0026quot;\u0026#39;]\\/(?!\\/)/g, \u0060$1=\u0026quot;${app_domain}/\u0060);\n\n    return new Response(html, {\n      status: originResponse.status,\n      headers: {\n        \u0026quot;Content-Type\u0026quot;: \u0026quot;text/html\u0026quot;,\n        \u0026quot;Cache-Control\u0026quot;: \u0026quot;public, max-age=60\u0026quot;\n      }\n    });\n  }\n\n  // Other file types (CSS, JSON, XML and so on)\n  return new Response(originResponse.body, {\n    status: originResponse.status,\n    headers: originResponse.headers\n  });\n}\u003C/div\u003E\u003C/div\u003E\u003Ch3 id=\u0022step_4__add_a_route_for_the_worker\u0022\u003EStep 4 - Add a route for the worker\u003C/h3\u003E\u003Cp\u003EIn Cloudflare, add a route for the worker that matches your path, for example \u003Ccode\u003Eexample.com/blog*\u003C/code\u003E, so requests under \u003Ccode\u003E/blog\u003C/code\u003E go to the worker and the rest of your site is unaffected. Then open a few URLs under \u003Ccode\u003E/blog\u003C/code\u003E to check that articles, images and search work.\u003C/p\u003E\u003Cp\u003ERelated: \u003Ca href=\u0022/article/site-map\u0022\u003ESite Map\u003C/a\u003E, \u003Ca href=\u0022/article/feeds-and-machine-readable-formats\u0022\u003EFeeds and Machine-Readable Formats\u003C/a\u003E, \u003Ca href=\u0022/article/finding-broken-links-with-the-seo-report\u0022\u003EFinding Broken Links with the SEO Report\u003C/a\u003E (covers \u003Cb\u003EForce Trailing Slash\u003C/b\u003E).\u003C/p\u003E","publish_status":0,"post_type":"Article","authoruid":"3dde8c16-763a-4a2b-ae0b-1d8c50c62e3d","author":{"authoruid":"3dde8c16-763a-4a2b-ae0b-1d8c50c62e3d"},"featured_image_updating":false,"meta_description":"Learn what a reverse proxy is and how to use it to migrate blog content to HelpGuides while maintaining your site\u0027s URLs and improving SEO.","display_toc":false,"has_workingcopy":false,"allow_indexing":true,"total_views":324,"date_published":"2025-06-16T18:34:00","date_updated":"2026-10-04T21:50:27.347","date_created":"2025-06-04T20:32:35.013"}}}