# static_status turns a bash script into a status page you can host anywhere

> The static_status project is a single Bash script that checks websites, services and pings, then renders a static HTML status page with JSON and an SVG icon, with no daemon, no database and no web server in the loop.

**Cyclenerd/static_status** — 🚦Bash script to generate a static status page.

- Repository: https://github.com/Cyclenerd/static_status
- Website: https://cyclenerd.github.io/static_status/
- Stars: 732 · Forks: 76
- Language: Shell
- License: GPL-3.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/cyclenerd-static-status

## What the script checks and what it produces

The project is a simple Bash script to generate a static status page, and the description is specific about the scope. It displays the status of websites, services such as HTTP, SAP and MySQL, and ping, and everything is easy to customize. The readme adds that you can check more complicated things with the script, for example whether a text is present on a web page, or whether a host appears in the route path using traceroute, and it explains why that matters, since checking the route path is useful if you have a backup mobile internet connection alongside a cable connection. The outputs are three things. There is the status web page, a JSON version of the same data, and an SVG icon you can embed elsewhere. There is also a separate alert.sh script that can notify you by email, SMS or Pushover when something goes down, which turns the generator into something you can run on a schedule rather than only look at once.

## Installation is two curl commands and a text file

The convention is to create a status directory inside your home directory and put everything in it.

```shell
mkdir ~/status
cd ~/status
```

Then you download the script and the configuration file that lists what to monitor.

```shell
curl -O "https://raw.githubusercontent.com/Cyclenerd/static_status/master/status.sh"
```

```shell
curl -O "https://raw.githubusercontent.com/Cyclenerd/static_status/master/status_hostname_list.txt"
```

Updating works exactly the same way as installing, since you simply download the latest version of status.sh again. The configuration file is where you define your targets.

```shell
vi status_hostname_list.txt
```

Optionally you can edit the script itself, but the readme suggests a better option, which is to add more configuration to the configuration file named config, and it ships an example of that file to download and edit.

## Each line names a check and a label

The configuration format is one line per target, with the check type first, then the target, then optional text to display instead of the raw hostname or URL.

```text
ping;8.8.8.8|Google DNS
nc;8.8.8.8|DNS @ Google;53
curl;http://www.heise.de/ping|www.heise.de
traceroute;192.168.211.1|DSL Internet;3
script;/bin/true|always up
```

The check types visible here are ping, nc for a raw TCP port, curl for an HTTP request, traceroute and script. The pipe separates the target from the display text, and the semicolon inside a label such as DNS @ Google;53 carries extra parameters for the check itself. The custom text feature is what makes the page readable, since you can display a friendly name instead of the address. The readme also shows the alternative form of the traceroute line with a hop count, and the script line is the hook that makes the tool more than a set of built-in probes.

## Custom scripts get a three state contract

The custom script check is the most reusable part of the project, and the contract is small. You extend the checks of status.sh with your own custom shell scripts, and the script's return code decides the state. A return code of 0 is evaluated as available, the special return code 80 means the target is not classified as down but as degraded, and all other return codes are a failure, an outage or down. That middle state is what makes this more than a ping wrapper, because a service that responds but is behaving badly should not page the same way as one that is gone. Adding a script to the configuration file is a one line change.

```text
script;script.sh
script;/path/to/your/script.sh|Custom Text
script;/path/to/your/script.sh parameterA parameterB|Custom Text
```

The repository ships an example, check-websites.sh, and the repository has test-script-checks.sh alongside test.sh and test-status-duration.sh, so the behaviour is covered rather than merely described.

## The dependency list is short and the packages are named

The requirements are only bash, coreutils, curl, grep, nc, ping, sed and traceroute, and in many Unix distributions including Ubuntu and macOS those commands are already installed. When they are not, the readme gives the Debian package names explicitly.

```shell
sudo apt install \
  coreutils \
  curl \
  grep \
  iputils-ping \
  netcat-openbsd \
  sed \
  traceroute
```

