Skip to content

Commit 52ae8be

Browse files
committed
Refactor README for clarity and comprehensive documentation
1 parent de650c6 commit 52ae8be

File tree

1 file changed

+56
-48
lines changed

1 file changed

+56
-48
lines changed

README.md

Lines changed: 56 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,42 @@
11
# Ghost Cache Invalidation Proxy
22

3-
## Overview
3+
A lightweight proxy that captures Ghost CMS cache invalidation signals (`X-Cache-Invalidate` headers) and forwards them to configurable webhook endpoints.
44

5-
This proxy sits between a Ghost CMS instance and clients. It monitors responses from Ghost for the `X-Cache-Invalidate` header and triggers configured webhooks when cache invalidation is needed.
5+
## Why Use This?
66

7-
When Ghost updates content, it includes an `X-Cache-Invalidate` header in its responses to indicate which content needs cache invalidation. This proxy captures that header and forwards the information to a configurable webhook endpoint, allowing integration with any cache service or CDN.
7+
Ghost provides webhook functionality, but it has limitations:
88

9-
This functionality is based on the cache invalidation mechanism implemented in Ghost as described in [TryGhost/Ghost issue #570](https://github.com/TryGhost/Ghost/issues/570), which established the standard for how Ghost communicates which content needs to be purged from caches.
9+
- Webhooks don't capture all types of content updates (without setting up multiple webhook types)
10+
- The `site.changed` webhook only tells you *that* something changed, not *what* exactly
11+
- Webhooks are stored in the database, creating persistent configuration that follows site migrations
12+
- Managing webhooks across multiple sites becomes a maintenance burden
13+
14+
This proxy solves these issues by monitoring the `X-Cache-Invalidate` header that Ghost sends with all content updates, including theme changes, route modifications, and other site-wide changes.
1015

11-
## Project History
1216

13-
This project evolved from [ghost-bunnycdn-perma-cache-purger](https://github.com/magicpages/ghost-bunnycdn-perma-cache-purger), which was specifically designed to work with BunnyCDN. While the original project served its purpose well, this version has been abstracted to work with any webhook-capable CDN or cache system, making it more versatile for different hosting setups. The core functionality of monitoring Ghost's X-Cache-Invalidate headers remains the same, but the cache purging mechanism has been generalized to support configurable webhooks.
1417

1518
## Usage
19+
The `magicpages/ghost-cache-invalidation-proxy` Docker image is available on
20+
[Docker Hub](https://hub.docker.com/r/magicpages/ghost-cache-invalidation-proxy). It can be used to deploy the proxy as part of a Docker Compose stack alongside Ghost.
1621

17-
The `magicpages/ghost-cache-invalidation-proxy` Docker image is available on [Docker Hub](https://hub.docker.com/r/magicpages/ghost-cache-invalidation-proxy). It can be used to deploy the proxy as part of a Docker Compose stack alongside Ghost.
22+
## How It Works
1823

19-
### Environment Variables
24+
The proxy sits between your Ghost instance and the internet, monitoring traffic for the `X-Cache-Invalidate` header. When it detects this header, it extracts the invalidation patterns and forwards them to your configured webhook endpoints.
2025

21-
#### Required variables
26+
This approach is particularly valuable for:
27+
- Managed hosting providers
28+
- Organizations running multiple Ghost sites
29+
- Anyone wanting precise cache invalidation without webhook management overhead
2230

23-
- `GHOST_URL`: The URL of your Ghost CMS instance. Ideally, the hostname of your Ghost container and the port it listens on (e.g., `http://ghost:2368`).
24-
- `WEBHOOK_URL`: The URL of the webhook endpoint to call when cache invalidation is needed.
31+
## Installation
2532

26-
#### Optional variables
33+
### Using Docker (recommended)
2734

28-
- `PORT`: The port on which the proxy listens for incoming requests. Defaults to `3000`.
29-
- `DEBUG`: Set to `true` to enable debug logging. Defaults to `false`.
30-
- `WEBHOOK_METHOD`: HTTP method to use for the webhook call. Defaults to `POST`.
31-
- `WEBHOOK_SECRET`: Secret key for webhook authentication. Will be used in the Authorization header if provided.
32-
- `WEBHOOK_HEADERS`: JSON string of additional headers to include in the webhook request.
33-
- `WEBHOOK_BODY_TEMPLATE`: JSON template for the webhook request body. Supports the following variables:
34-
- `${urls}`: Array of URLs/patterns from the `X-Cache-Invalidate` header.
35-
- `${purgeAll}`: Boolean indicating if all cache should be purged.
36-
- `${timestamp}`: Current timestamp.
37-
- `${pattern}`: Raw pattern from the `X-Cache-Invalidate` header.
38-
- `WEBHOOK_RETRY_COUNT`: Number of retry attempts for failed webhook calls. Defaults to `3`.
39-
- `WEBHOOK_RETRY_DELAY`: Delay in milliseconds between retry attempts. Defaults to `1000`.
35+
```
36+
docker pull magicpages/ghost-cache-invalidation-proxy:latest
37+
```
4038

41-
### Example Docker Compose Configuration
39+
### Docker Compose Example
4240

4341
```yaml
4442
version: '3.8'
@@ -58,11 +56,10 @@ services:
5856
environment:
5957
- GHOST_URL=http://ghost:2368
6058
- PORT=4000
61-
- DEBUG=true
6259
- WEBHOOK_URL=https://api.example.com/invalidate
6360
- WEBHOOK_METHOD=POST
6461
- WEBHOOK_SECRET=your_secret_key
65-
- WEBHOOK_HEADERS={"Custom-Header": "Value"}
62+
- WEBHOOK_HEADERS={"Custom-Header": "Value", "Authorization": "Bearer ${secret}"}
6663
- WEBHOOK_BODY_TEMPLATE={"urls": ${urls}, "timestamp": "${timestamp}", "purgeAll": ${purgeAll}}
6764
ports:
6865
- "4000:4000"
@@ -73,50 +70,61 @@ volumes:
7370
ghost_data:
7471
```
7572
76-
## Integration Examples
73+
See the [Complete Example](docker-compose.example.yml) for a full setup including MySQL and required reverse proxy configuration.
74+
75+
## Configuration
76+
77+
| Environment Variable | Description | Default |
78+
|---------------------|-------------|---------|
79+
| `GHOST_URL` | URL of your Ghost instance | Required |
80+
| `PORT` | Port to run the proxy on | `4000` |
81+
| `DEBUG` | Enable debug logging | `false` |
82+
| `WEBHOOK_URL` | URL to forward invalidation events to | Required |
83+
| `WEBHOOK_METHOD` | HTTP method for the webhook | `POST` |
84+
| `WEBHOOK_SECRET` | Secret to include in webhook requests | `""` |
85+
| `WEBHOOK_HEADERS` | JSON object of headers to include | `{}` |
86+
| `WEBHOOK_BODY_TEMPLATE` | Template for the webhook body | `{"urls": ${urls}}` |
87+
| `WEBHOOK_RETRY_COUNT` | Number of retry attempts for failed webhook calls | `3` |
88+
| `WEBHOOK_RETRY_DELAY` | Delay between retries in milliseconds | `1000` |
89+
90+
### Template Variables
7791

78-
### BunnyCDN Integration
92+
These variables can be used in both header values and the body template:
7993

80-
To use this with BunnyCDN, set up your webhook configuration like this:
94+
- `${urls}`: Array of URLs to invalidate
95+
- `${timestamp}`: Current timestamp
96+
- `${purgeAll}`: Boolean indicating if all content should be purged
97+
- `${secret}`: The value of `WEBHOOK_SECRET`
98+
99+
## CDN Examples
100+
101+
### Bunny.net
81102

82103
```
83104
WEBHOOK_URL=https://api.bunny.net/purge
84105
WEBHOOK_METHOD=POST
85-
WEBHOOK_SECRET=your_bunnycdn_api_key
106+
WEBHOOK_SECRET=your_bunny_api_key
86107
WEBHOOK_HEADERS={"AccessKey": "${secret}", "Content-Type": "application/json"}
87108
WEBHOOK_BODY_TEMPLATE={"urls": ${urls}}
88109
```
89110
90-
### Cloudflare Integration
91-
92-
For Cloudflare:
111+
### Cloudflare
93112
94113
```
95-
WEBHOOK_URL=https://api.cloudflare.com/client/v4/zones/YOUR_ZONE_ID/purge_cache
114+
WEBHOOK_URL=https://api.cloudflare.com/client/v4/zones/your_zone_id/purge_cache
96115
WEBHOOK_METHOD=POST
97116
WEBHOOK_SECRET=your_cloudflare_api_token
98117
WEBHOOK_HEADERS={"Authorization": "Bearer ${secret}", "Content-Type": "application/json"}
99118
WEBHOOK_BODY_TEMPLATE={"files": ${urls}}
100119
```
101120
102-
**Note**: Cloudflare has limits on how many URLs you can purge in a single API call:
103-
- Free/Pro/Business plans: Maximum of 30 URLs per request
104-
- Enterprise plans: Maximum of 500 URLs per request
105-
106-
If your Ghost updates might generate more URLs than these limits, consider implementing additional logic to batch requests (e.g. building your own webhook endpoint that batches requests).
107-
108-
## How It Works
109121
110-
1. The proxy forwards all client requests to the Ghost CMS instance.
111-
2. When Ghost responds, the proxy checks for the `X-Cache-Invalidate` header.
112-
3. If the header is present, the proxy extracts the invalidation patterns and constructs a webhook payload.
113-
4. The webhook is called with the configured parameters, headers, and body.
114-
5. The proxy supports retries for failed webhook calls.
115122
116123
## License
117124
118125
This project is licensed under the MIT License.
119126
120127
## Contributing
121128
122-
If you have any ideas for improvements or new features, feel free to open an issue or submit a pull request.
129+
If you have any ideas for improvements or new features, feel free to open an
130+
issue or submit a pull request.

0 commit comments

Comments
 (0)