1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
# umbrella
A safety-critical game server admin daemon written in C11. Monitors
multiple server processes via log file tailing, RCON, and A2S probing,
and exposes a Unix socket for CLI clients to attach, send commands, and
receive real-time output.
Comes with two clients: `umbrella-cli` (terminal) and `umbrella-bot`
(Matrix room bridge).
## Features
- Live log tailing via inotify with symlink resolution
- Pluggable per-unit output filters (any stdin→stdout executable)
- RCON command dispatch (Valve protocol)
- A2S health probing (Valve UDP)
- systemd unit state queries over D-Bus
- Ring buffer — 500 lines × 1024 bytes per unit, replayed on attach
- Reload without restart via SIGHUP
## Build
```bash
# Dependencies: libyaml-dev, libsystemd-dev
make
sudo make install
```
Compiler flags: `-Wall -Wextra -Wpedantic -std=c11 -D_GNU_SOURCE -O2`
## Install layout
| Path | Purpose |
|------|---------|
| `/usr/local/sbin/umbrella` | Daemon |
| `/usr/local/bin/umbrella-cli` | CLI client |
| `/etc/umbrella/umbrella.conf` | Daemon config |
| `/etc/umbrella/units/*.yaml` | Unit descriptors |
| `/usr/lib/umbrella/filters/` | Bundled log filters |
| `/run/umbrella/umbrella.sock` | Unix socket |
| `/run/umbrella/umbrella.pid` | PID file |
| `/var/log/umbrella/umbrella.log` | Daemon log |
## Unit descriptor format
```yaml
name: tf2 # used in CLI commands
display: "TF2 — novemen"
service: tf2-server.service # systemd unit for state queries
console:
type: rcon # rcon | stdin
host: 127.0.0.1
port: 27015
password_env: TF_RCON_PASSWORD # or: password: plaintext
health:
type: a2s # a2s | tcp | none
host: 127.0.0.1
port: 27015
timeout_ms: 5000
logs:
- /path/to/logs/current.log # up to 4 paths; symlinks resolved
# Optional filter — any executable reading stdin, writing stdout
log_filter: /usr/lib/umbrella/filters/source.py
broadcast_cmd: "say {msg}" # template for !broadcast
actions:
update: /path/to/update.sh
restart: /usr/bin/systemctl restart tf2-server.service
```
## Bundled filters
| Filter | Targets |
|--------|---------|
| `source.py` | TF2, GMod, CS2 — strips `server_cvar`/stuck spam, strips timestamp prefix |
| `minecraft.py` | vanilla/Paper/Spigot — strips keepAlive/autosave noise, strips `[HH:MM:SS] [thread]` prefix |
| `terraria.py` | vanilla/tModLoader — strips blank lines and mod-loading spam |
Custom filters: any executable at any path that reads stdin and flushes
stdout after each write works. Python, shell, compiled binary — anything.
## Log file setup
srcds and most dedicated servers create new log files per session.
Point `logs:` at a stable symlink and update it on each server start:
```bash
# In your startup script / ExecStartPre:
ln -sf /srv/game/logs/L0222000.log /srv/game/logs/current.log
# Then SIGHUP umbrella so it re-resolves the symlink:
kill -HUP $(cat /run/umbrella/umbrella.pid)
```
With `sv_log_onefile 1` (Source engine), the log file is fixed for the
server's lifetime, so the symlink only needs updating on restarts.
## CLI usage
```bash
umbrella-cli list
umbrella-cli status <unit>
umbrella-cli attach <unit> # live output; Ctrl+D to detach
umbrella-cli tail <unit> # dump ring buffer and exit
umbrella-cli input <unit> <cmd> # send RCON command or stdin line
umbrella-cli action <unit> <name> # run a named action script
umbrella-cli broadcast <message> # send to all units' broadcast_cmd
```
## Matrix bot
`umbrella-bot` bridges a Matrix room to umbrella units. Requires a
dedicated Matrix account and a room the bot is invited to.
### Dependencies
```bash
pip install matrix-nio[e2e] aiofiles markdown
```
### Setup
```bash
# 1. Copy and edit the config (chmod 600 — contains bot password)
sudo cp clients/umbrella-bot/bot.conf.example /etc/umbrella/bot.conf
sudo chmod 600 /etc/umbrella/bot.conf
# 2. First-run login — prints the device ID to add to bot.conf
python3 clients/umbrella-bot/umbrella-bot.py --setup
# 3. Run normally (or via systemd)
python3 clients/umbrella-bot/umbrella-bot.py
```
A systemd unit is provided at `clients/umbrella-bot/umbrella-bot.service`.
### Bot commands
Users require power level >= 50 in the room.
| Command | Description |
|---------|-------------|
| `!units` | List all units with state and player counts |
| `!status <unit>` | Show unit state, players, and map |
| `!tail <unit>` | Dump the last 30 lines of buffered output |
| `!cmd <unit> <command>` | Send a console command (logged to audit log) |
| `!broadcast <message>` | Send message to all running units |
| `!restart <unit>` | Run the restart action |
| `!update <unit>` | Run the update action |
| `!action <unit> <action>` | Run a named action |
| `!help` | Show command list |
### Config paths
| Path | Purpose |
|------|---------|
| `/etc/umbrella/bot.conf` | Bot credentials and room ID |
| `/etc/umbrella/bot-store/` | E2E encryption key store (SQLite) |
| `/var/log/umbrella/bot-audit.log` | Audit log of all `!cmd` invocations |
## Reload
```bash
kill -HUP $(cat /run/umbrella/umbrella.pid)
```
Reloads unit YAML files, restarts log tails and filter subprocesses.
Running processes are not touched.
|