This commit is contained in:
HueByte
2026-07-17 19:09:56 +00:00
parent dfbe5be317
commit a6bf50c567
73 changed files with 17893 additions and 427 deletions
+144 -3
View File
@@ -247,15 +247,30 @@ export Server__PublicServer=true
<td>Register on the <a href="https://echohub.voidcube.cloud/servers">public directory</a></td>
</tr>
<tr>
<td><code>Server:PublicHost</code></td>
<td><em>(empty)</em></td>
<td>Public hostname for the directory listing (e.g. <code>chat.example.com:5000</code>)</td>
<td><code>Server:PublicHosts</code></td>
<td><code>[]</code></td>
<td>Hostnames advertised to the directory (array, e.g. <code>[&quot;chat.example.com&quot;]</code>). Required when <code>PublicServer</code> is <code>true</code></td>
</tr>
<tr>
<td><code>Server:Tags</code></td>
<td><code>[]</code></td>
<td>Topic tags surfaced in the directory browser (array, e.g. <code>[&quot;community&quot;, &quot;gaming&quot;]</code>)</td>
</tr>
<tr>
<td><code>Server:Admins</code></td>
<td><code>[]</code></td>
<td>Array of admin usernames (e.g. <code>[&quot;alice&quot;, &quot;bob&quot;]</code>)</td>
</tr>
<tr>
<td><code>Server:Registration</code></td>
<td><code>open</code></td>
<td>Registration mode: <code>open</code>, <code>invite</code> (codes via <code>/invite</code>, Admin+), or <code>closed</code></td>
</tr>
<tr>
<td><code>Server:DirectoryClaimPath</code></td>
<td><em>(empty)</em></td>
<td>Overrides where the directory claim token file is stored. Empty = <code>directory-claim.json</code> next to the SQLite database. Treat it as a secret and back it up with the database</td>
</tr>
</tbody>
</table>
<h3 id="uploads">Uploads</h3>
@@ -300,6 +315,76 @@ absent or partial <code>Uploads</code> section keeps the built-in defaults. See
</table>
<p>The server sizes its request-body limits from these values, so raising a limit here is all
that's needed — no separate Kestrel tuning.</p>
<h3 id="spam-protection">Spam Protection</h3>
<p>Per-user flood, duplicate, join, and channel-create limits with auto-mute escalation. Mods and
above are always exempt, and the defaults are lenient enough that a fast typist never trips them.
An absent or partial <code>Spam</code> section keeps these defaults.</p>
<table>
<thead>
<tr>
<th>Key</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Spam:Enabled</code></td>
<td><code>true</code></td>
<td>Master switch for all spam protection</td>
</tr>
<tr>
<td><code>Spam:MaxMessagesPerWindow</code></td>
<td><code>8</code></td>
<td>Max messages per <code>WindowSeconds</code> before a send is rejected</td>
</tr>
<tr>
<td><code>Spam:WindowSeconds</code></td>
<td><code>5</code></td>
<td>Sliding window (seconds) for the message-rate check</td>
</tr>
<tr>
<td><code>Spam:MaxDuplicateMessages</code></td>
<td><code>3</code></td>
<td>Identical messages in a row tolerated before rejection (E2E rooms are exempt — ciphertext differs each time)</td>
</tr>
<tr>
<td><code>Spam:AutoMuteMinutes</code></td>
<td><code>5</code></td>
<td>Auto-mute duration once a user hits the violation threshold. <code>0</code> disables auto-mute (rejections still apply)</td>
</tr>
<tr>
<td><code>Spam:ViolationThreshold</code></td>
<td><code>5</code></td>
<td>Rejected sends within <code>ViolationWindowMinutes</code> that trigger an auto-mute</td>
</tr>
<tr>
<td><code>Spam:ViolationWindowMinutes</code></td>
<td><code>5</code></td>
<td>Window (minutes) over which violations accumulate</td>
</tr>
<tr>
<td><code>Spam:MaxJoinsPerWindow</code></td>
<td><code>25</code></td>
<td>Max first-time channel joins per <code>JoinWindowSeconds</code> — keep this above your public channel count</td>
</tr>
<tr>
<td><code>Spam:JoinWindowSeconds</code></td>
<td><code>30</code></td>
<td>Sliding window (seconds) for the join-rate check</td>
</tr>
<tr>
<td><code>Spam:MaxChannelCreatesPerWindow</code></td>
<td><code>3</code></td>
<td>Max channel creations per <code>ChannelCreateWindowMinutes</code></td>
</tr>
<tr>
<td><code>Spam:ChannelCreateWindowMinutes</code></td>
<td><code>10</code></td>
<td>Window (minutes) for the channel-create check</td>
</tr>
</tbody>
</table>
<h3 id="encryption">Encryption</h3>
<table>
<thead>
@@ -333,6 +418,11 @@ that's needed — no separate Kestrel tuning.</p>
</thead>
<tbody>
<tr>
<td><code>Storage:Path</code></td>
<td><em>(empty)</em></td>
<td>Directory for uploaded file blobs (attachments, avatars). Empty = <code>uploads/</code> in the app directory; the Docker image sets it to <code>/app/data/uploads</code> on the persistent volume</td>
</tr>
<tr>
<td><code>Storage:CleanupIntervalHours</code></td>
<td><code>1</code></td>
<td>How often the cleanup job runs (hours)</td>
@@ -396,6 +486,57 @@ that's needed — no separate Kestrel tuning.</p>
</tr>
</tbody>
</table>
<h3 id="server-logs-room">Server Logs Room</h3>
<p>When enabled, EchoHub auto-creates a read-only system channel and streams log events to it live,
so operators can watch the server from inside the app. Log lines are <strong>never stored as messages</strong>
the rolling Serilog files remain the only persistence, and the room replays recent lines from those
files when someone opens it.</p>
<table>
<thead>
<tr>
<th>Key</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>ServerLogs:Enabled</code></td>
<td><code>true</code></td>
<td>Master switch for the live log room</td>
</tr>
<tr>
<td><code>ServerLogs:RoomName</code></td>
<td><code>server-logs</code></td>
<td>Name of the auto-created channel (reserved — users can't create a channel with this name)</td>
</tr>
<tr>
<td><code>ServerLogs:MinRole</code></td>
<td><code>Mod</code></td>
<td>Minimum server role that can see and join the room (<code>Member</code>, <code>Mod</code>, <code>Admin</code>, <code>Owner</code>)</td>
</tr>
<tr>
<td><code>ServerLogs:MinLevel</code></td>
<td><code>Information</code></td>
<td>Minimum log level streamed to the room (<code>Verbose</code>, <code>Debug</code>, <code>Information</code>, <code>Warning</code>, <code>Error</code>, <code>Fatal</code>) — affects only the room, not the file/console sinks</td>
</tr>
<tr>
<td><code>ServerLogs:BacklogLines</code></td>
<td><code>100</code></td>
<td>Recent log lines replayed from file when someone opens the room</td>
</tr>
<tr>
<td><code>ServerLogs:LogDirectory</code></td>
<td><code>logs</code></td>
<td>Directory holding the rolling log files (must match the Serilog file sink path below)</td>
</tr>
<tr>
<td><code>ServerLogs:LogFilePattern</code></td>
<td><code>echohub-server-*.log</code></td>
<td>Filename glob for the rolling log files inside <code>LogDirectory</code></td>
</tr>
</tbody>
</table>
<h3 id="logging">Logging</h3>
<p>EchoHub uses <a href="https://serilog.net/">Serilog</a> for structured logging — console output + daily rolling files with 14-day retention by default.</p>
<table>