Self-hosted on Cloudflare Workers. Your data stays in your own account, served from your own domain.
Built on serverless infrastructure — zero servers to maintain, no subscription fees.
Your emails and feeds live exclusively in your own Cloudflare account. No shared infrastructure, no data mining.
Cloudflare Workers, KV, and Email Routing all fall within the generous free tier. Deploy at zero cost.
Subscribe to newsletters using addresses on your own domain (e.g. apple@yourdomain.com). No lock-in.
Use Cloudflare Email Routing (no third-party) or ForwardEmail webhooks — whichever fits your setup.
Email attachments are stored in Cloudflare R2 and exposed as RSS enclosures — no extra hosting needed.
Optionally delegate admin authentication to Authelia, Authentik, or any reverse proxy that sets Remote-User.
From email delivery to your RSS reader in milliseconds, with no moving parts.
Create a feed in the admin UI and get a unique address like newsletter.42@yourdomain.com. Subscribe to any newsletter with it.
When a newsletter arrives, Cloudflare routes it to your Worker. It parses the content and stores it in KV — attachments go to R2.
Your feed is live at /rss/:feedId. Add it to any RSS client and never miss an issue.
A single setup script handles KV namespaces, secrets, and wrangler.toml generation.
# 1. Clone the repo $ git clone https://github.com/juherr/kill-the-news.git && cd kill-the-news # 2. Log in to Cloudflare $ npx wrangler login # 3. Run the interactive setup (creates KV, sets secrets, writes wrangler.toml) $ bash setup.sh # 4. Deploy to the edge $ npm run deploy
Then choose how emails reach your Worker:
Everything you need to self-host kill-the-news on your own Cloudflare account, step by step.
You need a free Cloudflare account with a domain managed by Cloudflare DNS, and Node.js ≥ 18.
Clone the repo and log in to Cloudflare via Wrangler. This opens a browser window to authorize the CLI.
$ git clone https://github.com/juherr/kill-the-news.git $ cd kill-the-news $ npm install $ npx wrangler login
The interactive setup script creates the KV namespace, sets the admin password secret, and writes wrangler.toml for you.
$ bash setup.sh # The script will ask for: # - Your domain (e.g. newsletters.example.com) # - An admin password (stored as a Wrangler secret) # - Whether to enable R2 for attachments (optional)
This generates wrangler.toml from the example template. Do not commit it — it is gitignored.
$ npm run deploy # Wrangler compiles the Worker, uploads it to Cloudflare, # and prints the Worker URL. Your admin UI will be live at: # https://<your-domain>/admin
Choose how incoming emails reach your Worker:
In the Cloudflare dashboard, go to Email → Email Routing and enable it on your domain. Add a catch-all rule with action Send to Worker pointing to your deployed Worker. No third-party service required.
Point ForwardEmail MX records at your domain. ForwardEmail parses incoming mail and POSTs a JSON payload to /api/inbound. Useful if you already use ForwardEmail.
To store email attachments and expose them as RSS enclosures, create an R2 bucket and bind it in wrangler.toml:
[[r2_buckets]] binding = "ATTACHMENT_BUCKET" bucket_name = "kill-the-news-attachments"
Attachments will be served at /files/:id/:filename and linked as <enclosure> elements in the RSS feed.
Protect your endpoints against abuse using Cloudflare WAF custom rate-limiting rules — no code changes required, pure infrastructure.
Go to Security → Security rules, click Create rule, choose Rate limiting rule, and create one rule per endpoint below.
⚠️ Free tier limitations: only 1 rate limiting rule allowed; period and block duration capped at 10 seconds. Prioritise the /api/inbound rule — it's the public-facing attack surface. Upgrade to a paid plan for full coverage.
Use cloudflare_ruleset with phase = "http_ratelimit" — see the snippet below.
Recommended limits:
| Endpoint | Condition (URI Path) | Limit (recommended) | Limit (free tier) | Action (recommended) | Action (free tier) |
|---|---|---|---|---|---|
/api/inbound |
wildcard /api/inbound/* |
60 req / min / IP | 10 req / 10 s / IP | Block (1 min) | Block (10 s) |
/admin* |
wildcard /admin/* |
20 req / min / IP | 20 req / 10 s / IP | Managed Challenge (5 min) | Managed Challenge (10 s) |
Terraform equivalent (supports method filtering and longer periods — requires a paid Cloudflare plan):
resource "cloudflare_ruleset" "rate_limiting" { zone_id = var.cloudflare_zone_id name = "kill-the-news rate limiting" kind = "zone" phase = "http_ratelimit" rules { description = "Rate limit /api/inbound" expression = "(http.request.uri.path eq \"/api/inbound\" and http.request.method eq \"POST\")" action = "block" ratelimit { characteristics = ["ip.src"] period = 60 requests_per_period = 60 mitigation_timeout = 60 } } rules { description = "Rate limit /admin" expression = "starts_with(http.request.uri.path, \"/admin\")" action = "managed_challenge" ratelimit { characteristics = ["ip.src"] period = 60 requests_per_period = 20 mitigation_timeout = 300 } } }
These rules run at the Cloudflare edge before the Worker is invoked — zero latency impact on normal traffic.
If ForwardEmail's delivery IPs ever trigger the /api/inbound limit, add them as an IP Access Rule with action Allow under Security → WAF → Tools.
Minimal dependencies, maximum portability — runs entirely on Cloudflare's global network.
kill-the-news is free and open source. If it saves you time, consider supporting its development.
Sponsor on GitHub