Перейти к содержимому

What the relay logs and stores

Это содержимое пока не доступно на вашем языке.

The relay is designed so that its logs are not a record of who talks to whom. This page describes what the current server writes and keeps.

  • Message payloads and relay authentication tags.
  • Keys: token keys, key bundles and identity keys.
  • Raw or hex-dumped frames, and debug dumps of protocol messages.
  • HTTP request lines, headers and request paths.

Circuit IDs, client IDs, identity keys and message IDs never appear raw, and no log line carries two identity-derived values. Where a log line needs to tell events apart, it uses an 8-character tag: a keyed BLAKE3 hash of the value, keyed with a random secret generated at each start, truncated to 32 bits. A tag lets a developer follow one circuit within a single run. It cannot be reversed, and it does not match across restarts. Tags appear only at debug and trace.

LevelWhat appears
errorServer-side failures, such as TLS setup failures and certificate expiry. No identifiers, no addresses.
warnOperational faults in fixed wording: ACME problems, queue persistence failures, configuration notices. Client-triggerable faults, such as malformed messages, are logged at debug. No identifiers, no addresses, no client-supplied text.
infoStartup and configuration (version, bind address, TLS mode, limits, the relay’s pin), certificate status, and queue load and save counts when persistence is on. Nothing about any client, circuit or packet.
debugConnection diagnostics in fixed wording: timeouts, decode failures, unknown circuits, failed packet authentication, decoy responses. Client addresses appear only with log_client_ips = true.
tracePer-event flow for development, using tags only. Do not run production at trace: even tags show traffic patterns.

The default level is info, which is safe to send to a log aggregator.

Client IP addresses are not logged by default. To log them for abuse handling:

[logging]
log_client_ips = true # default false

This adds addresses to debug connection lines only, never to info, warn or error. You still need --log-level debug to see them. When it is on, the relay logs a warning at startup: logging.log_client_ips is enabled: client IPs will appear in debug logs. Treat those logs as sensitive and keep retention short.

The relay cannot decrypt messages, but routing requires some knowledge, held in memory only:

  • which accounts are connected, when, and from which IP address, and the public keys each connected account published (proven over its TLS session);
  • which two connections share an open conversation, and the size bucket, timing and direction of each packet between them. Since protocol v3, conversations after the first are matched by a blinded token that changes every 10 minutes and at every reconnect; the relay keeps only a keyed hash of it. While a conversation is open, the relay’s memory still links its two members (each side’s routing entry carries that account’s tag, as before), and anyone watching live sees two accounts pair at the same moment. Once both have been gone about 10 minutes, nothing it keeps names the pair; waiting blind asks name no one; and no token or circuit id links one connection period to the next;
  • on first contact, after a reinstall or key change, and at most once a day per pair as a fallback, which account is trying to reach which, for up to ten minutes; a request waiting for someone who is offline keeps a keyed pair tag until it is delivered, for at most 72 hours;
  • TLS resumption tickets are sealed with keys held in memory only, rotated every 6 hours and never written to disk;
  • for the per-address caps and fair shares, a keyed hash of each connected address, removed when its last connection closes.

Routing state is keyed with hashes that change at every restart. Conversation state is discarded within ten minutes of both people disconnecting (a blinded conversation’s routing record goes sooner: at once when its last member leaves, and within ten minutes after either leaves). None of it is written to the logs. Anyone who operates, seizes or gains root on a running relay can still read the connected accounts, and which of them share open conversations, from memory. Message content stays end-to-end encrypted.

  • The offline queue, in memory by default. Messages and message requests for someone who is offline are filed under the recipient only, keyed by a hash that changes at every restart. The sender’s identity is inside the encrypted payload. Each record holds only the payload, the time it was queued and whether it is a request. Items are deleted once delivered, or after ttl_secs (at most 72 hours, the default; requests at most 72 hours). Nothing is written to disk unless you turn on persistence.
  • Opt-in encrypted persistence. With [server.offline_queue] persist = true, the queue is written encrypted to persist_path, with its key on a memory filesystem that is lost when the machine reboots. See Offline queue.
  • The relay identity key at relay_identity_path, mode 0600.
  • The ACME cache in cache_dir: the ACME account key and the certificate private key, in files with mode 0600.
  • The decoy site, if you rendered one with --render-decoy: ordinary static files with nothing identifying the relay (no WebSocket path, pin, version or project name).

On first start after upgrading to protocol v2, the relay overwrites the old plaintext queue file (message_queues.json, which held sender and recipient identity keys) with zeros and deletes it.

Delivery and read receipts travel end-to-end encrypted, like messages. The relay may still infer that a receipt was sent from its timing.

  • Run at info, or warn.
  • Keep log_client_ips off unless you are handling active abuse.
  • Keep the metrics endpoint on loopback. It carries only aggregate counters, but it has no authentication.
  • Keep journal retention short (journalctl --vacuum-time=7d, or MaxRetentionSec= in journald.conf).
  • If you run a TCP front end, its logs are outside these guarantees. It can record client addresses unless you turn that off.
  • Leave [server.offline_queue] persist off unless you need held messages to survive restarts.