├── .gitignore ├── LICENSE.md ├── README.md ├── index.js ├── manifest.yml └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | .idea -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2020, Chris Muktar 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # netlify-purge-cloudflare-on-deploy 2 | Automatically purge Cloudflare cache on Netlify deploy. 3 | 4 | ## NOTES: 5 | * Cloudflare supports two methods of authentication. API TOKEN (Recommended) and API KEY (Legacy). 6 | * In the event the plugin finds both API Token and API Key environment variables, it will default to using API Token as this is the recommended method of authentication. 7 | 8 | ## API TOKEN Authentication (Recommended, granular security controls) 9 | From Cloudflare, you'll need: 10 | * Your Zone ID. Go to your Cloudflare dashboard, enter your website, and look in the bottom right hand corner under 'API'. 11 | * An API Token 12 | 13 | #### API TOKEN - Instructions for creating new Cloudflare API Token 14 | 1. In Cloudflare, navigate to My Profile --> API Tokens 15 | 2. Click Create Token Button 16 | 3. Click Custom Token Section --> Create Custom Token --> Get Started Button 17 | 4. On the Create Custom Token Page: 18 | * Token Name --> Netlify Purge Cache Token (or anything other name that is meaningful to you) 19 | * Permissions --> Zone --> Cache Purge --> Purge 20 | * Click Continue to Summary button 21 | 5. Click Create Token Button 22 | 6. Record the API Token to your password safe of choice. This is the last time you will have an opportunity to see this token. 23 | 24 | #### API TOKEN - Instructions for configuring Netlify 25 | In Netlify, go to Settings -> Build & Deploy -> Environment -> Environment variables and set up: 26 | * CLOUDFLARE_ZONE_ID 27 | * CLOUDFLARE_API_TOKEN 28 | 29 | ## API KEY Authentication (Legacy, full account access) 30 | It is recommended you use API Token authentication instead. Please see above for instructions. From Cloudflare, you'll need: 31 | * Your Cloudflare email address. 32 | * Your Zone ID. Go to your Cloudflare dashboard, enter your website, and look in the bottom right hand corner under 'API'. 33 | * Your Cloudflare API key. 34 | 35 | #### API KEY - Instructions for finding your Cloudflare API Key 36 | 1. In Cloudflare, navigate to My Profile --> API Tokens 37 | 2. Below the API Tokens section, you will see the API Keys section 38 | 3. Click the View button to the right of Global API Key 39 | 4. Authenticate again using your CLoudflare account password and hCaptcha 40 | 5. Your API Key is revealed. No need to record this as you can access it anytime again in the future. 41 | 42 | 43 | #### API KEY - Instructions for configuring Netlify 44 | In Netlify, go to Settings -> Build & Deploy -> Environment -> Environment variables and set up: 45 | * CLOUDFLARE_ZONE_ID 46 | * CLOUDFLARE_API_KEY 47 | * CLOUDFLARE_EMAIL 48 | 49 | 50 | 51 | ## Build failure with 'Bad request' 52 | Check you set up your environment variables properly. 53 | 54 | ## netlify.toml template 55 | 56 | [[plugins]] 57 | package = "./plugins/netlify-purge-cloudflare-on-deploy" 58 | 59 | ## netlify.toml template if you receive an error. 60 | 61 | [[plugins]] 62 | package = "netlify-purge-cloudflare-on-deploy" 63 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | const { 4 | env: { CLOUDFLARE_API_TOKEN, CLOUDFLARE_API_KEY, CLOUDFLARE_ZONE_ID, CLOUDFLARE_EMAIL }, 5 | } = require('process'); 6 | 7 | let authMethod = 'na'; 8 | switch( true ) { 9 | case typeof CLOUDFLARE_API_TOKEN !== 'undefined' && typeof CLOUDFLARE_ZONE_ID !== 'undefined': 10 | authMethod = 'TOKEN'; 11 | break; 12 | 13 | case typeof CLOUDFLARE_API_KEY !== 'undefined' && typeof CLOUDFLARE_ZONE_ID !== 'undefined' && typeof CLOUDFLARE_EMAIL !== 'undefined': 14 | authMethod = 'KEY'; 15 | break; 16 | } 17 | 18 | module.exports = { 19 | onPostBuild({ 20 | utils: { 21 | build: { failBuild }, 22 | }, 23 | }) { 24 | if( authMethod === 'na' ) { 25 | return failBuild( 26 | 'Could not determine auth method. Please review the plugin README file and verify your environment variables' 27 | ); 28 | } 29 | else if( authMethod !== 'TOKEN' && authMethod !== 'KEY' ) { 30 | return failBuild( 31 | "'" + authMethod + "' is not a valid Authentication Method. Please report this issue to the developer." 32 | ); 33 | } 34 | else { 35 | console.log('Cloudflare ' + authMethod + ' Authentication method detected.'); 36 | } 37 | }, 38 | async onSuccess({ 39 | utils: { 40 | build: { failPlugin }, 41 | }, 42 | }) { 43 | console.log('Preparing to trigger Cloudflare cache purge'); 44 | let baseUrl = `https://api.cloudflare.com/client/v4/zones/${CLOUDFLARE_ZONE_ID}/purge_cache`; 45 | let headers; 46 | switch( authMethod ) { 47 | case 'TOKEN': 48 | headers = { 49 | 'Authorization': 'Bearer ' + CLOUDFLARE_API_TOKEN, 50 | 'Content-Type': 'application/json' 51 | }; 52 | break; 53 | 54 | case 'KEY': 55 | headers = { 56 | 'X-Auth-Email': CLOUDFLARE_EMAIL, 57 | 'X-Auth-Key': CLOUDFLARE_API_KEY, 58 | 'Content-Type': 'application/json' 59 | }; 60 | break; 61 | } 62 | let body = { purge_everything: true }; 63 | 64 | try { 65 | const { status, statusText } = await fetch(baseUrl, { 66 | method: 'POST', 67 | headers: headers, 68 | body: JSON.stringify(body), 69 | }); 70 | 71 | if (status != 200) { 72 | return failPlugin( 73 | "Cloudflare cache couldn't be purged. Status: " + status + " " + statusText 74 | ); 75 | } 76 | console.log('Cloudflare cache purged successfully!'); 77 | } catch (error) { 78 | return failPlugin('Cloudflare cache purge failed', { error }); 79 | } 80 | }, 81 | }; 82 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | name: netlify-purge-cloudflare-cache-on-deploy 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "netlify-purge-cloudflare-on-deploy", 3 | "version": "1.2.0", 4 | "description": "Automatically purge Cloudflare cache on Netlify deploy.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/chrism2671/netlify-purge-cloudflare-on-deploy.git" 12 | }, 13 | "keywords": [ 14 | "cloudflare", 15 | "netlify", 16 | "cache", 17 | "purge", 18 | "netlify-plugin" 19 | ], 20 | "author": "Chris Muktar (https://www.wikijob.co.uk)", 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/chrism2671/netlify-purge-cloudflare-on-deploy/issues" 24 | }, 25 | "homepage": "https://github.com/chrism2671/netlify-purge-cloudflare-on-deploy#readme", 26 | "dependencies": { 27 | "node-fetch": "^2.6.0" 28 | } 29 | } 30 | --------------------------------------------------------------------------------