# Status VPS

**Jednoduchý open-source monitoring dostupnosti v PHP.** Weby, servery a porty na jedné přehledné status stránce. JSON konfigurace, barevné čárky historie a instalace bez Composeru.

- [Živé demo](https://status.jankaminsky.eu/)
- [Instalační návod](INSTALL.md)
- [Instalace v prostém textu](INSTALACE.txt)
- [Vzor konfigurace](config.example.json)
- [Krátký popis](POPIS.md)
- Licence [MIT](LICENSE)

## Co umí verze 1.0.0

- **HTTP/HTTPS:** odpověď webu, časový limit, kontrola TLS certifikátu a nastavitelný rozsah HTTP stavových kódů. Přesměrování sleduje nejvýše třikrát.
- **TCP:** navázání spojení na IP/doménu a port, například SSH 22 nebo HTTPS 443.
- **ICMP ping:** kontrola dosažitelnosti serveru na Linuxu s dostupným příkazem `ping` a příslušným oprávněním.
- Globální interval kontrol i vlastní interval pro každý monitor, od 60 sekund.
- Barevné čárky posledních měření, detail jednotlivé kontroly a hodinový graf odezvy.
- Dostupnost za 24 hodin, 7 dní a 30 dní podle skutečně provedených kontrol.
- Automatická evidence incidentů a jejich vyřešení; práh neúspěšných a úspěšných kontrol.
- Skupiny služeb, vyhledávání, režim údržby, světlý/tmavý vzhled a mobilní rozvržení.
- Rozlišení čekajícího měření, chybějících dat, nefunkční ICMP kontroly a zastaralého stavu plánovače.
- Automatické mazání historie podle `retention_days`, výchozí hodnota 30 dní.
- Veřejná stránka pouze pro čtení. Cíle se mění úpravou souboru na serveru.

## Požadavky

PHP **8.2 nebo novější**, rozšíření **curl, pdo_sqlite, mbstring**, webový server a plánovač úloh/cron s PHP CLI. SQLite je souborová databáze; MySQL není potřeba. Pro ICMP je navíc potřeba Linux, `/usr/bin/ping` nebo `/bin/ping`, funkce `proc_open` a systémové oprávnění ke spuštění pingu. Pokud nejsou dostupné, monitor zobrazí „Nelze ověřit“ a nenahlásí falešný výpadek služby.

## Rychlý start

```bash
cd /var/www/status-vps
php bin/install.php
# Upravte config.json: weby, IP adresy, porty a intervaly.
php bin/check.php --validate
php bin/check.php
```

Webový kořen musí směřovat na **`/var/www/status-vps/public`**. Do cronu přidejte:

```cron
* * * * * php /var/www/status-vps/bin/check.php >> /var/www/status-vps/storage/worker.log 2>&1
```

Podrobné nastavení oprávnění a Nginxu najdete v [INSTALL.md](INSTALL.md).

## Konfigurace

Při instalaci vznikne `config.json` kopií z `config.example.json`. Každá kontrola načte aktuální konfiguraci; samostatný dlouhodobý proces není potřeba restartovat.

```json
{
  "site": {
    "title": "status.vps.cz",
    "description": "Dostupnost našich služeb.",
    "timezone": "Europe/Prague",
    "refresh_seconds": 30,
    "demo": false
  },
  "monitoring": {
    "interval_seconds": 60,
    "timeout_seconds": 8,
    "failure_threshold": 2,
    "recovery_threshold": 1,
    "retention_days": 30,
    "history_bars": 60
  },
  "monitors": [
    {
      "id": "web",
      "name": "Firemní web",
      "group": "Weby",
      "type": "http",
      "url": "https://example.com",
      "expected_status_min": 200,
      "expected_status_max": 399
    },
    {
      "id": "ssh",
      "name": "VPS · SSH",
      "group": "Servery",
      "type": "tcp",
      "host": "127.0.0.1",
      "port": 22,
      "interval_seconds": 120
    }
  ]
}
```

### Nastavení stránky

| Klíč | Význam |
|---|---|
| `site.title` | Název v záhlaví. Jde o text, nikoli automatické nastavení domény nebo DNS. |
| `site.description` | Krátký veřejný popis. |
| `site.timezone` | Časové pásmo pro zobrazení, například `Europe/Prague`. |
| `site.refresh_seconds` | Obnova uloženého stavu v prohlížeči, 10–3600 sekund. **Nespouští měření.** |
| `site.demo` | Zobrazí informační štítek živého dema. Měření nadále zůstávají skutečná. |

### Nastavení monitoringu

| Klíč | Výchozí / rozsah | Význam |
|---|---|---|
| `interval_seconds` | 60 / 60–86400 | Minimální odstup kontrol; lze přepsat u monitoru. |
| `timeout_seconds` | 8 / 1–30 | Časový limit; lze přepsat u monitoru. |
| `failure_threshold` | 2 / 1–10 | Počet po sobě jdoucích selhání k potvrzení výpadku. |
| `recovery_threshold` | 1 / 1–10 | Počet po sobě jdoucích úspěchů k potvrzení obnovy. |
| `retention_days` | 30 / 1–365 | Uchování kontrol a uzavřených incidentů. |
| `history_bars` | 60 / 15–120 | Počet čárek posledních měření. **Jedna čárka znamená jednu kontrolu, nikoli den.** |

### Nastavení služby

Každá položka má jedinečné `id`, zobrazované `name` a `type` (`http`, `tcp`, `ping`). Volitelně nastavte `group`, `interval_seconds`, `timeout_seconds`, `enabled` a `maintenance`. Výchozí hodnoty posledních dvou jsou `true` a `false`. Pole `enabled: false` monitor zcela skryje a nekontroluje. `maintenance: true` jej ponechá viditelný jako údržbu a pozastaví kontroly.

- `http`: `url`, případně `expected_status_min` a `expected_status_max`, výchozí rozsah 200–399 včetně. Používá GET, následuje přesměrování a ověřuje HTTPS certifikát. Po přijetí 2 MiB těla odpovědi stahování ukončí a vyhodnotí již přijatý HTTP kód.
- `tcp`: `host` a `port`. Otevřený port potvrzuje pouze možnost TCP spojení, nikoli funkčnost protokolu či celé aplikace.
- `ping`: `host`. ICMP může být firewallem blokováno, přestože HTTP/SSH fungují. Pro běžný hosting doporučujeme HTTP nebo TCP.

ID používejte dlouhodobě pro stejnou službu. Při změně na jiný sledovaný cíl zvolte nové ID, aby se nesmíchala historie. Nejvýše 50 monitorů. Číselná pole musí být JSON čísla bez uvozovek, přepínače `true`/`false`. JSON nepodporuje komentáře ani čárku za poslední položkou.

## Jak měření funguje

Cron spouští `bin/check.php` každou minutu. Kontrolují se jen služby, kterým vypršel interval. Intervaly mají minutovou přesnost a jde o minimální odstup, nikoli záruku přesné sekundy. Například interval 90 sekund se při minutovém cronu obvykle vyhodnotí přibližně po dvou minutách.

Kontroly jsou sekvenční a přednost dostanou nejdéle neměřené služby. Běh po přibližně 50 sekundách nezačne další kontrolu; probíhající může doběhnout do svého limitu. Další běh pokračuje podle stáří výsledků. Souborový zámek brání souběžným běhům. Velké množství pomalých služeb proto prodlouží skutečný interval. DNS překlad u TCP závisí také na nastavení resolveru operačního systému.

První selhání pod prahem se zobrazí jako **Prověřování**. Po dosažení prahu vznikne incident; začátek odpovídá prvnímu selhání této série. Obnovení se potvrdí podle `recovery_threshold`. Technicky neproveditelná kontrola má stav **Nelze ověřit**. Pokud se nové měření neobjeví do zhruba dvojnásobku intervalu plus timeout (nejméně 120 sekund), stránka ukáže **Měření zastaralo**.

Dostupnost je **počet úspěšných kontrol / počet úspěšných a neúspěšných kontrol** v daném okně. Nejde o časově vážené SLA. Neznámé výsledky ani nenaměřená minulost se nepovažují za úspěch. Odezev se do grafu započítávají pouze úspěšné kontroly a jde o celkovou délku kontroly včetně navazování spojení, nikoli pouze síťový RTT.

## Provoz a bezpečnost

- Veřejný je pouze adresář `public/`. `config.json`, `src/`, `bin/` a `storage/` nesmějí být přístupné z webu.
- Konfiguraci upravuje vlastník serveru, nikoli veřejný návštěvník. Webové rozhraní nemá zápisové API, administraci ani veřejné spouštění kontrol.
- Sledujte vlastní cíle nebo cíle, ke kterým máte oprávnění. Aplikace může pro interní monitoring přistupovat i na privátní adresy.
- Veřejné API `?api=status` poskytuje jen zobrazované názvy, stavy a statistiky; nevrací URL, IP ani porty z konfigurace.
- Přístup do privátní konfigurace nastavte například na `0640`, adresář historie na `0750`. Nepoužívejte `777`.
- Zálohujte `config.json` a databázi; při běžícím WAL režimu použijte SQLite backup API nebo konzistentní snapshot, nikoli samotné kopírování otevřeného `.sqlite` bez WAL.
- Udržujte PHP a server aktualizované. Rotaci `storage/worker.log` nastavte na serveru.
- Toto vydání neposílá e-mailové/SMS notifikace, nemá přihlášení ani monitoring z více lokalit. Vydání je záměrně jednoduché.

## Struktura

```text
status-vps/
├── config.example.json
├── config.json           # vznikne instalací, neveřejný
├── bin/install.php
├── bin/check.php
├── src/                  # konfigurace, kontroly, statistiky
├── storage/              # vznikne instalací, SQLite a zámek
├── public/               # JEDINÝ webový kořen
│   ├── index.php
│   ├── assets/
│   └── downloads/
├── tests/run.php
├── INSTALL.md
├── INSTALACE.txt
└── LICENSE
```

## Ověření a řešení potíží

```bash
php bin/check.php --validate
php bin/check.php
php tests/run.php
```

- **Čeká na měření:** spusťte první kontrolu a zkontrolujte cron.
- **Měření zastaralo:** ověřte plánovač, oprávnění, cestu k PHP a log.
- **Prázdná historie:** normální stav nové instalace; minulost se nedoplňuje odhadem.
- **Nelze otevřít databázi:** web i cron musí mít zápis do adresáře `storage/`, nejen do samotného souboru.
- **Nefunguje ping:** ověřte dostupnost příkazu a oprávnění, případně zvolte TCP.
- **HTTPS selhává:** ověřte certifikát cíle a CA certifikáty serveru. Ověřování TLS se nevypíná.
- **Na hostingu není cron/PHP CLI:** tento balíček tam nebude pravidelně monitorovat. Je potřeba hosting s plánovačem nebo VPS.

## Licence a inspirace

MIT, © 2026 Jan Kaminský. Zdrojové kódy lze používat, upravovat i distribuovat při zachování licence. Jde o originální implementaci inspirovanou přehledností status nástrojů, například [Uptime Kuma](https://github.com/louislam/uptime-kuma), bez převzetí jeho zdrojových kódů a značky. Písma DM Sans a Manrope se načítají z Google Fonts; při jejich nedostupnosti se použije systémové písmo.
