WSM is a service for monitoring different aspects of a Windows server and alerting when certain conditions are met.
See Health Check Types for more detail but in a nutshell processes, ports, docker containers and disk space, free memory & http request for now.
I had a server which ran lots of different services, Plex, Game services, VPN, DNS and a bunch of docker containers and something would periodically fail, I wouldn't usually find this out until someone using one of the versions let me know. I wanted a tool that was free, and super easy to set up but couldn't find one that did everything I wanted, also I like coding so figured it was a good candidate for a project, 3 days later WSM was born.
Anyone. I wouldn't suggest running this in a large enterprise environment with system-critical infrastructure even though you technically could and it would be fine. It's designed for use with home labs and maybe small businesses.
WSM is split into two main components, the server and the client(s).
The client is responsible for running all of the configured health checks and reporting their state to the server
The server is responsible for keeping track of all health checks and ensuring they report a good status at regular intervals. If the service detects any issues then alerts can be sent. There are two different types of triggers for alerts
- Missed Check In
- Bad Status Reported
This can occur when the configured health check doesn't report to the server within the defined interval
By default, all health checks should report a state of "Available" to the server, any other state will be considered bad and will trigger alerts.
WSM is designed to run on two separate servers. An example is having a very cheap cloud-based VM that you can run wsm.server
on and the client on your home server.
There are two steps for installing the server
- Create an appsettings.json file
- Running the docker container
Create an appsettings.json file somewhere on your server e.g. /app/appsettings.json
Here is an example appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ReportSlipDuration": "00:00:10",
"AlertFrequency": "00:15:00",
"BackgroundServiceDelay": "00:00:30",
"Servers": [
{
"ApiKey": "YOUR_API_KEY",
"Name": "Home Lab"
}
],
"NotificationTypes": ["Email", "Twilio", "Telnyx"],
"Email": {
"Host": "",
"Username": "",
"Password": "",
"Port": 587,
"From": "",
"To": ""
},
"Twilio": {
"AccountId": "",
"AuthToken": "",
"From": "",
"To": ""
},
"Telnyx": {
"ApiKey": "",
"From": "",
"To": ""
}
Let's break the configuration down
ReportSlipDuration
allows a little bit of wiggle room should the server fail to check-in in time. If you have a health check configured to check-in every 15 seconds,
this would essentially allow it to check in every 25 seconds (the above example has a 10s slip duration). Set this to "00:00:00" if you don't want any slip duration
AlertFrequency
is the frequency that alerts are allowed to be sent out per health check. If a health check is reporting a bad status every 15 seconds, you
don't want a notification every 15 seconds. In the example above, a notification will be sent every 15mins.
BackgroundServiceDelay
is a small delay before the health check monitor actually starts up
Servers
is the list of servers that you expect health check reports from. Each server consists of a Name
and an ApiKey
. You can have multiple servers.
"Servers": [
{
"ApiKey": "YOUR_API_KEY",
"Name": "Home Lab1"
},
{
"ApiKey": "YOUR_API_KEY",
"Name": "Home Lab2"
}
],
The Name
of the server can be anything you one, it's included in alerts so make it something meaningful. The ApiKey
can actually be anything you want too, it's used for
authentication between client and server, use a secure string generator, keep it secret, keep it safe 😜.
"Servers": [
{
"ApiKey": "ba88a0fe-73d2-4815-9265-6d8259541322",
"Name": "Home Lab1"
},
{
"ApiKey": "bf4d22e0-b1fd-48d4-87a2-28060f1b7b0b",
"Name": "Home Lab2"
}
],
NotificationTypes
can be used to configure 0 or more notification types you'd like to send.
Supported values:
- Twilio
- Telnyx
Email
- Send email notifications
Host
the host of the email serverPort
the port of the email serverUsername
the username to authenticate withPassword
the password to authenticate withFrom
the email address the email should come fromTo
the email address the email should be sent to
Twilio
- This can be used to send SMS or WhatsApp messages via Twilio
AccountId
your Twilio Account Id - available within Twilio console https://console.twilio.comAuthToken
your Twilio Auth Token - available within Twilio console https://console.twilio.comFrom
your Twilio phone number that the message should be sent from. For WhatsApp it's in the format ofwhatsapp:+1555555555555
for SMS it'll be+1555555555555
To
is the number the message should be sent to. For WhatsApp it's in the format ofwhatsapp:+1555555555555
for SMS it'll be+1555555555555
Telnyx
- This can be used to send SMS via telnyx
ApiKey
your telnyx api keyFrom
your telnyx phone number that the message should be sent from.To
is the number the message should be sent to.
Running the container
docker run -d -p 80:80 -v /app/appsettings.json:/app/appsettings.json --name wsm.server --restart unless-stopped steveiwonder/wsm.server
There are three steps for installing the client
- Extracting the release zip
- Create an appsettings.json file
- Install the Windows service
Grab the latest copy of the wsm.client.zip and extract it to a location you want to run the Windows Service from
C:\wsm.server\
is where I have it.
Add an appsettings.json
just inside C:\wsm.server\
here is an example of the appsettings.json
{
"App": {
"Server": {
"Url": "https://localhost:7180",
"ApiKey": "YOUR_API_KEY"
},
"HealthChecks": [
{
"Name": "ServerHeartBeat",
"Type": "Heartbeat",
"Interval": "00:00:02"
}
]
}
}
Here is where you'll define everything you want to monitor, let's go through what all the config means.
Everything within the ServiceConfig
section is there for the Windows service, feel free to change this but the default is fine.
Everything within App
section is the app's configuration, and you will need to change it.
Server
- Here you need to configure both the Url
of where the wsm.server
docker image is hosted and the ApiKey
that identifies this client
HealthChecks
- This is everything you want to monitor
Every health check will have at least these values, each health check may have additional configuration.
Name
(Required) - The name of this health check, must be uniqueType
(Required) - The type of health check see Health Check Types for more detailInterval
(Optional) - The frequency at which this health check should run and is defined ashh:mm:ss
. This is optional and defaults to00:00:05
(5s)MissedCheckInLimit
(Optional) - The number of allowed missed check-ins before alerts are triggered, the default is 2.BadStatusLimit
(Optional) -The number of allowed bad status reports before alerts are triggered, the default is 2.
Checks free space on a given disk
{
"Name": "C Disk Space",
"Type": "DiskSpace",
"Interval": "00:05:00"
"DiskName": "C:\\",
"MinimumFreeSpace": 16106127360,
}
DiskName
(Required) - The disk name you want to monitorMinimumFreeSpace
(Required) - The minimum number of free bytes you want to maintain before alerts are sent.
Checks a given docker container to ensure it has a "running" state
{
"Name": "Docker Cloudflare DNS",
"Type": "DockerContainer",
"Interval": "00:01:00"
"ContainerName":"dns",
}
ContainerName
(Required) - The docker container name you want to monitor
A simple ping from client to server, to let the server know it's still online, only one of these can be configured
{
"Name": "ServerHeartBeat",
"Type": "Heartbeat",
"Interval": "00:00:05"
},
Attempts to connect to a given TCP port to see if something is listening
{
"Name": "Web Server",
"Type": "Port",
"Interval": "00:01:00"
"Port": 443,
"Host": "google.com",
}
Port
(Required) - The port number to connect toHost
(Optional) - The host you want to connect to, the default islocalhost
Checks for the existence of the given process
{
"Name": "PostgreSQL",
"Type": "Process",
"Interval": "00:01:00",
"ProcessName": "postgres",
"MinCount": 1,
"MaxCount": 1
}
ProcessName
(Required) - The name of the process to monitor without.exe
MinCount
(Optional) - The minimum number of instances, defaults to 1MaxCount
(Optional) - The maximum number of instances. If not specified, there is no limit
Sends a HTTP request and check for the correct status code, it can also optionally check for the response time and response body
{
"Name": "Google HTTP",
"Type": "Http",
"Interval": "00:00:02",
"Url": "https://google.com",
"Method": "get",
"ExpectedStatusCode": 200,
"MaxResponseDuration": "00:00:02",
"RequestBody": "",
"ExpectedResponseBody": "This response has been delayed for 1 seconds"
}
Url
(Required) - The URL that the request should be made tooMethod
(Optional) - The HTTP method to use, defaults to "Options"ExpectedStatusCode
(Optional) - The expected HTTP status, defaults to 200MaxResponseDuration
(Optional) - The maxiumum duration you would not expect the request to exceed, defaults to 100s HttpClient DefaultRequestBody
(Optional) - The payload that can be sent, make sure you change theMethod
to the appropriate valueExpectedResponseBody
(Optional) - An expected response body to validate upon request completion, if the response body does not match, it'll be considered a bad status report and alerts may be triggered.
Checks the system for free memory
{
"Name": "Free Memory",
"Type": "Free Memory",
"Interval": "00:01:00",
"MinimumFreeMemory": 100000
}
MinimumFreeMemory
(Required) - The minimum number of free bytes you expect the server to have
Run install-service.ps1
inside C:\wsm.client\
, this will install and start the service
And that's it, you're done. If you have a notifier configured, you'll see notifications every time a new health check registers itself with the server.
n.b. If you would like give the service a different name, open and modify both install-service.ps1
and uninstall-service.ps1
, change
"Windows Server Monitor"
to "My New Service Name Goes Here".
HTTPS is essential for the security I highly recommended configuring your docker container (server) with a HTTPS reverse proxy.
If you're unfamiliar with setting up HTTPS, one common approach is to use Nginx as a reverse proxy in front of your application, along with Let's Encrypt to obtain a free SSL certificate. There are plenty of tutorials out there, like this one for example Setup SSL with Docker, NGINX and Lets Encrypt
- Add more health check types
Create your own or raise an issue on github and I'll try to accomodate.
Take a look at WSM.PluginExample to see how you write your own health check. Once you've compiled it, drop it into the clients install directory\HealthChecks alongside WSM.HealthChecks.dll