End-to-end DoH-to-backend wiring for Mac auto-activation: Mac → dns.rebreak.org/dns-query/<token> → nginx → AdGuard → querylog.json (CP field) → watcher.py → POST /handshake → backend - ops/nginx/dns.rebreak.org.conf: vhost with `location ^~ /dns-query` prefix-match (not exact). proxy_pass without trailing slash preserves the full path so AdGuard parses the ClientID natively. - watcher.py: NDJSON tail with inode-based rotation safety, per-token 60s in-memory cooldown, urllib (no external deps), graceful 401/404/5xx - rebreak-handshake-watcher.service: systemd unit, EnvironmentFile with chmod 600 (HANDSHAKE_SECRET never in git), NoNewPrivileges + PrivateTmp - DOH_CLIENTID_HANDSHAKE.md: architecture + flow diagram + risk table - RUNBOOK.md: status/logs/restart commands + deploy ordering Not yet deployed. Verify-checklist before `nginx -s reload`: 1. confirm AdGuard DoH port (config assumes 127.0.0.1:3000) 2. confirm TLS cert exists for dns.rebreak.org 3. snapshot current nginx config 4. `nginx -t` dry-run 5. functional curl + grep CP in querylog before starting watcher
228 lines
5.3 KiB
Markdown
228 lines
5.3 KiB
Markdown
# MDM Server — Operations Runbook
|
|
|
|
## SSH-Zugriff
|
|
|
|
```bash
|
|
ssh rebreak-mdm
|
|
# entspricht: ssh root@178.105.101.137
|
|
```
|
|
|
|
## NanoMDM Container
|
|
|
|
### Status prüfen
|
|
```bash
|
|
ssh rebreak-mdm "docker ps | grep nanomdm"
|
|
ssh rebreak-mdm "cd /opt/nanomdm && docker compose ps"
|
|
```
|
|
|
|
### Logs anschauen
|
|
```bash
|
|
ssh rebreak-mdm "cd /opt/nanomdm && docker compose logs -f"
|
|
# Nur letzte 50 Zeilen:
|
|
ssh rebreak-mdm "cd /opt/nanomdm && docker compose logs --tail=50"
|
|
```
|
|
|
|
### Restart
|
|
```bash
|
|
ssh rebreak-mdm "cd /opt/nanomdm && docker compose restart"
|
|
```
|
|
|
|
### Stop + Start (hard restart)
|
|
```bash
|
|
ssh rebreak-mdm "cd /opt/nanomdm && docker compose down && docker compose up -d"
|
|
```
|
|
|
|
### Auf neue Version updaten
|
|
```bash
|
|
ssh rebreak-mdm "cd /opt/nanomdm && docker compose pull && docker compose up -d"
|
|
```
|
|
|
|
## PostgreSQL
|
|
|
|
### Zugriff auf nanomdm-DB
|
|
```bash
|
|
ssh rebreak-mdm "sudo -u postgres psql nanomdm"
|
|
```
|
|
|
|
### DB-Passwort abrufen
|
|
```bash
|
|
ssh rebreak-mdm "cat /root/.nanomdm_db_pass"
|
|
```
|
|
|
|
### Tabellen-Übersicht
|
|
```bash
|
|
ssh rebreak-mdm "sudo -u postgres psql nanomdm -c '\dt'"
|
|
```
|
|
|
|
### DB-Backup
|
|
```bash
|
|
ssh rebreak-mdm "sudo -u postgres pg_dump nanomdm > /tmp/nanomdm-$(date +%Y%m%d).sql"
|
|
# Lokal kopieren:
|
|
scp rebreak-mdm:/tmp/nanomdm-*.sql ./backups/
|
|
```
|
|
|
|
### DB-Restore (nach Backup)
|
|
```bash
|
|
# Achtung: destructive — nur nach User-Bestätigung
|
|
ssh rebreak-mdm "sudo -u postgres psql nanomdm < /path/to/backup.sql"
|
|
```
|
|
|
|
## nginx
|
|
|
|
### Config testen
|
|
```bash
|
|
ssh rebreak-mdm "nginx -t"
|
|
```
|
|
|
|
### Reload (nach Config-Änderung)
|
|
```bash
|
|
ssh rebreak-mdm "systemctl reload nginx"
|
|
```
|
|
|
|
### Vhost-Config
|
|
```bash
|
|
ssh rebreak-mdm "cat /etc/nginx/sites-available/mdm.rebreak.org"
|
|
```
|
|
|
|
### Logs
|
|
```bash
|
|
ssh rebreak-mdm "tail -f /var/log/nginx/access.log"
|
|
ssh rebreak-mdm "tail -f /var/log/nginx/error.log"
|
|
```
|
|
|
|
## TLS-Zertifikat (Let's Encrypt)
|
|
|
|
### Status prüfen
|
|
```bash
|
|
ssh rebreak-mdm "certbot certificates"
|
|
ssh rebreak-mdm "systemctl status certbot.timer"
|
|
```
|
|
|
|
### Manuelle Renewal (Notfall)
|
|
```bash
|
|
# ACHTUNG: Rate-Limit bei --force-renewal. Nur wenn wirklich nötig.
|
|
# Erst ohne force testen:
|
|
ssh rebreak-mdm "certbot renew --dry-run"
|
|
# Dann renewal:
|
|
ssh rebreak-mdm "certbot renew"
|
|
```
|
|
|
|
### Cert-Expiry prüfen
|
|
```bash
|
|
ssh rebreak-mdm "openssl x509 -in /etc/letsencrypt/live/mdm.rebreak.org/cert.pem -noout -dates"
|
|
```
|
|
|
|
## Apple Push Zertifikat
|
|
|
|
### Expiry prüfen
|
|
```bash
|
|
# Nach Phase D.1 (wenn push.pem vorhanden):
|
|
ssh rebreak-mdm "openssl x509 -in /opt/nanomdm/certs/push.pem -noout -dates"
|
|
```
|
|
|
|
### Jährliche Renewal
|
|
1. CSR-File ist noch da: `/opt/nanomdm/certs/push.csr`
|
|
2. Gleichen CSR auf identity.apple.com hochladen (neues Cert, gleicher Key)
|
|
3. Neues `.pem` auf Server kopieren: `scp ./MDMCertificate.pem rebreak-mdm:/opt/nanomdm/certs/push.pem`
|
|
4. `chmod 600 /opt/nanomdm/certs/push.pem`
|
|
5. `docker compose restart` auf Server
|
|
|
|
### Neues CSR generieren (nur wenn push.key verloren!)
|
|
```bash
|
|
# ACHTUNG: Neuer Key = alle Geräte müssen re-enrollen
|
|
ssh rebreak-mdm "cd /opt/nanomdm/certs && openssl req -newkey rsa:2048 -nodes \
|
|
-keyout push.key -out push.csr \
|
|
-subj '/CN=ReBreak MDM Push/O=Raynis/C=DE' && chmod 600 push.key"
|
|
ssh rebreak-mdm "cat /opt/nanomdm/certs/push.csr"
|
|
```
|
|
|
|
## Externer Health-Check
|
|
|
|
```bash
|
|
# Erwartet: HTTP 404 von nanomdm (normales Verhalten auf /)
|
|
curl -sI https://mdm.rebreak.org/
|
|
# Erwartet: "Bad Request" (MDM-Endpoint ohne gültigen Apple-Payload)
|
|
curl -s https://mdm.rebreak.org/mdm
|
|
```
|
|
|
|
## Firewall (UFW)
|
|
|
|
```bash
|
|
ssh rebreak-mdm "ufw status numbered"
|
|
# Regel hinzufügen (Beispiel SSH von spezifischer IP):
|
|
ssh rebreak-mdm "ufw allow from 1.2.3.4 to any port 22"
|
|
```
|
|
|
|
## System-Ressourcen
|
|
|
|
```bash
|
|
ssh rebreak-mdm "df -h && free -h && docker stats --no-stream"
|
|
```
|
|
|
|
## Handshake-Watcher (DoH ClientID → Backend)
|
|
|
|
### Status prüfen
|
|
```bash
|
|
ssh rebreak-mdm "systemctl status rebreak-handshake-watcher"
|
|
```
|
|
|
|
### Logs live
|
|
```bash
|
|
ssh rebreak-mdm "journalctl -u rebreak-handshake-watcher -f"
|
|
```
|
|
|
|
### Restart
|
|
```bash
|
|
ssh rebreak-mdm "systemctl restart rebreak-handshake-watcher"
|
|
```
|
|
|
|
### EnvironmentFile-Pfad (Secrets, chmod 600)
|
|
```
|
|
/etc/rebreak-handshake-watcher.env
|
|
```
|
|
Inhalt (nie committen, kommt aus Infisical):
|
|
```
|
|
HANDSHAKE_SECRET=<32hex>
|
|
BACKEND_URL=https://staging.rebreak.org
|
|
QUERYLOG_PATH=/opt/adguardhome/data/querylog.json
|
|
```
|
|
|
|
### Watcher-Code deployen (nach Code-Änderung)
|
|
```bash
|
|
scp ops/mdm/adguard-handshake-watcher/watcher.py rebreak-mdm:/opt/rebreak-handshake-watcher/watcher.py
|
|
ssh rebreak-mdm "systemctl restart rebreak-handshake-watcher"
|
|
```
|
|
|
|
### Vollständige Architektur-Doku
|
|
`ops/mdm/DOH_CLIENTID_HANDSHAKE.md`
|
|
|
|
## Troubleshooting
|
|
|
|
### nanomdm startet nicht
|
|
|
|
```bash
|
|
ssh rebreak-mdm "cd /opt/nanomdm && docker compose logs --tail=50"
|
|
```
|
|
|
|
Häufige Ursachen:
|
|
- DB-Verbindung: `postgres://nanomdm:PASS@127.0.0.1:5432/nanomdm` — postgres läuft? `systemctl is-active postgresql@16-main`
|
|
- CA-Cert fehlt: `/opt/nanomdm/certs/ca.crt` vorhanden?
|
|
- .env-File: `cat /opt/nanomdm/.env` — NANOMDM_DB_PASS gesetzt?
|
|
- network_mode host nötig: in docker-compose.yml prüfen
|
|
|
|
### 502 Bad Gateway von nginx
|
|
|
|
Bedeutet nanomdm läuft nicht oder antwortet nicht auf 127.0.0.1:9000.
|
|
|
|
```bash
|
|
ssh rebreak-mdm "curl -sv http://127.0.0.1:9000/"
|
|
ssh rebreak-mdm "cd /opt/nanomdm && docker compose up -d"
|
|
```
|
|
|
|
### Postgres startet nicht
|
|
|
|
```bash
|
|
ssh rebreak-mdm "journalctl -u postgresql@16-main -n 50"
|
|
ssh rebreak-mdm "pg_lsclusters"
|
|
```
|