feat(monitor): admin-only latest.log stream at monitor.
Phase 1 of plan/23-monitor.md: a small Go service that tails the Minecraft server's latest.log into an in-memory ring buffer and serves it to an embedded single-page UI (autoscroll, substring/regex filter, level chips). Read-only by construction — /data is mounted :ro, there is no mutating route, and the container holds no credentials. It publishes NO port: caddy's basic_auth vhost is the only way in, which is the point, since the service has no auth of its own and the log carries player IPs, chat and admin commands. Two non-obvious choices, both to avoid prod-only failures: - Polling, not SSE. The chain is host nginx -> caddy -> app, and nginx buffers proxied responses by default, so an EventSource would stall on cochi (whose vhost is an untracked per-host file) and not reproduce locally. Delay was accepted at design time, so polling is strictly better. - The cursor is a sequence number, not a byte offset, and the tailer reopens on inode change or size shrink. itzg rotates latest.log on every server restart, i.e. every deploy — a naive tailer goes silent afterwards while still answering HTTP 200. Verified against rotate, truncate, delete/recreate, partial-line and ring-overflow cases. MONITOR_ENABLED (on|off) gates both layers per host, mirroring FILES_BROWSE. MONITOR_PASSWORD_HASH must be bcrypt AND single-quoted in .env: Compose interpolates $-sequences in .env values, so a bare hash is silently mangled ($2a$14$abc... -> $$2a$$14...) and every login fails with no hint why. Confirmed empirically, and it is the opposite of filestash, which needs $6$. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8507ffd020
commit
fca6747bcc
13 files changed
+1241
-4
No files matched your search
@@ -0,0 +1,31 @@
|
||||
# Monitor (monitor.) — admin-only log stream, basic_auth enforced by caddy.
|
||||
#
|
||||
# Rendered into ulicraft-caddy.conf.tmpl at ${MONITOR_SERVER} by render-nginx.sh,
|
||||
# ONLY when MONITOR_ENABLED=on. With `off` the placeholder collapses to a
|
||||
# comment, so the name has no TLS vhost at all (and needs no cert — drop
|
||||
# `monitor` from LE_SUBDOMAINS on that host).
|
||||
#
|
||||
# proxy_buffering is left at the default ON: the log API is plain polling, not
|
||||
# SSE, precisely so this vhost needs no special treatment. If a future phase
|
||||
# switches to streaming, `proxy_buffering off;` MUST be added here or the stream
|
||||
# stalls on prod only — see plan/23-monitor.md.
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name monitor.${BASE_DOMAIN};
|
||||
|
||||
ssl_certificate ${APP_DIR}/certs/monitor.${BASE_DOMAIN}/cert.pem;
|
||||
ssl_certificate_key ${APP_DIR}/certs/monitor.${BASE_DOMAIN}/key.pem;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# Admin-only surface — keep it out of search engines even though it 401s.
|
||||
add_header X-Robots-Tag "noindex, nofollow" always;
|
||||
|
||||
location / {
|
||||
proxy_pass http://ulicraft_caddy;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ limit_req_zone $binary_remote_addr zone=files_admin:10m rate=6r/m;
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name ${BASE_DOMAIN} www.${BASE_DOMAIN} auth.${BASE_DOMAIN} distribution.${BASE_DOMAIN} avatar.${BASE_DOMAIN} status.${BASE_DOMAIN} upload.${BASE_DOMAIN}${FILES_BROWSE_NAME} generators.${BASE_DOMAIN};
|
||||
server_name ${BASE_DOMAIN} www.${BASE_DOMAIN} auth.${BASE_DOMAIN} distribution.${BASE_DOMAIN} avatar.${BASE_DOMAIN} status.${BASE_DOMAIN} upload.${BASE_DOMAIN}${FILES_BROWSE_NAME}${MONITOR_NAME} generators.${BASE_DOMAIN};
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
@@ -196,6 +196,11 @@ server {
|
||||
# spliced in by render-nginx.sh.
|
||||
${FILES_BROWSE_SERVER}
|
||||
|
||||
# monitor. (admin log stream, basic_auth in caddy) goes here — the whole server
|
||||
# block, or a single comment line when MONITOR_ENABLED=off. Source:
|
||||
# nginx/monitor.server.tmpl, spliced in by render-nginx.sh.
|
||||
${MONITOR_SERVER}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
Reference in new issue
Block a user