Skip to main content
The API reads /etc/kuro/api.toml. Secrets (database URL, encryption key) are in /etc/kuro/api.env, readable by the kuro user only. Everything else is set in the panel: Settings. Every key can be overridden by an environment variable KURO_API_<SECTION>__<KEY>, for example KURO_API_HTTP__BIND=127.0.0.1:9000.

Sections

After a change: sudo systemctl restart kuro-api.

On a node

The daemon reads /etc/kuro/daemon.toml, written at enrollment. Environment variables: KURO_DAEMON_<SECTION>__<KEY>. disk_measure_interval_secs (60 by default, 15 to 3600): seconds between two measurements of server disk usage, for quotas. Each measurement walks every file: on a node with very large worlds, raise it. A write (file, backup, install) triggers its own measurement anyway, and over-quota refusals stay current. After a change: sudo systemctl restart kuro-daemon.

Server outbound traffic

Each server has its own Docker network, isolated from other servers. From that network, however, a game can reach everything the host reaches: its private network, and on a cloud the instance metadata (169.254.169.254). The daemon does not filter this traffic, since that belongs in the host firewall. On a Linux node with rootful Docker, these rules in the DOCKER-USER chain reject traffic from Docker bridges to private ranges, without affecting the Internet, services of the same server, or published ports:
To allow a specific address (a database on the local network, for example), add its accept rule before these rejections:
Make the rules persistent with your distribution’s tool (iptables-persistent, nftables). They apply to every Docker network on the host, not just Kuro’s. With rootless Docker, the host firewall does not see container traffic: these rules belong in the user’s network namespace, which is beyond this guide.

What the panel configures

  • Settings › Project: server resource defaults and caps, audit log retention, opening the MCP server.
  • Settings › DNS: DNS provider zone and token (see DNS).
  • Access: admin accounts and roles.

Multiple API instances

Several kuro-api can run on the same PostgreSQL database, behind a load balancer: zero-downtime deploys, surviving the loss of a machine. Nothing to configure, each instance registers in the database at startup. Good to know:
  • Each instance keeps a dedicated connection for cross-instance notifications: database.max_connections must allow for it (10 by default).
  • Rate limits (http.rate_limit_per_minute) are counted per instance.
  • A server’s live console and stats are only available from the instance its node is connected to; from another, opening the console is refused with a clear message. Commands, files and backups work from any instance.

Probes and request log

  • GET /api/health: liveness, answers 200 as soon as the process runs.
  • GET /api/ready: readiness, 200 when the database answers and the daemon listener accepts connections, 503 otherwise with details (database, daemon_listener). This is the probe a load balancer or monitoring should query.
Every API request produces a request log line: method, path without parameters, status, duration, client address, x-request-id and authenticated actor. The id is also the audit log’s: it links a technical error to the action that caused it. Probes and panel files are only logged at debug (log.filter = "info,kuro_api::http::trace=debug" to see them).