Automating Cloudflare Worker Deployments with CodeShip

Written by: Karl Hughes
6 min read

As web developers, we typically have two options for deploying code: we can push our code to a remote server and run it there, or we can package our code as Javascript and run it in the end-user's web browser. Both options have their tradeoffs, but when I heard about Cloudflare Workers - an innovative edge-based hosting solution - I was really excited to try them out.

Cloudflare is a DNS provider and content delivery network (or CDN). As such, most users set Cloudflare up as a proxy between clients and their web server.

In a typical request, Cloudflare can resolve SSL certificates, handle DNS resolution, redirect routes, and cache long-lived resources sent from the server (eg: images, stylesheets, and Javascript files). All of these actions are performed in Cloudflare's distributed network of 152 data centers around the world, so web browsers will get responses back from the node that is closest to them. This can dramatically improve your site's load time and decrease the number of requests made to your servers.

But what are Cloudflare Workers?

Cloudflare Workers allow you to deploy Javascript code on Cloudflare's distributed network. This means that you may be able to build certain features without ever touching your servers while still getting the performance and security benefits of server-side Javascript. Some good use cases for this are dynamic image processing, managing authentication, or proxying private APIs.

While Cloudflare Workers are currently somewhat limited, as the trend towards serverless continues to grow, I think we'll see more and more services like them with huge potential for speeding up websites and lowering hosting costs.

Building a worker

In this tutorial, we'll see how to build and deploy a simple Cloudflare Worker using Codeship to automatically deploy our code. Before we get started though, it's important to understand some of the limitations of Cloudflare Workers:

  • Workers must run in Chrome's V8 Javascript engine.

  • They have to hook into a Javascript event (usually a fetch request).

  • They cannot be larger than 1MB Workers can only run for up to 15 seconds.

  • They must be compiled into a single Javascript file using Webpack or another build tool.

Even with these limitations, there are several open source examples of workers available. For this tutorial, we'll start from the Cloudlfare Webpack example repository, and end up with a working demo that is automatically deployed via Codeship.

Building the worker locally first, clone or fork this repository. This sample project simply intercepts all requests and shows the current time in the timezone a user specifies using the query string parameter tz. For example, you can see the restults of this worker by going to [https://builds.khughes.me/time-test?tz=America/Chicago][12].

The main logic of the application is handled in ./src/time.js:

import moment from 'moment'
import 'moment-timezone'
export async function handleRequest(request) {
     const time = moment(new Date)
     const url = new URL(request.url)
     let timezone = url.searchParams.get("tz")
     if (!timezone) {
        timezone = "America/Los_Angeles"
     }
     return new Response(time.tz(timezone).format())
} 

The project is already set up to use Webpack to build the Javascript and NPM packages into a single file at ./dist/worker.js, so if you want to build and deploy the woker manually, just run the following:

npm install
npm run build

Then copy ./dist/worker.js to Cloudflare or use their playground to see it in action.

Note: if you're going to use this worker on your own site, be sure to set up route pattern matching to define the routes your worker will run at.

Writing the deploy script Uploading the worker manually is fine for a simple test, but that's going to get annoying if we want to make frequent changes or let other developers update the worker. Fortunately, it's very simple to deploy a worker using Cloudflare's REST API, so let's write a script to handle that.

Create a new file in the scripts/ directory called deploy and add the following:

# !/bin/bash
echo "Deploy Started."
# Make the API call and sets a variable with the HTTP response code
response=$(curl -s -o /dev/null -w "%{http_code}" -X PUT "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/workers/script" -H "X-Auth-Email:$CLOUDFLARE_EMAIL" -H "X-Auth-Key:$CLOUDFLARE_AUTH_KEY" -H "Content-Type:application/javascript" --data-binary "@./dist/worker.js")
# If the response code was 200, the deploy succeeded, otherwise exit with the HTTP response code
if [ 200 -eq $response ]; then echo "Deploy Succeeded." exit 0 else echo "Deploy Failed." exit $response fi;

This bash script uses CURL to upload the build worker.js file to Cloudflare via their API and respond with a success or error in the command line.

Automating deployments

Method 1: CodeShip Basic

If your Cloudflare Worker is really simple and you want to deploy it alone in its own repository, I'd recommend using Codeship Basic. It's really easy to set up and it takes less configuration. After you push your code to Github or Bitbucket:

  1. Create a new project in Codeship Basic. Link it to your Worker's repository.

  2. Add your own setup and test commands.

  3. Add the following three environmental variables to Codeship from your Cloudflare account:

  • a. CLOUDFLARE_EMAIL

  • b. CLOUDFLARE_AUTH_KEY

  • c. CLOUDFLARE_ZONE_ID

  1. Add the following custom script to run when controller is updated:

nvm use 8
npm install
npm run build
bash scripts/deploy

Push to controller and make sure your build passes and the Worker is updated. That's it!

Method 2: CodeShip Pro

While Codeship Basic is the best option for simple projects, you may want to keep your Cloudflare Workers in a shared repository or perform integration tests using other services during your test suite. In that case, Codeship Pro will be your best option. While it takes slightly more configuration to set up, it offers much more flexibility.

  1. Add your project as a new Codeship Pro project and link it to your repository.

  2. Create a Dockerfile in the root directory of your project. This will install your NPM dependencies and build the Worker inside a Docker image:

FROM node:8
WORKDIR /app
COPY . /app RUN npm i --silent
RUN npm run build
  1. Create a .env file, add it to your .gitignore and .dockerignore files, and add the following Cloudflare environmental variables:

CLOUDFLARE_EMAIL=...
CLOUDFLARE_AUTH_KEY=...
CLOUDFLARE_ZONE_ID=...
  1. Encrypt the .env file as .env.encrypted using Jet and your Codeship AES key available in the settings for your application.

  2. Create a codeship-services.yml and codeship-steps.yml file in the root of your project:

# codeship-services.yml
deployer:
  build: .
  encrypted_env_file: .env.encrypted
# codeship-steps.yml
- name: deploy
  tag: pro
  service:deployer
  command:bash scripts/deploy

Commit and push your updates to Github and Codeship will automatically build and deploy the updates to your Cloudflare Worker. If you got lost in any of the steps above, check out the pro branch of this repository to see a working example.

Next steps

While the tutorial above illustrates how you can automatically deploy a Cloudflare Worker using Codeship Basic or Codeship Pro, there are still a few things you probably want to set up for a high quality, production-ready project. For example, I'd suggest creating and deploying a staging Worker and running automated unit tests as part of the continuous integration process. If you have your own tips for running Cloudflare Workers or deploying other serverless hosting solutions using Codeship, let me hear about them on Twitter.

Additional resources

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.