# ArchForge External Status 1.0.8 — Debian 13 ArchForge Edition

**New:** `.archforge` ArchForge migration, see `DEBIAN-13-GIT-URL-MIGRATION.md`.


**New:** `.archforge` ArchForge migration, see `DEBIAN-13-GIT-URL-MIGRATION.md`.


**New:** `.archforge` ArchForge migration, see `DEBIAN-13-GIT-URL-MIGRATION.md`.


Release 1.0.8: consistent ArchForge service naming across the independent public and admin status website.

Independent uptime monitoring at **https://status.archforge.nl**. This software runs on **a second VPS**, without Docker, Pterodactyl, ArchForge credentials, or any database connection to the main website.

**It does not modify the ArchForge main website.** If archforge.nl becomes unreachable, the external service continues monitoring, saving independent history and sending alerts.

## Nieuw in 1.0.6: veilige, aantoonbaar geïnstalleerde adminloginfix

Een browser met privacybescherming kan `Origin` of `Referer` normaliseren of afschermen.
De server verwerkt nu browser-origininformatie met `Sec-Fetch-Site`, terwijl
**cross-site formulierverzoeken nog steeds worden geweigerd** en elk POST-verzoek
een CSRF-token nodig heeft. De bestaande scrypt-wachtwoordcontrole, TOTP-2FA,
Secure cookies en rate limiting blijven actief.

**Update via je eigen ArchForge-repository:** pak de 1.0.6-update uit in
de checkout op je pc, commit en push de wijzigingen. Op Debian 13 (als root):

```bash
cd ~/archforge-external-status
git pull --ff-only
bash ./repair-admin-login.sh
```

De herstelactie maakt een private back-up van `status.env`, corrigeert alleen
`STATUS_PUBLIC_URL` als die afwijkt, deployt de geteste release met een bestaande
databaseback-up en code-rollback, verifieert daarna de **daadwerkelijk draaiende
versie** via `/healthz` én probeert drie onschuldige loginverzoeken zonder echte
wachtwoorden: een gewone same-origin browser, een browser met privacyheader,
en een geweigerd cross-site verzoek. Bij een mislukte controle meldt de tool
precies welke fase faalde. Hij raakt geen adminwachtwoorden, TOTP of Caddy aan.

Zie `FIX-ADMIN-LOGIN-1.0.6.md`. Een geslaagde lokale test bewijst nog niet wat
de browser op jouw apparaat verstuurt; als de 403 blijft, vermeld dan of de
melding hetzelfde is en welke foutregel de herstelactie heeft getoond.

## Nieuw in 1.0.5: adminlogin 403 Invalid origin oplossen

Als de browser na het inloggen op `/admin/login` de fout **403 Invalid origin** toont,
wordt de POST **voor** de wachtwoord- en 2FA-controle geblokkeerd. De app
vergelijkt de herkomst met `STATUS_PUBLIC_URL`; een afwijkende (oude) instelling,
of een geldig HTTPS-origin met expliciete standaardpoort 443, kon login blokkeren.

Pak versie 1.0.5 uit over de bestanden van je **bestaande** ArchForge-repository, commit en push.
Start op VPS 2 (als root):

```bash
cd ~/archforge-external-status
git pull --ff-only
bash ./fix-admin-origin.sh
```

Deze herstelactie controleert de draaiende statusapp en Caddy-domeinconfiguratie,
maakt een private back-up van `status.env`, synchroniseert zo nodig alleen
`STATUS_PUBLIC_URL`, installeert de bijgewerkte code met de bestaande geteste
deployer, en verifieert dat een HTTPS-loginformulier de origincheck passeert
maar niet de CSRF-check. Wachtwoorden/2FA worden niet aangeraakt; de bestaande
SQLite-database, incidenten en Caddy-configuratie blijven behouden.
Zie `FIX-ADMIN-403-1.0.5.md`.

## Nieuw in 1.0.4: HTTP 302 monitoringfix

