setup-external-relays.sh raw
1 #!/bin/bash
2
3 # Setup script for downloading and configuring external relay repositories
4 # for benchmarking
5
6 set -e
7
8 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9 EXTERNAL_DIR="${SCRIPT_DIR}/external"
10
11 echo "Setting up external relay repositories for benchmarking..."
12
13 # Create external directory
14 mkdir -p "${EXTERNAL_DIR}"
15
16 # Function to clone or update repository
17 clone_or_update() {
18 local repo_url="$1"
19 local repo_dir="$2"
20 local repo_name="$3"
21
22 echo "Setting up ${repo_name}..."
23
24 if [ -d "${repo_dir}" ]; then
25 echo " ${repo_name} already exists, updating..."
26 cd "${repo_dir}"
27 git pull origin main 2>/dev/null || git pull origin master 2>/dev/null || true
28 cd - > /dev/null
29 else
30 echo " Cloning ${repo_name}..."
31 git clone "${repo_url}" "${repo_dir}"
32 fi
33 }
34
35 # Clone khatru
36 clone_or_update "https://github.com/fiatjaf/khatru.git" "${EXTERNAL_DIR}/khatru" "Khatru"
37
38 # Clone relayer
39 clone_or_update "https://github.com/fiatjaf/relayer.git" "${EXTERNAL_DIR}/relayer" "Relayer"
40
41 # Clone strfry
42 clone_or_update "https://github.com/hoytech/strfry.git" "${EXTERNAL_DIR}/strfry" "Strfry"
43
44 # Clone nostr-rs-relay
45 clone_or_update "https://git.sr.ht/~gheartsfield/nostr-rs-relay" "${EXTERNAL_DIR}/nostr-rs-relay" "Nostr-rs-relay"
46
47 echo "Creating Dockerfiles for external relays..."
48
49 # Create Dockerfile for Khatru SQLite
50 cat > "${SCRIPT_DIR}/Dockerfile.khatru-sqlite" << 'EOF'
51 FROM golang:1.25-alpine AS builder
52
53 RUN apk add --no-cache git ca-certificates sqlite-dev gcc musl-dev
54
55 WORKDIR /build
56 COPY . .
57
58 # Build the basic-sqlite example
59 RUN cd examples/basic-sqlite && \
60 go mod tidy && \
61 CGO_ENABLED=1 go build -o khatru-sqlite .
62
63 FROM alpine:latest
64 RUN apk --no-cache add ca-certificates sqlite wget
65 WORKDIR /app
66 COPY --from=builder /build/examples/basic-sqlite/khatru-sqlite /app/
67 RUN mkdir -p /data
68 EXPOSE 8080
69 ENV DATABASE_PATH=/data/khatru.db
70 ENV PORT=8080
71 HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
72 CMD wget --quiet --tries=1 --spider http://localhost:8080 || exit 1
73 CMD ["/app/khatru-sqlite"]
74 EOF
75
76 # Create Dockerfile for Khatru Badger
77 cat > "${SCRIPT_DIR}/Dockerfile.khatru-badger" << 'EOF'
78 FROM golang:1.25-alpine AS builder
79
80 RUN apk add --no-cache git ca-certificates
81
82 WORKDIR /build
83 COPY . .
84
85 # Build the basic-badger example
86 RUN cd examples/basic-badger && \
87 go mod tidy && \
88 CGO_ENABLED=0 go build -o khatru-badger .
89
90 FROM alpine:latest
91 RUN apk --no-cache add ca-certificates wget
92 WORKDIR /app
93 COPY --from=builder /build/examples/basic-badger/khatru-badger /app/
94 RUN mkdir -p /data
95 EXPOSE 8080
96 ENV DATABASE_PATH=/data/badger
97 ENV PORT=8080
98 HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
99 CMD wget --quiet --tries=1 --spider http://localhost:8080 || exit 1
100 CMD ["/app/khatru-badger"]
101 EOF
102
103 # Create Dockerfile for Relayer basic example
104 cat > "${SCRIPT_DIR}/Dockerfile.relayer-basic" << 'EOF'
105 FROM golang:1.25-alpine AS builder
106
107 RUN apk add --no-cache git ca-certificates sqlite-dev gcc musl-dev
108
109 WORKDIR /build
110 COPY . .
111
112 # Build the basic example
113 RUN cd examples/basic && \
114 go mod tidy && \
115 CGO_ENABLED=1 go build -o relayer-basic .
116
117 FROM alpine:latest
118 RUN apk --no-cache add ca-certificates sqlite wget
119 WORKDIR /app
120 COPY --from=builder /build/examples/basic/relayer-basic /app/
121 RUN mkdir -p /data
122 EXPOSE 8080
123 ENV DATABASE_PATH=/data/relayer.db
124 ENV PORT=8080
125 HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
126 CMD wget --quiet --tries=1 --spider http://localhost:8080 || exit 1
127 CMD ["/app/relayer-basic"]
128 EOF
129
130 # Create Dockerfile for Strfry
131 cat > "${SCRIPT_DIR}/Dockerfile.strfry" << 'EOF'
132 FROM ubuntu:22.04 AS builder
133
134 ENV DEBIAN_FRONTEND=noninteractive
135
136 # Install build dependencies
137 RUN apt-get update && apt-get install -y \
138 git \
139 build-essential \
140 liblmdb-dev \
141 libsecp256k1-dev \
142 pkg-config \
143 libtool \
144 autoconf \
145 automake \
146 && rm -rf /var/lib/apt/lists/*
147
148 WORKDIR /build
149 COPY . .
150
151 # Build strfry
152 RUN make setup-golpe && \
153 make -j$(nproc)
154
155 FROM ubuntu:22.04
156 RUN apt-get update && apt-get install -y \
157 liblmdb0 \
158 libsecp256k1-0 \
159 curl \
160 && rm -rf /var/lib/apt/lists/*
161
162 WORKDIR /app
163 COPY --from=builder /build/strfry /app/
164 RUN mkdir -p /data
165
166 EXPOSE 8080
167 ENV STRFRY_DB_PATH=/data/strfry.lmdb
168 ENV STRFRY_RELAY_PORT=8080
169
170 HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
171 CMD curl -f http://localhost:8080 || exit 1
172
173 CMD ["/app/strfry", "relay"]
174 EOF
175
176 # Create Dockerfile for nostr-rs-relay
177 cat > "${SCRIPT_DIR}/Dockerfile.nostr-rs-relay" << 'EOF'
178 FROM rust:1.70-alpine AS builder
179
180 RUN apk add --no-cache musl-dev sqlite-dev
181
182 WORKDIR /build
183 COPY . .
184
185 # Build the relay
186 RUN cargo build --release
187
188 FROM alpine:latest
189 RUN apk --no-cache add ca-certificates sqlite wget
190 WORKDIR /app
191 COPY --from=builder /build/target/release/nostr-rs-relay /app/
192 RUN mkdir -p /data
193
194 EXPOSE 8080
195 ENV RUST_LOG=info
196
197 HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
198 CMD wget --quiet --tries=1 --spider http://localhost:8080 || exit 1
199
200 CMD ["/app/nostr-rs-relay"]
201 EOF
202
203 echo "Creating configuration files..."
204
205 # Create configs directory
206 mkdir -p "${SCRIPT_DIR}/configs"
207
208 # Create strfry configuration
209 cat > "${SCRIPT_DIR}/configs/strfry.conf" << 'EOF'
210 ##
211 ## Default strfry config
212 ##
213
214 # Directory that contains the strfry LMDB database (restart required)
215 db = "/data/strfry.lmdb"
216
217 dbParams {
218 # Maximum number of threads/processes that can simultaneously have LMDB transactions open (restart required)
219 maxreaders = 256
220
221 # Size of mmap to use when loading LMDB (default is 1TB, which is probably reasonable) (restart required)
222 mapsize = 1099511627776
223 }
224
225 relay {
226 # Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required)
227 bind = "0.0.0.0"
228
229 # Port to open for the nostr websocket protocol (restart required)
230 port = 8080
231
232 # Set OS-limit on maximum number of open files/sockets (if 0, don't attempt to set) (restart required)
233 nofiles = 1000000
234
235 # HTTP header that contains the client's real IP, before reverse proxying (ie x-real-ip) (MUST be all lower-case)
236 realIpHeader = ""
237
238 info {
239 # NIP-11: Name of this server. Short/descriptive (< 30 characters)
240 name = "strfry benchmark"
241
242 # NIP-11: Detailed description of this server, free-form
243 description = "A strfry relay for benchmarking"
244
245 # NIP-11: Administrative pubkey, for contact purposes
246 pubkey = ""
247
248 # NIP-11: Alternative contact for this server
249 contact = ""
250 }
251
252 # Maximum accepted incoming websocket frame size (should be larger than max event) (restart required)
253 maxWebsocketPayloadSize = 104857600
254
255 # Websocket-level PING message frequency (should be less than any reverse proxy idle timeouts) (restart required)
256 autoPingSeconds = 55
257
258 # If TCP keep-alive should be enabled (detect dropped connections to upstream reverse proxy) (restart required)
259 enableTcpKeepalive = false
260
261 # How much uninterrupted CPU time a REQ query should get during its DB scan
262 queryTimesliceBudgetMicroseconds = 10000
263
264 # Maximum records that can be returned per filter
265 maxFilterLimit = 500
266
267 # Maximum number of subscriptions (concurrent REQs) a connection can have open at any time
268 maxSubsPerConnection = 20
269
270 writePolicy {
271 # If non-empty, path to an executable script that implements the writePolicy plugin logic
272 plugin = ""
273 }
274
275 compression {
276 # Use permessage-deflate compression if supported by client. Reduces bandwidth, but uses more CPU (restart required)
277 enabled = true
278
279 # Maintain a sliding window buffer for each connection. Improves compression, but uses more memory (restart required)
280 slidingWindow = true
281 }
282
283 logging {
284 # Dump all incoming messages
285 dumpInAll = false
286
287 # Dump all incoming EVENT messages
288 dumpInEvents = false
289
290 # Dump all incoming REQ/CLOSE messages
291 dumpInReqs = false
292
293 # Log performance metrics for initial REQ database scans
294 dbScanPerf = false
295 }
296
297 numThreads {
298 # Ingester threads: route incoming requests, validate events/sigs (restart required)
299 ingester = 3
300
301 # reqWorker threads: Handle initial DB scan for events (restart required)
302 reqWorker = 3
303
304 # reqMonitor threads: Handle filtering of new events (restart required)
305 reqMonitor = 3
306
307 # yesstr threads: experimental yesstr protocol (restart required)
308 yesstr = 1
309 }
310 }
311 EOF
312
313 # Create nostr-rs-relay configuration
314 cat > "${SCRIPT_DIR}/configs/config.toml" << 'EOF'
315 [info]
316 relay_url = "ws://localhost:8080"
317 name = "nostr-rs-relay benchmark"
318 description = "A nostr-rs-relay for benchmarking"
319 pubkey = ""
320 contact = ""
321
322 [database]
323 data_directory = "/data"
324 in_memory = false
325 engine = "sqlite"
326
327 [network]
328 port = 8080
329 address = "0.0.0.0"
330
331 [limits]
332 messages_per_sec = 0
333 subscriptions_per_min = 0
334 max_event_bytes = 65535
335 max_ws_message_bytes = 104857600
336 max_ws_frame_bytes = 104857600
337
338 [authorization]
339 pubkey_whitelist = []
340
341 [verified_users]
342 mode = "passive"
343 domain_whitelist = []
344 domain_blacklist = []
345
346 [pay_to_relay]
347 enabled = false
348
349 [options]
350 reject_future_seconds = 30
351 EOF
352
353 echo "Creating data directories..."
354 mkdir -p "${SCRIPT_DIR}/data"/{next-orly,khatru-sqlite,khatru-badger,relayer-basic,strfry,nostr-rs-relay}
355 mkdir -p "${SCRIPT_DIR}/reports"
356
357 echo "Setup complete!"
358 echo ""
359 echo "External relay repositories have been cloned to: ${EXTERNAL_DIR}"
360 echo "Dockerfiles have been created for all relay implementations"
361 echo "Configuration files have been created in: ${SCRIPT_DIR}/configs"
362 echo "Data directories have been created in: ${SCRIPT_DIR}/data"
363 echo ""
364 echo "To run the benchmark:"
365 echo " cd ${SCRIPT_DIR}"
366 echo " docker-compose up --build"
367 echo ""
368 echo "Reports will be generated in: ${SCRIPT_DIR}/reports"