Jul 12, 2026

Hardening a Self-Hosted Ghost Site After Signup Abuse

Hardening a Self-Hosted Ghost Site After Signup Abuse

My self-hosted Ghost site started getting fake signups and automated abuse. Here is the security model I ended up with using Cloudflare, Turnstile, rate limiting, and better observability.

  • Jorge Perez Avatar
    Jorge Perez
    8 min read
  • I self-host Ghost because I like having control of the stack. But also means owning the problems when something goes wrong.

    A while ago, my Ghost site started getting fake newsletter signups. At first, it looked like harmless bot noise. Then I checked the logs and found the more important problem: automated traffic was repeatedly triggering Ghost's membership email flow.

    Fake members are mostly an annoyance.

    Unwanted email is not. It can damage sender reputation, generate complaints, and make legitimate newsletters harder to deliver.

    Ghost has acknowledged signup spam as a real problem, and the community has documented similar waves of fake registrations and membership-email abuse.

    So I stopped treating it as a spam problem and started treating it as an application-security problem.


    The security model

    I am intentionally keeping the implementation high-level.

    The current flow looks roughly like this:

    Visitor
       
    Cloudflare
       ├─ WAF rules
       ├─ bot protection
       ├─ rate limiting
       └─ analytics
       
    Protected signup flow
       ├─ Turnstile
       ├─ server-side validation
       └─ abuse checks
       
    Ghost
       
    Mail provider

    The goal is simple:

    Reject junk before Ghost has to process it.


    1. Put Ghost behind an edge layer

    The biggest structural improvement was putting the site behind Cloudflare.

    That gave me a place to filter obvious junk before it reached the origin:

    • exploit probes
    • abusive automation
    • suspicious membership requests
    • excessive non-static traffic
    • repeat abusive sources

    A CMS should spend its time serving content, not answering random PHP, WordPress, .env, debug, or framework probes.

    Cloudflare's WAF, rate limiting, bot controls, and analytics removed a large amount of useless traffic without requiring changes to Ghost itself.

    Cloudflare Security Overview showing mitigated and clean traffic

    Cloudflare's Security Overview makes it much easier to separate normal traffic from requests being blocked or challenged at the edge.


    2. Protect the action, not just the form

    A signup form is only a user interface. Bots can bypass it and talk directly to the underlying endpoint.

    So adding a challenge to the visible form is not enough.

    I moved the public newsletter signup through a small Cloudflare Worker that:

    • validates the request
    • checks a honeypot
    • verifies a Turnstile token server-side
    • rejects malformed or suspicious requests
    • forwards valid signups to Ghost

    Cloudflare explicitly recommends server-side Turnstile validation.

    The broader lesson matters more:

    If the backend cannot verify that a security check happened, the check did not happen.


    3. Block uncontrolled access to sensitive actions

    Once the protected flow worked, I stopped allowing arbitrary traffic to trigger the same sensitive membership action directly.

    I am deliberately not publishing the exact rules or verification mechanism.

    The principle is enough:

    If an action is supposed to come through a controlled application flow, make the uncontrolled path fail.

    That immediately removed a large amount of low-effort abuse.


    4. Prefer behavioral controls over giant IP blocklists

    IP blocking helps, but it does not scale well.

    Bot traffic rotates through cloud providers, proxies, IPv6 space, and disposable infrastructure.

    I still block repeat offenders when they generate large amounts of obvious junk, but most useful protection comes from behavior:

    • repeated sensitive requests
    • abnormal request rates
    • exploit scanning
    • traffic that does not match the expected application flow

    Cloudflare's rate-limiting guidance specifically recommends protecting account creation, authentication, APIs, and similar abuse-prone operations.

    Patterns are more useful than chasing individual addresses.


    5. Watch the origin, not just the traffic graph

    One useful lesson from this process: a scary Cloudflare graph does not automatically mean the server is under heavy load.

    Blocked requests still appear in analytics.

    So this:

    attacker
       
    Cloudflare
       
    BLOCK

    can still produce a large traffic spike.

    What matters more is what reaches Ghost.

    The metrics I now watch are:

    • total requests
    • mitigated requests
    • requests reaching the origin
    • 5xx errors
    • top paths
    • top source networks
    • cache status
    • signup activity
    Cloudflare Traffic Overview showing requests and cache activity

    Traffic volume alone does not tell you whether the application is in trouble. Origin traffic, errors, cache behavior, and request patterns provide much more useful context.

    A thousand blocked requests are less interesting than fifty suspicious requests reaching the application.

    The goal is not a clean graph. The goal is a quiet origin.


    6. Do not blindly block Ghost APIs

    Several Ghost API paths appear frequently during normal traffic. That does not necessarily make them malicious.

    Ghost uses its APIs for member state, newsletters, tiers, site settings, comments, Portal, Admin, and frontend behavior.

    Blocking anything that looks like /api/ is a fast way to break your own site.

    Before blocking something, look at:

    method
    path
    user agent
    frequency
    country
    ASN
    response
    security action

    Then decide.

    Security rules should be narrow enough that you know exactly why they exist.


    7. Protect the origin too

    A reverse proxy only helps if attackers actually have to go through it.

    Cloudflare recommends protecting the origin so it cannot simply be reached directly.

    For a self-hosted setup, review things like:

    • exposed DNS records
    • direct origin access
    • firewall rules
    • old hostnames pointing to the same server
    • whether Cloudflare Tunnel makes sense

    Cloudflare Tunnel is particularly interesting because it uses outbound-only connections from the server instead of requiring a publicly exposed web origin.


    8. Treat email reputation as part of security

    The attack changed how I think about email infrastructure.

    I now review:

    • bounces
    • complaints
    • suppressions
    • delivery failures
    • authentication records
    • unusual signup-email volume

    The important asset is not the member count.

    It is the reputation of the domain sending the mail, especially when using Ghost's built-in Mailgun integration.


    Ghost has been working on this too

    Ghost published an official Signup spam protection update after publishers started seeing bulk spam registrations.

    Community discussions have also documented fake-member floods and signup-email abuse.

    There is ongoing work around Ghost's request-integrity protections as well. If you self-host Ghost, check your version, changelog, and current security options before building custom workarounds.

    The answer is rarely one magic setting.

    It is defense in depth.


    If your Ghost site is getting fake signups

    This is the order I would investigate it:

    1. Update Ghost.
    2. Check your mail logs.
    3. Put the site behind a reverse proxy or WAF.
    4. Inspect the actual requests.
    5. Protect signup actions server-side.
    6. Add narrow rate limits around sensitive operations.
    7. Block obvious exploit probes.
    8. Protect the origin from direct access.
    9. Watch the results for a few days.
    10. Only then add persistent IP or network blocks.

    Visibility first. Controls second. Tuning last.


    What I deliberately do not publish

    I am not including:

    • complete WAF expressions
    • current IP or network blocklists
    • Worker secrets
    • validation headers
    • bypass conditions
    • internal logging identifiers

    Security writing should explain the model without publishing a map of the defenses.

    Nothing here makes the site "unhackable."

    That is not the goal.

    The goal is to remove cheap abuse paths, reduce unnecessary application work, protect sender reputation, and make suspicious behavior visible.


    Final thought

    Self-hosting is ownership. That is the appeal.

    It also means dealing with the headaches.

    The useful security model is not complicated:

    reduce the attack surface
    reject junk early
    protect expensive actions
    watch the origin
    keep useful logs

    The internet is noisy. A public server will be scanned.

    The important question is not whether bots reach your domain.

    It is what they can make your application do.


    Sources and Further Reading

    You Might Also Like...