Simple, free-tier heartbeat service for server uptime monitoring with AWS Lambda, DynamoDB, API Gateway, Cloudwatch and a Telegram bot
This script is useful when:
- you don't want to monitor any metrics on your server but just want to be notified when there's a power cut or internet interruption
- you don't have a public IP on the internet and cannot, for example, use uptimerobot.com. This is common on mobile networks
- you don't want to spend any $$$
- you want something lightweight and do not want to install any custom agent or bloat-ware on your server
The principle is simple: your server sends HTTP requests to a fixed URL at regular intervals. AWS Cloudwatch triggers a check at 1 minute intervals and if the last heartbeat didn't happen within a configured time window, a notification is sent to the configured Telegram chat.
aws-cli
python3-pip
- Create a Telegram bot and note down the bot token
- Create a Telegram group chat and fetch the group chat ID
- Rename
config.py.example
toconfig.py
and adjust the values. In particular, make sure you set thenotification_recipient_id
to your Telegram group chat ID andnotification_authorization_info
to your Telegram bot token - Run
setup.sh
to download required dependencies into thelibs
folder:
$ ./scripts/setup.sh
- Run
aws configure
and set yourAWS Access Key ID
,AWS Secret Access Key
and your region. - Create an AWS Lambda function named
my-heartbeat-service
- Run:
deploy.sh
to deploy the Lambda function code:
$ ./scripts/deploy.sh my-heartbeat-service
- Add an API Gateway trigger for the Lambda function.
Click to expand
- Create a
REST API
calledmy-heartbeat-service-API
- Note down the API URL and API Key
- Click on
Actions
->Create Resource
, checkConfigure as proxy resource
. The tree should look like this:/my-heartbeat-service/{proxy+}/ANY
- Enable the API key for added security
- Deploy the API:
Actions
->Deploy API
.
-
Create an AWS DynamoDB table named
heartbeats
with anint
PRIMARY KEY namedid
-
On AWS IAM, give your lambda function
my-heartbeat-service
read-write access to the DynamoDB tableheartbeats
. Below is a sample policy you can attach to your Lambda function role:
Click to expand
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadWriteTable",
"Effect": "Allow",
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:GetItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:BatchWriteItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem"
],
"Resource": "arn:aws:dynamodb:*:*:table/heartbeats"
},
{
"Sid": "GetStreamRecords",
"Effect": "Allow",
"Action": "dynamodb:GetRecords",
"Resource": "arn:aws:dynamodb:*:*:table/heartbeats/stream/* "
},
{
"Sid": "WriteLogStreamsAndGroups",
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Sid": "CreateLogGroup",
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "*"
}
]
}
- On the server to be monitored, create a script called
heartbeat.sh
(replace your API gateway URL/API key below):
while true; do
curl -v -X POST "https://<id>.execute-api.<region>.amazonaws.com/default/my-heartbeat-service/set" -H "X-API-Key: <API key>"
sleep 30
done
- Test the script by running it and verifying if you're getting a
200
status code. You can also open theheartbeats
table on AWS DynamoDB and verify if the heartbeats are being updated. - If everything is working fine, you can launch it in a screen/tmux session and also add it on startup:
screen -dmS heartbeat bash /path/to/heartbeat.sh
- On AWS Cloudwatch, go to
Events
->Rules
->Create Rule
. SelectSchedule
and a fixed rate of1 minute
. Select your Lambda function asTarget
and configure its input with the followingConstant(JSON Text)
:
{"httpMethod": "GET","pathParameters": {"proxy": "check"}}
- That's it you're finally done!