Initialize repo for strfry nostr relay Ansible Role.

This commit is contained in:
Brian Lee 2023-07-29 17:19:36 -07:00
commit ccb50b1ac2
16 changed files with 538 additions and 0 deletions

0
.gitignore vendored Normal file
View File

17
LICENSE Normal file
View File

@ -0,0 +1,17 @@
MIT No Attribution License
Copyright (c) 2023 Brian Lee
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the “Software”), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

46
README.md Normal file
View File

@ -0,0 +1,46 @@
# Ansible Role: strfry
This Ansible Role builds and installs [strfry](https://github.com/hoytech/strfry).
Future role improvements:
* The git tasks in this role are not yet idempotent due to handling a submodule.
* The installation process could be made to check if strfry is already running and perform a zero-downtime upgrade.
## Requirements
None.
## Role Variables
```yaml
strfry_version: beta # git repository branch or release tag
strfry_make_jobs: "{{ ansible_processor_cores }}" # number of CPUs to build with
strfry_skip_config: False
```
See `defaults/main.yml`
If you are not using the `beta` branch/version, you should override the template with your own by setting `strfry_skip_config` to true and manage the configuration manually.
For more configuration info, see the relevant upstream [configuration example](https://github.com/hoytech/strfry/blob/beta/strfry.conf) for your branch/version.
## Example Playbook
```yaml
- hosts: all
become: true
roles:
- role: bleetube.strfry
- role: nginxinc.nginx_core.nginx
tasks:
- import_tasks: nginx_conf.yml
```
## Troubleshooting
If `make` fails, try running on a single core:
```shell
ansible-playbook playbooks/strfry/main.yml -e 'strfry_make_jobs=1'
```

123
defaults/main.yml Normal file
View File

@ -0,0 +1,123 @@
---
strfry_version: beta
strfry_binary_path: /usr/local/bin/strfry
strfry_make_jobs: "{{ ansible_processor_cores }}"
strfry_skip_config: False
strfry_system_group: strfry
strfry_system_user: strfry
strfry_data_path: /var/lib/strfry
strfry_db: "./strfry-db/" # Becomes /var/lib/strfry/strfry-db
strfry_dbParams:
# Maximum number of threads/processes that can simultaneously have LMDB transactions open (restart required)
maxreaders: 256
# Size of mmap() to use when loading LMDB (default is 10TB, does *not* correspond to disk-space used) (restart required)
mapsize: 10995116277760
strfry_relay:
# Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required)
bind: "127.0.0.1"
# Port to open for the nostr websocket protocol (restart required)
port: 7777
# Set OS-limit on maximum number of open files/sockets (if 0, don't attempt to set) (restart required)
nofiles: 1000000
# HTTP header that contains the client's real IP, before reverse proxying (ie x-real-ip) (MUST be all lower-case)
realIpHeader: ""
info:
# NIP-11: Name of this server. Short/descriptive (< 30 characters)
name: "strfry default"
# NIP-11: Detailed information about relay, free-form
description: "This is a strfry instance."
# NIP-11: Administrative nostr pubkey, for contact purposes
pubkey: "unset"
# NIP-11: Alternative administrative contact (email, website, etc)
contact: "unset"
# Maximum accepted incoming websocket frame size (should be larger than max event and yesstr msg) (restart required)
maxWebsocketPayloadSize: 131072
# Websocket-level PING message frequency (should be less than any reverse proxy idle timeouts) (restart required)
autoPingSeconds: 55
# If TCP keep-alive should be enabled (detect dropped connections to upstream reverse proxy)
enableTcpKeepalive: false
# How much uninterrupted CPU time a REQ query should get during its DB scan
queryTimesliceBudgetMicroseconds: 10000
# Maximum records that can be returned per filter
maxFilterLimit: 500
# Maximum number of subscriptions (concurrent REQs) a connection can have open at any time
maxSubsPerConnection: 20
writePolicy:
# If non-empty, path to an executable script that implements the writePolicy plugin logic
plugin: ""
# Number of seconds to search backwards for lookback events when starting the writePolicy plugin (0 for no lookback)
lookbackSeconds: 0
compression:
# Use permessage-deflate compression if supported by client. Reduces bandwidth, but slight increase in CPU (restart required)
enabled: "true"
# Maintain a sliding window buffer for each connection. Improves compression, but uses more memory (restart required)
slidingWindow: "true"
logging:
# Dump all incoming messages
dumpInAll: "false"
# Dump all incoming EVENT messages
dumpInEvents: "false"
# Dump all incoming REQ/CLOSE messages
dumpInReqs: "false"
# Log performance metrics for initial REQ database scans
dbScanPerf: "false"
numThreads:
# Ingester threads: route incoming requests, validate events/sigs (restart required)
ingester: 3
# reqWorker threads: Handle initial DB scan for events (restart required)
reqWorker: 3
# reqMonitor threads: Handle filtering of new events (restart required)
reqMonitor: 3
# yesstr threads: Experimental yesstr protocol (restart required)
yesstr: 1
strfry_events:
# Maximum size of normalised JSON, in bytes
maxEventSize: 65536
# Events newer than this will be rejected
rejectEventsNewerThanSeconds: 900
# Events older than this will be rejected
rejectEventsOlderThanSeconds: 94608000
# Ephemeral events older than this will be rejected
rejectEphemeralEventsOlderThanSeconds: 60
# Ephemeral events will be deleted from the DB when older than this
ephemeralEventsLifetimeSeconds: 300
# Maximum number of tags allowed
maxNumTags: 2000
# Maximum size for tag values, in bytes
maxTagValSize: 1024

7
handlers/main.yml Normal file
View File

@ -0,0 +1,7 @@
---
- name: restart strfry
ansible.builtin.service:
name: strfry
state: restarted
daemon_reload: yes
become: true

2
meta/main.yml Normal file
View File

@ -0,0 +1,2 @@
---
dependencies: []

31
tasks/build.yml Normal file
View File

@ -0,0 +1,31 @@
---
- name: Avoid running as root
ansible.builtin.pause:
prompt: "Please run this role as a regular user with sudo/doas privileges. Or press enter to continue anyway (not recommended)."
when: ansible_user_id == 'root'
- name: Clone git repository
ansible.builtin.git:
repo: https://github.com/hoytech/strfry.git
dest: "{{ ansible_env.HOME }}/src/strfry"
version: "{{ strfry_version }}"
force: yes # required to avoid weird error when updating submodules via Ansible
register: git_repository
- name: Update git submodule (golpe)
ansible.builtin.command:
cmd: git submodule update --init
chdir: "{{ ansible_env.HOME }}/src/strfry"
when: git_repository.changed
- name: Run make setup-golpe
ansible.builtin.command:
cmd: make setup-golpe
chdir: "{{ ansible_env.HOME }}/src/strfry"
when: git_repository.changed
- name: Build strfry
ansible.builtin.command:
cmd: "make -j{{ strfry_make_jobs|default(1) }}"
chdir: "{{ ansible_env.HOME }}/src/strfry"
when: git_repository.changed

51
tasks/install.yml Normal file
View File

@ -0,0 +1,51 @@
---
- name: Install strfry binary
ansible.builtin.copy:
src: "{{ ansible_env.HOME }}/src/strfry/strfry"
dest: "{{ strfry_binary_path }}"
mode: 0755
remote_src: true
become: true
- name: Setup strfry service unit
ansible.builtin.template:
src: strfry.service
dest: /etc/systemd/system/strfry.service
become: true
notify: restart strfry
- name: Ensure strfry is enabled on boot
ansible.builtin.service:
name: strfry
enabled: true
state: started
become: true
- name: Configure strfry
ansible.builtin.template:
src: strfry.conf
dest: "{{ strfry_data_path }}/strfry.conf"
owner: "{{ strfry_system_user }}"
group: "{{ strfry_system_group }}"
when: not strfry_skip_config
become: true
tags: config
notify: restart strfry
- name: Ensure the configured database directory exists.
ansible.builtin.file:
path: "{{ strfry_db }}"
state: directory
owner: "{{ strfry_system_user }}"
group: "{{ strfry_system_group }}"
when: strfry_db.startswith('/')
become: true
- name: Ensure the configured database directory exists.
ansible.builtin.file:
path: "{{ strfry_data_path }}/{{ strfry_db }}"
state: directory
owner: "{{ strfry_system_user }}"
group: "{{ strfry_system_group }}"
when: not strfry_db.startswith('/')
become: true

24
tasks/main.yml Normal file
View File

@ -0,0 +1,24 @@
---
- name: Load a variable file based on the OS type.
include_vars: "{{ item }}"
with_first_found:
- "{{ ansible_distribution }}-{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_distribution }}.yml"
- "{{ ansible_os_family }}.yml"
- name: Install compiler dependencies (Debian)
ansible.builtin.package:
name: "{{ compiler_packages }}"
state: present
when: ansible_os_family == 'Debian'
become: true
- name: Set up strfry user
import_tasks: setup-user.yml
#- name: Run build tasks
# import_tasks: build.yml
# tags: build
- name: Install strfry
import_tasks: install.yml

39
tasks/setup-user.yml Normal file
View File

@ -0,0 +1,39 @@
---
- name: Get nologin path for strfry user
ansible.builtin.find:
paths:
- /bin
- /sbin
- /usr/bin
- /usr/sbin
patterns: nologin
register: nologin_bin
become: true
- name: Create the strfry group
ansible.builtin.group:
name: "{{ strfry_system_group }}"
state: present
system: true
when: strfry_system_group != "root"
become: true
- name: Create the strfry system user
ansible.builtin.user:
name: "{{ strfry_system_user }}"
groups: "{{ strfry_system_group }}"
shell: "{{ nologin_bin.files[0].path }}"
system: true
create_home: false
home: "{{ strfry_data_path }}"
when: strfry_system_user != "root"
become: true
- name: Ensure strfry_path exists.
ansible.builtin.file:
path: "{{ strfry_data_path }}"
owner: "{{ strfry_system_user }}"
group: "{{ strfry_system_group }}"
state: directory
mode: '0750'
become: true

129
templates/strfry.conf Normal file
View File

@ -0,0 +1,129 @@
##
## Default strfry config
##
# Directory that contains the strfry LMDB database (restart required)
# Ansible template for strfry.conf
db = "{{ strfry_db }}"
dbParams {
# Maximum number of threads/processes that can simultaneously have LMDB transactions open (restart required)
maxreaders = {{ strfry_dbParams.maxreaders }}
# Size of mmap() to use when loading LMDB (default is 10TB, does *not* correspond to disk-space used) (restart required)
mapsize = {{ strfry_dbParams.mapsize }}
}
relay {
# Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required)
bind = "{{ strfry_relay.bind }}"
# Port to open for the nostr websocket protocol (restart required)
port = {{ strfry_relay.port }}
# Set OS-limit on maximum number of open files/sockets (if 0, don't attempt to set) (restart required)
nofiles = {{ strfry_relay.nofiles }}
# HTTP header that contains the client's real IP, before reverse proxying (ie x-real-ip) (MUST be all lower-case)
realIpHeader = "{{ strfry_relay.realIpHeader }}"
info {
# NIP-11: Name of this server. Short/descriptive (< 30 characters)
name = "{{ strfry_relay.info.name }}"
# NIP-11: Detailed information about relay, free-form
description = "{{ strfry_relay.info.description }}"
# NIP-11: Administrative nostr pubkey, for contact purposes
pubkey = "{{ strfry_relay.info.pubkey }}"
# NIP-11: Alternative administrative contact (email, website, etc)
contact = "{{ strfry_relay.info.contact }}"
}
# Maximum accepted incoming websocket frame size (should be larger than max event and yesstr msg) (restart required)
maxWebsocketPayloadSize = {{ strfry_relay.maxWebsocketPayloadSize }}
# Websocket-level PING message frequency (should be less than any reverse proxy idle timeouts) (restart required)
autoPingSeconds = {{ strfry_relay.autoPingSeconds }}
# If TCP keep-alive should be enabled (detect dropped connections to upstream reverse proxy)
enableTcpKeepalive = {{ strfry_relay.enableTcpKeepalive }}
# How much uninterrupted CPU time a REQ query should get during its DB scan
queryTimesliceBudgetMicroseconds = {{ strfry_relay.queryTimesliceBudgetMicroseconds }}
# Maximum records that can be returned per filter
maxFilterLimit = {{ strfry_relay.maxFilterLimit }}
# Maximum number of subscriptions (concurrent REQs) a connection can have open at any time
maxSubsPerConnection = {{ strfry_relay.maxSubsPerConnection }}
writePolicy {
# If non-empty, path to an executable script that implements the writePolicy plugin logic
plugin = "{{ strfry_relay.writePolicy.plugin }}"
# Number of seconds to search backwards for lookback events when starting the writePolicy plugin (0 for no lookback)
lookbackSeconds = {{ strfry_relay.writePolicy.lookbackSeconds }}
}
compression {
# Use permessage-deflate compression if supported by client. Reduces bandwidth, but slight increase in CPU (restart required)
enabled = {{ strfry_relay.compression.enabled }}
# Maintain a sliding window buffer for each connection. Improves compression, but uses more memory (restart required)
slidingWindow = {{ strfry_relay.compression.slidingWindow }}
}
logging {
# Dump all incoming messages
dumpInAll = {{ strfry_relay.logging.dumpInAll }}
# Dump all incoming EVENT messages
dumpInEvents = {{ strfry_relay.logging.dumpInEvents }}
# Dump all incoming REQ/CLOSE messages
dumpInReqs = {{ strfry_relay.logging.dumpInReqs }}
# Log performance metrics for initial REQ database scans
dbScanPerf = {{ strfry_relay.logging.dbScanPerf }}
}
numThreads {
# Ingester threads: route incoming requests, validate events/sigs (restart required)
ingester = {{ strfry_relay.numThreads.ingester }}
# reqWorker threads: Handle initial DB scan for events (restart required)
reqWorker = {{ strfry_relay.numThreads.reqWorker }}
# reqMonitor threads: Handle filtering of new events (restart required)
reqMonitor = {{ strfry_relay.numThreads.reqMonitor }}
# yesstr threads: Experimental yesstr protocol (restart required)
yesstr = {{ strfry_relay.numThreads.yesstr }}
}
}
events {
# Maximum size of normalised JSON, in bytes
maxEventSize = {{ strfry_events.maxEventSize }}
# Events newer than this will be rejected
rejectEventsNewerThanSeconds = {{ strfry_events.rejectEventsNewerThanSeconds }}
# Events older than this will be rejected
rejectEventsOlderThanSeconds = {{ strfry_events.rejectEventsOlderThanSeconds }}
# Ephemeral events older than this will be rejected
rejectEphemeralEventsOlderThanSeconds = {{ strfry_events.rejectEphemeralEventsOlderThanSeconds }}
# Ephemeral events will be deleted from the DB when older than this
ephemeralEventsLifetimeSeconds = {{ strfry_events.ephemeralEventsLifetimeSeconds }}
# Maximum number of tags allowed
maxNumTags = {{ strfry_events.maxNumTags }}
# Maximum size for tag values, in bytes
maxTagValSize = {{ strfry_events.maxTagValSize }}
}

22
templates/strfry.service Normal file
View File

@ -0,0 +1,22 @@
[Unit]
Description=strfry nostr relay
[Service]
User={{ strfry_system_user }}
Group={{ strfry_system_group }}
WorkingDirectory={{ strfry_data_path }}
ExecStart={{ strfry_binary_path }} --config=strfry.conf relay
Restart=on-failure
RestartSec=15
LimitNOFILE=65536
# Hardening
ProtectHome=yes
NoNewPrivileges=yes
ProtectSystem=full
[Journal]
MaxRetentionSec=2h
[Install]
WantedBy=multi-user.target

11
vars/Archlinux.yml Normal file
View File

@ -0,0 +1,11 @@
---
compiler_packages:
- base-devel
- flatbuffers
- git
- lmdb
- openssl
- perl-regexp-grammars
- perl-template-toolkit
- perl-yaml
- zlib

13
vars/Debian.yml Normal file
View File

@ -0,0 +1,13 @@
---
compiler_packages:
- build-essential
- git
- libflatbuffers-dev
- liblmdb-dev
- libregexp-grammars-perl
- libsecp256k1-dev
- libssl-dev
- libtemplate-perl
- libyaml-perl
- libzstd-dev
- zlib1g-dev

9
vars/RedHat.yml Normal file
View File

@ -0,0 +1,9 @@
---
compiler_packages:
- @development-tools
- git
- lmdb-devel
- openssl-devel
- perl-Template-Toolkit
- perl-YAML
- zlib-devel

14
vars/Ubuntu.yml Normal file
View File

@ -0,0 +1,14 @@
---
compiler_packages:
- build-essential
- git
- libflatbuffers-dev
- liblmdb-dev
- libregexp-grammars-perl
- libsecp256k1-dev
- libssl-dev
- libtemplate-perl
- libyaml-perl
- libzstd-dev
- zlib1g-dev
- libb2-dev # Ubuntu 22.04