Own the renderer. Own the operations.
Prerender Buddy Engine is the Apache-2.0 rendering core for teams that want to run crawler rendering inside infrastructure they operate.
On this page
Overview
Run Prerender Buddy Engine when you want to operate the renderer in your own infrastructure. You manage its network, crawler integration, capacity, security, upgrades and incidents.
The standalone engine uses Playwright Chromium to produce crawler-readable HTML. Its cache and coordination of duplicate requests are local to one process. The repository is licensed under Apache-2.0. The managed dashboard, billing, distributed scheduling and service-level guarantees are outside this engine's scope.
These instructions use the versioned v0.1.3 release documented by the engine repository. They do not claim it is the newest release. Use a reviewed release tag for a reproducible deployment.
Before you start
You need Docker Engine with Docker Compose, a terminal with curl and OpenSSL, and exact public hostnames you control. Reserve a private working directory for the Compose file and .env secrets.
The repository suggests starting with 2 vCPU, 2 GB RAM and the Compose file's 1 GB shared-memory allocation. This is a workload-testing baseline, not a capacity guarantee. Measure representative pages before routing production crawler traffic.
The supported installation uses a versioned Docker image. The repository's Node package is not an npm installation interface for the released engine.
1. Download the release configuration
Run these commands inside the empty working directory chosen for this installation:
curl --fail --location --output docker-compose.yml \
https://github.com/kopachlager/prerenderbuddy-engine/releases/download/v0.1.3/docker-compose.yml
curl --fail --location --output .env.example \
https://github.com/kopachlager/prerenderbuddy-engine/releases/download/v0.1.3/prerenderbuddy.env.example
cp .env.example .env
openssl rand -hex 32Put the generated value in PRERENDER_TOKEN in .env. Replace the example ALLOWED_DOMAINS with the exact hostnames the engine may render. Do not commit .env or include the token in public logs.
For example, to render both an apex and its www hostname, list both in the comma-separated allowlist. Allowing one does not automatically allow the other.
The release Compose file selects ghcr.io/kopachlager/prerenderbuddy-engine:v0.1.3 by default. It binds its HTTP service to loopback, 127.0.0.1:3000, rather than all host interfaces.
2. Start and check the service
docker compose pull
docker compose up -d
docker compose ps
curl --fail http://127.0.0.1:3000/health
curl --fail http://127.0.0.1:3000/ready/health checks the HTTP process and returns build identity. /ready returns HTTP 200 with {"ready":true} when Chromium is connected, or HTTP 503 with {"ready":false} when it is not. Both endpoints are unauthenticated so health-check systems can call them; keep the service behind the intended network boundary.
Do not route crawler traffic until readiness and a representative render both succeed.
3. Render a page on an allowed hostname
After reviewing the .env file you created, load its variables into your local shell:
set -a
. ./.env
set +aThe following request uses a fictional example URL. Replace it with a public page on one of your configured hostnames:
curl --fail-with-body \
-X POST http://127.0.0.1:3000/render \
-H "Authorization: Bearer $PRERENDER_TOKEN" \
-H "Content-Type: application/json" \
--data '{"url":"https://example.com/","ttlSeconds":1800}'The engine returns rendered HTML and preserves the rendered document's HTTP status, including durable 404 and 410 results. Check the status as well as the body. A page returning an error document is different from a successful render of the expected page.
Response headers include X-Prerender-Cache, X-Prerender-Cache-Ttl, X-Prerender-Time, X-Prerender-Final-Url and X-Prerender-Coordination. In this engine version, MISS identifies fresh rendering and HIT identifies cached or coalesced output; COALESCED identifies a request that joined an active render.
4. Connect your request layer
Call the engine from a trusted server, edge worker or crawler-routing layer. Keep the token out of browser JavaScript. Installing the container does not configure your website's crawler routing.
Terminate TLS at the intended reverse proxy or private ingress and forward to the loopback engine port. Preserve document status codes and the X-Prerender-* headers. Apply an appropriate request-rate limit at the proxy.
Follow the repository's integration guide for routing patterns, then test the result on your actual public website. Correctly rendered HTML does not guarantee indexing, ranking, citations or traffic.
Configuration reference
The following values are documented in the v0.1.3 configuration. Keep PORT consistent with your container/proxy wiring; ENGINE_PORT controls the Compose host binding.
| Variable | Documented default | Purpose |
|---|---|---|
PRERENDER_TOKEN | None | Required secret, at least 32 characters. |
ALLOWED_DOMAINS | None | Exact allowed hostnames; required in the default restricted mode. |
ALLOW_ANY_PUBLIC_DOMAIN | false | Deliberate opt-in for arbitrary public destinations; keep restricted unless the broader use is intended and isolated. |
PORT | 3000 | Container HTTP port. |
ENGINE_PORT | 3000 | Compose host port. |
HEADLESS | true | Normal headless Chromium operation. |
RENDER_TIMEOUT_MS | 20000 | Render time bound; permitted 1–120 seconds. |
RENDER_MAX_REDIRECTS | 10 | Redirect bound; permitted 0–20 hops. |
RENDER_MAX_REQUESTS | 250 | Per-render HTTP(S) request budget; permitted 10–2,000. |
RENDER_MAX_CONCURRENCY | 4 | Concurrent-render bound; permitted 1–20. |
RENDER_SINGLE_FLIGHT_WAIT_MS | 30000 | Duplicate-request wait; permitted 1–60 seconds. |
MAX_RENDERED_HTML_BYTES | 5000000 | Output size bound; documented range 100 KB–20 MB. |
CACHE_TTL_SECONDS | 1800 | Default cache lifetime; permitted 1 second–7 days. |
CACHE_MAX_ENTRIES | 500 | Cached-document count bound; permitted 1–10,000. |
CACHE_MAX_BYTES | 100000000 | Cache size bound; documented range 1 MB–1 GB. |
ALLOWED_ORIGINS | Empty | Exact permitted browser CORS origins; normally leave empty for server-to-server use. |
DNS_LOOKUP_TIMEOUT_MS | 2000 | DNS lookup bound; permitted 100 ms–10 seconds. |
The Compose file also reads ENGINE_IMAGE_TAG, defaulting to v0.1.3, to select the image tag. Change it only to a deliberately chosen published release and keep the accompanying configuration compatible.
Security and isolation
Keep the engine private behind the intended TLS/proxy boundary. Restrict outbound access so it cannot reach cloud metadata services, internal control planes, private application networks or databases. Application-level URL validation is not a substitute for network isolation.
Use exact hostname allowlists, keep the token server-side, and keep browser CORS access disabled unless needed. For unrelated tenants, separate containers and tokens provide stronger isolation than a shared engine. Review the repository's security policy before production use.
Operations and cache behavior
Monitor readiness, memory, render latency, failures, active capacity and restarts. GET /internal/metrics requires the token and provides process/cache/capacity information; keep it internal.
Start with concurrency between 2 and 4, then adjust using measured page workloads. Duplicate simultaneous requests for a URL can share one render within the process. Multiple instances have independent caches and no cross-instance render coordination.
The cache disappears on restart. GET /cache/read?url=<encoded-url> reads a cache entry without initiating a render. POST /cache/clear with a URL body removes a single entry. Consult the engine API reference for the complete contract. These local engine routes and credentials differ from the hosted Developer API.
Updates and rollback
- Back up
.envsecurely, record the running image tag and preserve the current Compose file. - Review the intended release notes and its matching configuration files.
- Test the chosen version in staging with representative pages and the intended routing layer.
- Pull and start the selected release. Confirm readiness and inspect a representative render before restoring traffic.
- If verification fails, restore the prior Compose configuration or pinned image tag, restart, and repeat readiness/render checks.
Expect an empty cache after restart. The current engine's memory-only cache has no persistent cache data to migrate.
For a source build, use the matching release checkout and the documented build override:
docker compose -f docker-compose.yml -f docker-compose.build.yml up --build -dThis is the source-build alternative; the release image is the primary installation above.
Troubleshooting
| Symptom | Check | Next action |
|---|---|---|
| Service does not start | docker compose ps and docker compose logs engine | Check configuration, token length, hostname list and container failure details. |
/ready returns 503 | Chromium connection and available memory | Inspect logs and image/browser compatibility before routing traffic. |
| Render returns 401 | Authorization header | Correct the token without exposing it in diagnostic output. |
| Render returns 403 | Hostname, destination and redirect policy | Check exact allowed hostnames and blocked network resolution. |
| Render returns 404 | Response body and endpoint | Distinguish an origin's rendered 404 from an unknown route or cache miss. |
| Render returns 413 | Rendered document size | Investigate page size and the configured HTML bound. |
| Render returns 422 | Per-render request budget | Investigate excessive page requests before changing the budget. |
| Render returns 503 | Readiness, active capacity and coalescing wait | Reduce request pressure or use bounded backoff; 503 has more than one cause. |
| Render returns 504 | Page behavior and render timeout | Diagnose long-running page work; adjust bounds only after measuring. |
The API may return Retry-After for capacity responses. Use bounded exponential backoff with jitter for retryable 503/504 failures. Policy, size and request-budget failures need investigation or a changed request/configuration before retrying.
Ownership and support
Your team owns deployment, integration, security, uptime, capacity, monitoring, updates and incident response. The open-source engine is community-supported; no managed-service allowance or service-level guarantee comes with running the container. Compare this responsibility with the managed service when choosing an operating model.