Server Health Check in 30 Seconds
Run one command. Watch your CPU, memory, disk, and risks appear live on this page. No signup, nothing installed.
Never run a script you don’t trust
So we show you the code first. Read it, then run it — or change anything you don’t like.
How It Works
- Run one command — no install
- Your server connects — appears live below
- See real metrics — for 15 minutes
- Decide — walk away or keep it
What You Might Find
- β οΈ SSH wide open to the internet — a bot magnet
- πΎ Disk past 90% — an outage waiting to happen
- β‘ CPU or memory spikes — something’s off
- π An SSL certificate about to expire
- π§© Outdated packages — a security risk
Read the Script First
It’s longer than you’d guess — because we explain every line. The grey lines are our notes; read them. See the full line-by-line breakdown with links to the knowledge base.
#!/bin/bash
################################################################################
# CleverUptime #
# Monitoring Script v2.5 #
# 2026-06-11 #
# #
# https://cleveruptime.com #
# #
# This script collects data from your server so you can monitor it in #
# CleverUptime. #
# #
# WARNING: NEVER RUN A SCRIPT YOU DON'T UNDERSTAND. #
# That's why we explain EVERY LINE below β even if you're new to Linux. #
# #
# You can: #
# - Read every command and learn what it does #
# - Comment out lines you don't want to send #
# - Modify values (like server name) #
# - Learn how real server monitoring works #
# #
# Nothing is sent without your permission. #
# No hidden code. No surprises. #
# #
# Want to learn more about this script? #
# Visit: https://cleveruptime.com/the-script #
# We'll explain every single line of code with links to documentation. #
################################################################################
################################################################################
# STEP 1: CONFIGURATION #
# #
# These values control how your server appears in CleverUptime. #
# You can change them β or leave them as they are. #
# #
# IMPORTANT: UPLOAD_KEY is like a password. Keep it secret! #
################################################################################
# This is your private key. It tells CleverUptime: "This data is from me."
# It's like a password for your server. Never share it.
UPLOAD_KEY="b308b48ea43666a31d41bb25b3b0b0e1318d40ffbcae7d0d3c97631fdb2528597087169822417020d41ab3b225d43a53d2cc2a4b03601d58b4fd802df30f1cc5e627b665b7cf2b317f65054c32a8eb6555703d5a397bf8e6d94e953f719ca9260c6954e2cdad84c5c0ad82e0720899505181a0ca4b0276bc56cdd05bdd149cfefb42822a6307cf8e3f435ab6e74c73f2de7efa60a79c87585444d0ae24ad194af290442f13ef7f8634d9d0017ee92b49370f7a5994a11bc4f546acf2c54e2a43a71f210a04e79c5fef54ed61501b8f049d337facdb4a9e0938c555990c03d2b956f7e5dda354ee4d1c58c659990249aab85d2befb75d5449bc91b9d67e7f9dc6"
# This script version helps us make sure everything works correctly.
# Please do not change it.
SCRIPT_VERSION="2.4"
# This is where the data is sent. Do not change.
URL="https://upload.cleveruptime.net/"
# Where this exact script can be re-downloaded. Used by 'install' and 'update'
# so the agent can save a permanent copy of itself and update itself later.
DOWNLOAD_URL="%DOWNLOAD_URL"
INSTALL_PATH="/usr/local/bin/cleveruptime.sh"
SERVICE_PATH="/etc/systemd/system/cleveruptime.service"
# How often to send data (in seconds)
# - Free plan: every 300 seconds (5 minutes)
# - Pro/Business: every 60 seconds (1 minute)
# DO NOT SET BELOW 60! Otherwise your account may be blocked.
SLEEP_INTERVAL="60"
# Optional: Give your server a custom ID (e.g. "web01")
SERVER_ID="my_custom_server_id"
# Optional: A friendly name (e.g. "Main Web Server")
SERVER_NAME="my_custom_server_name "
# Optional: Add a description
DESCRIPTION="my_custom_server_description"
# Optional: Group servers (e.g. "blog", "api")
PROJECT="my_cool_project"
# Optional: Add tags to filter later (comma-separated)
TAGS="keywords_describing_my_server"
# Optional: Add location (helps with monitoring)
# If not set, we'll guess from your IP.
CONTINENT="where_my_server_is_located"
COUNTRY="where_my_server_is_located"
ZONE="available_zone_of_my_server"
CITY="city"
HOSTER="company_hosting_my_server"
DATACENTER="datacenter_of_my_server"
RACK="Rack_of_my_server"
################################################################################
# STEP 2: CHECK IF WE CAN RUN THIS SCRIPT #
# #
# Before doing anything, we check: #
# - Are required tools installed? (curl, gzip) #
# - Are we running as root? (needed to read some system files) #
# #
# If not, we stop and explain what to do. #
################################################################################
# Check if 'gzip' is installed
# gzip compresses the data so it uploads faster
if ! command -v gzip &> /dev/null; then
echo "ERROR: gzip is not installed." >&2
echo "It's used to compress data before sending." >&2
echo "Install it with: sudo apt install gzip" >&2
exit 1
fi
# Check if 'curl' is installed
# curl sends the data to CleverUptime
if ! command -v curl &> /dev/null; then
echo "ERROR: curl is not installed." >&2
echo "It's used to send data to the internet." >&2
echo "Install it with: sudo apt install curl" >&2
exit 1
fi
# Check if script is run as root (administrator)
# Many system files can only be read by root
if [ "$EUID" -ne 0 ]; then
echo "ERROR: This script needs root permissions." >&2
echo "It reads system files like /proc/meminfo and /etc/passwd." >&2
echo "Run it with: sudo ./cleveruptime.sh" >&2
exit 1
fi
################################################################################
# STEP 3: GET UNIQUE SERVER IDENTIFIERS #
# #
# CleverUptime uses these to recognize your server. #
# They are read from your system and should NEVER change. #
# #
# - HOSTNAME: your server's name (e.g. 'web01') #
# - PRODUCT_UUID: hardware ID (on physical servers) #
# - MACHINE_ID: system ID (on VMs and containers) #
# #
# These help us track your server even if the IP changes. #
################################################################################
# Read the server's hostname (e.g. "my-server")
HOSTNAME=$(cat /proc/sys/kernel/hostname)
# Read hardware ID (only on physical servers)
# If not available (e.g. in Docker), we'll use "n/a"
PRODUCT_UUID=$(cat /sys/class/dmi/id/product_uuid 2>/dev/null || echo "n/a")
# Read system ID (unique to this Linux install)
# Found in /etc/machine-id
MACHINE_ID=$(cat /etc/machine-id 2>/dev/null || echo "n/a")
################################################################################
# STEP 3.5: OPTIONAL β INSTALL AS A SERVICE (START AT BOOT) #
# #
# By default this script just runs (great for testing in tmux/screen). #
# To keep it running and start it automatically at boot, run: #
# #
# sudo ./cleveruptime.sh install #
# #
# That installs a small systemd service. To remove it: 'uninstall'. #
# To pull the latest version of this script: 'update'. #
################################################################################
# Save a permanent copy of this script and run it as a systemd service.
cu_install() {
[ "$EUID" -eq 0 ] || { echo "Please run install with sudo." >&2; exit 1; }
command -v systemctl >/dev/null || { echo "No systemd here β just run it in tmux instead." >&2; exit 1; }
# We may have arrived via 'curl | bash', so re-download a copy to disk.
curl -fsSL "${DOWNLOAD_URL}" -o "${INSTALL_PATH}"
chown root:root "${INSTALL_PATH}"; chmod 700 "${INSTALL_PATH}" # key stays root-only
# Write the service that keeps it running and starts it at boot.
cat > "${SERVICE_PATH}" <<EOF
[Unit]
Description=CleverUptime monitoring agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=${INSTALL_PATH} run
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now cleveruptime
echo "Installed. Live logs: journalctl -u cleveruptime -f"
}
# Remove the systemd service (leaves the script file in place).
cu_uninstall() {
[ "$EUID" -eq 0 ] || { echo "Please run uninstall with sudo." >&2; exit 1; }
systemctl disable --now cleveruptime 2>/dev/null
rm -f "${SERVICE_PATH}"; systemctl daemon-reload
echo "Removed the service (left ${INSTALL_PATH} in place)."
}
# Re-download the latest version of this script and restart the service.
cu_update() {
[ "$EUID" -eq 0 ] || { echo "Please run update with sudo." >&2; exit 1; }
curl -fsSL "${DOWNLOAD_URL}" -o "${INSTALL_PATH}"
chmod 700 "${INSTALL_PATH}"
systemctl restart cleveruptime 2>/dev/null
echo "Updated to the latest script."
}
# The first argument decides what to do. No argument = just run (tmux/screen).
case "${1:-run}" in
run) ;; # fall through to the monitoring loop below
install) cu_install; exit $? ;;
uninstall) cu_uninstall; exit $? ;;
update) cu_update; exit $? ;;
*) echo "Usage: cleveruptime.sh [run|install|uninstall|update]"; exit 1 ;;
esac
################################################################################
# STEP 4: THE MAIN LOOP β RUN FOREVER, SEND DATA REGULARLY #
# #
# The script runs in a loop: #
# 1. Collect data #
# 2. Send it to CleverUptime #
# 3. Wait a while #
# 4. Repeat #
# #
# This is how monitoring tools work: continuous, automatic checks. #
# #
# 'while true' means "do this forever" #
# You can stop it anytime with: Ctrl + C #
################################################################################
while true; do
# Record when this cycle started (for performance tracking)
startTime=$(date +"%s%3N")
# Show a message in the terminal
echo -n "$(date -u +'%Y-%m-%d %H:%M:%S') Running CleverUptime..."
# Now we do four things in a chain:
#
# 1. Collect all system data inside { ... }
# 2. Compress it with gzip (faster upload)
# 3. Send it with curl
# 4. Capture the HTTP status code (200 = success)
#
# Let's break it down step by step.
#
# You can learn more about this script in detail at:
# https://cleveruptime.com/the-script
#
status=$(
# Start of data collection block
{
# Force all commands to use English output
# Why? So we can parse the output correctly later
export LC_ALL=C
# This marker helps CleverUptime split the output into sections
# Example: "***CleverUptime_proc:cpuinfo" marks the start of CPU data
MARKER="***CleverUptime_"
# === REQUIRED: Identification ===
# These lines tell CleverUptime who you are (do not change anything here)
echo "${MARKER}general:uploadKey"; echo "$b308b48ea43666a31d41bb25b3b0b0e1318d40ffbcae7d0d3c97631fdb2528597087169822417020d41ab3b225d43a53d2cc2a4b03601d58b4fd802df30f1cc5e627b665b7cf2b317f65054c32a8eb6555703d5a397bf8e6d94e953f719ca9260c6954e2cdad84c5c0ad82e0720899505181a0ca4b0276bc56cdd05bdd149cfefb42822a6307cf8e3f435ab6e74c73f2de7efa60a79c87585444d0ae24ad194af290442f13ef7f8634d9d0017ee92b49370f7a5994a11bc4f546acf2c54e2a43a71f210a04e79c5fef54ed61501b8f049d337facdb4a9e0938c555990c03d2b956f7e5dda354ee4d1c58c659990249aab85d2befb75d5449bc91b9d67e7f9dc6"
echo "${MARKER}general:scriptVersion"; echo "${SCRIPT_VERSION}"
echo "${MARKER}general:hostname"; echo "${HOSTNAME}"
echo "${MARKER}general:productUuid"; echo "${PRODUCT_UUID}"
echo "${MARKER}general:machineId"; echo "${MACHINE_ID}"
# === OPTIONAL: Custom Metadata ===
# You can use these to organize your servers
echo "${MARKER}general:serverId"; echo "${SERVER_ID}"
echo "${MARKER}general:serverName"; echo "${SERVER_NAME}"
echo "${MARKER}general:description"; echo "${DESCRIPTION}"
echo "${MARKER}general:project"; echo "${PROJECT}"
echo "${MARKER}general:tags"; echo "${TAGS}"
echo "${MARKER}general:continent"; echo "${CONTINENT}"
echo "${MARKER}general:country"; echo "${COUNTRY}"
echo "${MARKER}general:zone"; echo "${ZONE}"
echo "${MARKER}general:city"; echo "${CITY}"
echo "${MARKER}general:hoster"; echo "${HOSTER}"
echo "${MARKER}general:datacenter"; echo "${DATACENTER}"
echo "${MARKER}general:rack"; echo "${RACK}"
# === Time & Timezone ===
# We record start time to measure performance and calculate metrics like Bytes/sec
echo "${MARKER}time:start"; timeout 5 date -u +"%Y-%m-%dT%H:%M:%S.%3NZ"
echo "${MARKER}time:timezone"; timeout 5 date +"%Z"
# === /proc β Performance Data ===
# These files contain live system metrics
# They are updated regularly by the Linux kernel
echo "${MARKER}proc:version"; timeout 5 cat /proc/version
echo "${MARKER}proc:uptime"; timeout 5 cat /proc/uptime
echo "${MARKER}proc:cpuinfo"; timeout 5 cat /proc/cpuinfo
echo "${MARKER}proc:stat"; timeout 5 cat /proc/stat
echo "${MARKER}proc:loadavg"; timeout 5 cat /proc/loadavg
echo "${MARKER}proc:meminfo"; timeout 5 cat /proc/meminfo
echo "${MARKER}proc:sys:vm:swappiness"; timeout 5 cat /proc/sys/vm/swappiness
echo "${MARKER}proc:partitions"; timeout 5 cat /proc/partitions
echo "${MARKER}proc:diskstats"; timeout 5 cat /proc/diskstats
echo "${MARKER}proc:mdstat"; timeout 5 cat /proc/mdstat
echo "${MARKER}proc:swaps"; timeout 5 cat /proc/swaps
echo "${MARKER}proc:mounts"; timeout 5 cat /proc/mounts
echo "${MARKER}proc:net:dev"; timeout 5 cat /proc/net/dev
echo "${MARKER}proc:pressure:cpu"; timeout 5 cat /proc/pressure/cpu
echo "${MARKER}proc:pressure:io"; timeout 5 cat /proc/pressure/io
echo "${MARKER}proc:pressure:memory"; timeout 5 cat /proc/pressure/memory
echo "${MARKER}proc:vmstat"; timeout 5 cat /proc/vmstat
echo "${MARKER}proc:net:snmp"; timeout 5 cat /proc/net/snmp
echo "${MARKER}proc:net:netstat"; timeout 5 cat /proc/net/netstat
echo "${MARKER}proc:sys:fs:file-nr"; timeout 5 cat /proc/sys/fs/file-nr
echo "${MARKER}proc:sys:net:netfilter:nf_conntrack_count"; timeout 5 cat /proc/sys/net/netfilter/nf_conntrack_count
echo "${MARKER}proc:sys:net:netfilter:nf_conntrack_max"; timeout 5 cat /proc/sys/net/netfilter/nf_conntrack_max
echo "${MARKER}proc:net:sockstat"; timeout 5 cat /proc/net/sockstat
echo "${MARKER}proc:net:sockstat6"; timeout 5 cat /proc/net/sockstat6
echo "${MARKER}proc:sys:kernel:pid-max"; timeout 5 cat /proc/sys/kernel/pid_max
echo "${MARKER}proc:sys:kernel:entropy-avail"; timeout 5 cat /proc/sys/kernel/random/entropy_avail
# === /sys/class/dmi β Hardware Info ===
# Only available on physical servers
# Not present in Docker or some VMs
echo "${MARKER}dmi:id:boardSerial"; timeout 5 cat /sys/class/dmi/id/board_serial
echo "${MARKER}dmi:id:chassisSerial"; timeout 5 cat /sys/class/dmi/id/chassis_serial
echo "${MARKER}dmi:id:chassisVendor"; timeout 5 cat /sys/class/dmi/id/chassis_vendor
echo "${MARKER}dmi:id:productFamily"; timeout 5 cat /sys/class/dmi/id/product_family
echo "${MARKER}dmi:id:productName"; timeout 5 cat /sys/class/dmi/id/product_name
echo "${MARKER}dmi:id:sysVendor"; timeout 5 cat /sys/class/dmi/id/sys_vendor
# === /sys/class/hwmon β Temperatures, Fans (straight from the kernel) ===
# The Linux kernel exposes hardware sensors as plain files here.
# No extra tools needed (no lm-sensors) β we just read the files.
# Temperatures are in milli-Β°C (86750 means 86.75 Β°C), fans in RPM.
echo "${MARKER}sys:hwmon:name"; timeout 5 grep -H . /sys/class/hwmon/hwmon*/name
echo "${MARKER}sys:hwmon:tempInput"; timeout 5 grep -H . /sys/class/hwmon/hwmon*/temp*_input
echo "${MARKER}sys:hwmon:tempLabel"; timeout 5 grep -H . /sys/class/hwmon/hwmon*/temp*_label
echo "${MARKER}sys:hwmon:fanInput"; timeout 5 grep -H . /sys/class/hwmon/hwmon*/fan*_input
echo "${MARKER}sys:hwmon:fanLabel"; timeout 5 grep -H . /sys/class/hwmon/hwmon*/fan*_label
echo "${MARKER}sys:hwmon:powerInput"; timeout 5 grep -H . /sys/class/hwmon/hwmon*/power*_input
echo "${MARKER}sys:hwmon:currInput"; timeout 5 grep -H . /sys/class/hwmon/hwmon*/curr*_input
# === CPU frequency, throttling & power (kernel sysfs, no tools) ===
# scaling_cur_freq/cpuinfo_max_freq in kHz; energy_uj is a running
# microjoule counter (two samples give watts). Server does the math.
echo "${MARKER}sys:cpufreq:cur"; timeout 5 grep -H . /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
echo "${MARKER}sys:cpufreq:max"; timeout 5 grep -H . /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq
echo "${MARKER}sys:cpufreq:governor"; timeout 5 grep -H . /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
echo "${MARKER}sys:throttle"; timeout 5 grep -H . /sys/devices/system/cpu/cpu*/thermal_throttle/*_count
echo "${MARKER}sys:powercap"; timeout 5 grep -H . /sys/class/powercap/*/name /sys/class/powercap/*/energy_uj
# === ECC memory errors (EDAC) β predicts failing RAM ===
# ce = correctable, ue = uncorrectable. Per controller (mc*) and per DIMM.
echo "${MARKER}sys:edac:ce"; timeout 5 grep -H . /sys/devices/system/edac/mc/mc*/ce_count
echo "${MARKER}sys:edac:ue"; timeout 5 grep -H . /sys/devices/system/edac/mc/mc*/ue_count
echo "${MARKER}sys:edac:dimmLabel"; timeout 5 grep -H . /sys/devices/system/edac/mc/mc*/dimm*/dimm_label
echo "${MARKER}sys:edac:dimmCe"; timeout 5 grep -H . /sys/devices/system/edac/mc/mc*/dimm*/dimm_ce_count
echo "${MARKER}sys:edac:dimmUe"; timeout 5 grep -H . /sys/devices/system/edac/mc/mc*/dimm*/dimm_ue_count
# === btrfs allocation β unallocated space (the real ENOSPC signal) ===
# df can show terabytes free while btrfs is wedged: when there is no
# unallocated space left to carve a new metadata chunk, btrfs flips the
# filesystem read-only. The truth lives in chunk allocation, not df.
# allocation/ β per-profile total_bytes/disk_total/bytes_used;
# devices/ β which devices back each filesystem (sizes come from
# /proc/partitions above). Unallocated = device size β allocated.
echo "${MARKER}sys:btrfs:allocation"; timeout 5 grep -rH . /sys/fs/btrfs/*/allocation/ 2>/dev/null
echo "${MARKER}sys:btrfs:devices"; timeout 5 grep -H . /sys/fs/btrfs/*/devices/*/size 2>/dev/null
# === Network interfaces β link state ===
# operstate up/down, carrier 1/0 (flapping), mtu.
# NOTE: /sys/class/net/*/speed is deliberately NOT read β it can block
# for seconds on virtual/down NICs; fetch via ethtool on-demand instead.
echo "${MARKER}sys:net:operstate"; timeout 5 grep -H . /sys/class/net/*/operstate
echo "${MARKER}sys:net:carrier"; timeout 5 grep -H . /sys/class/net/*/carrier
echo "${MARKER}sys:net:mtu"; timeout 5 grep -H . /sys/class/net/*/mtu
# === /etc β System Config Files ===
# These help us understand your OS and users
# Note: Passwords are NOT stored in /etc/passwd β they're in /etc/shadow
echo "${MARKER}etc:passwd"; timeout 5 cat /etc/passwd
echo "${MARKER}etc:group"; timeout 5 cat /etc/group
echo "${MARKER}etc:osRelease"; timeout 5 cat /etc/os-release
echo "${MARKER}etc:resolv.conf"; timeout 5 cat /etc/resolv.conf
# === /proc β Per-Process Data ===
# Raw kernel data for each process: CPU jiffies, memory, I/O, OOM score.
# The server computes CPU% and I/O rates from deltas between uploads.
# Comment out the cmdline line if you don't want to send command arguments.
echo "${MARKER}proc:processes"
for p in /proc/[0-9]*/; do
echo "${p}"
cat "${p}stat" "${p}status" "${p}io" "${p}oom_score" 2>/dev/null
tr '\0' ' ' < "${p}cmdline" 2>/dev/null
echo
done
# === Commands β Network & System ===
# You can comment out any line if you don't want to send that data
echo "${MARKER}command:who"; timeout 5 who
echo "${MARKER}command:ip:address"; timeout 5 ip address
echo "${MARKER}command:ss"; timeout 5 ss -lntup
echo "${MARKER}command:df"; timeout 5 df -l --output
echo "${MARKER}command:df:inodes"; timeout 5 df -li
# ZFS pool capacity β CoW pools degrade past ~80% regardless of size.
# 'cap' is the percentage we band on; -Hp gives exact bytes, no header.
echo "${MARKER}command:zpool"; timeout 5 zpool list -Hp -o name,size,alloc,free,cap,frag,health
# LVM thin pools β a thin pool can exhaust (data OR metadata) while the
# filesystem df looks half-empty, then errors/goes read-only. Only the
# device-mapper status exposes the fill level; emits nothing without pools.
echo "${MARKER}command:dmsetup:thin"; timeout 5 dmsetup status --target thin-pool
echo "${MARKER}command:apt"; timeout 5 apt list --installed
echo "${MARKER}command:wg"; timeout 5 wg
# === SMART Data β Disk Health ===
# Reads health info from hard drives and SSDs
# Requires 'smartmontools' to be installed
# Only runs if the disk exists
for d in /dev/sd[a-z] /dev/nvme[0-9]n1; do
if [ -e "${d}" ]; then
echo "${MARKER}command:smartctl:${d}"; timeout 10 /usr/sbin/smartctl -a "${d}"; echo "exit status: $?"
fi
done
# === Application Checks ===
# Optional: Monitor services you use
# Comment out if not installed
echo "${MARKER}docker:ps"; timeout 5 docker ps -a
echo "${MARKER}apache:serverNames"; timeout 5 grep -h -E 'ServerAlias|ServerName' /etc/apache2/sites-enabled/*
echo "${MARKER}mysql:processlist"; timeout 5 mysql -u root -N -e "SET STATEMENT MAX_STATEMENT_TIME = 5 FOR SHOW PROCESSLIST"
echo "${MARKER}mysql:databases"; timeout 5 mysql -u root -N -e "SET STATEMENT MAX_STATEMENT_TIME = 5 FOR SHOW DATABASES"
echo "${MARKER}mysql:globalStatus"; timeout 5 mysql -u root -N -e "SET STATEMENT MAX_STATEMENT_TIME = 5 FOR SELECT * FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME IN ('COM_SELECT','COM_INSERT','QUERIES','ROWS_READ')"
echo "${MARKER}mysql:tables"; timeout 5 mysql -u root -N -e "SET STATEMENT MAX_STATEMENT_TIME = 5 FOR SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('mysql','information_schema','performance_schema')"
echo "${MARKER}mysql:partitions"; timeout 5 mysql -u root -N -e "SET STATEMENT MAX_STATEMENT_TIME = 5 FOR SELECT * FROM information_schema.PARTITIONS WHERE PARTITION_NAME IS NOT NULL"
echo "${MARKER}ceph:status"; timeout 5 ceph status
# === Custom Data (Example) ===
# You can add your own commands here
echo "${MARKER}custom:myOwnData"; timeout 5 echo "You can add your own data here."
echo "${MARKER}custom:someOtherData"; timeout 5 echo "Just return a single line of text."
# === Conditional Data (Example) ===
# Only collect data on specific servers
if [[ "${HOSTNAME}" =~ "myHostName" ]]; then
echo "${MARKER}custom:myHostData"; timeout 5 echo "Only collected on myHostName."
fi
# === End timestamp ===
# Marks the end of this cycle
echo "${MARKER}time:end"; timeout 5 date -u +"%Y-%m-%dT%H:%M:%S.%3NZ"
} 2>/dev/null \
| gzip --fast \
| curl -X POST \
--silent \
--fail \
--max-time 5 \
-H "Content-Encoding: gzip" \
--output /dev/null \
--write-out "%{http_code}" \
--data-binary @- \
"${URL}"
)
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
# Let's break down what happens in the pipeline above:
#
# { ... } : Groups all commands so their output is combined
# 2>/dev/null : Hides error messages (like "permission denied")
# | gzip --fast : Compresses the data (smaller, faster upload)
# | curl ... : Sends the compressed data to CleverUptime
#
# Why use { } and a pipe?
# - We want to collect ALL output from the commands above
# - Then compress it
# - Then send it in one request
# This is efficient and secure.
#
# curl flags explained:
#
# -X POST : Sends data as a POST request (standard for APIs)
# --silent : No progress bar (cleaner output)
# --fail : Return error code if HTTP fails (e.g. 404)
# --max-time 5 : Give up after 5 seconds (don't hang forever)
# -H "Content-Encoding: gzip" : Tells server the data is compressed
# --output /dev/null : Don't print the server's response
# --write-out "%{http_code}" : Instead, return only the HTTP status code
# --data-binary @- : Read compressed data from stdin (the pipe)
# "${URL}" : Where to send it
#
# This is safe and transparent:
# - You can see every command that runs
# - No data is sent without your permission
# - You can comment out any line
#
# Want to learn more?
# Visit: https://cleveruptime.com/the-script
#
# Measure how long this cycle took
endTime=$(date +"%s%3N")
duration=$((endTime - startTime))
# Print result
echo "HTTP status code ${status} (execution time ${duration} ms)"
# Handle errors
case "${status}" in
"200") true ;; # All good
"400")
echo "ERROR: Bad Request. Check scriptVersion, hostname, productUuid, machineId." >&2
exit 1
;;
"401")
echo "ERROR: Unauthorized. Check your upload key." >&2
exit 1
;;
"403")
echo "ERROR: Forbidden. Upload key may be invalid or revoked." >&2
exit 1
;;
"429")
echo "WARNING: Too Many Requests. Increasing interval." >&2
sleep "${SLEEP_INTERVAL}"
;;
*)
echo "WARNING: Unexpected HTTP status: ${status}. Retrying..." >&2
sleep 5
;;
esac
# Wait before next run
sleep "${SLEEP_INTERVAL}"
done
What It Does
- Reads system files like
/proc/loadavg - Collects CPU, memory, and disk numbers
- Sends them securely to CleverUptime
What It Doesn’t Do
- Read or exfiltrate your private data
- Install an agent or background service
- Change your system or keep data around
Private by design
Data lives for 15 minutes, then it’s deleted. No IP logging, no spam.
Only run this on servers you own or are allowed to monitor.
Run This Command
curl -s "https://cleveruptime.com/script?uploadKey=b308b48ea43666a31d41bb25b3b0b0e1318d40ffbcae7d0d3c97631fdb2528597087169822417020d41ab3b225d43a53d2cc2a4b03601d58b4fd802df30f1cc5e627b665b7cf2b317f65054c32a8eb6555703d5a397bf8e6d94e953f719ca9260c6954e2cdad84c5c0ad82e0720899505181a0ca4b0276bc56cdd05bdd149cfefb42822a6307cf8e3f435ab6e74c73f2de7efa60a79c87585444d0ae24ad194af290442f13ef7f8634d9d0017ee92b49370f7a5994a11bc4f546acf2c54e2a43a71f210a04e79c5fef54ed61501b8f049d337facdb4a9e0938c555990c03d2b956f7e5dda354ee4d1c58c659990249aab85d2befb75d5449bc91b9d67e7f9dc6&project=HealthCheckDemo" | sudo bash
- Runs with
sudo— only do this once you’ve read the script above. - The key is unique and valid for 15 minutes; it links your server to this page.
- Prefer to download it? Get the script with your key pre-filled.
Your Server Appears Here
Live preview time remaining: 00:15:00
Waiting for your server to connectβ¦
After 15 minutes the preview ends and the data is discarded. Reload to start over.
Why Trust This?
- It’s the real dashboard, not a canned demo — just time-limited to 15 minutes.
- No signup, no install, no tricks.
- We’re developers too. We’ve broken servers and lost data — this is the tool we wished we’d had.
See an example • Read our story
Want This for Every Server?
Sign up free — one server is free, forever.
| size | |
|---|---|
| partitions | |
| smartStatus | |
| modelFamily | |
| deviceType | |
| deviceModel | |
| serialNumber | |
| formFactor | |
| rotationRate | |
| revision | |
| firmwareVersion | |
| temperature | |
| powerOnHours | |
| startStopCount | |
| powerCycleCount | |
| availableSpare | |
| reallocatedSectorCount | |
| rawReadErrorRate | |
| wearLevelingCount | |
| discardsCompleted | |
| discardsMerged | |
| iosInProgress | |
| readsCompleted | |
| readsMerged | |
| sectorsDiscarded | |
| sectorsRead | |
| sectorsWritten | |
| readSpeed | |
| writeSpeed | |
| readOpsPerSecond | |
| writeOpsPerSecond | |
| timeSpentDiscarding | |
| timeSpentDoingIos | |
| timeSpentReading | |
| timeSpentWriting | |
| weightedTimeSpentDoingIos | |
| writesCompleted | |
| writesMerged | |
| size | |
|---|---|
| partitions | |
| discardsCompleted | |
| discardsMerged | |
| iosInProgress | |
| readsCompleted | |
| readsMerged | |
| sectorsDiscarded | |
| sectorsRead | |
| sectorsWritten | |
| readSpeed | |
| writeSpeed | |
| readOpsPerSecond | |
| writeOpsPerSecond | |
| timeSpentDiscarding | |
| timeSpentDoingIos | |
| timeSpentReading | |
| timeSpentWriting | |
| weightedTimeSpentDoingIos | |
| writesCompleted | |
| writesMerged | |
| size | |
|---|---|
| raidLevel | |
| members | |
| membersActive | |
| membersTotal | |
| raidStatus | |
| readOnly | |
| checkProgress | |
| checkRemainingTime | |
| checkSpeed | |
| resyncStatus | |
| discardsCompleted | |
| discardsMerged | |
| iosInProgress | |
| readsCompleted | |
| readsMerged | |
| sectorsDiscarded | |
| sectorsRead | |
| sectorsWritten | |
| timeSpentDiscarding | |
| timeSpentDoingIos | |
| timeSpentReading | |
| timeSpentWriting | |
| weightedTimeSpentDoingIos | |
| writesCompleted | |
| writesMerged | |
| size | |
|---|---|
| partOfRaidDevice | |
| discardsCompleted | |
| discardsMerged | |
| iosInProgress | |
| readsCompleted | |
| readsMerged | |
| sectorsDiscarded | |
| sectorsRead | |
| sectorsWritten | |
| timeSpentDiscarding | |
| timeSpentDoingIos | |
| timeSpentReading | |
| timeSpentWriting | |
| weightedTimeSpentDoingIos | |
| writesCompleted | |
| writesMerged | |
| size | |
|---|---|
| discardsCompleted | |
| discardsMerged | |
| iosInProgress | |
| readsCompleted | |
| readsMerged | |
| sectorsDiscarded | |
| sectorsRead | |
| sectorsWritten | |
| timeSpentDiscarding | |
| timeSpentDoingIos | |
| timeSpentReading | |
| timeSpentWriting | |
| weightedTimeSpentDoingIos | |
| writesCompleted | |
| writesMerged | |
/
/
/
/
| model | |
|---|---|
| modelName | |
| mhz | |
| bogoMips | |
| cacheSize | |
| modelFamilyId | |
| modelId | |