De hoofdwebsite kan een HTTP 302 naar een andere pagina **op hetzelfde HTTPS-domein** teruggeven. Vóór 1.0.4 werd dit ten onrechte als outage beschouwd. De websitecheck volgt nu maximaal 3 veilige redirects en accepteert alleen een uiteindelijke HTTP 200. Dit controleert **bereikbaarheid**, niet alle websitefuncties. API en ArchForge-controles blijven strikt.

Als je al bent ingelogd als root op VPS 2, voer na commit/push van de 1.0.4-bestanden op je ArchForge-server uit:

```bash
cd ~/archforge-external-status
git pull --ff-only
bash ./apply-monitor-fix.sh
```

Dit hergebruikt de bestaande code-deployer, inclusief back-up en rollback bij een mislukte restart. De eerste geslaagde check start meteen na het herstarten; na standaard 2 succesvolle controles verdwijnt het bestaande automatische incident. **Historische 302-fouten blijven in de uptimehistorie staan**. Zie `FIX-HTTP-302-1.0.4.md`.

## Nieuw in 1.0.3: directe HTTPS-reparatie

Wanneer Caddy alleen op `:80` luistert en `status.archforge.nl` een `Connection refused` op `:443` geeft, gebruik op **VPS 2** na `git pull --ff-only`:

```bash
bash ./fix-https.sh
```

Deze root-only herstelactie controleert de lokale statusapp, back-upt `/etc/caddy/Caddyfile`, vervangt **alleen op een dedicated status-VPS** de standaard `:80`-configuratie door een direct HTTPS-domeinblok en herstart Caddy. Wanneer Caddy op `:443` niet kan luisteren, herstelt hij de vorige configuratie en toont de concrete servicefout. Hij raakt `/etc/archforge-status/status.env`, SQLite en je adminaccount niet aan. Hij weigert een Caddy-setup met extra sites in `/etc/caddy/conf.d/`. Zie `FIX-HTTPS-1.0.3.md`.

## Nieuw in 1.0.2: domein en SSL regelen na de installatie

Een **aparte ArchForge-ready wizard** koppelt een statusdomein aan de tweede Debian 13 VPS, controleert A/AAAA-records, configureert Caddy en verifieert de uitgegeven HTTPS-verbinding. De oude SQLite-, admin- en `.env`-instellingen blijven bestaan.

```bash
cd ~/archforge-external-status
git pull --ff-only
sudo bash ./configure-domain.sh
```

Als je al root bent, mag je `bash ./configure-domain.sh` gebruiken. Je hoeft `./install.sh` of `./update.sh` niet opnieuw te starten. **Lees eerst `DOMAIN-SSL-DEBIAN-13.md`.**

## Admin wizard hotfix / interrupted v1.0.0 installation

If the old installer hangs after the admin username, **do not delete the SQLite database or `.env`**. Update your ArchForge checkout to this release (or copy the hotfix `src/cli.js` and `recover-admin.sh` into it), then, on VPS 2:

```bash
# If you are logged in as root:
cd ~/archforge-external-status
bash ./recover-admin.sh

# Or if logged in as a regular sudo user:
sudo bash ./recover-admin.sh
```

This only replaces the CLI wizard and finishes admin creation. It does not reinstall packages, restart the service, modify the config or overwrite an existing admin account. Read `HOTFIX-ADMIN-1.0.1.md` for details. `sudo ./install.sh` on an already running installation also delegates to this recovery script.

**Security:** v1.0.0's old `stty`/readline combination could echo the password. Use a fresh unique admin password, especially if the previous one was typed at that prompt.

## Included

