Herkos

你自己的邮箱中继

最后更新:2026 年 10 月 3 日

Herkos 的邮件以密封信封(NIP-59 gift wrap)的形式传递,并在你的 DM 中继列表中的 中继上等待,直到你的应用把它取走。大多数公共中继会把这些信封交给任何索取的人。没有人 能打开它们,但任何人都可以统计谁在何时收到邮件,而且中继可以随时删除它们。

一个会询问读者身份(NIP-42)的自有中继,只会把你的信封交给你,不会交给任何其他人, 并按你决定的时长保存它们。本页介绍如何分三步搭建一个这样的中继,外加每晚备份。如果你 已经有服务器,大约需要十五分钟。

选用哪个中继

我们在 2026 年 9 月 24 日运行了两个候选方案,检验了它们实际上如何处理邮件,而不是它们 宣传的内容。

nogringo/nostr-relay HAVEN 1.2.2
谁能读取你的信封 只有你,需先验明身份 /chat:你信任网络中的任何人,需先验明身份。/inbox:任何人,无需验明身份
谁能给你投递邮件 任何验明身份的发件人 只有你的信任网络
删除你收到的邮件 可以 不可以
快速重新同步(NIP-77) 支持 不支持
许可证 MIT MIT

请使用 nogringo/nostr-relay 作为你的 邮箱。 它才是满足邮件需求的那个:任何人都可以给你写信,而只有你能读。HAVEN 适合做 其他事情(个人发件箱、媒体、私人笔记),但作为邮箱,它会拒收你未关注的任何人发来的邮件, 包括转发普通电子邮件的桥接服务。

你需要什么

第 1 步:运行中继

git clone https://github.com/nogringo/nostr-relay
cd nostr-relay
cp .env.example .env

编辑 .env:给中继起个名字(RELAY_NAME),并将 RELAY_URLS 设为它的公开地址 wss://relay.example.com。

然后打开 docker-compose.yml,把端口那一行改为 "127.0.0.1:3334:3334"。中继在检查 谁在验明身份时,会信任代理转发给它的地址,因此它必须只能通过代理访问。启动它:

docker compose up -d

第 2 步:在前面加上 HTTPS

使用 Caddy 时,完整的配置(/etc/caddy/Caddyfile)就是:

relay.example.com {
    reverse_proxy 127.0.0.1:3334
}

重新加载 Caddy(sudo systemctl reload caddy)。现在在浏览器中打开 https://relay.example.com 应该会有响应。

第 3 步:告诉 Herkos

  1. 在 Herkos 中打开 设置 → 网络与服务器 → 你自己的中继,点按 检查中继。 输入 wss://relay.example.com。
  2. Herkos 会连接并测试它:它会尝试索取别人的邮件,并留下一封来自陌生人的测试信封 (随后删除)。你应该会看到 只有你能在这里读取邮件 和 接受任何发件人的邮件。
  3. 点按 设为第一个 DM 中继,然后点按顶部的 保存。

列表中也请保留一个公共中继,排在第二位:如果你的服务器宕机,邮件仍有地方等待。 relay.damus.io 是不错的第二选择,因为它也会询问读者身份。

第 4 步:每晚备份

Herkos 会保留它已取回邮件的副本,但在你的应用关闭期间到达的信封,在你打开 Herkos 之前 只存在于你的服务器上。每晚一次的备份可以填补这个空当,并且在磁盘损坏或服务商关闭你的 账户时,让你能够重建服务器。

中继把所有内容保存在 Docker 卷 nostr-relay_relay-db 内的一个 LMDB 数据库中(卷名以你 克隆到的文件夹名开头;可用 docker volume ls 查看)。在中继写入时复制的 LMDB 文件可能 无法打开,因此脚本会在制作本地副本的几秒钟内停止中继,然后重新启动它,之后才上传副本。 中继停止期间,邮件会在你列表中排第二的公共中继上等待。

副本通过 restic 送出服务器,restic 会在数据离开之前对其加密。 请使用与服务器不同服务商的存储位置:一个 SFTP 账户(存储盒、家用电脑)或一个 兼容 S3 的存储桶。

  1. 安装工具并创建仓库。也请把密码保存在你的密码管理器中:没有它,副本就无法读取; 而如果密码只存在服务器上,它会随服务器一起消失。使用 SFTP 时,root 还需要一个 备份机器接受的 SSH 密钥(sudo ssh-keygen -t ed25519,然后把 /root/.ssh/id_ed25519.pub 添加到那里)。

    sudo apt install restic rsync
    sudo sh -c 'openssl rand -base64 32 > /root/.restic-password'
    sudo sh -c 'cat > /root/.restic-env' <<'END'
    export RESTIC_REPOSITORY=sftp:backup@backup.example.com:/relay
    export RESTIC_PASSWORD_FILE=/root/.restic-password
    END
    sudo chmod 600 /root/.restic-password /root/.restic-env
    sudo sh -c '. /root/.restic-env && restic init'
    
  2. 将以下内容保存为 /usr/local/bin/backup-relay 并设为可执行 (sudo chmod 700 /usr/local/bin/backup-relay)。如果你没有克隆到 /root/nostr-relay,请修改 RELAY_DIR。它会保留最近 14 天、8 周和 12 个月的副本: 可回溯一年,占用空间接近数据库本身的大小。

    #!/bin/sh
    set -eu
    . /root/.restic-env
    RELAY_DIR=/root/nostr-relay
    COPY=/var/backups/relay-db
    VOLUME=$(docker volume inspect --format '{{ .Mountpoint }}' nostr-relay_relay-db)
    mkdir -p "$COPY"
    cd "$RELAY_DIR"
    docker compose stop relay
    trap 'docker compose start relay' EXIT
    rsync -a --delete "$VOLUME/" "$COPY/"
    docker compose start relay
    trap - EXIT
    restic backup "$COPY" --tag relay
    restic forget --tag relay --keep-daily 14 --keep-weekly 8 --keep-monthly 12 --prune
    
  3. 先手动运行一次(sudo /usr/local/bin/backup-relay),然后用 sudo crontab -e 安排定时任务。第二行每月读回十分之一的已存数据,每次读取不同的十分之一,以证明副本 仍能打开。时常看一看 /var/log/backup-relay.log:出现含 Fatal 的行,就表示那天 夜里的备份失败了。

    15 4 * * * /usr/local/bin/backup-relay >> /var/log/backup-relay.log 2>&1
    45 5 1 * * . /root/.restic-env && restic check --read-data-subset=10% >> /var/log/backup-relay.log 2>&1
    

恢复方法(换新服务器,或磁盘故障之后):重新搭建中继(第 1 到 3 步),并对同一个 仓库重复本步骤的第 1 点和第 2 点,但不要生成新密码,而是把你保存的密码写入 /root/.restic-password,并跳过 restic init。然后把最新的备份复制到中继的卷中:

sudo sh -c '. /root/.restic-env && restic restore latest --tag relay --target /'
cd /root/nostr-relay && sudo docker compose stop relay
sudo rsync -a --delete /var/backups/relay-db/ "$(sudo docker volume inspect --format '{{ .Mountpoint }}' nostr-relay_relay-db)/"
sudo docker compose start relay

每年在一台备用机器上做一次这样的恢复,确认中继启动后你的邮件都在:这是唯一能证明 整条链路(包括密码)可用的测试。

须知