echoIRCd/docs/deployment.md

125 lines
4 KiB
Markdown

# Deployment
Running echoIRCd in production. The repo ships ready-to-use units and scripts in
[`deploy/`](../deploy).
## 1. Build a release binary
Always run the **release** build in production — a debug build is unoptimized and
far slower on the CPU-bound paths (TLS crypto, password hashing, cloaking, line
parsing):
```sh
cargo build --release
```
## 2. Pin the binary
Copy the release binary to a **stable path** and run *that*, not `target/`. This
decouples "what's running" from "what you're compiling" — a stray `cargo build`
can never change what a restart would launch:
```sh
mkdir -p bin
cp target/release/echoircd bin/echoircd
```
`bin/` is gitignored. **Deploying an update** is then: build release → copy over
`bin/echoircd` → restart the service.
## 3. Supervise it with systemd
[`deploy/echoircd-dev.service`](../deploy/echoircd-dev.service) runs the pinned
binary, restarts on failure, raises the file-descriptor limit, and starts on boot:
```ini
[Service]
Type=simple
User=youruser
WorkingDirectory=/path/to/echoIRCd
LimitNOFILE=200000
ExecStart=/path/to/echoIRCd/bin/echoircd /path/to/echoIRCd/echoircd.conf
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target
```
Install it (adjust the paths / `User` first):
```sh
sudo cp deploy/echoircd-dev.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now echoircd-dev.service
```
`LimitNOFILE` is what lets the reactor pool reach tens of thousands of
connections — each connection is a file descriptor. `Restart=on-failure` means a
crash self-heals instead of leaving the network down.
## 4. Add a liveness probe
`Restart=on-failure` catches a *crash*, but not a *hang* (a process that's alive
but stopped answering). [`deploy/echoircd-liveness.timer`](../deploy/echoircd-liveness.timer)
runs [`scripts/liveness.sh`](../scripts/liveness.sh) every couple of minutes: it
does a real NICK/USER register round-trip on the plaintext port and restarts the
service if it doesn't get a welcome.
```sh
sudo cp deploy/echoircd-liveness.service deploy/echoircd-liveness.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now echoircd-liveness.timer
```
## 5. Harden the firewall
Add the kernel-layer connection-rate limit (see [anti-abuse](anti-abuse.md)):
```sh
sudo deploy/firewalld-echoircd.sh add
```
For volumetric (SYN/UDP) floods, rely on your upstream provider's scrubbing —
nothing on the host can absorb a saturating flood.
## Behind a reverse proxy / load balancer
If a TCP proxy (HAProxy, nginx stream) sits in front, enable the **PROXY protocol**
so the real client IP is used instead of the proxy's:
```text
proxy = 10.0.0.0/8 # trust the PROXY header from these sources (repeatable)
```
A connection from a trusted proxy must lead with a PROXY (v1 or v2) header. This
applies to the plaintext and TLS client listeners; for browser clients over
WebSocket, use `ws_proxyranges` with `X-Forwarded-For` instead.
## Log shipping
| Setting | Sends the notice/log stream to |
|---------|--------------------------------|
| `syslog = yes` (+ `syslog_target`) | the system logger (`/dev/log` or `host:port`) |
| `log_json = <path>` | a file, as JSON lines (easy to ingest) |
| `chanlog = #snotices` | an in-network channel staff can watch |
The core also surfaces its own health: `slow_command_ms` raises a notice when an
event runs long, and `watchdog_ms` logs if the core is stuck.
## TLS certificates
Point `tls_cert` / `tls_key` at your PEM files (the same pair serves `bind_tls`
and `wss://`). After renewing a certificate, `REHASH` reloads it without dropping
the server. Client-certificate fingerprints are read automatically for SASL
EXTERNAL / CertFP.
## Updating checklist
1. `git pull` && `cargo build --release`
2. `cargo test` (the integration suite spawns the binary and exercises the real
paths)
3. `cp target/release/echoircd bin/echoircd`
4. `sudo systemctl restart echoircd-dev.service`
5. Confirm: `systemctl is-active echoircd-dev.service`, then check a client
connects on the TLS port.