From 190b0c2c16c1669955c7f3a7a04c7d603ede8c7e Mon Sep 17 00:00:00 2001 From: Daniel Cadenas Date: Wed, 18 Dec 2024 07:18:22 -0300 Subject: [PATCH 1/3] Playbook for groups_relay --- inventories/groups_relay/README.md | 2 + .../groups_relay/group_vars/all/vault.yml | 0 inventories/groups_relay/inventory.yml | 16 ++ new-server-vars.yml | 22 +++ playbooks/groups_relay.yml | 8 + roles/groups_relay/README.md | 31 ++++ roles/groups_relay/defaults/main.yml | 0 roles/groups_relay/files/settings.yml | 8 + roles/groups_relay/files/strfry.conf | 144 ++++++++++++++++++ roles/groups_relay/meta/main.yml | 6 + roles/groups_relay/tasks/main.yml | 85 +++++++++++ .../templates/docker-compose.yml.tpl | 44 ++++++ .../templates/settings.production.yml.tpl | 2 + 13 files changed, 368 insertions(+) create mode 100644 inventories/groups_relay/README.md create mode 100644 inventories/groups_relay/group_vars/all/vault.yml create mode 100644 inventories/groups_relay/inventory.yml create mode 100644 playbooks/groups_relay.yml create mode 100644 roles/groups_relay/README.md create mode 100644 roles/groups_relay/defaults/main.yml create mode 100644 roles/groups_relay/files/settings.yml create mode 100644 roles/groups_relay/files/strfry.conf create mode 100644 roles/groups_relay/meta/main.yml create mode 100644 roles/groups_relay/tasks/main.yml create mode 100644 roles/groups_relay/templates/docker-compose.yml.tpl create mode 100644 roles/groups_relay/templates/settings.production.yml.tpl diff --git a/inventories/groups_relay/README.md b/inventories/groups_relay/README.md new file mode 100644 index 0000000..a5ea8c0 --- /dev/null +++ b/inventories/groups_relay/README.md @@ -0,0 +1,2 @@ +# groups_relay Inventory +# groups_relay Inventory diff --git a/inventories/groups_relay/group_vars/all/vault.yml b/inventories/groups_relay/group_vars/all/vault.yml new file mode 100644 index 0000000..e69de29 diff --git a/inventories/groups_relay/inventory.yml b/inventories/groups_relay/inventory.yml new file mode 100644 index 0000000..8975bbd --- /dev/null +++ b/inventories/groups_relay/inventory.yml @@ -0,0 +1,16 @@ +--- +groups_relay: + hosts: + communities.nos.social: + vars: + admin_username: admin + ansible_user: '{{ admin_username }}' + homedir: /home/{{ admin_username }} + cert_email: ops@planetary.social + domain: '{{ inventory_hostname }}' + groups_relay_image: ghcr.io/verse-pbc/groups_relay + groups_relay_image_tag: stable + groups_relay_health_endpoint: https://{{ inventory_hostname }}/health +prod: + hosts: + communities.nos.social: diff --git a/new-server-vars.yml b/new-server-vars.yml index f2d7773..a62167d 100644 --- a/new-server-vars.yml +++ b/new-server-vars.yml @@ -219,3 +219,25 @@ # inv: relay # inv_groups: # - relay + +#----------------------------- +# Groups Relay example +# ansible-playbook -i inventories/groups_relay/inventory.yml playbooks/new-do-droplet.yml -e '@new-server-vars.yml' +#----------------------------- +domain: communities.nos.social +do_droplet_size: s-1vcpu-1gb +do_droplet_image: ubuntu-22-04-x64 +do_droplet_region: NYC3 +do_droplet_project: Nos +do_droplet_tags: +- prod +gh_user_keys_to_add: +- mplorentz +- dcadenas +- nbenmoody +inv: groups_relay +inv_groups: +- groups_relay +- prod +additional_roles: +- groups_relay diff --git a/playbooks/groups_relay.yml b/playbooks/groups_relay.yml new file mode 100644 index 0000000..0ce5b6e --- /dev/null +++ b/playbooks/groups_relay.yml @@ -0,0 +1,8 @@ +- name: Install new server for groups_relay + hosts: groups_relay:&prod + vars: + ansible_user: admin + domain: "{{ inventory_hostname }}" + roles: + - groups_relay + diff --git a/roles/groups_relay/README.md b/roles/groups_relay/README.md new file mode 100644 index 0000000..a192bd1 --- /dev/null +++ b/roles/groups_relay/README.md @@ -0,0 +1,31 @@ +# groups_relay role + +This role sets up a Nostr groups relay server using strfry as the backend relay. It's designed to handle NIP-29 group messages. + +## Architecture + +The role deploys two main services: +1. `groups_relay` - A specialized relay that handles NIP-29 group messages +2. `strfry` - A lightweight Nostr relay that serves as the backend storage + +## Variables + +| Variable | Example | Purpose | +|-----------------------------|--------------------------------------------|--------------------------------------------| +| domain | communities.nos.social | The FQDN of the service | +| cert_email | ops@planetary.social | The email used for LetsEncrypt certificate | +| groups_relay_image | ghcr.io/verse-pbc/groups_relay | The Docker image name | +| groups_relay_image_tag | stable | The Docker image tag | +| groups_relay_health_endpoint| https://{{ inventory_hostname }}/health | Health check endpoint | + +## Dependencies + +The role depends on: +- common +- digital-ocean +- docker +- traefik + +## Network Configuration + +The service exposes the groups relay on port 8080 through Traefik, while strfry runs internally and is not exposed to the internet. All traffic is routed through the `proxy` network managed by Traefik. diff --git a/roles/groups_relay/defaults/main.yml b/roles/groups_relay/defaults/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/groups_relay/files/settings.yml b/roles/groups_relay/files/settings.yml new file mode 100644 index 0000000..c3a5c37 --- /dev/null +++ b/roles/groups_relay/files/settings.yml @@ -0,0 +1,8 @@ +# Default relay configuration +relay: + # Relay secret key (hex format) + # This is a test key, replace with your own in settings.local.yml + relay_secret_key: "6b911fd37cdf5c81d4c0adb1ab7fa822ed253ab0ad9aa18d77257c88b29b718e" + local_addr: "0.0.0.0:8080" + auth_url: "ws://localhost:8080" + relay_url: "ws://127.0.0.1:7777" \ No newline at end of file diff --git a/roles/groups_relay/files/strfry.conf b/roles/groups_relay/files/strfry.conf new file mode 100644 index 0000000..c7b19ff --- /dev/null +++ b/roles/groups_relay/files/strfry.conf @@ -0,0 +1,144 @@ +## +## Default strfry config +## + +# Directory that contains the strfry LMDB database (restart required) +db = "/strfry/data" + +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 + + # Disables read-ahead when accessing the LMDB mapping. Reduces IO activity when DB size is larger than RAM. (restart required) + noReadAhead = false +} + +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 +} + +relay { + # Interface to listen on. Use 0.0.0.0 to listen on all interfaces (restart required) + bind = "0.0.0.0" + + # 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 = "" + + # NIP-11: Alternative administrative contact (email, website, etc) + contact = "" + + # NIP-11: URL pointing to an image to be used as an icon for the relay + icon = "" + + # List of supported lists as JSON array, or empty string to use default. Example: "[1,2]" + nips = "" + } + + # Maximum accepted incoming websocket frame size (should be larger than max event) (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 = "" + } + + 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 + + # Log reason for invalid event rejection? Can be disabled to silence excessive logging + invalidEvents = true + } + + 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 + + # negentropy threads: Handle negentropy protocol messages (restart required) + negentropy = 2 + } + + negentropy { + # Support negentropy protocol messages + enabled = true + + # Maximum records that sync will process before returning an error + maxSyncEvents = 1000000 + } +} diff --git a/roles/groups_relay/meta/main.yml b/roles/groups_relay/meta/main.yml new file mode 100644 index 0000000..f53b0aa --- /dev/null +++ b/roles/groups_relay/meta/main.yml @@ -0,0 +1,6 @@ +--- +dependencies: + - role: common + - role: digital-ocean + - role: docker + - role: traefik diff --git a/roles/groups_relay/tasks/main.yml b/roles/groups_relay/tasks/main.yml new file mode 100644 index 0000000..9165a50 --- /dev/null +++ b/roles/groups_relay/tasks/main.yml @@ -0,0 +1,85 @@ +--- +- name: Set groups_relay dir + ansible.builtin.set_fact: + groups_relay_dir: "{{ homedir }}/services/groups_relay" + +- name: Ensure services/groups_relay exists + ansible.builtin.file: + path: "{{ groups_relay_dir }}" + state: directory + mode: '0755' + +- name: Copy necessary template files to groups_relay dir + ansible.builtin.template: + src: "docker-compose.yml.tpl" + dest: "{{ groups_relay_dir }}/docker-compose.yml" + mode: 0644 + +- name: UFW - Allow http/https connections + become: true + community.general.ufw: + rule: allow + port: "{{ item }}" + proto: tcp + loop: + - "80" + - "443" + +- name: Ensure cert directory exist + ansible.builtin.file: + path: "{{ groups_relay_dir }}/certs" + state: directory + mode: '0755' + +- name: Ensure config directory exist + ansible.builtin.file: + path: "{{ groups_relay_dir }}/config" + state: directory + mode: '0755' + +- name: Copy settings.production.yml to config dir + ansible.builtin.template: + src: settings.production.yml.tpl + dest: "{{ groups_relay_dir }}/config/settings.production.yml" + mode: '0644' + +- name: Copy strfry.conf to config dir + ansible.builtin.copy: + src: strfry.conf + dest: "{{ groups_relay_dir }}/config/strfry.conf" + mode: '0644' + +- name: Copy settings.yml to config dir + ansible.builtin.copy: + src: settings.yml + dest: "{{ groups_relay_dir }}/config/settings.yml" + mode: '0644' + +- name: ensure docker is running + ansible.builtin.service: + name: docker + state: started + +- name: Start up docker services + ansible.builtin.shell: "docker compose down && docker compose up -d" + args: + chdir: "{{ groups_relay_dir }}" + register: service_started + retries: 5 + until: service_started is success + +- name: Setup the image updater + ansible.builtin.include_role: + name: image-update-service + vars: + service_name: groups_relay + service_image: "{{ groups_relay_image }}" + service_image_tag: "{{ groups_relay_image_tag }}" + frequency: 3m + working_dir: "{{ groups_relay_dir }}" + +- name: Setup the health check + ansible.builtin.include_role: + name: health-check + vars: + health_endpoint: "{{ groups_relay_health_endpoint }}" diff --git a/roles/groups_relay/templates/docker-compose.yml.tpl b/roles/groups_relay/templates/docker-compose.yml.tpl new file mode 100644 index 0000000..92000dc --- /dev/null +++ b/roles/groups_relay/templates/docker-compose.yml.tpl @@ -0,0 +1,44 @@ +services: + groups_relay: + container_name: groups_relay + image: "{{ groups_relay_image }}:{{ groups_relay_image_tag }}" + platform: linux/amd64 + volumes: + - ./config:/app/config:ro + environment: + RUST_LOG: "${RUST_LOG:-info}" + RUST_BACKTRACE: 1 + NIP29__ENVIRONMENT: production + NIP29__relay__relay_url: "ws://strfry:7777" + ports: + - "8080:8080" + labels: + - "traefik.enable=true" + - "traefik.http.routers.groups_relay.rule=Host(`{{ domain }}`)" + - "traefik.http.routers.groups_relay.entrypoints=websecure" + - "traefik.http.services.groups_relay.loadbalancer.server.port=8080" + depends_on: + strfry: + condition: service_started + restart: always + networks: + - proxy + + strfry: + container_name: strfry + image: ghcr.io/hoytech/strfry:latest + platform: linux/amd64 + volumes: + - strfry-data:/strfry/data + - ./config/strfry.conf:/etc/strfry.conf:ro + command: relay --config /etc/strfry.conf + restart: always + networks: + - proxy + +volumes: + strfry-data: + +networks: + proxy: + external: true diff --git a/roles/groups_relay/templates/settings.production.yml.tpl b/roles/groups_relay/templates/settings.production.yml.tpl new file mode 100644 index 0000000..779f8c9 --- /dev/null +++ b/roles/groups_relay/templates/settings.production.yml.tpl @@ -0,0 +1,2 @@ +relay: + auth_url: "wss://{{ inventory_hostname }}" \ No newline at end of file From a10886304fb91dcf8124f97c64d54f3d26b02fe5 Mon Sep 17 00:00:00 2001 From: Daniel Cadenas Date: Sat, 21 Dec 2024 10:03:55 -0300 Subject: [PATCH 2/3] Events db instead of strfry + communities2 --- inventories/groups_relay/inventory.yml | 5 ++++- new-server-vars.yml | 2 +- roles/groups_relay/files/settings.yml | 2 +- roles/groups_relay/tasks/main.yml | 3 ++- .../templates/docker-compose.yml.tpl | 21 +++---------------- .../templates/settings.production.yml.tpl | 3 ++- 6 files changed, 13 insertions(+), 23 deletions(-) diff --git a/inventories/groups_relay/inventory.yml b/inventories/groups_relay/inventory.yml index 8975bbd..29c99b5 100644 --- a/inventories/groups_relay/inventory.yml +++ b/inventories/groups_relay/inventory.yml @@ -2,6 +2,9 @@ groups_relay: hosts: communities.nos.social: + groups_relay_image_tag: stable + communities2.nos.social: + groups_relay_image_tag: latest vars: admin_username: admin ansible_user: '{{ admin_username }}' @@ -9,8 +12,8 @@ groups_relay: cert_email: ops@planetary.social domain: '{{ inventory_hostname }}' groups_relay_image: ghcr.io/verse-pbc/groups_relay - groups_relay_image_tag: stable groups_relay_health_endpoint: https://{{ inventory_hostname }}/health prod: hosts: communities.nos.social: + communities2.nos.social: diff --git a/new-server-vars.yml b/new-server-vars.yml index a62167d..b67ba49 100644 --- a/new-server-vars.yml +++ b/new-server-vars.yml @@ -224,7 +224,7 @@ # Groups Relay example # ansible-playbook -i inventories/groups_relay/inventory.yml playbooks/new-do-droplet.yml -e '@new-server-vars.yml' #----------------------------- -domain: communities.nos.social +domain: communities2.nos.social do_droplet_size: s-1vcpu-1gb do_droplet_image: ubuntu-22-04-x64 do_droplet_region: NYC3 diff --git a/roles/groups_relay/files/settings.yml b/roles/groups_relay/files/settings.yml index c3a5c37..6e648be 100644 --- a/roles/groups_relay/files/settings.yml +++ b/roles/groups_relay/files/settings.yml @@ -5,4 +5,4 @@ relay: relay_secret_key: "6b911fd37cdf5c81d4c0adb1ab7fa822ed253ab0ad9aa18d77257c88b29b718e" local_addr: "0.0.0.0:8080" auth_url: "ws://localhost:8080" - relay_url: "ws://127.0.0.1:7777" \ No newline at end of file + relay_url: "ws://localhost:8080" \ No newline at end of file diff --git a/roles/groups_relay/tasks/main.yml b/roles/groups_relay/tasks/main.yml index 9165a50..e059db4 100644 --- a/roles/groups_relay/tasks/main.yml +++ b/roles/groups_relay/tasks/main.yml @@ -15,7 +15,7 @@ dest: "{{ groups_relay_dir }}/docker-compose.yml" mode: 0644 -- name: UFW - Allow http/https connections +- name: UFW - Allow http/https/strfry connections become: true community.general.ufw: rule: allow @@ -24,6 +24,7 @@ loop: - "80" - "443" + - "7777" - name: Ensure cert directory exist ansible.builtin.file: diff --git a/roles/groups_relay/templates/docker-compose.yml.tpl b/roles/groups_relay/templates/docker-compose.yml.tpl index 92000dc..0818ca4 100644 --- a/roles/groups_relay/templates/docker-compose.yml.tpl +++ b/roles/groups_relay/templates/docker-compose.yml.tpl @@ -5,11 +5,11 @@ services: platform: linux/amd64 volumes: - ./config:/app/config:ro + - db-data:/db/data environment: - RUST_LOG: "${RUST_LOG:-info}" + RUST_LOG: info RUST_BACKTRACE: 1 NIP29__ENVIRONMENT: production - NIP29__relay__relay_url: "ws://strfry:7777" ports: - "8080:8080" labels: @@ -17,27 +17,12 @@ services: - "traefik.http.routers.groups_relay.rule=Host(`{{ domain }}`)" - "traefik.http.routers.groups_relay.entrypoints=websecure" - "traefik.http.services.groups_relay.loadbalancer.server.port=8080" - depends_on: - strfry: - condition: service_started - restart: always - networks: - - proxy - - strfry: - container_name: strfry - image: ghcr.io/hoytech/strfry:latest - platform: linux/amd64 - volumes: - - strfry-data:/strfry/data - - ./config/strfry.conf:/etc/strfry.conf:ro - command: relay --config /etc/strfry.conf restart: always networks: - proxy volumes: - strfry-data: + db-data: networks: proxy: diff --git a/roles/groups_relay/templates/settings.production.yml.tpl b/roles/groups_relay/templates/settings.production.yml.tpl index 779f8c9..c4e0834 100644 --- a/roles/groups_relay/templates/settings.production.yml.tpl +++ b/roles/groups_relay/templates/settings.production.yml.tpl @@ -1,2 +1,3 @@ relay: - auth_url: "wss://{{ inventory_hostname }}" \ No newline at end of file + auth_url: "wss://{{ inventory_hostname }}" + db_path: "/db/data" \ No newline at end of file From eb9cf6185986b11003f4a0d00f91ac48a452e3e4 Mon Sep 17 00:00:00 2001 From: Daniel Cadenas Date: Sat, 21 Dec 2024 10:06:05 -0300 Subject: [PATCH 3/3] Better readme --- inventories/groups_relay/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/inventories/groups_relay/README.md b/inventories/groups_relay/README.md index a5ea8c0..0406b87 100644 --- a/inventories/groups_relay/README.md +++ b/inventories/groups_relay/README.md @@ -1,2 +1,3 @@ # groups_relay Inventory -# groups_relay Inventory + +Hosts running our Nip 29 relay. Meant to be used with the `groups_relay` role.