Executar o relay
Para o seu relay nostrfy: iniciar e parar, logs e estatísticas, recarga a quente da configuração, várias instâncias e ajuste em grande escala.
Iniciar e parar
Inicie o relay como daemon em segundo plano:
nostrfy --config nostrfy.toml start=> nostrfy started (pid 12345)
Ou execute em primeiro plano no terminal:
nostrfy --config nostrfy.toml start --foregroundParar:
nostrfy --config nostrfy.toml stopVerifique se está no ar:
curl http://127.0.0.1:8080/health=> {"status":"ok"}
Logs e estatísticas
O daemon grava em daemon.log_file. Quando o arquivo ultrapassa max_log_size_bytes é rotacionado automaticamente (nostrfy.log.1, .2…até max_log_files gerações):
tail -f nostrfy.logO nível de log é controlado pela variável de ambiente RUST_LOG (por exemplo, RUST_LOG=debug).
Estatísticas
Estatísticas ao vivo pela CLI:
nostrfy statsOu via HTTP:
curl http://127.0.0.1:8080/relay/statsMostra conexões, eventos aceitos/recusados, tamanho do banco e mais.
Métricas Prometheus
curl http://127.0.0.1:8080/metricsRecarga a quente (SIGHUP)
Depois de editar o arquivo de configuração, recarregue sem reiniciar:
kill -HUP $(cat nostrfy.pid)| Aplica na recarga | Exige reinício |
|---|---|
| Identidade do relay, public_url | private_key |
| a maioria de [limits], reject_ephemeral, enabled_git, enabled_nip78_auth | api_host, metrics_enabled, configurações do LiveKit |
| — | enabled_nips / disabled_nips, server.host / port / ws_paths |
| — | database.* (incluindo search_index), blossom.* |
O log avisa quando uma configuração que exige reinício muda.
Executar várias instâncias
O nostrfy suporta vários relays independentes em um mesmo servidor (portas diferentes). Cada instância precisa do próprio server.port, dos próprios pid_file/log_file/stats_file em [daemon] (valores compartilhados fazem a segunda instância recusar a inicialização com already running),
do próprio database.path, bem como (quando usados) do próprio api_host / blossom.host:
[server]
port = 8080
[database]
path = "/var/lib/nostrfy-a"
[daemon]
pid_file = "/var/run/nostrfy-a.pid"
log_file = "/var/log/nostrfy-a.log"
stats_file = "/var/lib/nostrfy-a/stats.json"
[server]
port = 8081
[database]
path = "/var/lib/nostrfy-b"
[daemon]
pid_file = "/var/run/nostrfy-b.pid"
log_file = "/var/log/nostrfy-b.log"
stats_file = "/var/lib/nostrfy-b/stats.json"Cada instância é gerenciada com sua própria configuração: nostrfy --config /etc/nostrfy/a.toml start e assim por diante.
Implantações em grande escala
O relay foi projetado para escalar a centenas de milhares de conexões em um único host — a entrega ao vivo acorda apenas os assinantes que podem coincidir com um evento, e a memória por conexão é pequena. Para chegar a milhões é preciso ajuste no nível do host:
| Configuração | Valor | Motivo |
|---|---|---|
ulimit -n / systemd LimitNOFILE | ≥ 2× as conexões alvo (+1000) | cada conexão ocupa um fd |
net.core.somaxconn | ≥ 1024 | Fila de accept pendente em picos de conexão |
net.ipv4.tcp_fin_timeout | baixo (por exemplo, 10) | Libera sockets TIME_WAIT mais rápido |
vm.overcommit_memory | 1 ou 2 | O mapa LMDB é uma grande reserva virtual esparsa |
No FreeBSD, os parâmetros correspondentes são kern.maxfiles / kern.maxfilesperproc mais ulimit -n, e kern.ipc.somaxconn substitui net.core.somaxconn. A memória do kernel por conexão é de cerca de 80 KiB e a de espaço do usuário cerca de 10 KiB, então um milhão de conexões exige aproximadamente 90 GiB de memória do kernel e do usuário além do banco.
Taxa de transferência (eventos por segundo)
A gravação de eventos é limitada por dois custos: a verificação de assinatura Schnorr (cerca de 30–50 µs por evento) e o flush síncrono em disco que o escritor LMDB faz após cada lote de commits. Ambos são ajustáveis no arquivo nostrfy.toml:
| Configuração | Motivo |
|---|---|
database.disabled_fsync = true | Commit no cache de páginas do SO (microssegundos); uma queda de energia perde apenas as gravações desde o último flush — comece por aqui |
| Núcleos de CPU ≥ 8 vCPU | O caminho EVENT em lote verifica assinaturas em paralelo pelos núcleos |
database.search_index = false | Remove a gravação do índice de palavras NIP-50 por evento para instâncias com muita escrita |
A verificação paralela de assinaturas valida todas as assinaturas de um lote pendente de uma vez, num pool de threads (máximo 8; lotes com menos de 16 eventos são verificados em linha). As checagens baratas de cada evento continuam vindo primeiro, então o texto de rejeição é idêntico ao caminho sequencial — só o trabalho Schnorr é distribuído entre os núcleos. Uma compilação single-thread permanece sequencial.
Limites fixos contra abuso
Alguns limites rígidos são fixos (não configuráveis) para manter o relay responsivo sob abuso:
- Um filtro carrega no máximo 512 entradas em
ids,authorsoukinds; valores de tags#...usam um orçamento separado de 512 valores. Filtros maiores são recusados (CLOSED invalid: ...). max_connections_per_sec_per_iprastreia no máximo 10.000 IPs de origem; quando cheio, IPs nunca vistos são recusados (fail closed).idsnos filtros podem ser prefixos, mas só coincidem ids completos de 32 bytes e prefixos de comprimento par (entradas ímpares ou vazias são ignoradas tanto no histórico quanto na entrega ao vivo).- Chaves de índice longas demais (valores de tags, palavras do conteúdo, tags
dalém do limite de tamanho de chave do LMDB) são ignoradas na indexação; o evento ainda é armazenado.