feat(syslog): set-up help on the page, port 5514 published, Docker-hidden senders called out (#6003)
CI / lint (push) Successful in 2s
CI / unit (push) Successful in 1m29s
CI / integration (push) Successful in 1m38s
CI / publish (push) Successful in 20s

The Syslog page says where to send (this server, its port and protocols) and
where the setting is on Synology, QNAP, TrueNAS, OpenWrt, UniFi and rsyslog,
open until a device sends. A sender whose address is on Steward's own
container network (Swarm ingress publishing hides the real sender) is
flagged, with the host-mode ports to publish instead. compose files and the
Dockerfile publish 5514/udp and /tcp; docs/plugins/syslog.md describes the
plugin and the deploy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 07:01:56 -04:00
co-authored by Claude Opus 5.5
parent 96f774ce24
commit ed9da56efa
10 changed files with 221 additions and 5 deletions
+34 -2
View File
@@ -34,6 +34,38 @@
{% if listener.senders_full %}<p class="tone-warn" style="margin:0.4rem 0 0;">Steward knows {{ listener.max_senders }} senders, the most it keeps; a new one is counted, not offered{% if listener.unoffered %} ({{ "{:,}".format(listener.unoffered) }} line{{ "s" if listener.unoffered != 1 }} so far){% endif %}. Remove ones you don't need.</p>{% endif %}
</section>
{% set hidden_senders = (offered + sources)|selectattr("docker_address")|list %}
{% if hidden_senders %}
<p class="tone-warn" role="status">{{ hidden_senders|map(attribute="address")|unique|join(", ") }} {{ "is" if hidden_senders|map(attribute="address")|unique|list|length == 1 else "are" }} on Steward's own container network: Docker is most likely standing in for the real devices, so they all read as one sender. Publish the port in host mode, as <a href="#syslog-setup">Point a device here</a> shows.</p>
{% endif %}
<details class="card" id="syslog-setup"{% if not sources and not offered %} open{% endif %}>
<summary class="section-title" style="cursor:pointer;">Point a device here</summary>
{% set port = listener.port %}
{% set proto = listener.protocols|join(" or ") or "UDP or TCP" %}
<p style="margin:0.75rem 0 0.5rem;">In the device's remote syslog settings, send to <span class="mono">{{ server }}</span>, port <span class="mono">{{ port }}</span>, {{ proto }}. If the device can't resolve that name, use the server's IP address. Choose the RFC 5424 (IETF) format where it is offered: its lines carry their zone. Once a device sends, it appears above as sending, and Add keeps its lines.</p>
<table class="table" style="width:100%;font-size:0.82rem;">
<thead><tr><th>Device</th><th>Where</th></tr></thead>
<tbody>
<tr><td>Synology (DSM)</td><td>Log Center → Log Sending: send logs to a syslog server, with the server, port, protocol and the IETF format.</td></tr>
<tr><td>QNAP (QTS)</td><td>QuLog Center → Log Sender: add a destination with the server, port, protocol and RFC 5424.</td></tr>
<tr><td>TrueNAS</td><td>System → Advanced Settings → Syslog: the remote syslog server as <span class="mono">{{ server }}:{{ port }}</span>, and its transport.</td></tr>
<tr><td>OpenWrt</td><td>System → System → Logging: the external system log server, its port and protocol.</td></tr>
<tr><td>UniFi</td><td>Network settings, under remote logging (named Activity Logging or SIEM server in newer versions): the server and port.</td></tr>
<tr><td>Linux (rsyslog)</td><td><span class="mono">*.* @{{ server }}:{{ port }}</span> (UDP) or <span class="mono">*.* @@{{ server }}:{{ port }}</span> (TCP) in <span class="mono">/etc/rsyslog.d/90-steward.conf</span>, then restart rsyslog.</td></tr>
</tbody>
</table>
<h3 class="section-title" style="margin:1rem 0 0.4rem;font-size:0.9rem;">Nothing arriving?</h3>
<ul class="field-hint" style="margin:0;padding-left:1.1rem;">
<li>Steward's container must publish port {{ port }}. In Docker Swarm publish it in <strong>host mode</strong>: through Swarm's default ingress every device reaches Steward from one internal address and can't be told apart.</li>
<li>A firewall on the server, or between the device's network and the server's, may drop it.</li>
<li>Ports below 1024, such as syslog's usual 514, can't be opened by Steward. Map 514 to {{ port }} where the port is published, or point devices at {{ port }}.</li>
</ul>
<pre class="mono" style="margin:0.6rem 0 0;font-size:0.78rem;white-space:pre-wrap;">ports:
- { target: {{ port }}, published: {{ port }}, protocol: udp, mode: host }
- { target: {{ port }}, published: {{ port }}, protocol: tcp, mode: host }</pre>
</details>
{% if offered %}
<section class="card" aria-labelledby="syslog-offered">
<h2 id="syslog-offered" class="section-title">Sending, not added</h2>
@@ -43,7 +75,7 @@
<tbody>
{% for s in offered %}
<tr>
<td><span class="mono">{{ s.address }}</span>{% if s.hostname_seen %}<div class="field-hint">calls itself {{ s.hostname_seen }}</div>{% endif %}</td>
<td><span class="mono">{{ s.address }}</span>{% if s.hostname_seen %}<div class="field-hint">calls itself {{ s.hostname_seen }}</div>{% endif %}{% if s.docker_address %}<div class="tone-warn" style="font-size:0.78rem;">Docker's address, not the device's</div>{% endif %}</td>
<td>{{ "{:,}".format(s.lines_total) }}</td>
<td>{{ s.last_seen_at|ago }}</td>
<td class="mono" style="max-width:28rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="{{ s.last_line }}"><span class="{{ tone(s.level) }}">{{ s.severity or "" }}</span> {{ s.last_line or "—" }}</td>
@@ -82,7 +114,7 @@
<tbody>
{% for s in sources %}
<tr>
<td><a href="/plugins/syslog/sources/{{ s.id }}">{{ s.name }}</a><div class="field-hint mono">{{ s.address }}</div></td>
<td><a href="/plugins/syslog/sources/{{ s.id }}">{{ s.name }}</a><div class="field-hint mono">{{ s.address }}</div>{% if s.docker_address %}<div class="tone-warn" style="font-size:0.78rem;">Docker's address, not the device's</div>{% endif %}</td>
<td>{% if s.host %}<a href="/hosts/{{ s.host.id }}">{{ s.host.name }}</a>{% else %}—{% endif %}</td>
<td class="num">{{ "{:,}".format(s.rate or 0) }}</td>
<td>{{ s.last_seen_at|ago }}</td>