# Reverse-proxy — any HTTP origin

experimental · Next.js, Astro, Nuxt, SvelteKit, Rails, Django, WordPress…

Sit in front of your existing app as a Node reverse-proxy. Your framework runs unchanged on a localhost port; agentsite intercepts HTML responses and injects the bundle.

**Start here first.** Every platform recipe below assumes the canonical Express + Docker install at [/install/express-docker](/install/express-docker). The snippets on this page are the platform-specific deltas on top of that baseline.

Rather than ship a per-framework adapter, agentsite can sit in front of your existing app as a Node reverse-proxy. Your framework runs unchanged on a localhost port; agentsite intercepts HTML responses, mutates the `<head>` + injects the markdown body inside a preboot `<div>` (CSS-hidden the moment JS boots), and serves `/llms.txt` / `/.well-known/*` on the same domain.

```
your domain (:443/:80)
        │
        ▼
┌─────────────────────────────────┐
│  agentsite  (Node, :3000)        │  ← reads HTML responses, injects
│   - express + agentsite.cjs      │     <head> tags, JSON-LD, markdown
│   - proxies through to upstream  │     preboot <div>, /llms.txt, etc.
└──────────┬──────────────────────┘
           │  HTTP fetch
           ▼
┌─────────────────────────────────┐
│  your framework  (:3001)         │  ← unchanged: 'next start',
│   next / nuxt / astro / sveltekit│     'nuxt preview', 'astro preview',
│   rails / django / wordpress     │     'rails s', 'gunicorn', anything
└─────────────────────────────────┘
```

agentsite/server.mjscopy

```js
// agentsite/server.mjs — reverse-proxy mode (Express-Sidecar)
import express from 'express'
import { createRequire } from 'node:module'

const require = createRequire(import.meta.url)
const agentsite = require('./agentsite.cjs')

const PORT     = parseInt(process.env.PORT || '3000', 10)
const UPSTREAM = process.env.UPSTREAM_ORIGIN || 'http://127.0.0.1:3001'
const SITE     = process.env.AGENTSITE_SITE
const TOKEN    = process.env.AGENTSITE_TOKEN

const app = express()
app.set('trust proxy', true)

app.use(agentsite({
  upstream: UPSTREAM,          // ← no distDir; we fetch HTML from your app
  site: SITE,
  token: TOKEN,
  fetchTimeoutMs: 4000,
  log: process.env.NODE_ENV !== 'production',
}))

app.listen(PORT, () => console.log(`agentsite proxy → ${UPSTREAM} on :${PORT}`))
```

docker-compose.ymlcopy

```yaml
# docker-compose.yml — agentsite in front, your framework behind
services:
  agentsite:
    build: ./server
    ports: ['3000:3000']
    environment:
      AGENTSITE_TOKEN: ${AGENTSITE_TOKEN}
      AGENTSITE_SITE:  https://yoursite.com
      UPSTREAM_ORIGIN: http://app:3001
    depends_on: [app]

  app:
    # Your framework's container — runs 'next start' / 'nuxt preview' /
    # 'astro preview' / 'rails s' / whatever — listening on :3001.
    build: .
    expose: ['3001']
    environment:
      PORT: 3001
      # (your framework's normal env)
```

Framework-specific notes:

- **Next.js:** `next start` on `PORT=3001`. App Router and Pages Router both work; agentsite sees the rendered HTML the same way a browser does.
- **Astro / Nuxt / SvelteKit:** use the framework's Node-server adapter (`@astrojs/node`, `nuxt build --preset=node-server`, `@sveltejs/adapter-node`) on `PORT=3001`.
- **Rails / Django / Laravel / WordPress / anything else that speaks HTTP:** point `UPSTREAM_ORIGIN` at it. Works the same way.

**Streaming SSR — use the SDK install instead.** The reverse-proxy buffers the upstream response, which kills time-to-first-byte and may break framework streaming guarantees for React Server Components / Suspense / chunked HTML. For those stacks the SDK install (in-process hooks calling our `/bundle` API during SSR) preserves streaming. Runnable references: [`demos/after/next/`](https://github.com/agentsite/integration/tree/main/demos/after/next) and [`demos/after/nuxt/`](https://github.com/agentsite/integration/tree/main/demos/after/nuxt).