[转]Nostr代理转发中继部署过程

软件选型

github上有很多Nostr代理转发的现成项目可以直接拿来用,而且自己写也很费时间,我自己对这块程序也不太熟,所以选择直接拿来主义。

我前几天尝试的第一个项目是 https://github.com/bndw/nostr-relay-proxy.git ,这个项目是golang写的,编译部署也不麻烦,就是有内存泄漏,我买的便宜低配的vps主机(cloudcone的kvm主机,可以支付宝付款比较方便),跑一会儿就OOM了,进程会反复重启,1G内存都不够,没法用。

这两天尝试的是另外一个项目 https://github.com/Yonle/bostr.git ,这个项目比上面那个可以配置的选项更多,是node.js写的,编译部署也比较简单(唯一要注意的是依赖的node版本>=16),最主要的是他不占用啥资源,我新买的1CPU/512M内存的VPS目前看起来也跑的很欢快(也是cloudcone的,主要是前两天买的那个退款之后,那个促销的配置卖完了,尴尬。。。这次买的是包月的,先用几天试试看好不好用吧,好用再说)。


部署过程

- 买vps

这个不多说,随便整一个国外的vps就行,有公网地址那种。我选的操作系统是ubuntu 20.04,其实我想选22.04,但是512M内存不够用起不来。。。内存够用的话还是用新版本比较好。

- 申请域名

我是申请的免费的域名,试了3个才找到一个能用的(有些是国内dns解析不到,有些是不能申请ssl证书),我是用这个网站申请的免费域名 https://freedns.afraid.org/

其实我自己有付费域名,但是是国内买的,容易泄漏个人信息,还是免费的凑合用吧。我注册的二级域名是 nostr-bostr-relay-proxy.ignorelist.com ( 已更新为:tnruygu.cn ) ,这个测试了下可以用certbot申请免费ssl证书,国内外dns解析也正常。

最后就是配置dns A记录,把 nostr-bostr-relay-proxy.ignorelist.com 解析到你的vps 公网地址,等十几分钟才会生效,可以ping一下域名看看解析地址,或者用dig、nslookup之类的工具查询dns记录。

- 部署代理软件