There is one dependency you can remove outright, since the readme notes that you can disable the traceroute dependency by adding MY_TRACEROUTE_HOST='' to your config. That is a small design point with a real effect, because traceroute is the slowest of the checks and the one that needs elevated or unusual network access, and on a locked down network it is often the one that fails. The rest of the dependency list is deliberately made of things that behave the same everywhere, which is what makes the generated page comparable between machines.

## Running it from cron and reading the output

The usage block lists the options the script takes. There is a silent mode with no output from faulty connections, a loud mode that also reports successful connections, a debug mode that displays all variables, and help. The default for both silent and loud is no, which is a slightly confusing way of writing it and worth knowing before you script around it.

```shell
bash status.sh loud
```

The intended deployment is a cron job every minute, edited with crontab -e.

```shell
crontab -e
```

```text
*/1 * * * * bash "/path/to/status.sh" silent >> /dev/null
```

The silent flag and the redirect to /dev/null are both there for the same reason, which is that a status checker that emails you every minute is worse than no status checker. The page itself is regenerated in place each run, and the screenshots show the states it can render, an all clear page, a maintenance page, an outage page, a major outage page and a page of past incidents.

## Where a static status page is the wrong answer

Three limits are worth naming. The first is that the checks run from wherever you run the script, so the page tells you what that one machine sees. That is fine for a homelab and useless for a public status page, where the interesting question is what a customer in another country sees, and no amount of cron will answer it. The second is that the data is a file. There is a JSON output and a history of past incidents, but there is no uptime calculation, no percentile reporting and no live endpoint for a status API, because a static site cannot provide one. The third is the input method, where a check is a shell command and a label, which is a low barrier for simple probes and a high one for anything that needs a real client with a timeout, a retry and a certificate check. A team that needs those things should write a small script and use the script check, which is exactly what the custom script contract is for, but then they own the probe quality too. The readme's own TODO list, which covers documentation, code cleanup and a security review, is an honest statement of where the project stands.

## Conclusion

static_status suits a homelab operator, a small hosting provider or a team that wants a status page on GitHub Pages without running a status page service, and it suits anyone who already lives in cron and shell scripts. It is the wrong tool for a public SaaS status page, because the checks run wherever you run the script and the output is a file, not a live endpoint, and it is the wrong tool if you need per-region probing or historical uptime, since the page records past incidents but the data is only as good as the machine generating it. Before deploying it, read the custom script contract, because the return code 80 degraded state is the part that makes it more than a ping wrapper, and set the cron entry to run silently so the output does not fill your mail. The last push was on 2026-10-16 and the current release is v1.0.0 from 2025-01-27.

## FAQ

### What does the static_status script check?

It displays the status of websites, services such as HTTP, SAP and MySQL, and ping. The configuration format allows check types of ping, nc for a TCP port, curl for HTTP, traceroute and script, and it can also check whether a text is present on a page or whether a host appears in the route path.

### How do I run static_status on a schedule?

Add a cron entry that runs the script silently, for example */1 * * * * bash "/path/to/status.sh" silent >> /dev/null. The script takes a single option, silent, loud, debug or help, and running it with no arguments uses the default options.

### How do I add my own check to static_status?

Write a shell script and add it to the configuration file with the script check type. The return code decides the state: 0 is available, the special return code 80 is degraded rather than down, and all other return codes are treated as an outage. The repository ships an example called check-websites.sh.

## Sources

- [Cyclenerd/static_status on GitHub](https://github.com/Cyclenerd/static_status)
- [License: GPL-3.0](https://github.com/Cyclenerd/static_status/blob/master/LICENSE)
- [Project website](https://cyclenerd.github.io/static_status/)
- [README](https://github.com/Cyclenerd/static_status/blob/master/README.md)
- [Releases](https://github.com/Cyclenerd/static_status/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cyclenerd-static-status
