Cloudprober
Overview
Cloudprober is an open-source active monitoring tool. Instead of waiting for an outage to be reported, it probes your endpoints on a schedule over HTTP, HTTPS, PING, DNS, TCP, gRPC and external commands. It turns the results into availability and latency time series that you can alert on.
This SecureAnyCloud image runs Cloudprober 0.14.3 on Ubuntu 24.04 on Azure, installed from the official upstream release binary (a single self-contained Go binary) and run under systemd as an unprivileged cloudprober user. Cloudprober's built-in web server, which serves the status page and the /metrics endpoint, is bound to the loopback interface only on port 9313. nginx is the only network-facing service: it terminates TLS on port 443 and protects the whole monitoring surface with HTTP basic authentication.
Cloudprober's own HTTP surface has no authentication, so this image never exposes it directly. Nothing secret is baked into the image. On the first boot of every instance, the image generates a unique HTTP basic authentication username and password and a unique self-signed TLS certificate, and writes the credentials to a root-only file. A demonstration probe monitors the instance itself, so metrics flow as soon as the VM boots and you can then point Cloudprober at your own targets.
What you get:
- Cloudprober 0.14.3 from the official upstream release binary, run under systemd (
cloudprober.service) as an unprivilegedcloudproberuser, with the status page and/metricsbound to127.0.0.1:9313 - nginx (
nginx.service) terminating TLS on port 443 as the only network-facing service, protecting the status page and metrics with HTTP basic auth, plus an unauthenticated/healthzfor load balancer probes - A per-instance HTTP basic authentication credential and TLS certificate, generated on first boot, with the per-instance values written to
/root/cloudprober-credentials.txt - A Prometheus metrics endpoint (
/metrics) and a live status page (/and/status), ready to scrape into Prometheus and visualise in Grafana - A demonstration probe,
sac_selfcheck, and the whole configuration in one readable file,/etc/cloudprober.cfg, that you can keep under version control and reload with a single command
Prerequisites
Before you deploy, make sure you have:
- An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region
- A subscription to the Cloudprober listing on Azure Marketplace
- Network security group (NSG) rules that allow TCP 22 (administration) and TCP 443 (HTTPS, for the status page and metrics) from the operators and monitoring systems that will reach the server
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is ample for monitoring a few dozen targets. Choose a larger size for very large numbers of probes or very short probe intervals.
Deploy from the Azure Portal
Search the Azure Marketplace for Cloudprober, select the SecureAnyCloud publisher, and click Create.
Configure the NSG to allow TCP 443 from the operators and monitoring systems that will reach the status page and metrics, and TCP 22 for administration. Restrict port 443 to the networks you serve, because a monitoring appliance rarely needs to be reachable from the whole internet.
Deploy from the Azure CLI
RG="monitoring-prod"; LOCATION="eastus"; VM_NAME="cloudprober1" IMAGE_URN="sac1647283583153:cloudprober-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION"
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:cloudprober-ubuntu-24-04:default:latest
az vm create \
--resource-group "$RG" --name "$VM_NAME" \
--image "$IMAGE_URN" \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values "$SSH_KEY" \
--public-ip-sku Standard
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 443 --priority 1001
az vm open-port --resource-group "$RG" --name "$VM_NAME" --port 22 --priority 1002First boot and per instance credentials
On first boot the image resolves the VM's IP address, generates a per-instance HTTP basic authentication username and password and a per-instance TLS certificate, and writes everything to /root/cloudprober-credentials.txt. This completes within seconds. SSH in as azureuser and read the credentials file:
sudo cat /root/cloudprober-credentials.txtThe file is 0600 root:root. It records the console user and password, the HTTPS URL, and the paths for the status page, metrics and health endpoints. These values are unique to this instance.
Confirm the services are running
Confirm that cloudprober.service and nginx.service are both active and that cloudprober --version reports 0.14.3. Then use ss to confirm that nginx owns port 443 and that the Cloudprober web surface is bound to loopback only on port 9313.
systemctl is-active cloudprober.service nginx.service /opt/cloudprober/cloudprober --version sudo ss -tlnp | grep -E ':443 |:9313 'The monitoring surface is never open
The status page and the metrics endpoint are reachable only through nginx on port 443, and only with the per-instance HTTP basic authentication. An unauthenticated request returns 401, and a request with the per-instance credentials returns 200. Only the /healthz load balancer probe is served without credentials.
The following block reads the credentials from the instance credentials file, so it works unchanged on any instance.
CLOUDPROBER_USER=$(sudo grep -E '^CLOUDPROBER_USER=' /root/cloudprober-credentials.txt | cut -d= -f2-)
CLOUDPROBER_PASSWORD=$(sudo grep -E '^CLOUDPROBER_PASSWORD=' /root/cloudprober-credentials.txt | cut -d= -f2-)
curl -sk -o /dev/null -w 'healthz (no auth) -> HTTP %{http_code}\n' https://127.0.0.1/healthz
curl -sk -o /dev/null -w 'metrics (no auth) -> HTTP %{http_code}\n' https://127.0.0.1/metrics
curl -sk -u "$CLOUDPROBER_USER:$CLOUDPROBER_PASSWORD" -o /dev/null -w 'status (with auth) -> HTTP %{http_code}\n' https://127.0.0.1/statusThe -k flag tells curl to accept the self-signed per-instance certificate. The unauthenticated /metrics request returns 401, and the status page returns 200 only when you supply the per-instance credentials.
View the probe metrics
Cloudprober exports the standard success, total, latency and resp_code series for every probe in Prometheus format on /metrics. The demonstration probe sac_selfcheck monitors this instance's own status endpoint, so metrics are already flowing.
Read the metrics through nginx with the per-instance credentials.
CLOUDPROBER_USER=$(sudo grep -E '^CLOUDPROBER_USER=' /root/cloudprober-credentials.txt | cut -d= -f2-)
CLOUDPROBER_PASSWORD=$(sudo grep -E '^CLOUDPROBER_PASSWORD=' /root/cloudprober-credentials.txt | cut -d= -f2-)
curl -sk -u "$CLOUDPROBER_USER:$CLOUDPROBER_PASSWORD" https://127.0.0.1/metrics | grep -E '^(total|success|latency|resp_code)\{'Each series is labelled by probe type (ptype), probe name (probe) and destination (dst). For the demonstration probe, success equals total and resp_code carries code="200", which confirms that the probe is running and every request has succeeded.
Point your Prometheus scraper at this endpoint to collect the metrics.
The live status page
Cloudprober serves a live status page at / and /status that lists every configured probe with its recent success and latency. nginx serves it over HTTPS with the same per-instance credentials.
Open https://<vm-ip>/status in your browser and accept the self-signed certificate. Alternatively, confirm from the shell that the page is served:
CLOUDPROBER_USER=$(sudo grep -E '^CLOUDPROBER_USER=' /root/cloudprober-credentials.txt | cut -d= -f2-)
CLOUDPROBER_PASSWORD=$(sudo grep -E '^CLOUDPROBER_PASSWORD=' /root/cloudprober-credentials.txt | cut -d= -f2-)
curl -sk -u "$CLOUDPROBER_USER:$CLOUDPROBER_PASSWORD" https://127.0.0.1/status | grep -iE 'cloudprober|probe|selfcheck' | headAdd probes for your own targets
Cloudprober is configured entirely in /etc/cloudprober.cfg. Each probe block sets a type, a set of targets and an interval.
The following example adds an HTTP probe that checks a website you own. The same pattern works for PING, DNS, TCP and GRPC probes. Edit the config, then reload.
# append a probe to /etc/cloudprober.cfg, for example an HTTP check of your own site:
# probe {
# name: "my_website"
# type: HTTP
# targets { host_names: "<your-domain>" }
# http_probe { protocol: HTTPS }
# interval_msec: 15000
# timeout_msec: 5000
# }
# then apply the change (Cloudprober re-reads its config on restart):
sudo systemctl restart cloudproberCloudprober re-reads its config on reload. The new probe appears on the status page, and its success, total and latency series appear on /metrics within one interval. See the Cloudprober documentation for the full set of probe types and options.
Scrape the metrics into Prometheus
To collect the metrics centrally, point a Prometheus server at this instance's authenticated metrics endpoint. Replace <vm-ip> with the instance's address, and use the per-instance credentials from /root/cloudprober-credentials.txt.
# prometheus.yml scrape config scrape_configs: - job_name: cloudprober scheme: https tls_config: insecure_skip_verify: true
# or provide the per instance CA certificate basic_auth: username: <user> password: <password> static_configs: - targets: ['<vm-ip>']For production, replace the self-signed certificate with a CA-signed certificate and a DNS name. Prometheus can then trust the connection without insecure_skip_verify.
Security recommendations
Restrict the NSG. Allow TCP 443 only from the operators and monitoring systems that reach the status page and metrics, and TCP 22 only from your administration network. A monitoring appliance rarely needs to be public.
Protect the console password. It lives in /root/cloudprober-credentials.txt (0600 root:root). The status page and metrics are reachable only through nginx and only with this password. To rotate it, update /etc/nginx/cloudprober.htpasswd with htpasswd and reload nginx.
Keep the web surface on loopback. Cloudprober's built-in server is bound to 127.0.0.1:9313. Leave it that way so that nginx and its basic auth remain the only path to the monitoring data.
Use a real certificate in production. The per-instance certificate is self-signed. Put a CA-signed certificate and a DNS name in front of the instance so that clients and scrapers trust the connection without extra configuration.
Keep the OS patched. Unattended security upgrades remain enabled on the running VM.
Support and Licensing
Cloudprober is open-source software distributed under the Apache License 2.0. This SecureAnyCloud image bundles the unmodified official Cloudprober release binary.
SecureAnyCloud provides the packaging, the systemd hardening, the nginx TLS front, the loopback-only web surface with per-instance basic auth, the per-instance credential automation, the paired deployment guide, and 24/7 support with a guaranteed 24-hour response SLA.
SecureAnyCloud is not affiliated with or endorsed by the Cloudprober project. Cloudprober is a mark of its respective owner and is used here only to identify the software.
Deploy on Azure
Find Cloudprober on Ubuntu 24.04 LTS in the Azure Marketplace, published by SecureAnyCloud. Deploy from the Azure Portal or the Azure CLI as shown above.
Need Help?
Email sales@secureanycloud.com for deployment help, configuration questions or licensing enquiries.
Deploy on Azure
Launch Cloudprober 0.14.3 on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Cloudprober is an open-source active monitoring tool that continuously answers one question: are my services working, and how fast? It probes your endpoints on a schedule over HTTP, HTTPS, PING, DNS, TCP, gRPC and external commands. It turns the results into availability and latency time series that you can alert on.
Cloudprober is built for black-box, prober-style monitoring. You describe the targets and the probes, and Cloudprober measures reachability, success ratio and latency from the vantage point of this instance.
This SecureAnyCloud image installs Cloudprober as a single static Go binary and puts it behind nginx. Cloudprober's own HTTP server has no authentication, so the image never exposes it. The built-in status page and Prometheus metrics endpoint are pinned to 127.0.0.1:9313, and nginx on port 443 is the only network-facing service. nginx terminates TLS and enforces HTTP basic authentication that is generated uniquely on each instance's first boot, so no credential is baked into the image and no two instances share one. A separate unauthenticated health endpoint is available for load balancer probes.
What you get:
- Cloudprober as a single static Go binary (
/opt/cloudprober/cloudprober), installed from the official upstream release and checksum-verified at build time - Textproto configuration at
/etc/cloudprober.cfgwith a Prometheus surfacer enabled cloudprober.servicerunning as the dedicated non-rootcloudproberuser, bound to loopback127.0.0.1:9313nginx.serviceterminating TLS on port 443 and protecting the whole monitoring surface with HTTP basic authenticationcloudprober-firstboot.servicegenerating a unique per-instance basic authentication credential and a per-instance self-signed TLS certificate on first boot- A demonstration probe (
sac_selfcheck) that reports success out of the box, so metrics flow as soon as the instance boots - An unauthenticated
/healthzendpoint for load balancer and liveness probes - An Ubuntu 24.04 LTS base with the latest patches and unattended security upgrades enabled
- 24/7 SecureAnyCloud support
Prerequisites
Before you deploy this image, make sure you have:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group that allows inbound port 22 from your management network and inbound port 443 from the networks you will reach the status page from
- The AWS CLI (version 2) installed locally, if you plan to deploy from the command line
Connecting to your instance
Connect over SSH on port 22 as the default login user for the operating system variant you launched. This listing ships the following variant:
OS variant SSH login user
Ubuntu 24.04 LTS ubuntu
The status page and metrics are served on port 443 through nginx (Cloudprober itself listens only on 127.0.0.1:9313).
Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Cloudprober. Select the SecureAnyCloud listing, choose Select, then choose Continue on the subscription summary.
Pick an instance type of m5.large or larger. Cloudprober is very light, but m5.large is the tested recommendation. Choose your EC2 key pair under Key pair (login).
Under Network settings, select your VPC and subnet, then create or select a security group that allows inbound port 22 from your management network and inbound port 443 from the networks you will reach the status page from. Keep the root volume at the default size or larger.
Select Launch instance. First-boot initialisation takes under a minute after the instance state becomes Running and the status checks pass.
Launch the Instance from the AWS CLI
The following block launches an instance from the SecureAnyCloud Cloudprober Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing and <key-name> with your EC2 key pair name. Replace <subnet-id> with your subnet ID and <security-group-id> with a security group that opens ports 22 and 443 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--metadata-options "HttpTokens=required,HttpEndpoint=enabled" \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=cloudprober}]'On first boot, the image resolves the instance's public address using the EC2 Instance Metadata Service (IMDSv2), so it works with HttpTokens=required enabled. That address becomes the common name and a subject alternative name on the per-instance TLS certificate.
Connect via SSH
Connect as the ubuntu user, as listed in Connecting to your instance above.
ssh ubuntu@<public-ip>When you log in, the message of the day prints the status page URL and the key operational commands.
Retrieve the per instance credentials
First boot generates a unique basic authentication username and password for this instance and writes them, with the resolved status page URL, to a root-only file. Nothing secret ships inside the image, so this file is the only place the credential exists.
sudo cat /root/cloudprober-credentials.txtReal output from a running instance, with the secrets redacted:
# Cloudprober on Ubuntu 24.04 LTS (sac AWS Marketplace image) - this VM.
# Generated per-VM on first boot. Keep this file secret (0600 root:root).
# --- Cloudprober console + metrics (HTTPS, per-VM HTTP basic auth via nginx) --- CLOUDPROBER_USER=sac CLOUDPROBER_PASSWORD=<CLOUDPROBER_PASSWORD> CLOUDPROBER_URL=https://<public-ip>/Confirm the services are running
Cloudprober and nginx start automatically after the first-boot service has generated the per-instance credential and certificate. Confirm that both are active:
systemctl is-active cloudprober nginxBoth report active.
Confirm the monitoring surface is bound to loopback only
This is the most important security property of the image. Cloudprober's own HTTP server has no authentication, so it must never be reachable from the network directly. Confirm that it is bound to 127.0.0.1 and that only nginx listens on the public interface:
ss -ltn | grep -E '9313|:443'Real output from a running instance:
LISTEN 0 511 0.0.0.0:443 0.0.0.0:* LISTEN 0 4096 127.0.0.1:9313 0.0.0.0:* LISTEN 0 511 [::]:443 [::]:*Port 9313 is bound to 127.0.0.1 only. Port 443 is nginx.
Confirm the monitoring surface refuses unauthenticated requests
The status page and the metrics endpoint must reject unauthenticated requests. The following check succeeds when the request is refused:
if curl -sk --fail -o /dev/null -m 10 https://127.0.0.1/metrics; then echo "UNEXPECTED: metrics were served without a credential" exit 1 else echo "refused (exit $?) - correct, the monitoring surface requires the per instance credential" fiThe unauthenticated health endpoint, which exists for load balancers, is served without credentials:
curl -sk -o /dev/null -w 'GET /healthz -> HTTP %{http_code}\n' https://127.0.0.1/healthzNow authenticate with the per-instance credential and confirm that the status page answers. This reads the credential straight from the root-only file, so the password is never typed or echoed:
U=$(sudo grep -E '^CLOUDPROBER_USER=' /root/cloudprober-credentials.txt | cut -d= -f2-)
P=$(sudo grep -E '^CLOUDPROBER_PASSWORD=' /root/cloudprober-credentials.txt | cut -d= -f2-)
curl -sk -u "$U:$P" -o /dev/null -w 'authenticated GET /status -> HTTP %{http_code}\n' https://127.0.0.1/statusOpen the status page in a browser
Browse to https://<public-ip>/ and sign in with the username and password from Step 4. The certificate is self-signed and generated per instance, so your browser warns you once. Accept it, or replace the certificate with your own as described later in this guide.
The status page shows every configured probe, its success ratio over several time windows, and a chart of that ratio over time. Out of the box it shows the bundled sac_selfcheck demonstration probe, which monitors this instance's own status endpoint. This exercises the full probe-to-surfacer-to-metrics pipeline with no external dependency.
Review the running configuration
The /config view renders the configuration that Cloudprober is running, including every probe with its type, interval, timeout and targets, and the configured surfacers.
You can also read the same configuration on the instance:
grep -vE '^\s*#' /etc/cloudprober.cfg | grep -vE '^\s*$'Real output from a running instance:
host: "127.0.0.1" port: 9313 surfacer { type: PROMETHEUS } probe { name: "sac_selfcheck" type: HTTP targets { host_names: "127.0.0.1" } http_probe { port: 9313 relative_url: "/status" } interval_msec: 5000 timeout_msec: 3000 }Scrape the Prometheus metrics
Every probe exports the standard total, success, latency, timeouts and failure series in Prometheus format. Confirm that the demonstration probe is reporting success:
U=$(sudo grep -E '^CLOUDPROBER_USER=' /root/cloudprober-credentials.txt | cut -d= -f2-)
P=$(sudo grep -E '^CLOUDPROBER_PASSWORD=' /root/cloudprober-credentials.txt | cut -d= -f2-)
curl -sk -u "$U:$P" https://127.0.0.1/metrics | grep -E 'probe="sac_selfcheck"'Real output from a running instance:
total{ptype="http",probe="sac_selfcheck",dst="127.0.0.1"} 18 success{ptype="http",probe="sac_selfcheck",dst="127.0.0.1"} 18 latency{ptype="http",probe="sac_selfcheck",dst="127.0.0.1"} 13142.685 timeouts{ptype="http",probe="sac_selfcheck",dst="127.0.0.1"} 0 resp_code{ptype="http",probe="sac_selfcheck",dst="127.0.0.1",code="200"} 18 failure{ptype="http",probe="sac_selfcheck",dst="127.0.0.1"} 0Here success equals total and failure is zero, so every probe attempt has succeeded.
To scrape this instance from an external Prometheus server, point a job at port 443 with scheme: https, tls_config.insecure_skip_verify: true (or trust your own certificate) and a basic_auth block carrying this instance's username and password.
Add probes for your own targets
Cloudprober is configured through a single file. Add a probe block for each target, then apply the change. Cloudprober supports HTTP, PING, DNS, TCP, GRPC and EXTERNAL probe types.
For example, to monitor two public web endpoints every thirty seconds, add:
probe { name: "my_website" type: HTTP targets { host_names: "www.example.com,api.example.com" } http_probe { protocol: HTTPS relative_url: "/" } interval_msec: 30000 timeout_msec: 5000 }Edit the file and apply the change. cloudprober.service defines no reload action, so systemctl reload does not apply here. Use restart instead, which is effectively instant for a single static binary.
sudo nano /etc/cloudprober.cfg
sudo systemctl restart cloudproberConfirm that the service came back up cleanly after the restart:
sudo systemctl restart cloudprober && sleep 3 && systemctl is-active cloudproberEach probe you add appears on the status page. It also exports its own success, total and latency series to /metrics under its probe label, ready to alert on.
Review the probe logs
The /logs view shows Cloudprober's structured log, filterable by source and level. It is the quickest way to confirm that a newly added probe is resolving its targets.
You can read the same log from systemd:
sudo journalctl -u cloudprober --no-pager | tail -5Replacing the TLS certificate
First boot generates a self-signed certificate whose common name and subject alternative names cover this instance's public address, hostname and 127.0.0.1. For production use, replace it with a certificate issued for a DNS name you control. Install your certificate and key over the two files below, keeping the same paths and permissions, then reload nginx.
sudo ls -l /etc/nginx/tls/Place your PEM encoded certificate at /etc/nginx/tls/cloudprober.crt and your private key at /etc/nginx/tls/cloudprober.key (mode 0600, owned by root), then validate and reload:
sudo nginx -tIf the configuration test passes, apply it with sudo systemctl reload nginx.
Changing the basic authentication password
The per-instance credential lives in an nginx htpasswd file. To rotate it, generate a new entry and reload nginx. Replace <password> with your own value.
sudo sh -c 'printf "sac:%s\n" "$(openssl passwd -apr1 "<password>")" > /etc/nginx/cloudprober.htpasswd'
sudo chown root:www-data /etc/nginx/cloudprober.htpasswd
sudo chmod 0640 /etc/nginx/cloudprober.htpasswd
sudo systemctl reload nginxUpdate /root/cloudprober-credentials.txt as well, so that the stored note stays accurate.
Maintenance
Check the installed version:
/opt/cloudprober/cloudprober --versionReal output from a running instance:
v0.14.3Restart or reload the services after a configuration change:
systemctl status cloudprober --no-pager | head -4Unattended upgrades apply operating system security updates automatically. To upgrade Cloudprober itself, download the newer release from the upstream project, verify its checksum, replace /opt/cloudprober/cloudprober and restart the service.
Support
SecureAnyCloud provides 24/7 technical support for this image via email and live chat.
- Email: sales@secureanycloud.com
- Live chat: available 24/7 on secureanycloud.com
We help with deployment, upgrades, probe configuration, TLS termination, scraping the metrics into your existing monitoring stack, and troubleshooting.
Deploy on AWS
Launch Cloudprober on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com