7 Commits
Author SHA1 Message Date
raucao 9c04b393ec Merge pull request 'Upgrade strfry to 1.1.1' (#1) from chore/upgrade_strfry into master
Reviewed-on: #1
2026-08-07 14:23:46 +00:00
raucao cb11817dcd Upgrade strfry to 1.1.1
Remove obsolete dependencies, introduce new config attributes, improve
comments for existing config
2026-08-07 08:21:57 -06:00
raucao 2c6e64d231 Don't dump all incoming messages by default 2025-06-01 20:05:21 +04:00
raucao 5f661d7304 Make all config values configurable
And use a standard scheme for variable/key naming
2025-06-01 19:57:04 +04:00
raucao 8df7c00a14 Add relay icon 2024-10-16 12:42:03 +02:00
raucao 1f34459091 Upgrade strfry to 1.0.1 2024-10-16 12:41:51 +02:00
raucao a4756377b4 Add stryfry policy option 2024-06-11 22:55:51 +02:00
6 changed files with 130 additions and 62 deletions
+16 -5
View File
@@ -1,10 +1,21 @@
node.default["strfry"]["repo"] = "https://github.com/hoytech/strfry.git" node.default["strfry"]["repo"] = "https://github.com/hoytech/strfry.git"
node.default["strfry"]["revision"] = "master" node.default["strfry"]["revision"] = "1.1.1"
node.default["strfry"]["download_url"] = nil node.default["strfry"]["download_url"] = nil
node.default["strfry"]["checksum"] = nil node.default["strfry"]["checksum"] = nil
node.default["strfry"]["user"] = "strfry" node.default["strfry"]["user"] = "strfry"
node.default["strfry"]["group"] = "strfry" node.default["strfry"]["group"] = "strfry"
node.default["strfry"]["db_path"] = "/var/lib/strfry" node.default["strfry"]["config"] = {
node.default["strfry"]["bind_ip"] = "0.0.0.0" db: "/var/lib/strfry"
node.default["strfry"]["real_ip_header"] = "" # db_params: {},
node.default["strfry"]["info"] = {} # events: {},
# relay: {
# auth: {},
# info: {},
# write_policy: {},
# compression: {},
# logging: {},
# num_threads: {},
# negentropy: {},
# filter_validation: {}
# }
}
+8
View File
@@ -35,3 +35,11 @@ suites:
verifier: verifier:
inspec_tests: inspec_tests:
- test/integration/default - test/integration/default
attributes:
strfry:
config:
relay:
bind: 0.0.0.0
port: 7778
info:
name: "Test relay"
+1 -1
View File
@@ -3,7 +3,7 @@ maintainer 'Kosmos'
maintainer_email 'ops@kosmos.org' maintainer_email 'ops@kosmos.org'
license 'MIT' license 'MIT'
description 'Installs/configures strfry' description 'Installs/configures strfry'
version '0.1.0' version '0.2.0'
chef_version '>= 18.0' chef_version '>= 18.0'
issues_url 'https://gitea.kosmos.org/kosmos/strfry-cookbook/issues' issues_url 'https://gitea.kosmos.org/kosmos/strfry-cookbook/issues'
source_url 'https://gitea.kosmos.org/kosmos/strfry-cookbook' source_url 'https://gitea.kosmos.org/kosmos/strfry-cookbook'
+7 -15
View File
@@ -23,9 +23,8 @@ else
# Install by building from source # Install by building from source
# #
%w[ %w[
git build-essential libyaml-perl libtemplate-perl libregexp-grammars-perl git build-essential libssl-dev zlib1g-dev liblmdb-dev libflatbuffers-dev
libssl-dev zlib1g-dev liblmdb-dev libflatbuffers-dev libsecp256k1-dev libsecp256k1-dev libzstd-dev
libzstd-dev
].each do |pkg| ].each do |pkg|
package pkg package pkg
end end
@@ -55,11 +54,11 @@ group node["strfry"]["group"]
user node["strfry"]["user"] do user node["strfry"]["user"] do
gid node["strfry"]["group"] gid node["strfry"]["group"]
manage_home false manage_home true
shell "/usr/sbin/nologin" shell "/bin/bash"
end end
directory node["strfry"]["db_path"] do directory node["strfry"]["config"]["db"] do
owner node["strfry"]["user"] owner node["strfry"]["user"]
group node["strfry"]["group"] group node["strfry"]["group"]
mode "0755" mode "0755"
@@ -70,14 +69,7 @@ template "/etc/strfry.conf" do
mode "0644" mode "0644"
owner node["strfry"]["user"] owner node["strfry"]["user"]
group node["strfry"]["group"] group node["strfry"]["group"]
variables config: { variables config: node["strfry"]["config"]
db_path: node["strfry"]["db_path"],
bind: node["strfry"]["bind_ip"],
real_ip_header: node["strfry"]["real_ip_header"],
port: node["strfry"]["port"],
nofiles: node["strfry"]["nofiles"],
info: node["strfry"]["info"]
}
notifies :restart, "service[strfry]", :delayed notifies :restart, "service[strfry]", :delayed
end end
@@ -97,7 +89,7 @@ systemd_unit "strfry.service" do
ExecStart: "/usr/local/bin/strfry relay", ExecStart: "/usr/local/bin/strfry relay",
Restart: "on-failure", Restart: "on-failure",
RestartSec: "5", RestartSec: "5",
ProtectHome: "yes", ProtectHome: "no",
NoNewPrivileges: "yes", NoNewPrivileges: "yes",
ProtectSystem: "full", ProtectSystem: "full",
LimitCORE: "1000000000" LimitCORE: "1000000000"
+96 -40
View File
@@ -1,134 +1,190 @@
# Directory that contains the strfry LMDB database (restart required) # Directory that contains the strfry LMDB database (restart required)
db = "<%= @config[:db_path] %>/" db = "<%= @config.dig(:db) || "" %>/"
dbParams { dbParams {
# Maximum number of threads/processes that can simultaneously have LMDB transactions open (restart required) # Maximum number of threads/processes that can simultaneously have LMDB transactions open (restart required)
maxreaders = 256 maxreaders = <%= @config.dig(:db_params, :maxreaders) || "256" %>
# Size of mmap() to use when loading LMDB (default is 10TB, does *not* correspond to disk-space used) (restart required) # Size of mmap() to use when loading LMDB (default is 10TB, does *not* correspond to disk-space used) (restart required)
mapsize = 10995116277760 mapsize = <%= @config.dig(:db_params, :mapsize) || "10995116277760" %>
# Disables read-ahead when accessing the LMDB mapping. Reduces IO activity when DB size is larger than RAM. (restart required) # Disables read-ahead when accessing the LMDB mapping. Reduces IO activity when DB size is larger than RAM. (restart required)
noReadAhead = false noReadAhead = <%= @config.dig(:db_params, :no_read_ahead) || "false" %>
} }
events { events {
# Maximum size of normalised JSON, in bytes # Maximum size of normalised JSON, in bytes
maxEventSize = 65536 maxEventSize = <%= @config.dig(:events, :max_event_size) || "65536" %>
# Events newer than this will be rejected # Events newer than this will be rejected
rejectEventsNewerThanSeconds = 900 rejectEventsNewerThanSeconds = <%= @config.dig(:events, :reject_events_newer_than_seconds) || "900" %>
# Events older than this will be rejected # Events older than this will be rejected
rejectEventsOlderThanSeconds = 94608000 rejectEventsOlderThanSeconds = <%= @config.dig(:events, :reject_events_older_than_seconds) || "94608000" %>
# Ephemeral events older than this will be rejected # Ephemeral events older than this will be rejected
rejectEphemeralEventsOlderThanSeconds = 60 rejectEphemeralEventsOlderThanSeconds = <%= @config.dig(:events, :reject_ephemeral_events_older_than_seconds) || "60" %>
# Ephemeral events will be deleted from the DB when older than this # Ephemeral events will be deleted from the DB when older than this
ephemeralEventsLifetimeSeconds = 300 ephemeralEventsLifetimeSeconds = <%= @config.dig(:events, :ephemeral_events_lifetime_seconds) || "300" %>
# Maximum number of tags allowed # Maximum number of tags allowed
maxNumTags = 2000 maxNumTags = <%= @config.dig(:events, :max_num_tags) || "2000" %>
# Maximum size for tag values, in bytes # Maximum size for tag values, in bytes
maxTagValSize = 1024 maxTagValSize = <%= @config.dig(:events, :max_tag_val_size) || "1024" %>
} }
relay { relay {
# Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required) # Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required)
bind = "<%= @config[:bind] || "127.0.0.1" %>" bind = "<%= @config.dig(:relay, :bind) || "127.0.0.1" %>"
# Port to open for the nostr websocket protocol (restart required) # Port to open for the nostr websocket protocol (restart required)
port = <%= @config[:port] || "7777" %> port = <%= @config.dig(:relay, :port) || "7777" %>
# Set OS-limit on maximum number of open files/sockets (if 0, don't attempt to set) (restart required) # Set OS-limit on maximum number of open files/sockets (if 0, don't attempt to set) (restart required)
nofiles = <%= @config[:nofiles] || "524288" %> nofiles = <%= @config.dig(:relay, :nofiles) || "524288" %>
# HTTP header that contains the client's real IP, before reverse proxying (ie x-real-ip) (MUST be all lower-case) # HTTP header that contains the client's real IP, before reverse proxying (ie x-real-ip) (MUST be all lower-case)
realIpHeader = "<%= @config[:real_ip_header] %>" realIpHeader = "<%= @config.dig(:relay, :real_ip_header) || "" %>"
auth {
# Enable NIP-42 authentication
enabled = <%= @config.dig(:relay, :auth, :enabled) || "false" %>
# External relay URL (beginning with wss://). Required in order to validate challenge responses.
serviceUrl = "<%= @config.dig(:relay, :auth, :service_url) || "" %>"
}
# NIP-11
info { info {
# NIP-11: Name of this server. Short/descriptive (< 30 characters) # NIP-11: Name of this server. Short/descriptive (< 30 characters)
name = "<%= @config[:info][:name] || "strfry default" %>" name = "<%= @config.dig(:relay, :info, :name) || "strfry default" %>"
# NIP-11: Detailed information about relay, free-form # NIP-11: Detailed information about relay, free-form
description = "<%= @config[:info][:description] || "This is a strfry instance." %>" description = "<%= @config.dig(:relay, :info, :description) || "This is a strfry instance." %>"
# NIP-11: Administrative nostr pubkey, for contact purposes # NIP-11: Administrative nostr pubkey (in npub or 32-byte HEX format), for contact purposes
pubkey = "<%= @config[:info][:pubkey] || "" %>" pubkey = "<%= @config.dig(:relay, :info, :pubkey) || "" %>"
# NIP-11: Relay's own pubkey (in npub or 32-byte HEX format)
self = "<%= @config.dig(:relay, :info, :self) || "" %>"
# NIP-11: Alternative administrative contact (email, website, etc) # NIP-11: Alternative administrative contact (email, website, etc)
contact = "<%= @config[:info][:contact] || "" %>" contact = "<%= @config.dig(:relay, :info, :contact) || "" %>"
# NIP-11: URL pointing to an image to be used as an icon for the relay
icon = "<%= @config.dig(:relay, :info, :icon) || "" %>"
# NIP-11: URL pointing to an image to be used as an banner for the relay
banner = "<%= @config.dig(:relay, :info, :banner) || "" %>"
# NIP-11: Privacy policy URL
privacy = "<%= @config.dig(:relay, :info, :privacy) || "" %>"
# NIP-11: Terms of service URL
terms = "<%= @config.dig(:relay, :info, :terms) || "" %>"
# List of supported lists as JSON array, or empty string to use default. Example: "[1,2]"
nips = "<%= @config.dig(:relay, :info, :nips) || "" %>"
} }
# Maximum accepted incoming websocket frame size (should be larger than max event) (restart required) # Maximum accepted incoming websocket frame size (should be larger than max event) (restart required)
maxWebsocketPayloadSize = 131072 maxWebsocketPayloadSize = <%= @config.dig(:relay, :max_websocket_payload_size) || "131072" %>
# Maximum number of filters allowed in a REQ
maxReqFilterSize = <%= @config.dig(:relay, :max_req_filter_size) || "200" %>
# Websocket-level PING message frequency (should be less than any reverse proxy idle timeouts) (restart required) # Websocket-level PING message frequency (should be less than any reverse proxy idle timeouts) (restart required)
autoPingSeconds = 55 autoPingSeconds = <%= @config.dig(:relay, :auto_ping_seconds) || "55" %>
# If TCP keep-alive should be enabled (detect dropped connections to upstream reverse proxy) # If TCP keep-alive should be enabled (detect dropped connections to upstream reverse proxy)
enableTcpKeepalive = false enableTcpKeepalive = <%= @config.dig(:relay, :enable_tcp_keepalive) || "false" %>
# How much uninterrupted CPU time a REQ query should get during its DB scan # How much uninterrupted CPU time a REQ query should get during its DB scan
queryTimesliceBudgetMicroseconds = 10000 queryTimesliceBudgetMicroseconds = <%= @config.dig(:relay, :query_timeslice_budget_microseconds) || "10000" %>
# Maximum records that can be returned per filter # Maximum records that can be returned per filter
maxFilterLimit = 500 maxFilterLimit = <%= @config.dig(:relay, :max_filter_limit) || "500" %>
# Maximum records that can be counted by a COUNT request (set 0 to disable COUNT)
maxFilterLimitCount = <%= @config.dig(:relay, :max_filter_limit_count) || "1000000" %>
# Maximum number of subscriptions (concurrent REQs) a connection can have open at any time # Maximum number of subscriptions (concurrent REQs) a connection can have open at any time
maxSubsPerConnection = 20 maxSubsPerConnection = <%= @config.dig(:relay, :max_subs_per_connection) || "200" %>
writePolicy { writePolicy {
# If non-empty, path to an executable script that implements the writePolicy plugin logic # If non-empty, path to an executable script that implements the writePolicy plugin logic
plugin = "" plugin = "<%= @config.dig(:relay, :write_policy, :plugin) || "" %>"
# Number of seconds to wait for a plugin to respond
timeoutSeconds = <%= @config.dig(:relay, :write_policy, :timeout_seconds) || "10" %>
} }
compression { compression {
# Use permessage-deflate compression if supported by client. Reduces bandwidth, but slight increase in CPU (restart required) # Use permessage-deflate compression if supported by client. Reduces bandwidth, but slight increase in CPU (restart required)
enabled = true enabled = <%= @config.dig(:relay, :compression, :enabled) || "true" %>
# Maintain a sliding window buffer for each connection. Improves compression, but uses more memory (restart required) # Maintain a sliding window buffer for each connection. Improves compression, but uses more memory (restart required)
slidingWindow = true slidingWindow = <%= @config.dig(:relay, :compression, :sliding_window) || "true" %>
} }
logging { logging {
# Dump all incoming messages # Dump all incoming messages
dumpInAll = false dumpInAll = <%= @config.dig(:relay, :logging, :dump_in_all) || "false" %>
# Dump all incoming EVENT messages # Dump all incoming EVENT messages
dumpInEvents = false dumpInEvents = <%= @config.dig(:relay, :logging, :dump_in_events) || "false" %>
# Dump all incoming REQ/CLOSE messages # Dump all incoming REQ/CLOSE messages
dumpInReqs = false dumpInReqs = <%= @config.dig(:relay, :logging, :dump_in_reqs) || "false" %>
# Log performance metrics for initial REQ database scans # Log performance metrics for initial REQ database scans
dbScanPerf = false dbScanPerf = <%= @config.dig(:relay, :logging, :db_scan_perf) || "false" %>
# Log reason for invalid event rejection? Can be disabled to silence excessive logging # Log reason for invalid event rejection? Can be disabled to silence excessive logging
invalidEvents = true invalidEvents = <%= @config.dig(:relay, :logging, :invalid_events) || "true" %>
} }
numThreads { numThreads {
# Ingester threads: route incoming requests, validate events/sigs (restart required) # Ingester threads: route incoming requests, validate events/sigs (restart required)
ingester = 3 ingester = <%= @config.dig(:relay, :num_threads, :ingester) || "3" %>
# reqWorker threads: Handle initial DB scan for events (restart required) # reqWorker threads: Handle initial DB scan for events (restart required)
reqWorker = 3 reqWorker = <%= @config.dig(:relay, :num_threads, :req_worker) || "3" %>
# reqMonitor threads: Handle filtering of new events (restart required) # reqMonitor threads: Handle filtering of new events (restart required)
reqMonitor = 3 reqMonitor = <%= @config.dig(:relay, :num_threads, :req_monitor) || "3" %>
# negentropy threads: Handle negentropy protocol messages (restart required) # negentropy threads: Handle negentropy protocol messages (restart required)
negentropy = 2 negentropy = <%= @config.dig(:relay, :num_threads, :negentropy) || "2" %>
} }
negentropy { negentropy {
# Support negentropy protocol messages # Support negentropy protocol messages
enabled = true enabled = <%= @config.dig(:relay, :negentropy, :enabled) || "true" %>
# Maximum records that sync will process before returning an error # Maximum records that sync will process before returning an error
maxSyncEvents = 1000000 maxSyncEvents = <%= @config.dig(:relay, :negentropy, :max_sync_events) || "1000000" %>
}
filterValidation {
# Enable strict filter validation for REQ messages
enabled = <%= @config.dig(:relay, :filter_validation, :enabled) || "false" %>
# Maximum number of filters allowed per REQ (when validation enabled)
maxFiltersPerReq = <%= @config.dig(:relay, :filter_validation, :max_filters_per_req) || "3" %>
# Minimum number of filters required per REQ (when validation enabled)
minFiltersPerReq = <%= @config.dig(:relay, :filter_validation, :min_filters_per_req) || "1" %>
# Maximum number of kinds allowed per filter (when validation enabled)
maxKindsPerFilter = <%= @config.dig(:relay, :filter_validation, :max_kinds_per_filter) || "3" %>
# Comma-separated list of allowed kinds (empty = all allowed)
allowedKinds = "<%= @config.dig(:relay, :filter_validation, :allowed_kinds) || "" %>"
# Require at least one author, p tag, or e tag in each filter
requireAuthorOrTag = <%= @config.dig(:relay, :filter_validation, :require_author_or_tag) || "false" %>
} }
} }
+2 -1
View File
@@ -18,13 +18,14 @@ end
describe file('/etc/strfry.conf') do describe file('/etc/strfry.conf') do
it { should exist } it { should exist }
its('content') { should match(/name\s*=\s*"Test relay"/m) }
end end
describe file('/var/lib/strfry') do describe file('/var/lib/strfry') do
it { should be_directory } it { should be_directory }
end end
describe port(7777) do describe port(7778) do
it { should be_listening } it { should be_listening }
its('addresses') { should include '0.0.0.0' } its('addresses') { should include '0.0.0.0' }
end end