# The observer daemon: watches the configured Quantus chains, keeps the # standings, and serves REST + WebSocket to the site's nginx. # # Runs beside quantus-node on the same host and reads its loopback JSON-RPC, so # it needs no chain data of its own, no credentials for the node, and no route # to anything but Postgres and the telemetry feed. [Unit] Description=blackbeard.observer API (Quantus mining leaderboard) Documentation=https://git.lair.cafe/Quantus-Network/blackbeard.observer After=network-online.target Wants=network-online.target # Not Requires=: the node restarting must not take the site down. The daemon # reconnects on its own and keeps serving what it already knows. After=quantus-node.service [Service] # The binary sends sd_notify(READY=1) after it binds, so systemctl restart # returns when the port is actually accepting rather than when the process # started. Type=notify User=blackbeard Group=blackbeard ExecStart=/usr/local/bin/blackbeard-api --config /etc/blackbeard/config.toml # SIGTERM drains in-flight requests and exits 0. Long-lived WebSockets are what # this bound is for: without it, a deploy would wait for the last browser tab to # close. KillSignal=SIGTERM TimeoutStopSec=20s Restart=always RestartSec=5s # Hardening per architecture/generic.md ยง8. Nothing here is relaxed: the daemon # reads two sockets and one config file and writes nothing to disk. NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true PrivateDevices=true ProtectKernelTunables=true ProtectKernelModules=true ProtectControlGroups=true RestrictRealtime=true RestrictSUIDSGID=true LockPersonality=true MemoryDenyWriteExecute=true SystemCallArchitectures=native RestrictNamespaces=true ProtectClock=true ProtectHostname=true ProtectProc=invisible # ProtectSystem=strict makes everything read-only; the daemon keeps no state on # disk, so it needs no ReadWritePaths at all. If one is ever added here, ask # first what state left the database. RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 [Install] WantedBy=multi-user.target