# System Administration — Docker Procedures

## Resource Limits Calculation

Calculate limits based on actual container RSS and host RAM budget:

1. **Measure actual RSS** via `/proc/PID/status` (VmRSS field) or cgroup files
2. **Subtract llama-server's host RAM** (dominant consumer, typically 25-30 GB)
3. **Allocate remaining RAM** to containers with 2x headroom over observed RSS

**Pitfall — `docker stats` hangs in foreground mode:** It's a streaming command. Use `docker stats --no-stream` or `/proc/<pid>/status` VmRSS instead.

**Pitfall — `docker inspect --format '{{.State.Memory}}'` returns empty:** For containers managed by containerd, this field is not populated. Use cgroup files or host PID VmRSS.

### Recommended Limits (64GB RAM, RTX 2080 Ti example)

| Container | Observed RSS | --memory | Rationale |
|-----------|-------------|----------|-----------|
| open-webui | 844 MB | 2g | Python + embeddings. 2.4x headroom |
| nexstream-scraper | 35 MB | 1g | Node.js scraper, bursts during scraping |
| searxng-core | 72 MB | 512m | Python web search. 7x headroom |
| open-terminal | 44 MB | 512m | ttyd terminal server |
| searxng-valkey | 16 MB | 256m | Redis-compatible cache |

## Logging Rotation
Always set: `--log-opt max-size=10m --log-opt max-file=3` (caps each container's logs at 30 MB).

## Restart Policy
Use `--restart unless-stopped` for all containers.

## Secrets in docker-compose
docker-compose.yml may have masked values (`***`). Get actual secrets from `.env` file or running container's env BEFORE removing it.

## Container Recreation
When adding limits to existing containers, stop in dependency order (dependents first), remove containers (volumes preserved), then recreate with new flags.

## Service Binding Hardening (0.0.0.0 → 127.0.0.1)

**Docker containers with `network_mode: host`:** Switch to bridge networking with port mapping. Update internal URLs from `127.0.0.1` to `host.docker.internal` (requires `extra_hosts: - "host.docker.internal:host-gateway"`).

**Systemd services:** Update `ExecStart` to add `--host 127.0.0.1` or `--listen 127.0.0.1:PORT`. Run `sudo systemctl daemon-reload && sudo systemctl restart <service>`.

**Config-file-based services:** Find `listen: :PORT` or `bind: 0.0.0.0:PORT` and change to `listen: 127.0.0.1:PORT`.

**Manually-started processes:** Kill the old PID and re-launch with `--host 127.0.0.1`.

**Verification:** `ss -tlnp | grep 127.0.0.1:PORT` shows the service bound to loopback only.

## Web Service Security Hardening
- Bind non-essential services to `127.0.0.1` or Tailscale IP only
- Open WebUI: disable `ENABLE_CODE_EXECUTION`, set `CORS_ALLOW_ORIGIN` to specific domains
- Nginx: add security headers (X-Frame-Options, X-Content-Type-Options, HSTS, CSP)
- Container vuln scanning: install Trivy and scan images
