Added better documentation for fixing my own broken installs, and updated the install script to patch issues
Container image / image (push) Successful in 4m40s

This commit is contained in:
2026-05-15 07:56:13 +00:00
parent ea30dbb895
commit f60b0a0609
4 changed files with 81 additions and 11 deletions
+15
View File
@@ -4,6 +4,21 @@ All notable changes to this project are documented here. The format
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Changed
- **`install.sh` now repairs data-dir permissions on every run.**
Re-running the installer reasserts the canonical ownership
(`quptime:quptime`) and modes across `/etc/quptime/``0750` on
the dir, `0700` on `keys/`, `0600` on `node.yaml`, `cluster.yaml`,
`trust.yaml`, and `keys/private.pem`, `0644` on `keys/public.pem`
and `keys/cert.pem`. Makes the installer the one-step recovery
path when something has tampered with modes (e.g. a stray
`chmod -R`, a backup restore, or an accidental `sudo qu init`
that left files owned by root). Unknown files in the dir are left
alone.
## [v0.1.0] — 2026-05-15 ## [v0.1.0] — 2026-05-15
### Changed ### Changed
+9
View File
@@ -70,6 +70,15 @@ What it does:
`/etc/systemd/system/quptime.service` (hardened — matches the unit `/etc/systemd/system/quptime.service` (hardened — matches the unit
in [systemd.md](deployment/systemd.md)). Enables but does not start in [systemd.md](deployment/systemd.md)). Enables but does not start
the service, so you can configure identity before first boot. the service, so you can configure identity before first boot.
5. Repairs ownership and modes under `/etc/quptime/` to the canonical
layout (`0750` on the dir, `0700` on `keys/`, `0600` on
`node.yaml` / `cluster.yaml` / `trust.yaml` / `keys/private.pem`,
`0644` on `keys/public.pem` / `keys/cert.pem`). This makes the
installer idempotent for permission damage — if something
tightened or loosened modes (a stray `chmod -R`, a misguided
backup restore, an accidental `sudo qu init`), re-running
`install.sh` puts everything back without touching the contents
of those files.
## Build from source ## Build from source
+6 -2
View File
@@ -172,7 +172,9 @@ still see this error, the most likely causes are:
- The data directory is read-only or owned by a different user — the - The data directory is read-only or owned by a different user — the
bootstrap can't write `node.yaml`. Fix permissions on bootstrap can't write `node.yaml`. Fix permissions on
`$QUPTIME_DIR`. `$QUPTIME_DIR`. The fastest fix on a standard install is just to
re-run `install.sh` — it reasserts the canonical ownership and
modes on the whole tree without touching your config.
- Something else removed `node.yaml` mid-run (a config-management - Something else removed `node.yaml` mid-run (a config-management
tool, a misconfigured volume). Re-run `qu serve` and it will tool, a misconfigured volume). Re-run `qu serve` and it will
rebuild from env, or run `qu init` manually with the flags you rebuild from env, or run `qu init` manually with the flags you
@@ -197,7 +199,9 @@ load private key: ...
``` ```
Permissions on `keys/private.pem` are wrong — should be 0600 and owned Permissions on `keys/private.pem` are wrong — should be 0600 and owned
by the daemon user. Fix and restart. by the daemon user. Fix and restart. Re-running `install.sh` on a
standard install is the easiest path: it repairs ownership and modes
on the entire data dir.
## Probes look much slower than expected ## Probes look much slower than expected
+50 -8
View File
@@ -175,20 +175,62 @@ fi
install -d -o "$SERVICE_USER" -g "$SERVICE_GROUP" -m 0750 "$DATA_DIR" install -d -o "$SERVICE_USER" -g "$SERVICE_GROUP" -m 0750 "$DATA_DIR"
# Reassert ownership on the dir's contents. Two cases this catches: # Repair ownership and permissions on the data dir's contents. Catches:
# - re-running the installer over a previous install where the # - re-running the installer over a previous install where the
# service user/group changed # service user/group changed.
# - the operator ran `qu init` or `qu serve` as root once (easy # - the operator ran `qu init` or `qu serve` as root once (easy
# mistake: `sudo qu init` is shorter than the documented # mistake: `sudo qu init` is shorter than the documented
# `sudo -u quptime qu init`). When the daemon runs as root its # `sudo -u quptime qu init`). When the daemon runs as root its
# DataDir() resolves to /etc/quptime, so any files it writes land # DataDir() resolves to /etc/quptime, so any files it writes land
# here owned by root:root mode 0600 — the systemd service then # owned by root:root — the systemd service then fails with
# fails with `open node.yaml: permission denied`. # `open node.yaml: permission denied`.
# chown -R only changes ownership, not perms, so file modes set by # - someone or something (a stray `chmod -R`, a misguided backup
# the daemon (0600 for node.yaml, 0700 for keys/) are preserved. # restore) tightened or loosened modes. Re-running the installer
if [ -n "$(ls -A "$DATA_DIR" 2>/dev/null)" ]; then # should be enough to get back to a working baseline.
# The canonical layout (mirrors the modes the daemon writes itself
# in internal/config and internal/crypto):
# /etc/quptime/ quptime:quptime 0750
# /etc/quptime/keys/ quptime:quptime 0700
# /etc/quptime/node.yaml quptime:quptime 0600
# /etc/quptime/cluster.yaml quptime:quptime 0600
# /etc/quptime/trust.yaml quptime:quptime 0600
# /etc/quptime/keys/private.pem quptime:quptime 0600
# /etc/quptime/keys/public.pem quptime:quptime 0644
# /etc/quptime/keys/cert.pem quptime:quptime 0644
# The runtime dir /var/run/quptime is owned by systemd via
# RuntimeDirectory= and rebuilt at each service start, so we leave it
# alone.
repair_perms() {
# Always reset the top-level dir mode — `install -d` only sets it
# on creation, not on re-run.
chown "$SERVICE_USER:$SERVICE_GROUP" "$DATA_DIR"
chmod 0750 "$DATA_DIR"
# Reassert ownership across the whole tree in one pass.
if [ -n "$(ls -A "$DATA_DIR" 2>/dev/null)" ]; then
chown -R "$SERVICE_USER:$SERVICE_GROUP" "$DATA_DIR" chown -R "$SERVICE_USER:$SERVICE_GROUP" "$DATA_DIR"
fi fi
# keys/ is a directory with its own tighter mode.
if [ -d "$DATA_DIR/keys" ]; then
chmod 0700 "$DATA_DIR/keys"
fi
# Each known file gets its canonical mode if it exists. We don't
# create anything that isn't already there — that's `qu init`'s
# job — and we don't touch unknown files an operator may have
# parked in the dir.
local f
for f in node.yaml cluster.yaml trust.yaml keys/private.pem; do
[ -f "$DATA_DIR/$f" ] && chmod 0600 "$DATA_DIR/$f"
done
for f in keys/public.pem keys/cert.pem; do
[ -f "$DATA_DIR/$f" ] && chmod 0644 "$DATA_DIR/$f"
done
}
repair_perms
echo "> reasserted ownership ($SERVICE_USER:$SERVICE_GROUP) and modes under $DATA_DIR"
echo "> writing $SERVICE_FILE" echo "> writing $SERVICE_FILE"
cat > "$SERVICE_FILE" <<'EOF' cat > "$SERVICE_FILE" <<'EOF'