Skip to content

Latest commit

 

History

History
343 lines (214 loc) · 9.99 KB

File metadata and controls

343 lines (214 loc) · 9.99 KB

Cloudflare Deployment Guide

This guide walks through everything needed to deploy ghost-llm to Cloudflare Workers, from account setup through to a live webhook receiving events from Ghost.


Prerequisites

Verify your Node version:

node --version  # should be >= 18

Step 1 — Install dependencies

npm install

This installs Wrangler (Cloudflare's CLI) and the TypeScript types for Workers.


Step 2 — Authenticate Wrangler with Cloudflare

npx wrangler login

This opens a browser window. Log in to your Cloudflare account and grant Wrangler access. You only need to do this once per machine.

To confirm the login worked:

npx wrangler whoami

This prints every account your login has access to along with its ID:

 Account Name: Personal Blog    Account ID: aaa111bbb222...
 Account Name: Work             Account ID: ccc333ddd444...

Step 2a — Pin your account (required if you have multiple accounts)

If wrangler whoami shows more than one account, you must pin the correct one in wrangler.toml. Without this, Wrangler may silently deploy to the wrong account.

Open wrangler.toml and set the account_id field:

account_id = "aaa111bbb222..."  # ← paste your target account ID here

You can also find your account ID in the Cloudflare dashboard URL: dash.cloudflare.com/<account-id>/workers

Note: account_id is not a credential — it's safe to commit to source control.

To verify the correct account is targeted before deploying:

npx wrangler deploy --dry-run

This compiles and reports what would be deployed without uploading anything.


Step 3 — Create the KV namespace

The Worker stores the generated files in Cloudflare KV. You need two namespaces: one for production, one for local development.

# Production namespace
npx wrangler kv namespace create LLMS_KV

# Preview namespace (used by wrangler dev)
npx wrangler kv namespace create LLMS_KV --preview

Each command prints output like this:

✅ Created namespace "ghost-llm-LLMS_KV" with id "abc123def456..."

Copy both IDs and paste them into wrangler.toml:

[[kv_namespaces]]
binding = "LLMS_KV"
id = "abc123def456..."          # ← production ID here
preview_id = "xyz789ghi012..."  # ← preview ID here

If you see "A KV namespace with that title already exists" a previous session already created it. Run npx wrangler kv namespace list to retrieve the existing IDs.


Step 4 — Set your Ghost URL

Open wrangler.toml and update the GHOST_URL variable to your Ghost instance's root URL. No trailing slash.

[vars]
GHOST_URL = "https://your-blog.ghost.io"

For a self-hosted Ghost instance this might look like https://blog.example.com.


Step 5 — Get your Ghost Content API key

  1. In Ghost Admin, go to Settings → Integrations
  2. Click Add custom integration
  3. Give it a name (e.g. LLM Files) and click Create
  4. Copy the Content API Key — you'll need it in Step 7

Step 6 — Deploy the Worker

npm run deploy

Wrangler compiles the TypeScript, bundles the Worker, and uploads it to Cloudflare. On success it prints your Worker's URL:

✅ Deployed ghost-llm to https://ghost-llm.<your-subdomain>.workers.dev

Note this URL — you will need it for the Ghost redirects in Step 9.

If prompted to register a workers.dev subdomain select yes. This is a one-time step per Cloudflare account. All future Workers you deploy use the same subdomain automatically.

Why deploy before setting secrets? Secrets are attached to a named Worker that already exists in Cloudflare. Deploying first creates that Worker. If you try to set secrets before deploying, Wrangler will ask if it should create a blank Worker stub — that works too, but deploying first is the cleaner path.


Step 7 — Set secrets in Cloudflare

Secrets are encrypted values stored by Cloudflare. They are never written to wrangler.toml or checked into source control.

npx wrangler secret put GHOST_CONTENT_API_KEY

Wrangler will prompt you to paste the Content API key from Step 5. Press Enter to confirm.

To verify it's registered:

npx wrangler secret list

Step 8 — Seed the KV store on first deploy

The Worker runs on a cron schedule (every hour by default) but the KV store is empty until the cron fires. Cloudflare does not provide a "Run now" button in the dashboard, so the easiest way to seed immediately is to temporarily set the cron to every minute, wait for it to fire, then restore the original schedule.

8a — Set the cron to every minute

Edit wrangler.toml:

[triggers]
crons = ["* * * * *"]

Then deploy:

npm run deploy

8b — Wait up to 60 seconds

Monitor the Logs tab in the Cloudflare dashboard (Workers & Pages → ghost-llm → Logs) until you see a "Scheduled rebuild complete" entry.

8c — Restore the hourly schedule

Edit wrangler.toml back:

[triggers]
crons = ["0 * * * *"]

Then redeploy:

npm run deploy

Verify both files are live:

curl https://ghost-llm.<your-subdomain>.workers.dev/llms.txt
curl https://ghost-llm.<your-subdomain>.workers.dev/llms-full.txt

Step 10 — Serve from your blog's domain via Ghost redirects

Ghost manages its own CDN and does not allow Cloudflare to proxy traffic on Ghost-hosted domains. The way to expose yourblog.com/llms.txt is with Ghost's built-in redirect system, which issues a 301 redirect to the Worker URL.

Create a redirects.yaml file with the following content, replacing the target URLs with your actual Worker URL:

301:
  /llms.txt: https://ghost-llm.<your-subdomain>.workers.dev/llms.txt
  /llms-full.txt: https://ghost-llm.<your-subdomain>.workers.dev/llms-full.txt

Upload it to Ghost:

  1. In Ghost Admin, go to Settings → Labs
  2. Scroll to Redirects and click Upload redirects file
  3. Select your redirects.yaml file and click Upload

Ghost will immediately start issuing 301 redirects for those two paths.

Verify:

curl -I https://yourblog.com/llms.txt
# Should show: HTTP/2 301 and Location: https://ghost-llm...workers.dev/llms.txt

curl -L https://yourblog.com/llms.txt
# -L follows the redirect and returns the full file content

Note: Most HTTP clients and LLMs follow 301 redirects automatically, so yourblog.com/llms.txt will work transparently as the canonical URL.


Local development

To run the Worker locally against a live Ghost instance:

npm run dev

Wrangler starts a local server at http://localhost:8787. The preview KV namespace is used (separate from production data).

Seed the local KV store by triggering the scheduled handler:

curl "http://localhost:8787/cdn-cgi/handler/scheduled"

Then test the endpoints:

curl http://localhost:8787/llms.txt
curl http://localhost:8787/llms-full.txt

Note: wrangler dev uses the preview KV namespace (preview_id in wrangler.toml), not the production namespace. The Worker still reads from your live Ghost instance — Ghost is the data source in both environments. Only where the generated files are written differs. Any files stored in preview KV are lost when you stop wrangler dev. Production KV data is never touched during local development.


Updating the Worker

After changing src/index.ts, redeploy with:

npm run deploy

Wrangler does a zero-downtime deployment — the previous version continues serving requests until the new version is ready.


Viewing logs

To tail live logs from the deployed Worker:

npx wrangler tail

Each incoming request and any console.error output appears in real time. Useful for debugging webhook failures.


Changing the Worker URL

If you ever rename the Worker or move it to a different account, the workers.dev URL will change. Because the public-facing URLs (blog.big.fan/llms.txt etc.) go through Ghost redirects, the blog domain address stays the same — you only need to update one thing:

  1. Ghost redirects — upload a new redirects.yaml in Ghost Admin → Settings → Labs pointing to the new Worker URL

No DNS changes, no code changes, no KV migration required.

Tip: Use 302 (temporary) redirects in redirects.yaml during initial setup and testing. Switch to 301 (permanent) once the Worker URL is confirmed stable. This avoids browsers and HTTP caches locking in a stale destination.


Rotating secrets

To update a secret (e.g. if you rotate your Ghost API key):

npx wrangler secret put GHOST_CONTENT_API_KEY

Paste the new value when prompted. The change takes effect immediately — no redeployment needed.


Troubleshooting

llms.txt returns 404 The KV store has not been seeded yet. Follow Step 8 to trigger an immediate cron run.

Cron shows errors in the Cloudflare dashboard Go to Workers & Pages → ghost-llm → Logs to see the error message. The most common cause is an incorrect GHOST_URL (check for a trailing slash) or a missing/expired GHOST_CONTENT_API_KEY.

Custom domain routes return 404 Ensure the domain is proxied through Cloudflare (orange cloud in DNS settings, not grey). DNS-only records bypass Workers routing entirely.

wrangler login opens a blank page Try npx wrangler login --no-browser and follow the printed URL manually.

KV reads return stale content KV has eventual consistency. Changes written during a cron run may take up to 60 seconds to propagate globally. The Cache-Control: max-age=3600 header on responses means a CDN edge may cache the file for up to an hour. For immediate freshness during testing, add ?v=$(date +%s) to the URL to bypass the cache.