MoreRSS

site iconLala | 荒岛修改

一个应用分享、教程类的博客,主要是那些需要自部署的。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Lala | 荒岛的 RSS 预览

Windows压缩卷扩容Btrfs

2026-08-29 15:03:38

我是双系统Windows10和openSUSE风滚草,openSUSE这边的文件系统是Btrfs,因为磁盘快满了所以我就想着扩容一下,这是我之前遇到的一个问题,今天有时间顺带记录一下扩容办法。

Btrfs内置了类似LVM的多盘组合功能,简单点说就是可以将多个盘的容量(或者分区)合成一个使用。这应该是Btrfs为数不多的优点了。。。

我当初是在一块硬盘上面分了100GB安装了openSUSE,这块硬盘对应我Windows系统内的D盘。我现在的操作步骤是先在Windows的磁盘管理使用压缩卷,把D盘的空间腾一部分出来,这里我压缩50GB:

成功后这里会显示未分配的空间48.83GB:

不要给这个空间创建新加卷什么的,直接重启到openSUSE,先找到在Windows里的这块D盘,这里对应的是/dev/sda,我这机器盘子有点乱,有nvme有hdd还有外挂硬盘= =:

给D盘(/dev/sda)创建新分区,这里我用cfdisk,这是我认为在Linux下创建分区最简单的一款工具了:

cfdisk /dev/sda

选中刚才从Windows压缩出来的这48.83GB:

完成后,最后一步就是把/dev/sda5加入到btrfs:

sudo btrfs device add /dev/sda5 /

检查状态,可以看到/dev/sda5已经存在于未附加里面了,btrfs后续会自动按需分配这些空间:

这个方法也适用于直接加新硬盘,你在机器上装一块新盘,也可以这么操作,反正都是加到一个存储池里面。

5分钟部署一个可供Netcatty同步的WebDAV服务

2026-08-29 14:49:06

Netcatty是一款现代化的跨平台SSH客户端和终端管理器,最近尝试切换到这个SSH客户端使用,用了也有一段时间了,确实挺好用的,开源免费还支持多端同步,为了使用它的同步功能,我自建了一个WebDAV服务,本文记录下WebDAV服务部署和Netcatty同步配置。

安装Docker:

apt update
apt install curl nginx python3-certbot-nginx
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

创建目录和compose文件:

mkdir -p /opt/webdav/data/netcatty && cd /opt/webdav && nano docker-compose.yml

写入如下内容:

name: webdav

services:
  webdav:
    container_name: webdav
    image: ghcr.io/hacdias/webdav:latest
    ports:
     - 127.0.0.1:6065:6065
    restart: always
    volumes:
      - ./data:/data
      - ./config.yml:/config.yml:ro

新建一个配置文件:

nano config.yml

写入如下内容,注意将password改为一个高强度的密码:

address: 0.0.0.0
port: 6065
tls: false
prefix: /
debug: false
noSniff: false
behindProxy: true
directory: /data
permissions: CRUD

log:
  format: console
  colors: true
  outputs:
    - stderr
users:
  - username: netcatty
    password: hidden
    directory: /data/netcatty

启动:

docker compose up -d

请务必配置TLS反向代理,以保护basic auth的账号密码防止被中间人获取。

nano /etc/nginx/sites-available/webdav

写入如下内容:

server {
    listen 80;
    listen [::]:80;
    server_name webdav.example.com;
    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:6065;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;

        set $dest $http_destination;
        if ($http_destination ~ "^https://webdav.example.com/(?(.+))") {
            set $dest /$path;
        }
        proxy_set_header Destination $dest;
    }
}

启用站点:

ln -s /etc/nginx/sites-available/webdav /etc/nginx/sites-enabled/webdav

签发证书:

certbot --nginx

下面简单说一下Netcatty的同步配置,我主要用Windows10和openSUSE风滚草,两边设置同一个主密码,然后配置刚部署的WebDAV服务连接信息正常情况下就能用了。Windows这边没啥问题开箱即用,主要是openSUSE这边,我用的是KDE桌面,配置好了后同步报错:

