summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-16 09:06:42 +0300
committerPaul Buetow <paul@buetow.org>2026-04-16 09:06:42 +0300
commitee8221e6c88640dba31c69c59c19e65a8dc54a3e (patch)
tree5c7f26b74d4a6c785f9d8fdf97d0da6f8138ae70
parent442236f8515e761c1bd97f2cf3fd6b102bdecb64 (diff)
Release 0.5.0: upload client docs for all OSes, host exclusion, Prometheus metrics0.5.0
- docs/upload-client.md: per-OS install instructions (FreeBSD, Linux, OpenBSD) covering script install, token setup, cron/systemd automation, and test runs - README.md: replace long upload section with pointer to docs/upload-client.md - Bump version to 0.5.0 (new features: excluded_hosts, /metrics endpoint, unified upload script with non-root/XDG support) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--README.md193
-rw-r--r--docs/upload-client.md248
-rw-r--r--internal/version/version.go2
3 files changed, 255 insertions, 188 deletions
diff --git a/README.md b/README.md
index 4db2dbc..da7e44e 100644
--- a/README.md
+++ b/README.md
@@ -252,195 +252,14 @@ sudo loginctl enable-linger "$USER"
If there are **no** keys in the auth database, uploads are accepted without **`Authorization`** (useful for local testing only).
-### Manual hourly upload (single host, not config-managed)
+### Manual upload client (all operating systems)
-Use this when the machine is **not** deployed from a Rex/Ansible repo. The unified script is **`scripts/goprecords-upload-client.sh`** (POSIX **`sh`**: Linux, FreeBSD, OpenBSD; runs as root or as a regular user). A copy is also kept in **`contrib/`** for backward compatibility.
+The unified script **`scripts/goprecords-upload-client.sh`** works on
+FreeBSD, Linux, and OpenBSD as root or a regular user. A copy is also kept in
+**`contrib/`** for backward compatibility.
-The script works on all host types:
-
-| Host class | OS | Privilege | Token path |
-|------------|----|-----------|------------|
-| **f0–f3** | FreeBSD | root via `doas` | `/etc/goprecords-upload.token` |
-| **pi0–pi3** | Rocky Linux (aarch64) | root via `sudo` | `/etc/goprecords-upload.token` |
-| **earth** (laptop) | Fedora / Linux | user (no root) | `$XDG_CONFIG_HOME/goprecords-upload-<HOST>/token` |
-| **blowfish**, **fishfinger** | OpenBSD | root (Rex) | deployed by Rex from template |
-
-**SSH vs upload name:** **`GOPRECORDS_HOST`** must stay the **short** stats name (**`f0`**, **`pi2`**, **`earth`**). For **SSH**, use a real host — e.g. **`ssh -p 22 paul@f0.lan.buetow.org`** or **`paul@192.168.1.130`**, not **`f0.lan`** (incomplete / invalid). OpenBSD frontends may use **port 2** in Rex; **f0–f3** and **Pis** use **port 22**.
-
-**Privilege on FreeBSD:** many hosts (e.g. **f0–f3**) ship **`doas`** and no **`sudo`**. Use **`doas`** for install, writing the token, and one-off test runs below; on Linux (Pis) use **`sudo`**.
-
-**Token path (non-root):** when run as a non-root user the script defaults to **`${XDG_CONFIG_HOME:-$HOME/.config}/goprecords-upload-${GOPRECORDS_HOST}/token`** (mode **`600`**). Override with **`GOPRECORDS_TOKEN_FILE`**.
-
-**On each host**
-
-1. Install **`curl`** and **`uptimed`**, and ensure **`uptimed`** is running.
-2. Install the script (path is up to you; **`755`**, owned by **`root`** for system-wide use or **`700`** in `~/.local/bin` for user installs):
-
- **Linux (root)**
-
- ```bash
- sudo install -m 755 scripts/goprecords-upload-client.sh /usr/local/bin/goprecords-upload-client.sh
- ```
-
- **FreeBSD (root)**
-
- ```bash
- doas install -m 755 scripts/goprecords-upload-client.sh /usr/local/bin/goprecords-upload-client.sh
- ```
-
- **Linux (user, e.g. earth)**
-
- ```bash
- install -m 700 scripts/goprecords-upload-client.sh ~/.local/bin/goprecords-upload-client.sh
- ```
-
-3. Create a token on the goprecords server (hostname must match **`GOPRECORDS_HOST`** exactly, e.g. **`f0`**, **`pi2`**, **`earth`**):
-
- ```bash
- kubectl exec -n services deployment/goprecords -- \
- goprecords --create-client-key f0 -stats-dir=/data/stats
- ```
-
-4. Save the printed secret, mode **`600`**:
-
- **Linux / FreeBSD (root)**
-
- ```bash
- # Linux
- umask 077
- sudo sh -c ‘cat > /etc/goprecords-upload.token’
- sudo chmod 600 /etc/goprecords-upload.token
- # FreeBSD
- umask 077
- doas sh -c ‘cat > /etc/goprecords-upload.token’
- doas chmod 600 /etc/goprecords-upload.token
- ```
-
- **Linux (user, e.g. earth)**
-
- ```bash
- mkdir -p ~/.config/goprecords-upload-earth
- umask 077
- cat > ~/.config/goprecords-upload-earth/token
- ```
-
-5. **FreeBSD — hourly cron** (example for **`f0`**; use **`/etc/crontab`** or **`root`**’s crontab). **`curl`** must be on **`PATH`** for cron (often **`/usr/local/bin`**):
-
- ```cron PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
- 0 * * * * root /usr/bin/env GOPRECORDS_HOST=f0 /usr/local/bin/goprecords-upload-client.sh
- ```
-
- Repeat for **`f1`**, **`f2`**, **`f3`**, … with the matching **`GOPRECORDS_HOST`**.
-
-6. **Linux (systemd) — hourly timer, system-wide** (example for **`pi0`**). **`/etc/goprecords-upload.env`** (mode **`644`**, root):
-
- ```ini
- GOPRECORDS_HOST=pi0
- ```
-
- **`/etc/systemd/system/goprecords-upload.service`**:
-
- ```ini
- [Unit]
- Description=Upload uptimed stats to goprecords
-
- [Service]
- Type=oneshot
- EnvironmentFile=/etc/goprecords-upload.env
- Environment=GOPRECORDS_TOKEN_FILE=/etc/goprecords-upload.token
- ExecStart=/usr/local/bin/goprecords-upload-client.sh
- ```
-
- **`/etc/systemd/system/goprecords-upload.timer`**:
-
- **`OnActiveSec`** runs once soon after **`enable --now`**, so the first upload is not delayed until the next full hour (otherwise run **`systemctl start goprecords-upload.service`** manually once).
-
- ```ini
- [Unit]
- Description=Hourly uptimed upload to goprecords
-
- [Timer]
- OnCalendar=hourly
- OnActiveSec=90s
- RandomizedDelaySec=300
- Persistent=true
-
- [Install]
- WantedBy=timers.target
- ```
-
- Then:
-
- ```bash
- sudo systemctl daemon-reload
- sudo systemctl enable --now goprecords-upload.timer
- ```
-
- Use a different **`GOPRECORDS_HOST`** in **`/etc/goprecords-upload.env`** on **`pi1`**, **`pi2`**, **`pi3`**.
-
-7. **Linux (systemd) — hourly timer, user session** (example for **`earth`** laptop). **`~/.config/systemd/user/goprecords-upload-earth.service`**:
-
- ```ini
- [Unit]
- Description=Upload uptimed stats to goprecords
-
- [Service]
- Type=oneshot
- Environment=GOPRECORDS_HOST=earth
- ExecStart=%h/.local/bin/goprecords-upload-client.sh
- ```
-
- **`~/.config/systemd/user/goprecords-upload-earth.timer`**:
-
- ```ini
- [Unit]
- Description=Hourly uptimed upload to goprecords (earth)
-
- [Timer]
- OnCalendar=hourly
- OnActiveSec=90s
- RandomizedDelaySec=300
- Persistent=true
-
- [Install]
- WantedBy=timers.target
- ```
-
- Then (enable lingering so uploads continue without an active login session):
-
- ```bash
- sudo loginctl enable-linger "$USER"
- systemctl --user daemon-reload
- systemctl --user enable --now goprecords-upload-earth.timer
- ```
-
-**Environment (optional)**
-
-| Variable | Default (root) | Default (non-root) |
-|----------|----------------|--------------------|
-| **`GOPRECORDS_HOST`** | (required) | (required) |
-| **`GOPRECORDS_TOKEN_FILE`** | **`/etc/goprecords-upload.token`** | **`$XDG_CONFIG_HOME/goprecords-upload-<HOST>/token`** |
-| **`GOPRECORDS_BASE_URL`** | **`https://goprecords.f3s.buetow.org`** | same |
-
-**Test one run**
-
-**Linux (root)**
-
-```bash
-sudo env GOPRECORDS_HOST=pi0 /usr/local/bin/goprecords-upload-client.sh
-```
-
-**FreeBSD (root)**
-
-```bash
-doas env GOPRECORDS_HOST=f0 /usr/local/bin/goprecords-upload-client.sh
-```
-
-**Linux (user)**
-
-```bash
-GOPRECORDS_HOST=earth ~/.local/bin/goprecords-upload-client.sh
-```
+Full per-OS installation instructions (token setup, cron/systemd automation,
+test runs) are in **[docs/upload-client.md](docs/upload-client.md)**.
## Test
diff --git a/docs/upload-client.md b/docs/upload-client.md
new file mode 100644
index 0000000..943d09d
--- /dev/null
+++ b/docs/upload-client.md
@@ -0,0 +1,248 @@
+# Upload client installation
+
+`scripts/goprecords-upload-client.sh` is a POSIX `sh` script that uploads
+uptimed record files to a running `goprecords` daemon. It works on FreeBSD,
+Linux, and OpenBSD, and runs as root or as a regular user.
+
+A copy is also kept in `contrib/` for backward compatibility.
+
+## Prerequisites
+
+Install `curl` and `uptimed` on every client host and ensure `uptimed` is
+running before setting up uploads.
+
+| OS | Package manager |
+|----|-----------------|
+| FreeBSD | `pkg install curl uptimed` |
+| Rocky Linux / Fedora | `sudo dnf install curl uptimed` |
+| OpenBSD | `pkg_add curl uptimed` |
+
+## Token path
+
+| Privilege | Path |
+|-----------|------|
+| root | `/etc/goprecords-upload.token` (mode `600`) |
+| non-root | `${XDG_CONFIG_HOME:-$HOME/.config}/goprecords-upload-<HOST>/token` (mode `600`) |
+
+Override with `GOPRECORDS_TOKEN_FILE`.
+
+## Environment variables
+
+| Variable | Default (root) | Default (non-root) |
+|----------|----------------|--------------------|
+| `GOPRECORDS_HOST` | **required** | **required** |
+| `GOPRECORDS_TOKEN_FILE` | `/etc/goprecords-upload.token` | `$XDG_CONFIG_HOME/goprecords-upload-<HOST>/token` |
+| `GOPRECORDS_BASE_URL` | `https://goprecords.f3s.buetow.org` | same |
+
+## Step 1 — Issue a token on the server
+
+`HOSTNAME` must match the short stats name used in every upload URL (e.g.
+`f0`, `pi2`, `earth`, `blowfish`).
+
+```bash
+# daemon running in Kubernetes
+kubectl exec -n services deployment/goprecords -- \
+ goprecords --create-client-key HOSTNAME -stats-dir=/data/stats
+
+# daemon running locally
+goprecords --create-client-key HOSTNAME -stats-dir=/var/lib/goprecords/stats
+```
+
+The plaintext token is printed once. Store it only on the client.
+Re-running `--create-client-key` for the same hostname replaces the previous token.
+
+## Step 2 — Install the script
+
+**FreeBSD**
+
+```sh
+doas install -m 755 scripts/goprecords-upload-client.sh \
+ /usr/local/bin/goprecords-upload-client.sh
+```
+
+**Linux (root)**
+
+```sh
+sudo install -m 755 scripts/goprecords-upload-client.sh \
+ /usr/local/bin/goprecords-upload-client.sh
+```
+
+**OpenBSD**
+
+```sh
+doas install -m 755 scripts/goprecords-upload-client.sh \
+ /usr/local/bin/goprecords-upload-client.sh
+```
+
+**Linux (user session, e.g. earth)**
+
+```sh
+install -m 700 scripts/goprecords-upload-client.sh \
+ ~/.local/bin/goprecords-upload-client.sh
+```
+
+## Step 3 — Store the token
+
+**FreeBSD / Linux (root)**
+
+```sh
+# FreeBSD
+umask 077
+echo 'TOKEN' | doas tee /etc/goprecords-upload.token
+doas chmod 600 /etc/goprecords-upload.token
+
+# Linux
+umask 077
+echo 'TOKEN' | sudo tee /etc/goprecords-upload.token
+sudo chmod 600 /etc/goprecords-upload.token
+```
+
+**OpenBSD**
+
+```sh
+umask 077
+echo 'TOKEN' | doas tee /etc/goprecords-upload.token
+doas chmod 600 /etc/goprecords-upload.token
+```
+
+**Linux (user session)**
+
+```sh
+mkdir -p ~/.config/goprecords-upload-earth
+umask 077
+echo 'TOKEN' > ~/.config/goprecords-upload-earth/token
+```
+
+## Step 4 — Automate
+
+### FreeBSD — hourly cron
+
+Add to root's crontab (`crontab -e` as root, or `/etc/crontab`). `curl` must
+be on `PATH` for cron:
+
+```cron
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+0 * * * * root /usr/bin/env GOPRECORDS_HOST=f0 /usr/local/bin/goprecords-upload-client.sh
+```
+
+Repeat with the matching `GOPRECORDS_HOST` value on each host (`f1`, `f2`, `f3`, …).
+
+### Linux (Rocky/Fedora) — hourly systemd timer, system-wide
+
+`/etc/goprecords-upload.env` (mode `644`):
+
+```ini
+GOPRECORDS_HOST=pi0
+```
+
+`/etc/systemd/system/goprecords-upload.service`:
+
+```ini
+[Unit]
+Description=Upload uptimed stats to goprecords
+
+[Service]
+Type=oneshot
+EnvironmentFile=/etc/goprecords-upload.env
+Environment=GOPRECORDS_TOKEN_FILE=/etc/goprecords-upload.token
+ExecStart=/usr/local/bin/goprecords-upload-client.sh
+```
+
+`/etc/systemd/system/goprecords-upload.timer`:
+
+```ini
+[Unit]
+Description=Hourly uptimed upload to goprecords
+
+[Timer]
+OnCalendar=hourly
+OnActiveSec=90s
+RandomizedDelaySec=300
+Persistent=true
+
+[Install]
+WantedBy=timers.target
+```
+
+```sh
+sudo systemctl daemon-reload
+sudo systemctl enable --now goprecords-upload.timer
+```
+
+Use a different `GOPRECORDS_HOST` in `/etc/goprecords-upload.env` on each Pi
+(`pi1`, `pi2`, `pi3`).
+
+### Linux — hourly systemd timer, user session (earth)
+
+`~/.config/systemd/user/goprecords-upload-earth.service`:
+
+```ini
+[Unit]
+Description=Upload uptimed stats to goprecords
+
+[Service]
+Type=oneshot
+Environment=GOPRECORDS_HOST=earth
+ExecStart=%h/.local/bin/goprecords-upload-client.sh
+```
+
+`~/.config/systemd/user/goprecords-upload-earth.timer`:
+
+```ini
+[Unit]
+Description=Hourly uptimed upload to goprecords (earth)
+
+[Timer]
+OnCalendar=hourly
+OnActiveSec=90s
+RandomizedDelaySec=300
+Persistent=true
+
+[Install]
+WantedBy=timers.target
+```
+
+Enable lingering so uploads continue without an active login session:
+
+```sh
+sudo loginctl enable-linger "$USER"
+systemctl --user daemon-reload
+systemctl --user enable --now goprecords-upload-earth.timer
+```
+
+### OpenBSD — daily cron via /etc/daily.local
+
+OpenBSD's `uptimed` only updates its records file once per day, so a daily run
+is sufficient. Add to `/etc/daily.local`:
+
+```sh
+GOPRECORDS_HOST=blowfish /usr/local/bin/goprecords-upload-client.sh
+```
+
+Adjust `GOPRECORDS_HOST` for each OpenBSD host (`fishfinger`, etc.).
+
+## Step 5 — Test one run
+
+**FreeBSD**
+
+```sh
+doas env GOPRECORDS_HOST=f0 /usr/local/bin/goprecords-upload-client.sh
+```
+
+**Linux (root)**
+
+```sh
+sudo env GOPRECORDS_HOST=pi0 /usr/local/bin/goprecords-upload-client.sh
+```
+
+**OpenBSD**
+
+```sh
+doas env GOPRECORDS_HOST=blowfish /usr/local/bin/goprecords-upload-client.sh
+```
+
+**Linux (user session)**
+
+```sh
+GOPRECORDS_HOST=earth ~/.local/bin/goprecords-upload-client.sh
+```
diff --git a/internal/version/version.go b/internal/version/version.go
index 8102711..3328b71 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -1,4 +1,4 @@
package version
// Tag is the application release version.
-const Tag = "0.4.1"
+const Tag = "0.5.0"