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:

sh
nostrfy --config nostrfy.toml start

=> nostrfy started (pid 12345)

Ou execute em primeiro plano no terminal:

sh
nostrfy --config nostrfy.toml start --foreground

Parar:

sh
nostrfy --config nostrfy.toml stop

Verifique se está no ar:

sh
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):

sh
tail -f nostrfy.log

O 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:

sh
nostrfy stats

Ou via HTTP:

sh
curl http://127.0.0.1:8080/relay/stats

Mostra conexões, eventos aceitos/recusados, tamanho do banco e mais.

Métricas Prometheus

sh
curl http://127.0.0.1:8080/metrics

Recarga a quente (SIGHUP)

Depois de editar o arquivo de configuração, recarregue sem reiniciar:

sh
kill -HUP $(cat nostrfy.pid)
Aplica na recargaExige reinício
Identidade do relay, public_urlprivate_key
a maioria de [limits], reject_ephemeral, enabled_git, enabled_nip78_authapi_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:

toml
[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çãoValorMotivo
ulimit -n / systemd LimitNOFILE≥ 2× as conexões alvo (+1000)cada conexão ocupa um fd
net.core.somaxconn≥ 1024Fila de accept pendente em picos de conexão
net.ipv4.tcp_fin_timeoutbaixo (por exemplo, 10)Libera sockets TIME_WAIT mais rápido
vm.overcommit_memory1 ou 2O 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çãoMotivo
database.disabled_fsync = trueCommit 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 vCPUO caminho EVENT em lote verifica assinaturas em paralelo pelos núcleos
database.search_index = falseRemove 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, authors ou kinds; valores de tags #... usam um orçamento separado de 512 valores. Filtros maiores são recusados (CLOSED invalid: ...).
  • max_connections_per_sec_per_ip rastreia no máximo 10.000 IPs de origem; quando cheio, IPs nunca vistos são recusados (fail closed).
  • ids nos 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 d além do limite de tamanho de chave do LMDB) são ignoradas na indexação; o evento ainda é armazenado.