I run a couple of websites for personal use, Nextcloud (an open source Dropbox alternative) and this WordPress site for personal use using a single EC2 instance. As this architecture is susceptible to a host of problems due to a lack of redundancy, I needed a way to keep an eye on site availability and get notified if the websites were unavailable for any reason.
I had a couple of basic requirements:
- The monitoring needed to be run outside the server to rule out any issues with the EC2 instance
- The monitoring needed to check the websites from multiple locations
- The monitoring needed to be free or as close to free as possible
There were a few ways I could solve this:
- Use a managed service like pingdom, but the free tier is usually limited to only 1 url
- install a dedicated monitoring solution
- write a basic custom solution
I only need to check if the websites are up every 5 minutes, so any solution requiring the use of a virtual server or container that runs all the time would be a waste of resources, not to mention expensive. As a result, I chose to use a serverless function that is triggered every 5 minutes using AWS Lambda which gives me solution that is “almost free”, i.e. a few cents a month.
The basic architecture for this serverless monitoring is as follows:
- Check the website using an AWS Lambda function
- If a HTTP 200 or HTTP 304 is returned, the site is up and a metric value of 200 is sent to AWS CloudWatch
- If anything else is returned the site is unavailable and a metric value of < 200 is sent to AWS CloudWatch so an alert can be raised.
Here’s a checklist of things that need to be in place for this to work:
- The python script that will check website availability
- AWS Simple Notification Service Topic
- IAM Role (lambda_basic_execution) with the following permissions for the Lambda Function:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowLogCreation", "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents", "logs:CreateLogGroup" ], "Resource": "arn:aws:logs:*:*:*" }, { "Sid": "AllowMetricAlarmCreation", "Effect": "Allow", "Action": [ "cloudwatch:PutMetricAlarm", "cloudwatch:PutMetricData" ], "Resource": "*" }, ] }