Cloudflare Workers + Twilio + Mailgun: A DIY Uptime Monitoring Solution
Tags: api, serverless, javascript, programming
Published: 2023-01-07 10:10:37


Uptime monitoring is a crucial aspect of any online business or service. It ensures that your website or application is running smoothly and is available to your users at all times. In case of any downtime, it is essential to be notified immediately so that you can take appropriate measures to fix the issue.

![A Screenshot showing that a website is down](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0dic460l8ndb4wb8l6kt.png)

There are various tools available in the market that can monitor the uptime of your website or application and alert you in case of any downtime. One such tool is [Uptime Robot](https://uptimerobot.com/), which offers a free plan for monitoring up to 50 websites. However, if you want to monitor more websites or need additional features, you have to opt for a paid plan. Also Uptime Robot just sends an Email Notification in the free plan. One cannot get an SMS notification without the upgrade. In such cases, it makes more sense to have a self-hosted uptime monitoring solution that can be easily customized and scaled according to your needs. With Cloudflare Workers and the APIs of messaging and email services such as Twilio and Mailgun, you can build your own uptime monitoring solution that can send SMS and email notifications whenever your website goes down. This not only saves you money, but also gives you the flexibility to customize the notification channels as needed.

In this tutorial, we will see how to build your own uptime monitoring solution using Cloudflare Workers, Twilio and Mailgun.

## <u>TLDR</u>

- Cloudflare Workers is a serverless platform that allows you to run your code on Cloudflare's edge network.
- Twilio is a communication platform that enables you to send and receive SMS and voice calls.
- Mailgun is an email automation service that allows you to send, receive, and track emails.
- Telegram is a cloud-based instant messaging app that focuses on speed and security.

We will use these four platforms and their API's to build a simple uptime monitoring solution.

## Prerequisites:
### Setting up Cloudflare Worker

To get started with Cloudflare Workers, you need to sign up for a [Cloudflare account](https://dash.cloudflare.com/sign-up). Once you have signed up, follow the steps given below:

 - Navigate to the [Cloudflare Workers](https://workers.cloudflare.com/) and login to your account. From the dashboard, click on the **Create a Service** button.
 - Enter a name for your worker and click on the **Create Service** button. For this tutorial, I am following the **Service Worker Syntax**, you can select **Module Syntax**, if you are good with Javascript ES6.
 - This will open the Cloudflare Workers editor, where you can write and test your code.

### Setting up Twilio (For SMS Notifications)
To set up Twilio, you need to sign up for a [Twilio](https://www.twilio.com/) account. Once you have signed up, follow the steps given below:

 - If you are creating an account for the first time you can use Twilio's free credits to get a Free Trial Number.
 - Navigate to the **Phone Numbers** section of the Twilio Console and click on the **Buy a Number** button.
 - Select a phone number and click on the **Buy** button.
 - After purchasing the phone number, you will be redirected to the phone number's configuration page. Here, you can find your **Account SID** and **Auth Token**, which you will need to use Twilio's API.

### Setting up Mailgun (For Email Notifications)
To set up Mailgun, you need to sign up for a [Mailgun](https://www.mailgun.com/) account. Once you have signed up, follow the steps given below:

 - Go to the Mailgun dashboard and log in to your account.
 - You can get a free Mailgun Domain, and add authorized emails in your account that you can send to.
 - Click on the **Sending** menu in the top menu and then click on **Domains**.
 - Click on the **Add New Domain** button.
 - Follow the prompts to add a new domain. Make note of the **API Key** on the dashboard, as you will need it later.

### Setting up Telegram (Completely Optional)

You can skip this, if you don't need Telegram notifications. But incase if you do, checkout my [other post](https://dev.to/dhanushreddy29/host-a-serverless-stable-diffusion-image-search-bot-on-vercel-2552), where I setup a Telegram Bot.

## Writing the Code
Now that we have all of the necessary accounts and API keys set up, we can start writing the code for our uptime monitoring solution. We shall define the following functions:

 - **checkWebsiteStatus**: This function will perform an __HTTP HEAD__ request to the specified website URL and return a boolean value indicating whether the website is up or down.
 - **handleRequest**: This is the main function that will be executed when the worker is invoked. It will call the `checkWebsiteStatus` function and, in case of any downtime, calls the `sendTwilioMessage`, `sendEmail` functions to send the notifications.
 - **sendTwilioMessage**: This function will use Twilio's API to send an SMS to the specified phone number.
 - **sendEmail**: This function will use Mailgun's API to send an email notification.
 - **sendTelegramMessage**: This function will use Telegram's Bot API to send the notification via Telegram.

The code of the above functions are very minimal and simple to implement. You just need time and patience in referring to the Documentations of the respective API services. Having strong documentation reading skills is important for any developer today as it allows them to efficiently learn about new technologies and understand how to use them effectively. Being able to effectively read and comprehend the docs, helps us in utilizing the various API services. You don't need to understand how the API's of Twilio/Mailgun/Telegram work. You just need to know how to use them and implement it as per your requirements.

### Docs/Resources:
 - [Cloudflare Workers](https://developers.cloudflare.com/workers/)
 - [Twilio](https://www.twilio.com/docs/sms)
 - [Mailgun](https://documentation.mailgun.com/en/latest/index.html)
 - [Telegram](https://core.telegram.org/bots/api)

I hope you have given a glimpse into the above docs. Even if you haven't, just go through the below code very slowly and understand how it works. Everything here is just based on simple `if else` logic. I have just modified most of the code from their documentation for our needs here.

```javascript
addEventListener('scheduled', event => {
	event.waitUntil(
		handleRequest()
	)
})

async function checkWebsiteStatus(website_url) {
    try {
        const response = await fetch(website_url, {
            method: "HEAD"
        });
        return response.ok;
    } catch (error) {
        return false;
    }
}

async function sendTwilioMessage(textToSend) {
    try {
        const response = await fetch(`https://api.twilio.com/2010-04-01/Accounts/${twilioAccountSid}/Messages.json`, {
            method: 'POST',
            headers: {
                'Authorization': `Basic ${btoa(`${twilioAccountSid}:${twilioAuthToken}`)}`
            },
            body: new URLSearchParams({
                Body: textToSend,
                From: fromNum,
                To: toNum
            })
        });
        return response.ok;
    } catch (error) {
        return false;
    }
}

async function sendEmail(textToSend) {
    try {
        const response = await fetch(`https://api.mailgun.net/v3/${mailGunDomain}/messages`, {
            method: "POST",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
                "Authorization": `Basic ${btoa(`api:${mailGunAPIKEY}`)}`
            },
            body: new URLSearchParams({
                from: mailGunFromAddress,
                to: mailGunToAddress,
                subject: "Your Website is Offline",
                text: textToSend
            })
        });
        return response.ok;
    } catch (error) {
        return false;
    }
}

async function sendTelegramMessage(textToSend) {
    try {
        const response = await fetch(`https://api.telegram.org/bot${botToken}/sendMessage?chat_id=${telegramChatID}&text=${textToSend}`);
        return response.ok;
    } catch (error) {
        return false;
    }
}

const handleRequest = async () => {
    const isWebsiteUp = await checkWebsiteStatus(websiteURL);
    if (!isWebsiteUp) {
        messageToSend = `Dear ${name}, your website ${websiteURL} is down. Please check`;
        await sendTwilioMessage(messageToSend);
        await sendEmail(messageToSend);
        await sendTelegramMessage(messageToSend);  // Optional
    }
}
```
There is an `scheduled` event listener in the above code. It allows the worker to respond to Cron Triggers.

## Setting up the Environment Variables:

In Cloudflare Workers, you can access environment variables directly using their names, just like you would access normal variables in JavaScript. Under the hood, the Workers runtime uses V8 engine, there is no need to use `process.env` to access them as it is not based on Node.js.

For example, if you have an environment variable named `API_KEY` setup in Cloudflare settings, you can access its value in your Cloudflare Worker code like this:
```javascript
const key = API_KEY;
```

In the code which I have written above, there are several Environment Variables:

![Environment Variables](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rglpfp5cicnh86d4yt7k.png)

 - **websiteURL**: The URL of the website which we are monitoring.
 - **twilioAccountSid**: Twilio Account SID from Twilio's dashboard
 - **twilioAuthToken**: Twilio Account Auth Token from Twilio's dashboard
 - **fromNum**: Your Twilio Mobile Number
 - **toNum**: Your Mobile number where you wish to receive notifications to (including country code)
 - **name**: Your name (used in Notification message)
 - **mailGunAPIKEY**: Your Mailgun API Key
 - **mailGunDomain**: Your Mailgun Domain Address
 - **mailGunFromAddress**: Just add any Prefix to your Mailgun Domain Address. (Suppose if your mailgun domain is `example.com`, you can keep it as `mailgun@example.com`)
 - **mailGunToAddress**: The email address where you intend to receive the notifications.
 - **botToken**: Telegram API Bot Token from Bot Father
 - **telegramChatID**: The chatID of the Telegram User where you want to receive notifications to.

Now enter your own values for the above environment variables in Cloudflare settings.

## Setting up the CRON job
 - In the Cloudflare Workers dashboard, click on **Triggers** and then **CRON Triggers**.
 - Set up a CRON job to trigger your worker function every 5 minutes (or any other desired interval as per your needs).

When the CRON job runs, it will call the `checkWebsiteStatus` function to check the status of the website. If the website is down, it will call the `sendTwilioMessage` function to send an SMS to the specified phone number, and the `sendEmail` function to send an email to a specified address. We can also call the `sendTelegramMessage` function to send a message to a specified Telegram chat. This way, we can be alerted whenever the website goes down, and take necessary action to fix the issue.

That's it! Your DIY uptime monitoring solution is now set up and ready to use. Every time your website goes down, you will receive SMS, email and Telegram notifications. You can also add additional functionality, such as sending a notification to a Slack group or integrating with other APIs. That is the homework I am giving you to implement it by referring to their docs 🙂.

I hope this tutorial was helpful in showing you how to build your own uptime monitoring solution using Cloudflare Workers and third-party APIs. Let me know if you have any questions or suggestions for improvement.

In case if you still have any questions regarding this post or want to discuss something with me feel free to connect on [LinkedIn](https://www.linkedin.com/in/dhanushreddy29/) or [Twitter](https://twitter.com/dhanushreddy291).


> If you run an organization and want me to write for you, please connect with me on my Socials 🙃