feat: systemd user service file for headless deployment

Hardened unit with ProtectSystem/ProtectHome, auto-restart on failure,
and ExecReload for SIGHUP hot config reload. Docs updated with setup,
management, and enable-linger instructions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
user
2026-02-21 19:25:36 +01:00
parent 638f12dbb3
commit f4f3132b6b
7 changed files with 104 additions and 5 deletions

View File

@@ -35,13 +35,12 @@
- [x] Client-side TLS (accept TLS from clients)
- [x] Channel key support (JOIN #channel key)
- [x] Hot config reload (SIGHUP)
- [ ] Systemd service file
- [x] Systemd service file
## v0.4.0
- [ ] Per-client backlog tracking (multi-user)
- [ ] Web status page
- [ ] DCC passthrough
- [ ] Containerfile for podman deployment
## v1.0.0

View File

@@ -28,5 +28,5 @@
- [x] P2: Client-side TLS support
- [x] P2: Channel key support
- [x] P2: Hot config reload (SIGHUP + REHASH refactor)
- [ ] P3: Systemd service file
- [x] P3: Systemd service file
- [ ] P3: Containerfile for podman deployment

View File

@@ -3,14 +3,12 @@
## Features
- [ ] Web status dashboard
- [ ] DCC passthrough
- [ ] Per-client backlog tracking (multi-user)
- [ ] Farm: configurable ephemeral deadline
- [ ] Farm: per-network enable/disable override
## Infrastructure
- [ ] Systemd unit file
- [ ] Containerfile for podman deployment
- [ ] PyPI packaging

36
config/bouncer.service Normal file
View File

@@ -0,0 +1,36 @@
[Unit]
Description=IRC bouncer with stealth connect and multi-network multiplexing
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=user
Group=user
ExecStart=%h/git/bouncer/.venv/bin/bouncer -c %h/git/bouncer/config/bouncer.toml
ExecReload=kill -HUP $MAINPID
Restart=on-failure
RestartSec=10
# Logging (stdout/stderr -> journal)
StandardOutput=journal
StandardError=journal
SyslogIdentifier=bouncer
# Hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=tmpfs
BindPaths=%h/git/bouncer
PrivateTmp=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictNamespaces=yes
RestrictRealtime=yes
MemoryDenyWriteExecute=yes
[Install]
WantedBy=default.target

View File

@@ -9,6 +9,18 @@ bouncer --version # version
bouncer --help # help
```
## Systemd
```bash
systemctl --user enable bouncer # enable at boot
systemctl --user start bouncer # start
systemctl --user stop bouncer # stop
systemctl --user restart bouncer # restart
systemctl --user reload bouncer # hot reload (SIGHUP)
systemctl --user status bouncer # status
journalctl --user -u bouncer -f # follow logs
```
## Podman
```bash
@@ -219,6 +231,7 @@ password # optional, IRC server PASS
|------|---------|
| `config/bouncer.toml` | Active config (gitignored) |
| `config/bouncer.example.toml` | Example template |
| `config/bouncer.service` | Systemd user service unit |
| `config/bouncer.db` | SQLite backlog (auto-created) |
| `{data_dir}/bouncer.pem` | Listener TLS cert (auto-created) |
| `{data_dir}/certs/{net}/{nick}.pem` | Client certificates (auto-created) |

View File

@@ -68,6 +68,45 @@ Verify:
which bouncer
```
## Systemd (User Service)
Install and enable the bouncer as a user service (no root required):
```bash
mkdir -p ~/.config/systemd/user
cp config/bouncer.service ~/.config/systemd/user/bouncer.service
```
Edit `ExecStart=` paths if your install differs from the defaults:
```bash
$EDITOR ~/.config/systemd/user/bouncer.service
```
Enable and start:
```bash
systemctl --user daemon-reload
systemctl --user enable bouncer
systemctl --user start bouncer
```
Enable lingering so the service runs without an active login session:
```bash
sudo loginctl enable-linger $USER
```
### Management
```bash
systemctl --user status bouncer # check status
systemctl --user restart bouncer # restart
systemctl --user stop bouncer # stop
journalctl --user -u bouncer -f # follow logs
systemctl --user reload bouncer # hot reload config (SIGHUP)
```
## Dependencies
Installed automatically by `make dev`:

View File

@@ -684,6 +684,20 @@ Results are sent back as NOTICE messages.
| farm_enabled, farm_interval, etc. | Farm started/stopped |
| bind, port, password, client_tls | Warning logged (restart required) |
## Systemd
The bouncer ships with a systemd user service file. See [INSTALL.md](INSTALL.md)
for setup. Key operations:
```bash
systemctl --user start bouncer # start
systemctl --user stop bouncer # stop
systemctl --user reload bouncer # hot reload (SIGHUP)
journalctl --user -u bouncer -f # follow logs
```
The service restarts automatically on failure (`RestartSec=10`).
## Stopping
Press `Ctrl+C` or send `SIGTERM`. The bouncer shuts down gracefully, closing