项目的README文档写的比较清楚了,主要是依赖的nmp和node.js运行环境要装好。

  1. 安装npm:apt install npm (最好先执行 apt-get update
  2. 安装node运行环境:curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash , 然后 nvm install v18.19.0 ,我选择的是18版本,比16高就行。
  3. 下载bostr项目代码:git clone https://github.com/Yonle/bostr.git
  4. 编译bostr项目:cd bostr ; npm i
  5. 修改bostr配置:cp config.js.example config.jsvi config.js ; 修改内容如下:

// Bostr config

module.exports = {
  // Server listener [Required]
  address: "0.0.0.0",
  port: "8080",


  // 独立 HTTPS 服务器。通常情况下,bostr 接受不安全的连接。
  // 指定私钥/证书的绝对路径将使 bostr 只接受安全连接。
  //
  // 提示:如果在反向代理(reverse proxy)后面运行 bostr,则不需要此项。
  https: {
    privKey: "",
    certificate: "",
    ticketKey: ""
  },

  // 集群。
  // 0 将使 bostr 运行可用并行性/CPU 内核的集群。
  clusters: 0,

  // 使用继电器连接保镖的日志?  
  log_about_relays: false,

  // 对 websocket 使用 deflate 压缩。
  perMessageDeflate: true,

  // 重新连接继电器前的时间(毫秒)。
  reconnect_time: 5000,

  // 在上游中继器发出限制后的限制到期时间,单位为毫秒。
  // 设置为 0 时,将禁用鼠限处理。
  upstream_ratelimit_expiration: 10000,

  // 客户端可打开的最大订阅。
  // 设置为 -1 将禁用最大订阅限制。
  max_client_subs: -1,

  // 等待每个连接的继电器发送 EOSE。
  // 可以提高接收事件的准确性。
  //
  // 取决于您配置的中继、
  // 由于弹跳器发送 EOSE 的速度较慢,这可能会导致客户端出现加载问题。
  // 可以尝试通过更改 <eose_timeout> 或 <max_eose_score> 值来解决这个问题。
  wait_eose: true,

  // 当订阅达到 <filter.limit> 时,暂停订阅,不再接收其他事件。
  // 可以节省客户端带宽。如果需要获取更多事件,请禁用此功能。
  // 这也被称为保存模式。
  //
  // 您可能还需要调整 <max_eose_score>。
  pause_on_limit: true,

  // 从中继站接收到 EOSE 后向客户端发送 EOSE 的最大值。
  // 通常,等待 3 个中继器的 EOSE 就足够了。将其设为 0 等于等待每一个已建立的中继站。
  // 注意:请根据您配置的中继正确调整最大值。
  // 如果只设置了 3 个继电器,请将 <max_eose_score> 设置为 0。
  // 提示:越大 = EOSE 发送越准确,越小 = EOSE 发送越早。
  max_eose_score: 0,

  // 客户端事件广播限制(以毫秒为单位)。
  // 客户端只能在 <broadcast_ratelimit> 之后向该弹跳器广播新事件。
  // 将其设为 0 将禁用此功能。
  broadcast_ratelimit: 0,

  // 传入 websocket 连接速率限制(单位:毫秒)。
  // 设置为 0 将禁用此功能。
  incomming_ratelimit: 0,

  // 可以使用此保镖的用户公钥白名单。
  // 留空此项将允许所有人使用此保镖。
  // NOTE: - Require NIP-42 compatible nostr client.
  // 如果客户端不支持 NIP-42,可以使用 <allowed_event_authors> 代替。
  authorized_keys: [
    // "pubkey-in-hex",
    // "npub ....",
    // ....
  ],

  // 经批准的事件发布者白名单。
  // 将此项留空将允许所有人使用此弹跳器发布事件。
  approved_publishers: [
    // "pubkey-in-hex",
    // "npub ....",
    // ....
  ],

  // 被阻止的事件发布者黑名单。
  blocked_publishers: [
    // "pubkey-in-hex",
    // "npub ....",
    // ....
  ],

  // 阻止来自以下主机的 websocket 连接。
  blocked_hosts: [
    // "127.0.0.1",
    // "127.0.0.2",
    // "::1",
    // "::2",
    // ....
  ],

  // 用于从某些继电器访问受 NIP-42 保护的事件。
  // 这可能是您的密钥。将其留空可完全禁用 NIP-42 功能。
  //
  // 您甚至可以将此函数用作公共保镖。
  // 不会有安全风险,因为它会利用 NIP-42 识别客户端公钥。
  //
  // 注意: - 需要与 NIP-42 兼容的 nostr 客户端
  private_keys: {
    // "pubkey-in-hex": "privatekey-in-hex",
    // "pubkey-in-hex": "nsec ...."
  },
  // 提示:如果要将密钥/私人密钥转换为十六进制、
  // 您可以运行以下命令:
  //  $ node hexconverter.js npub....
  //  $ node hexconverter.js nsec....
  // 或
  //  $ bostr hexconverter npub....
  //  $ bostr hexconverter nsec....
  // 服务器信息。
  // 仅在 nostr 客户端请求服务器信息时使用。
  server_meta: {
    "contact": "https://cfblog.lepidus.me",
    "pubkey": "09fbf8f3be5ae763435881698d6e845de83be9b5e1cca99988918d17fa3d60f0",
    "description": "Make yourself stronger.",
    "name": "Lepidus",
    "software": "git+https://github.com/Yonle/bostr",

    // 某些 nostr 客户端可能会读取以下内容,以进行兼容性检查。
    // 你可以修改 supported_nips 来匹配你的中继支持。
    "supported_nips": [1,2,9,11,12,15,16,20,22,33,40,42,50],
    // "icon_url": ""
  },

  // favicon 文件的路径。
  favicon: "img/favicon.ico",

  // 使用 x-forwarded-for 将客户端 IP 地址转发给上游中继器
  forward_ip_address_to_upstream: true,

  // Nostr 继电器跳转 [必填]
  relays: [
    "wss://relayable.org",
    "wss://ca.relayable.org",
    "wss://la.relayable.org",
    "wss://relay.damus.io",
    "wss://purplerelay.com",
    "wss://tw.purplerelay.com",
    "wss://jp.purplerelay.com",
    "wss://za.purplerelay.com",
    "wss://ae.purplerelay.com",
    "wss://relay-jp.shino3.net",
    "wss://nostrich.friendship.tw",
    "wss://relay.nostr.band",
    "wss://relay.snort.social",
    "wss://offchain.pub",
    "wss://relay.primal.net",
    "wss://nostr-pub.wellorder.net",
    "wss://nostr.wine",
    "wss://nos.lol",
    "wss://relay.mostr.pub",
    "wss://nostr.wine",
    "wss://nostr21.com",
    "wss://relay.freefrom.space",
    "wss://relay.nostrcheck.me",
    "wss://yabu.me",
    "wss://relay.nostrr.de",
    "wss://damus.relay.center",
    "wss://eden.relay.center",
    "wss://adre.su",
    "wss://public.relaying.io",
    "wss://relay.noswhere.com",
    "wss://nostr.globals.fans",
    "wss://nostr.zkid.social",
    "wss://relay.leligobit.link",
    "wss://nostr-relay.derekross.me",
    "wss://nostr.coinfund.app",
    "wss://nostr.data.haus",
    "wss://nostr-02.yakihonne.com",
    "wss://relay.plebstr.com",
    "wss://nostr.blockpower.capital",
    "wss://nostr.swiss-enigma.ch",
    "wss://relay.sendstr.com",
    // "wss://example3.com",
    // ...and so on
  ]
}

ps.

  • /root/bostr/favicon.ico 这个网站图标是在网上随便做的: https://favicon.io/favicon-generator/
  • authorized_keys 和 approved_publishers 和 server_meta 这三个配置写的hex格式的pubkey,不是npub开头的,需要用 node hexconverter.js npub…. 转换格式
  • 运行bostr软件: node index.js 测试下能不能跑起来,跑起来之后,可以新开一个vps ssh窗口,curl 127.0.0.1:8080 看下输出是否正常:

      Hello. This nostr bouncer (bostr) is bouncing the following relays:
    
      - wss://relay.damus.io
      - wss://purplerelay.com
      ......省略更多内容
    

    看到上面的输出就表示运行正常了,这个时候其实代理relay已经可以用了,只不过是明文http协议(实际是websocket协议,ws://开头的),没有加密,谁都能看到你往这个代理中继上发送了什么内容(可能nostr协议本身也有消息加密,但是我不确定),因此还要配置ssl加密也就是wss。


Docker部署

项目提供docker的部署方式,编辑好上面的config.js文件。执行以下命令

git clone https://github.com/Yonle/bostr
cd bostr
docker build -t bostr:local .
docker run -d --name bostr -p 8080:8080 -v ./config.js:/usr/src/app/config.js bostr:local

Docker部署,打包到hub.docker.com

克隆作者的仓库到自己的仓库,或者直接用作者的仓库也可以
docker login登录docker hub账号
#将github打包镜像
docker build -t zhoupingxiao/bostr:latest https://github.com/zhoupingxiao/bostr.git
docker push zhoupingxiao/bostr:latest
docker run -d --name bostr -p 8080:8080 -v ./config.js:/usr/src/app/config.js zhoupingxiao/bostr

部署nginx反向代理

这个很简单,apt install nginx 安装上nginx,然后写一个转发配置,把指定域名请求转发到 bostr 程序的指定端口上,例如:

server {

        server_name nostr-bostr-relay-proxy.ignorelist.com;

        location / {
                proxy_pass http://127.0.0.1:8080;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;
        }
}

把这个配置保存到 /etc/nginx/sites-available/relay-proxy , 然后 cd /etc/nginx/sites-enabled/ ; ln -s ../sites-available/relay-proxy . ; 启用转发配置,最后reload nginx进程 systemctl reload nginx.service 。

部署Caddy配置反向代理(Caddy可以自动部署证书,只需要以下代码就行)

你的域名 {
    handle {
        reverse_proxy http://bostr:8080 {     #反代对应的websocket网站
            header_up X-Forwarded-Host {host}
            header_up X-Real-IP {remote_host}
            header_up Host {upstream_hostport}    #header_up Host {host}
        }
    }
}

配置ssl加密

默认websocket协议不加密,也就是ws://不是wss://,多一个s表示ssl加密。

配置ssl加密可以使用certbot,非常简单易用,最主要的是免费。。。

安装certbot:先安装snapd apt install snapd ; 再用snap安装certbot(这样才能安装最新版本certbot,老版本不好用) snap install certbot —classic
用certbot申请免费ssl证书:certbot —nginx -d nostr-bostr-relay-proxy.ignorelist.com ,输入邮箱,之后就会自动申请这个域名的ssl证书了,并且会自动添加ssl相关配置到 /etc/nginx/sites-available/relay-proxy ,包括监听443端口等。另外注意邮箱要是你自己真正的,会发确认邮件,需要点击确认。网上也有很多nginx配置ssl的教程,可以搜索看看。还要在 /etc/nginx/sites-available/relay-proxy 配置文件中加一行 proxy_set_header X-Forwarded-Proto “https”; ,位置就在 proxy_set_header 那几行都可以。
最后reload nginx进程 systemctl reload nginx.service ,就可以通过https或者wss访问中继代理服务器了。 curl https://nostr-bostr-relay-proxy.ignorelist.com/ :

Hello. This nostr bouncer (bostr) is bouncing the following relays:

    - wss://relay.damus.io
    - wss://purplerelay.com
    ......省略输出

看到上述内容就表示ssl加密配置ok了。

然后你就可以添加 wss://nostr-bostr-relay-proxy.ignorelist.com/ ( 请使用更新后的域名:wss://tnruygu.cn/ ) 到你的nostr客户端的中继列表里面使用了。