这里说的钥匙串指的就是系统的安全存储,然后用这个命令看了一下当前系统用的是哪种安全存储:

busctl --user list | grep -Ei 'kwallet|secrets'

不知道为啥明明是KDE桌面却使用的是gnome-keyring:

正常情况下应该使用KDE钱包才对,然后我找到系统设置-KDE密码库:

1.在这里点击“启用KDE密码库子系统”

2.勾选使用KWallet密码库作为密码服务接口。

3.如果没有默认密码库,就点击“新建”创建一个密码库。

配置好了后光注销不行必须重启系统。再执行之前的命令验证一遍:

busctl --user list | grep -Ei 'kwallet|secrets'

正常的话应该显示:

回到Netcatty检查一下就正常了,也可以同步了:

有点抽象的是,遇到这个问题的时候openSUSE这边的Netcatty不知道怎么回事把我云端(WebDAV服务器)的数据给覆盖了。。正常情况下我Windows这边假设同步到云端有3个主机,那么openSUSE这边也应该同步获取这3个主机才对,但是openSUSE直接把云端的3个主机给删了,这导致Windows这边再去同步云端的数据把我Windows这边的3个主机也搞没了。不过还好当时我主要是测试还没正式使用,在解决KDE的问题后,双端已经能够正常同步了,只是我觉得Netcatty在处理这种意外情况的时候表现有点不佳。

Armada:基于Nostr的开源端到端加密聊天应用

2026-08-21 17:10:22

本文仅记录Armada的部署过程,有关具体的技术细节(如Nostr、Concord),这里只简单介绍一下,如果你对Armada背后的这些技术感兴趣,可以Google或者AI探索一下。

Nostr是一个简单、开放的去中心化网络协议,旨在创建一个抗审查的全球化社交网络。而Concord是基于Nostr网络构建的开源通信协议,用于私密、加密的群聊和社区。

Armada主要分为:前端 + 后端(Nostr中继)+ 语音服务(Livekit)+ Blossom服务(媒体存储服务)

关于自托管Armada,其实可以根据自己的需要来选择是否要托管上述所有的服务,如果你接受将数据保存到别人的服务器上,那么可以只托管一个前端。我们这里做事做全套,本文会把所有的服务都搭建起来。如果你选择和本文一样自建全部服务,服务器的内存最好有8GB,主要是Docker镜像在构建过程中需要较多内存以及运行时的OpenSearch需要很多内存。当然你也可以选择更轻量的开源中继服务实现,这里就不多说了。

准备工作,一个域名添加如下解析记录:

名称 类型 内容 注释
relay A 8.9.6.4 #后端(中继)服务
blossom-armada A 8.9.6.4 #媒体存储服务
av A 8.9.6.4 #音视频通话服务
armada A 8.9.6.4 #前端服务

安装Docker等需要用到的软件包:

apt update
apt install curl nginx python3-certbot-nginx git
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

因Armada前端代码仓库托管在Nostr网络上,其地址以nostr://开头,Git本身无法识别这些地址,我们需要安装ngit,这是一个Git插件:

wget https://github.com/DanConwayDev/ngit-cli/releases/download/v2.6.3/ngit-v2.6.3-x86_64-unknown-linux-gnu.2.17.tar.gz
tar -xzvf ngit-v2.6.3-x86_64-unknown-linux-gnu.2.17.tar.gz -C /usr/local/bin/

验证安装:

ngit --version
git-remote-nostr --version

安装一下nak这个CLI工具,后续会用到:

wget https://github.com/fiatjaf/nak/releases/download/v0.20.6/nak-v0.20.6-linux-amd64
chmod +x nak-v0.20.6-linux-amd64
mv nak-v0.20.6-linux-amd64 /usr/local/bin/nak

验证安装:

nak --version

Nostr虽然是去中心化的,但是你的数据最终会保存到中继服务器和Blossom服务器,中继服务器负责传递和存储文本等结构化事件数据,而Blossom服务器专门负责大文件(如图片、视频、音频)的存储与分发。我们这里先把最关键且最核心的中继服务搭起来。其实Github上有非常多的开源Nostr中继服务实现,你并不一定要使用和我一样的中继服务实现,只是为了与Armada完美结合,这里我使用Ditto Relay,因为它支持NIP-50 / NIP-42。

