Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The Docker Hub repository description is published from `README.md` on each
stable release.

- The support documentation describes the log format, the level abbreviations
and how to read the logs.

### Changed

- The container prints six lines when it starts, instead of twenty-three.

- Nginx request errors now appear in `docker logs`, and Nginx no longer writes
an access log to a file inside the container that nothing rotated.

- A misconfigured `TRUST_PROXY` produces one short warning instead of two long
ones.

### Fixed

- The Books, Now Playing and Backup widgets now show why they failed, such as a
Expand All @@ -20,12 +33,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The last visible row in a Settings group no longer draws a separator under
itself, which showed under Password Protection whenever protection was off.

- The startup banner no longer prints a Web UI address that pointed at the
internal API port and worked for nobody.

### Security

- A Connections tile that cannot reach a service now says so in plain words
instead of printing the address it tried, which put an internal host and port
on the dashboard.

- A failed connection test no longer writes the request path to the log, where
a service that carries its API key in the path would have left it.

## [1.5.2] - 2026-08-09

### Changed
Expand Down
5 changes: 3 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ services:
# - PASSWORD_HASH_MEMORY=64mib
# Set to true to allow widget URLs using private/LAN IP addresses
# - ALLOW_PRIVATE_IPS=true
# Log verbosity: debug, info, warn or error. Settings, General sets this
# too, and that wins once the config has loaded.
# Log verbosity: debug, info, warn or error, where warn and error behave
# the same. Settings, General sets this too, and that wins once the config
# has loaded.
# - LOG_LEVEL=info
# Where the widget folders are read from. Only if you have moved them.
# - WIDGETS_PATH=/usr/share/nginx/html/widgets
Expand Down
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Everything is optional; the defaults are what the container ships with.
| `ICONS_PATH` | `/icons` | Where uploaded icons are written. |
| `WIDGETS_PATH` | `/usr/share/nginx/html/widgets` | Where the widget folders are read from. Point it elsewhere only if you have moved them; a wrong path loads an empty registry, and every widget then reports as unknown. |
| `PORT` | `3000` | The port the API listens on. nginx proxies to it, so changing it means changing `nginx/dashboard.conf` too. |
| `LOG_LEVEL` | `info` | `debug`, `info`, `warn` or `error`. Settings, General also sets this, and that setting wins from the moment the config loads; the variable is what applies during boot and if no setting is stored. |
| `LOG_LEVEL` | `info` | `debug`, `info`, `warn` or `error`, where `warn` and `error` behave the same: both show warnings and errors. Settings, General also sets this, and that setting wins from the moment the config loads; the variable is what applies during boot and if no setting is stored. |
| `APP_VERSION` | the version in `package.json` | What the update check compares against. The release build stamps it, so leave it alone outside a build. |
| `TRUST_PROXY` | unset | Believe `X-Forwarded-Proto`, so a request through a TLS-terminating proxy gets a `Secure` cookie. Only behind a proxy you control. See [security.md](./security.md#https-and-the-session-cookie). |
| `TRUSTED_PROXY` | unset | Where a front proxy sits, so nginx can resolve the real client for rate limiting. See [security.md](./security.md#authentication). |
Expand Down
31 changes: 29 additions & 2 deletions docs/support.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Redact secrets before pasting logs or config.

## Reading the logs

Both Nginx and the API log to the container's stdout:
The API logs to the container's stdout. Nginx logs request errors to stderr and
keeps no access log, so both reach the same place:

```
docker logs <container-name>
Expand All @@ -31,7 +32,33 @@ docker compose logs -f

In Portainer, open the container and use the **Logs** view.

The API logs `key=value` pairs; errors carry an `error=` field.
### What a log line looks like

Every API record is one line:

```
<ISO-8601 UTC timestamp> <LVL> msg=<message> key=value
```

`LVL` is one of `DBG`, `INF`, `WRN`, `ERR` or `AUD`. `AUD` marks a
security-relevant event and is never filtered by the level setting.

A few things worth knowing when reading them:

- Warnings are emitted at both `warn` and `error`, so choosing Errors in
Settings still shows them.
- The startup banner is not a record. It has no timestamp and no level, and it
always prints.
- Secrets are never logged. Values that could carry one, such as the address of
a service that failed a connection test, are reduced to the host.
- Lines from supervisord and Nginx have their own shapes and are not Stackyard
records.

The format is logfmt, so anything shipping to Loki or Grafana parses it with
`| logfmt` and no custom rules.

To change how much is logged, see the `LOG_LEVEL` row in
[architecture.md](architecture.md#environment).

## Common problems

Expand Down
Loading