- Independent checks for main HTTPS website, optional public API, optional public ArchForge HTTPS, ArchForge SSH banner, DNS, and HTTPS TLS certificate.
- Startup and repeating checks (default every 60 seconds). Three failures to confirm an outage; two successes to confirm recovery.
- Responsive dark-blue status website, 7/30/90-day history, incident timeline, per-service details, observed uptime and monitoring coverage.
- Automatic outage incidents and recovery records; manual admin incident updates and scheduled public maintenance notices.
- Discord webhook and email through **the second VPS's own SMTP configuration**. Confirmed subscriptions and unsubscribe links.
- Independent admin credentials, password hashing with scrypt, TOTP authenticator 2FA, session-based CSRF protection.
- SQLite WAL database outside the ArchForge repository; systemd service; Caddy HTTPS; root-controlled secrets.
- ArchForge-based manual updates, local release snapshots, `rollback.sh`, daily SQLite backups, `restore.sh` and `uninstall.sh`.

## Requirements

A clean **Debian 13 (Trixie)** VPS with root/sudo access, a network connection for packages, DNS control for `status.archforge.nl`, ports 80/443 inbound, and an SMTP account if email alerts are needed. By default Node.js 24 is installed via a signed NodeSource APT repository. `sudo ./install.sh` makes system-level changes; examine scripts before executing.

## Step 1 — Put the project in ArchForge

Create a repository, e.g. `archadmin/archforge-external-status`. Unzip this project locally, then run:

```bash
git init
git branch -M main
git add .
git commit -m "Initial independent status server"
git remote add origin <ACTUAL_CLONE_URL_FROM_ARCHFORGE>
git push -u origin main
```

Do **not** commit a real `.env`, database, backup, SSH key or webhook token. `.gitignore` excludes local secrets. `.env.example` is a harmless template.

## Step 2 — DNS (second VPS)

Add a DNS `A` record for `status.archforge.nl` pointing to the **public IPv4 of VPS 2**. Add an `AAAA` record only if the VPS has working public IPv6. Allow TCP 80 and 443 through provider firewall and OS firewall. Do not proxy the subdomain through VPS 1.

## Existing install: branding repair (v1.0.9)

If your status page still shows **Git SSH** / **Git Smart HTTP** after upgrades, use the
[branding repair guide](BRANDING-FIX-V109.md). No clean install is needed.
The repair script only deploys the new application code and preserves the existing
SQLite database, admin login, monitoring data and Caddy configuration.

## Step 3 — Install on Debian 13

On VPS 2:

```bash
sudo apt-get update
sudo apt-get install -y git
# Use the clone URL displayed by YOUR ArchForge repository.
git clone <ACTUAL_CLONE_URL_FROM_ARCHFORGE> archforge-external-status
cd archforge-external-status
chmod +x install.sh
sudo ./install.sh
```

The interactive wizard checks Debian 13, installs ArchForge, SQLite, Node.js 24, Caddy, msmtp and other requirements, creates a dedicated `archforge-status` service user, asks for domain/targets, Discord webhook and optional SMTP. The wizard generates `/etc/archforge-status/status.env` and an encrypted TOTP secret in SQLite. You must pair an authenticator app and verify a six-digit code during initial admin setup.

**Do not use `sudo ./install.sh` on the main VPS!** Install it only on VPS 2.

### Secrets and data are not in ArchForge

| File | Purpose |
| --- | --- |
| `/etc/archforge-status/status.env` | Root-controlled configuration, encryption key, Discord webhook |
| `/etc/archforge-status/msmtprc` | Restricted SMTP client configuration |
| `/var/lib/archforge-status/status.db` | Independent SQLite database and admin credentials |
| `/opt/archforge-status/app` | Running, installed program code |
| `/var/backups/archforge-status/` | Private database and configuration backups |

Do not lose the environment encryption key or TOTP recovery will fail. **Backups include sensitive credentials** and should be stored on an encrypted disk and ideally copied to a secure location *outside* VPS 2.

## Step 4 — Confirm operation

```bash
sudo systemctl status archforge-status --no-pager
sudo journalctl -u archforge-status -n 80 --no-pager
curl -fsS http://127.0.0.1:3000/healthz
curl -I https://status.archforge.nl
```

Open `https://status.archforge.nl`, and log in at `/admin/login` with the separate admin credentials and TOTP. First-time uptime history starts empty; days without measurements are shown as **Unknown**, not as successful uptime.