cd /opt
git clone https://gitlab.com/soapbox-pub/ditto-relay.git
cd ditto-relay/

复制一份配置文件:

cp .env.example .env

编辑配置文件:

nano .env

这里只列出特别重要以及我修改过的内容:

PORT="13131"
RELAY_URL="wss://relay.example.com/"
NOSTR_NSEC="nsec..."
IP_HEADER="X-Real-IP"

1.修改RELAY_URL为你自己的域名。

2.NOSTR_NSEC填写中继的私钥,私钥可以使用之前安装的nak工具生成:

nak key generate

生成出来的内容还需要进行转换,因为Ditto Relay只支持nsec...这种格式,而nak默认生成出来的是十六进制私钥,例如你生成的值是:

fca5f6b1f172d57dbd89f3f6bb21aac93d828256082665bfa470301e1c20e549

转换为nsec:

nak encode nsec fca5f6b1f172d57dbd89f3f6bb21aac93d828256082665bfa470301e1c20e549

最终的值就是:

nsec1ljjldv03wt2hm0vf70mtkgd2ey7c9qjkpqnxt0aywqcpu8pqu4ystz0zpt

[可选]这里额外记录一下如何通过私钥获取对应的公钥,首先使用你的十六进制私钥获取:

nak key public fca5f6b1f172d57dbd89f3f6bb21aac93d828256082665bfa470301e1c20e549

对应的公钥就是:

8671a5f886f16deeda11ddd998c7fe61cdf9fc2589d5e954caa0852f9931a5bc

将公钥转换为npub...的格式:

nak encode npub 8671a5f886f16deeda11ddd998c7fe61cdf9fc2589d5e954caa0852f9931a5bc

对应的npub公钥就是:

npub1sec6t7yx79k7aks3mhve33l7v8xlnlp93827j4x25zzjlxf35k7qve74ml

3.我们使用NGINX反向代理Ditto Relay,所以IP_HEADER请务必配置为X-Real-IP或者X-Forwarded-For

启动Ditto Relay,请注意官方没有发布预构建的镜像,目前是在本地构建镜像再启动:

docker compose up -d

Ditto Relay反向代理配置:

nano /etc/nginx/sites-available/ditto-relay

写入如下内容,请注意WebSocket是必须要启用的,Nostr的中继完全依靠WebSocket通信:

