├── .env ├── README.md ├── docker-compose.yml └── config.toml /.env: -------------------------------------------------------------------------------- 1 | RELAY_DOMAIN=nostr.example-domain.ai 2 | RELAY_PORT=8080 3 | RELAY_TAG=0.6.0 4 | 5 | TRAEFIK_TAG=2.5 6 | TRAEFIK_ACME_EMAIL=info@example-domain.ai 7 | TRAEFIK_LOGLEVEL=DEBUG 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nostr-rs-relay-compose 2 | 3 | Docker compose deployment for [nostr](https://github.com/fiatjaf/nostr), using the Rust relay [nostr-rs-relay](https://sr.ht/~gheartsfield/nostr-rs-relay/) and [Traefik](https://traefik.io/). 4 | 5 | ## Requirements 6 | 7 | - Docker (tested with 20.10.12) 8 | 9 | - Docker compose (tested with 1.29.2) 10 | 11 | ## Instructions 12 | 13 | 1. Edit the .env var and adjust it to your needs (domain, email for Let's Encrypt, ...) 14 | 15 | 2. Edit the config file `config.toml` with your preferred settings. 16 | 17 | 3. Pull and start: 18 | 19 | ``` 20 | docker-compose pull 21 | docker-compose up -d 22 | ``` 23 | 24 | 4. Check the logs: 25 | 26 | ``` 27 | docker-compose logs nostr-rs-relay 28 | 29 | ``` 30 | 31 | 5. Done! You can test the WebSocket connectivity with [websocat](https://github.com/vi/websocat): 32 | 33 | ``` 34 | > echo '["REQ", "test", {}]' | websocat -1 -n wss://nostr.unknown.place 35 | ["EVENT","test",{"id":"19070d74d81118aa9b412b597615f380778ededd1df71f551a5aa83dd02ae91b","pubkey":"48bd69736fa9e0a322aa132ec7613313b84fd064319c4f0ef4fdb8a55a66ad09","created_at":1645103669,"kind":1,"tags":[],"content":"this is a test","sig":"517f8073f2ea8d5e2de6d51b42e3c32d79994b02d744a1d28e5bd56213af0248e64119ec5d034dc5b3fbc4d6d535238b5cb3683752d3a392be5715136a063362"}] 36 | ``` 37 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | services: 4 | nostr-rs-relay: 5 | container_name: nostr-rs-relay 6 | image: scsibug/nostr-rs-relay:${RELAY_TAG} 7 | sysctls: 8 | net.core.somaxconn: 8128 9 | # command: 10 | user: "appuser" 11 | volumes: 12 | - "relay-db:/usr/src/app/db" 13 | - "./config.toml:/usr/src/app/config.toml" 14 | labels: 15 | - "traefik.enable=true" 16 | # - "traefik.http.routers.nostr-rs-relay.rule=(Host(`${RELAY_DOMAIN}`) && PathPrefix(`/ws`))" 17 | - "traefik.http.routers.nostr-rs-relay.rule=(Host(`${RELAY_DOMAIN}`))" 18 | - "traefik.http.routers.nostr-rs-relay.entrypoints=websecure" 19 | - "traefik.http.routers.nostr-rs-relay.tls.certresolver=le" 20 | - "traefik.http.routers.nostr-rs-relay.service=nostr-rs-relay" 21 | - "traefik.http.services.nostr-rs-relay.loadbalancer.server.port=${RELAY_PORT}" 22 | - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto = https" 23 | # - "traefik.http.routers.nostr-rs-relay.middlewares=wss-stripprefix" 24 | # - "traefik.http.middlewares.wss-stripprefix.stripprefix.prefixes=/wss" 25 | # - "traefik.http.services.nostr-rs-relay.loadbalancer.sticky.cookie=true" 26 | # - "traefik.http.services.nostr-rs-relay.loadbalancer.sticky.cookie.name=io" 27 | # - "traefik.http.services.nostr-rs-relay.loadbalancer.sticky.cookie.httponly=true" 28 | # - "traefik.http.services.nostr-rs-relay.loadbalancer.sticky.cookie.secure=true" 29 | # - "traefik.http.services.nostr-rs-relay.loadbalancer.sticky.cookie.samesite=io" 30 | 31 | traefik: 32 | image: traefik:${TRAEFIK_TAG} 33 | container_name: traefik 34 | ports: 35 | - 80:80 36 | - 443:443 37 | volumes: 38 | - "./letsencrypt:/letsencrypt" 39 | - "/var/run/docker.sock:/var/run/docker.sock:ro" 40 | command: 41 | - "--log.level=${TRAEFIK_LOGLEVEL}" 42 | - "--providers.docker=true" 43 | - "--providers.docker.exposedbydefault=false" 44 | - "--entrypoints.web.address=:80" 45 | - "--entrypoints.web.http.redirections.entryPoint.to=websecure" 46 | - "--entrypoints.web.http.redirections.entryPoint.scheme=https" 47 | - "--entrypoints.web.http.redirections.entrypoint.permanent=true" 48 | - "--entrypoints.websecure.address=:443" 49 | - "--certificatesresolvers.le.acme.httpchallenge=true" 50 | - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web" 51 | - "--certificatesresolvers.le.acme.email=${TRAEFIK_ACME_EMAIL}" 52 | - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json" 53 | restart: always 54 | 55 | volumes: 56 | relay-db: {} 57 | -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | # Nostr-rs-relay configuration 2 | 3 | [info] 4 | # The advertised URL for the Nostr websocket. 5 | relay_url = "wss://nostr.example-domain.ai/" 6 | 7 | # Relay information for clients. Put your unique server name here. 8 | name = "nostr-rs-relay" 9 | 10 | # Description 11 | description = "A newly created nostr-rs-relay.\n\nCustomize this with your own info." 12 | 13 | # Administrative contact pubkey 14 | #pubkey = "0c2d168a4ae8ca58c9f1ab237b5df682599c6c7ab74307ea8b05684b60405d41" 15 | 16 | # Administrative contact URI 17 | #contact = "mailto:contact@example.com" 18 | 19 | [database] 20 | # Directory for SQLite files. Defaults to the current directory. Can 21 | # also be specified (and overriden) with the "--db dirname" command 22 | # line option. 23 | data_directory = "." 24 | 25 | # Database connection pool settings for subscribers: 26 | 27 | # Minimum number of SQLite reader connections 28 | #min_conn = 4 29 | 30 | # Maximum number of SQLite reader connections 31 | #max_conn = 128 32 | 33 | [network] 34 | # Bind to this network address 35 | address = "0.0.0.0" 36 | 37 | # Listen on this port 38 | port = 8080 39 | 40 | [options] 41 | # Reject events that have timestamps greater than this many seconds in 42 | # the future. Defaults to rejecting anything greater than 30 minutes 43 | # from the current time. 44 | reject_future_seconds = 1800 45 | 46 | [limits] 47 | # Limit events created per second, averaged over one minute. Must be 48 | # an integer. If not set (or set to 0), defaults to unlimited. 49 | #messages_per_sec = 0 50 | 51 | # Limit the maximum size of an EVENT message. Defaults to 128 KB. 52 | # Set to 0 for unlimited. 53 | #max_event_bytes = 131072 54 | 55 | # Maximum WebSocket message in bytes. Defaults to 128 KB. 56 | #max_ws_message_bytes = 131072 57 | 58 | # Maximum WebSocket frame size in bytes. Defaults to 128 KB. 59 | #max_ws_frame_bytes = 131072 60 | 61 | # Broadcast buffer size, in number of events. This prevents slow 62 | # readers from consuming memory. 63 | #broadcast_buffer = 16384 64 | 65 | # Event persistence buffer size, in number of events. This provides 66 | # backpressure to senders if writes are slow. Defaults to 16. 67 | #event_persist_buffer = 16 68 | 69 | [authorization] 70 | # Pubkey addresses in this array are whitelisted for event publishing. 71 | # Only valid events by these authors will be accepted, if the variable 72 | # is set. 73 | #pubkey_whitelist = [ 74 | # "35d26e4690cbe1a898af61cc3515661eb5fa763b57bd0b42e45099c8b32fd50f", 75 | # "887645fef0ce0c3c1218d2f5d8e6132a19304cdc57cd20281d082f38cfea0072", 76 | #] 77 | 78 | [verified_users] 79 | # NIP-05 verification of users. Can be "enabled" to require NIP-05 80 | # metadata for event authors, "passive" to perform validation but 81 | # never block publishing, or "disabled" to do nothing. 82 | #mode = "disabled" 83 | 84 | # Domain names that will be prevented from publishing events. 85 | #domain_blacklist = ["wellorder.net"] 86 | 87 | # Domain names that are allowed to publish events. If defined, only 88 | # events NIP-05 verified authors at these domains are persisted. 89 | #domain_whitelist = ["example.com"] 90 | 91 | # Consider an pubkey "verified" if we have a successful validation 92 | # from the NIP-05 domain within this amount of time. Note, if the 93 | # domain provides a successful response that omits the account, 94 | # verification is immediately revoked. 95 | #verify_expiration = "1 week" 96 | 97 | # How long to wait between verification attempts for a specific author. 98 | #verify_update_frequency = "24 hours" 99 | 100 | # How many consecutive failed checks before we give up on verifying 101 | # this author. 102 | #max_consecutive_failures = 20 103 | --------------------------------------------------------------------------------