If HTTPS is not issuing, verify DNS points to VPS 2, ports 80/443, `sudo systemctl status caddy`, and `sudo journalctl -u caddy -n 80`. The installer does not modify `archforge.nl` or its reverse proxy.

## Operations

```bash
sudo systemctl restart archforge-status
sudo systemctl status archforge-status
sudo journalctl -u archforge-status -f
./update.sh             # run as the ArchForge checkout owner, NOT with sudo
./backup.sh             # invokes sudo
./rollback.sh           # restores previous installed application code
./restore.sh /var/backups/archforge-status/backup-YYYYMMDD-HHMMSS.tar.gz
sudo bash scripts/uninstall.sh
```

`./update.sh` fetches from the configured ArchForge remote using `git pull --ff-only`, confirms the intended deployment, tests the staged release and backs up SQLite before changing the installed application. ArchForge connectivity is required **only for fetching new code**. A primary VPS outage does not affect the running monitoring service.

`./rollback.sh` returns the prior *code* snapshot; it does not reverse database schema migrations. `restore.sh` restores config and database from a manually selected backup (after explicit confirmation). A daily systemd timer performs a SQLite-consistent backup with 14-day local rotation. This retention period is configurable in `scripts/backup.sh`.

## Monitoring targets

Use `TARGET_WEBSITE=https://archforge.nl`. The default public API target is an **optional, separately monitored service**, not a data source required by the monitor. An inaccessible API is reported as an observed failure while VPS 2 remains operational. Leave `TARGET_API_URL=` blank to disable it.

For real public ArchForge HTTPS checking, configure `TARGET_GIT_HTTP_URL` to an existing **public repository** route ending with `/info/refs`. For example: `https://archforge.nl/USER/PUBLIC_REPO.archforge/info/refs` *if that matches your ArchForge-server URL*. The request is read-only and requires a valid ArchForge upload-pack discovery response. Leave empty if your ArchForge HTTPS endpoint is private or unavailable.

ArchForge SSH checks only test TCP plus an SSH protocol banner, **not an authenticated ArchForge push**. DNS resolution only verifies DNS lookups. A successful HTTPS check does not mean all website features work. Internal components without external endpoints must not be labeled independently healthy.

## Configuration

All primary options are documented in `.env.example`. Modify the real file with:

```bash
sudoedit /etc/archforge-status/status.env
sudo systemctl restart archforge-status
```

For SMTP changes, update `/etc/archforge-status/msmtprc` as well (owned by `archforge-status`, mode `600`). The app sends mail using Debian's `msmtp` binary and never relies on VPS 1 SMTP. Discord messages use the standard Discord channel webhook format `https://discord.com/api/webhooks/ID/TOKEN`, NOT an invite URL such as `https://discord.gg/...`.

Monitoring runs once per minute by default (30-second minimum). The last ~400 days of raw samples are retained. Use the Admin Control Center to publish incident progress and announce planned maintenance. Scheduled maintenance **informs visitors**, but cannot execute remote maintenance on VPS 1.

## Independent security model

- The status site listens only on `127.0.0.1:3000`; Caddy handles HTTPS.
- No shared login tokens with ArchForge, no database credentials from the main platform, no remote shell, no arbitrary URL checking from the admin dashboard.
- Public subscriptions are confirmed via email and include unsubscribe links; HTTP forms have CSRF protection and simple rate limits.
- Rate limiting is in-process and resets after a service restart; a network-level reverse-proxy limit is recommended for high-traffic installations.
- Systemd hardening and per-file permissions are used. Keep Debian, Caddy, Node.js and the service patched.
- This is **one external monitor on one VPS**. If VPS 2 or its network goes down, it cannot independently report its own outage. Consider a third-party heartbeat for that later.

## Tests

```bash
node --version  # supported in production: v24 or later
npm test
npm run check
bash -n install.sh scripts/*.sh
```

This is a first release. Run the installer and a controlled failure/recovery test on your VPS before relying on it for production alerts. Never upload real secrets or your SQLite database to ArchForge.