server {
    listen 80;
    server_name relay.example.com;
    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:13131;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

启用站点:

ln -s /etc/nginx/sites-available/ditto-relay /etc/nginx/sites-enabled/ditto-relay

签发证书:

certbot --nginx

访问你的中继域名,应该可以看到如图所示的页面:

查看日志:

docker compose logs -f

如有类似输出,则说明中继服务一切正常:

relay-1  | {"level":"info","msg":"index_created","index":"nostr-events"}
relay-1  | {"level":"info","msg":"opensearch_connected","node":"http://opensearch:9200"}
relay-1  | {"level":"info","msg":"indexer_worker_started"}
relay-1  | {"level":"info","msg":"protocol_pool_started","workers":1}
relay-1  | {"level":"info","msg":"protocol_worker_started"}
relay-1  | {"level":"info","msg":"started","port":13131,"log_level":"info","protocol_workers":1}
relay-1  | {"level":"info","msg":"trends_scheduled","interval_ms":900000}
relay-1  | {"level":"info","msg":"bg_worker_started"}

现在我们来部署Blossom服务,与中继服务一样,Github上也有相当多的开源Blossom服务实现,你并不一定要使用和我一样的实现,这里我选择hzrd149开源的Blossom服务实现,因为该存储库的作者hzrd149正是Blossom协议规范的提出者与核心设计者。克隆blossom-server存储库到本地:

cd /opt
git clone https://github.com/hzrd149/blossom-server.git
cd blossom-server/

复制一份配置文件:

cp config.example.yml config.yml

编辑配置文件:

nano config.yml

这里只列出我修改过的内容:

port: 3005
host: 0.0.0.0
publicDomain: "blossom-armada.example.com"

storage:
  rules:
    - type: "*"
      expiration: 100 year

dashboard:
  enabled: true
  username: admin
  password: "89641937"
  lookupRelays:
    - wss://relay.example.com

1.默认的3000端口改为3005,因我的服务器3000端口被别的程序占用了。

2.publicDomain改为你自己的域名。

3.默认情况下blossom-server不永久保存用户上传的文件,我这里改为永久保存,配置成100 year是因为该程序目前有BUG,按正常情况下来说将rules这里配置成[]就可以,但实测这会导致用户无法上传任何类型的文件。

4.务必修改管理员密码,并将中继地址lookupRelays改为你自己的。

编辑一下compose文件:

nano docker-compose.yml

将端口映射改为仅监听在本地:

services:
  blossom:
    build: .
    ports:
      - "127.0.0.1:3005:3005"

启动blossom-server,该项目同样没有提供预构建的镜像,首次启动会先在本地构建:

docker compose up -d --build

blossom-server反向代理配置:

nano /etc/nginx/sites-available/blossom-server

写入如下内容:

server {
    listen 80;
    server_name blossom-armada.example.com;
    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:3005;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

启用站点:

ln -s /etc/nginx/sites-available/blossom-server /etc/nginx/sites-enabled/blossom-server

签发证书:

certbot --nginx

现在我们来部署前端,前端就是一个纯静态的网站,仓库内提供了一个Dockerfile构建脚本,该脚本会构建网站并使用NGINX在80端口上提供服务。让我们先克隆仓库:

cd /opt
git clone nostr://soapbox.pub/relay.ngit.dev/armada
cd armada

配置是在构建时作为Docker构建参数嵌入的,新建一个compose文件:

nano docker-compose.yml

写入如下内容:

services:
  kirara-chat:
    image: moyu-chat:latest
    container_name: moyu-chat
    restart: always
    build:
      context: . # 以当前Git根目录作为构建上下文
      args:
        VITE_APP_NAME: "MoYu Chat"
        VITE_APP_RELAYS: "wss://relay.example.com"
        VITE_SEARCH_RELAYS: "wss://relay.example.com"
        VITE_APP_BLOSSOM_SERVERS: "https://blossom-armada.example.com"
        VITE_CONCORD_AV_SERVERS: "https://av.example.com"
    ports:
      - "127.0.0.1:8085:80"

1.完整的构建时参数(环境变量)见:Configuration (build-time env)

2.构建时的参数,如果修改了这些内容,必须重新构建,否则新配置是不会生效的。

3.该镜像使用NGINX在80端口提供服务,但我们使用反向代理,所以端口映射这里配置的端口为8085。

构建并启动前端:

docker compose up -d --build

前端反向代理配置:

nano /etc/nginx/sites-available/armada

写入如下内容:

server {
    listen 80;
    server_name armada.example.com;
    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:8085;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

启用站点:

ln -s /etc/nginx/sites-available/armada /etc/nginx/sites-enabled/armada

签发证书:

certbot --nginx

现在我们来部署语音服务器,这也是最麻烦的一步了,因为该项目的默认设置没有考虑到将所有服务部署在同一台服务器内的场景,这导致我们需要修改一些配置才能使其与之前部署的这些服务共存。如果你愿意单独将语音服务部署在另外一台服务器内,那没什么好说的,官方的配置直接就能跑起来,但我还是更倾向于将一个完整的项目部署在同一台服务器内。

克隆语音服务的存储库:

git clone nostr://[email protected]/relay.ngit.dev/armada-av
cd armada-av/deploy/single

复制一份配置文件:

cp .env.example .env

编辑.env:

nano .env

需要修改的内容如下:

AV_DOMAIN=av.example.com
LIVEKIT_API_KEY=
LIVEKIT_API_SECRET=

1.AV_DOMAIN请与之前在构建前端时的配置VITE_CONCORD_AV_SERVERS保持一致

2.LIVEKIT_API_KEY / LIVEKIT_API_SECRET使用如下命令生成:

docker run --rm livekit/livekit-server generate-keys

编辑compose文件:

nano docker-compose.yml

将Caddy服务注释或者删除掉,以防止Caddy抢占主机NGINX的80 / 443端口,另外一定要将livekit的镜像TAG从v1.8改为latest,v1.8已经无法与Armada的前端一起正常工作了,这是我踩过的一个坑,可能是作者忘了修改:

# One box: the broker, one LiveKit node, and TLS. `cp .env.example .env`, edit,
# then `docker compose up -d`.
#
# All three services share the host network namespace: media is latency-
# sensitive UDP at thousands of packets per second, and Docker's userland
# proxy adds per-packet cost, so this is the configuration LiveKit itself
# recommends.

services:
  livekit:
    image: livekit/livekit-server:latest
    network_mode: host
    restart: unless-stopped
    command: --config /etc/livekit.yaml
    volumes:
      - ./livekit.yaml:/etc/livekit.yaml:ro
    environment:
      LIVEKIT_KEYS: "${LIVEKIT_API_KEY}: ${LIVEKIT_API_SECRET}"

  broker:
    build:
      context: ../..
    network_mode: host
    restart: unless-stopped
    depends_on:
      - livekit
    environment:
      PORT: "8086"
      # Loopback only. All three services share the host's network namespace,
      # so without this the broker answers on every interface — and with
      # TRUST_PROXY on, a caller reaching it directly could forge
      # X-Forwarded-For and rotate its rate-limit key at will. Caddy is the
      # only way in.
      HOST: "127.0.0.1"
      # What clients sign their grants against — the public name, not the
      # container's. A mismatch here rejects every request (CORD-07 §2 `u` tag).
      PUBLIC_ORIGIN: "https://${AV_DOMAIN}"
      # What clients are told to connect to. A BARE origin: the LiveKit SDK
      # appends /rtc itself, and a url that already carries it breaks signaling.
      LIVEKIT_URL: "wss://${AV_DOMAIN}"
      # Health probes take the loopback shortcut rather than going out and back
      # through TLS.
      LIVEKIT_API_URL: "http://127.0.0.1:7880"
      LIVEKIT_API_KEY: "${LIVEKIT_API_KEY}"
      LIVEKIT_API_SECRET: "${LIVEKIT_API_SECRET}"
      # Caddy sets X-Forwarded-For, and it is the only thing in front of us. The
      # broker reads the client IP from the rightmost entry (the peer Caddy saw),
      # so a client cannot spoof its rate-limit key by stuffing the header.
      TRUST_PROXY: "1"
      TOKEN_TTL_SECONDS: "${TOKEN_TTL_SECONDS:-21600}"
      RATE_LIMIT_PER_MINUTE: "${RATE_LIMIT_PER_MINUTE:-60}"

#  caddy:
#    image: caddy:2-alpine
#    network_mode: host
#    restart: unless-stopped
#    volumes:
#      - ./Caddyfile:/etc/caddy/Caddyfile:ro
#      - caddy_data:/data
#      - caddy_config:/config
#    environment:
#      AV_DOMAIN: "${AV_DOMAIN}"

#volumes:
#  caddy_data:
#  caddy_config:

启动:

docker compose up -d --build

该项目必须使用反向代理,现在改为用主机的NGINX反向代理:

nano /etc/nginx/sites-available/armada-av

写入如下内容:

server {
    listen 80;
    server_name av.example.com;
    client_max_body_size 0;

    location /rtc {
        proxy_pass http://127.0.0.1:7880;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }

    location ~ ^/\.well-known/concord/av {
        proxy_pass http://127.0.0.1:8086;
    }

    location / {
        default_type text/plain;
        return 200 "armada-av";
    }
}

启用站点:

ln -s /etc/nginx/sites-available/armada-av /etc/nginx/sites-enabled/armada-av

签发证书:

certbot --nginx

到这里整个项目就全部部署完成了,该项目目前还在大力开发中(大量使用AI)基本每天发布一个新版本,如果没有重大的破坏性更改,那么要更新的话基本上就是拉新代码、重新构建:

git pull
docker compose up -d --build

接下来简单说一下如何使用Armada,因为Nostr中继的特殊性,你自建了中继,并不代表你的数据只存在于你自建的中继内,如果你没有预先设置好,你的数据可能会发往多个公共的中继。当然这是Nostr设计之初的意图:去中心化。且Armada本身就是端到端加密的,即便你把数据写到其它的中继了,中继服务器也看不到明文。

别说中继了,就是你通过Armada上传到blossom-server的大部分图片、视频、音频等文件都是加密的,相当于blossom-server服务器管理员知道你上传了一张图片文件,但看不到你的图片是什么内容。所以安全这块不用担心。

但我想的是完全掌控自己的数据,我不需要其它中继参与进来,我想在Nostr上建一个封闭的圈子,所有的数据只存在于我自己的中继服务器和blossom-server服务器内。所以下面的配置可能不适用于每个人。

首次访问Armada会显示下图内容,点加入:

如果你没有账户就点击创建账户按钮,你也可以使用nak再生成一个私钥,这里所谓的账户其实就是一串nsec格式的私钥:

生成私钥:

妥善保管你的私钥,这是你账户唯一的登录凭证:

登录后,找到社区中继,把这些中继全部删除,然后添加自己的:

或者在创建群组的时候,这里只使用自己的中继,那么这个群组就只存在于你自己的中继上:

还有一个用于DM(私聊)的中继,这里默认有一个relay.armada.buzz(Armada官方的中继)删掉:

请注意的上面配置仅生效于你自己的账号,别人使用你自建的Armada客户端还是遵循Armada默认的配置,啥意思呢?比如另外一个人用你的Armada客户端给你发消息,Armada默认的DM配置中有一个relay.armada.buzz,这是Armada官方运营的中继,他没删除这个中继的话,他发给你的消息就会存储到relay.armada.buzz这个中继。目前这个设置没办法全局生效,这算是一个小问题吧。啥时候官方能够支持在构建镜像的时候指定这个配置就好了。

只使用自己的中继,如何确保别人能够找到我?给我发消息?配置一下NIP-65就行了,把自己的中继加上去,点保存:

这会把你当前使用的中继列表发送给purplepag.es,一个存储用户NIP-65列表的公共“黄页”中继,类似于通讯录。别人(别的客户端)就可以通过查询purplepag.es知道你的专属中继地址,从而正确地读取你的动态并向你发送消息。除了purplepag.es外,Armada默认还会将列表发给user.kindpag.es和relay.nos.social。这个行为可以在构建镜像的时候使用VITE_NIP65_DISCOVERY_RELAYS指定要发送的中继,但我觉得没有必要去改动。

除了中继,还有媒体服务,确保使用的是自己的:

音视频通话我也试了一下,群组里面可以正常用,私聊不行,应该是BUG,之前用自建的服务器是点了双方都没反应,现在是点了之后对方没反应,过一会儿提示no answer就自动挂断了。。。不过有点神奇的是,大概一个月以前私聊可以用官方的服务器,现在连官方的服务器都不行了。。。

这应该是目前Nostr生态环境中比较成熟的聊天项目了,除了上述的私聊音视频通话有点问题外,没发现明显的BUG,E2EE特别牛逼,群聊甚至发送的图片都是加密的。硬要说缺点的话就是使用起来有点门槛,得先了解什么是Nostr,尤其是各种NIP。这让我想起了某人的一句话:Nostr去中心化的意思就是有一堆中心化的中继,以至于你不知道哪个是中心。。。

rqbit:用Rust打造的高性能、可流式播放的BitTorrent客户端

2026-08-17 15:37:17

前几天通过一个偶然的方式了解到这款BT客户端,试用了几天,我只想说这个下载速度和上传速度是真的牛批,公网BT轻轻松松跑满2Gbps,还支持流式传输,意味着可以边下边播,用处嘛你懂的~

作者发版比较慢,即便仓库累计了很多更新,也可能很长一段时间不发Release,所以我当时用的Docker镜像标签是main。巧合的是就在两天前作者发布了9.0正式版,要知道上一个版本发布还是半年前,我刚得知这项目还用没两天就发布新版本了,也是有点缘分= =。rqbit自带一个Web UI,有点糙但是够用。你要想把这个rqbit拿来跑PT的话也不是不行,就是得自己改UA和Peer ID,撸代码这种事交给AI去做行了,其实rqbit本身也基本实现了自定义UA这个功能,但还差临门一脚,我用AI给加上了。还差自定义Peer ID这个功能没做,我也不打算弄了,想来想去PT我还是用qBittorrent,这个rqbit就单纯拿来看片= =

安装Docker:

apt update
apt install curl nginx python3-certbot-nginx
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

创建目录和compose文件:

mkdir -p /opt/rqbit && cd /opt/rqbit && nano docker-compose.yml

写入如下内容:

services:
  rqbit:
    image: ikatson/rqbit:latest
    network_mode: host
    environment:
      - RQBIT_HTTP_API_LISTEN_ADDR=0.0.0.0:3030
      - RQBIT_LISTEN_PORT=4240
      - RQBIT_HTTP_BASIC_AUTH_USERPASS=imlala:89641937
    volumes:
      - db:/home/rqbit/db
      - cache:/home/rqbit/cache
      - ./download:/home/rqbit/downloads

volumes:
  db:
  cache:

1.建议使用主机网络,达到最佳的网络传输性能。

2.如果你打算使用反向代理Web UI,可以把3030端口监听在本地。

3.全部可配置的环境变量见:rqbit.conf

启动:

docker compose up -d

[可选]配置反向代理:

nano /etc/nginx/sites-available/rqbit

写入如下内容:

server {
    listen 80;
    server_name rqbit.example.com;
    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:3030;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

启用站点:

ln -s /etc/nginx/sites-available/rqbit /etc/nginx/sites-enabled/rqbit

签发证书:

certbot --nginx

流式传输视频有两种,一种是复制播放列表URL:

可以在VLC等视频播放器中打开:

另外一种是直接在浏览器播放,这种应该只支持少量格式,比如MP4这种:

之前作者没发布新版本的时候,我遇到了这两个BUG:#600 / #552 为此我还特地手动编译了个仓库里面的main分支版本,但现在看来已经没有记录的必要了,新版本已经修复了这些BUG,而且手动部署很麻烦,不如Docker一根。

CrowdSec AppSec WAF误报处理

2026-08-14 14:09:54

CrowdSec常规的白名单不能用于启用了CRS的AppSec WAF,如果是被CRS规则拦截的,则最好使用插件的方式来排除。创建插件目录,例如grafana-exclusions:

mkdir -p /var/lib/crowdsec/data/crs-plugins/grafana-exclusions

创建*-before.conf文件,例如grafana-before.conf:

nano /var/lib/crowdsec/data/crs-plugins/grafana-exclusions/grafana-before.conf

文件名必须以-before.conf结尾,这样包含的规则才会在CRS主规则集执行之前生效(才能提前排除规则或更改参数)写入SecRule规则:

SecRule REQUEST_FILENAME "@beginsWith /apis/dashboard.grafana.app/" \
    "id:9900001,\
    phase:1,\
    pass,\
    nolog,\
    ctl:ruleRemoveById=911100,\
    ctl:ruleRemoveById=932115,\
    ctl:ruleRemoveById=942100"

SecRule REQUEST_FILENAME "@beginsWith /api/ds/query" \
    "id:9900002,\
    phase:1,\
    pass,\
    nolog,\
    ctl:ruleRemoveById=942100"

SecRule REQUEST_FILENAME "@beginsWith /api/datasources" \
    "id:9900003,\
    phase:1,\
    pass,\
    nolog,\
    ctl:ruleRemoveById=911100,\
    ctl:ruleRemoveById=931100"

1.排除规则自身的ID最好从9900001开始,避免与其它的规则ID冲突。

2.排除规则不会写没关系,只要能找到误报的规则ID和详情,后面的事交给AI就行了,AI会帮你写排除规则。

误报的规则ID,可以通过这个命令查询:

cscli alerts list

找到ID后,再用这个命令查看详情:

cscli alerts inspect 24705

会输出类似下面这样的内容:

################################################################################################
 - ID           : 24705
 - Date         : 2026-08-14T04:26:51Z
 - Machine      : 33229323947d41878f3730daae8f8f340mkPL0rvRql9cJd3
 - Simulation   : false
 - Remediation  : false
 - Kind         : waf
 - Reason       : anomaly score block: anomaly: 8, 
 - Events Count : 5
 - Scope:Value  : Ip:130.12.180.77
 - Country      : US
 - AS           : Railnet LLC
 - Begin        : 2026-08-14T04:26:50Z
 - End          : 2026-08-14T04:26:50Z
 - UUID         : edf7d1f7-3d6f-41c1-99e8-b55a64aea6ef
 - Context  :
╭───────────────┬──────────────────────────────────────────────────────────────╮
│      Key      │                             Value                            │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ ja4h          │ ge11nn010000_b8bcd45ac095_000000000000_000000000000          │
│ matched_zones │ REQUEST_HEADERS.Host                                         │
│ matched_zones │ REQUEST_BASENAME                                             │
│ matched_zones │ TX.extension                                                 │
│ method        │ GET                                                          │
│ msg           │ Host header is a numeric IP address                          │
│ msg           │ URL file extension is restricted by policy                   │
│ name          │ native_rule:920350                                           │
│ name          │ native_rule:920440                                           │
│ target_uri    │ /config.php.bak                                              │
│ user_agent    │ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 │
│               │ (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36           │
╰───────────────┴──────────────────────────────────────────────────────────────╯

触发的规则ID是920350和920440,触发的URI是/config.php.bak,你直接把这些内容全部复制给AI,让AI写排除规则就行了,当然我这里只是演示,这并不是一个真正的误报。

建议每次添加或者修改规则后,先检查一遍有无错误:

crowdsec -t

没问题再重载配置:

systemctl reload crowdsec

龟壳降配及彻底修复引导丢失的问题

2026-08-14 11:35:00

前几天龟壳发邮件说让降配到2C12G,不然就删鸡了。。我登上去找半天才找到降配的页面:

把这里改成2和12:

保存之后小鸡会重新引导,然后不出意外就要出意外了,因为我是私自安装的Debian系统,所以又遇到了之前GRUB引导丢失的问题了:龟壳ARM Debian11 UEFI GRUB启动项丢失修复,如果按照我之前这篇文章的步骤操作,只能暂时修复,如果龟壳哪天又维护,估计引导又丢了。

我这回仔细研究了一下,发现是龟壳维护后以及某些场景下会重置小鸡的NVRAM(UEFI的非易失性存储),Debian在默认情况下又不会将GRUB安装到UEFI的fallback路径,这就导致找不到引导最终进入EFI shell。解决办法其实很简单,重新安装GRUB的时候带上--removable参数即可:

grub-install --target=arm64-efi --efi-directory=/boot/efi --bootloader-id=debian --removable

这会在/boot/efi/EFI/BOOT/目录下生成BOOTAA64.EFI文件:

/EFI/BOOT/BOOTAA64.EFI是UEFI规范中的默认路径,这样即便NVRAM被重置,系统也能自动识别并开机。

还有一个需要注意的地方:Debian自身的系统更新,如果Debian更新了grub-efi软件包,系统可能会重新运行默认的grub-install,从而只更新/EFI/debian而忘记更新/EFI/BOOT,最好运行以下命令重新配置grub-efi:

dpkg-reconfigure grub-efi-arm64

前面弹出配置内核参数的界面都保持默认直接回车就好了,在下面这两个界面选择Yes:

配置完成后,以后无论是龟壳维护,还是你自己运行apt full-upgrade升级系统内核与GRUB,系统都会自动保证/EFI/BOOT里的兜底文件是最新的。

另外现在创建控制台连接也不用那么麻烦了,可以直接用龟壳的Cloud Shell:

如果小鸡引导丢了,此时在Cloud Shell敲一个回车就能看到EFI shell了,然后输入exit还是quit我忘了= =,即可看到小鸡的BIOS界面:

然后按照之前文章里面的步骤从Boot维护管理里面的Boot From File先把机子启动再重新安装GRUB即可。