MoreRSS

site iconLala | 荒岛修改

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

Inoreader Feedly Follow Feedbin Local Reader

Lala | 荒岛的 RSS 预览

La Suite Meet:基于LiveKit的开源视频会议程序

2026-01-29 17:06:56

La Suite Meet由LiveKit提供技术支持,拥有媲美Zoom的卓越性能和高质量音视频体验。

特点:

  • 针对大型会议的稳定性进行了优化(100+人)
  • 支持多屏幕共享
  • 非持久性、安全聊天
  • 端到端加密(即将推出)
  • 会议记录
  • 会议记录及摘要(目前处于测试阶段)
  • 电话系统集成
  • 通过强大的身份验证和访问控制机制确保安全参与
  • 可定制的前端样式

这个项目也是法国政府主导的,引用下面这段话:

On the 25th of January 2026, David Amiel, France’s Minister for Civil Service and State Reform, announced the full deployment of Visio—the French government’s dedicated Meet platform—to all public servants

这哥们打算让法国所有公务员都用这个开会= =这么牛b的程序(其实牛b的是LiveKit)必须部署逝一下。。。

本文根据官方的文档编写,主要记录并解决目前官方部署文档内的一些错误。

准备工作:

1.准备一个域名做好解析:meet.example.com(主程序),livekit.example.com(livekit服务)

2.部署VoidAuth OIDC身份验证服务,示例域名:voidauth.example.com

3.服务器的这些端口不能被其他程序占用:80、443、7880、7881、7882(UDP)、8086

在VoidAuth创建OIDC APP:

请将Redirect URLs配置为,注意URL最后的/,不要少了这个/:

https://meet.example.com/api/v1.0/callback/

请将PostLogout URL配置为,注意URL最后的/,不要少了这个/:

https://meet.example.com/api/v1.0/logout-callback/

做好上述准备工作后,现在就可以来部署Meet了,安装Docker:

apt -y update
apt -y install curl
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

下载compose文件以及需要用到的环境变量配置文件、LiveKit配置文件、NGINX配置文件:

cd /opt
mkdir -p meet/env.d && cd meet
curl -o compose.yaml https://raw.githubusercontent.com/suitenumerique/meet/refs/heads/main/docs/examples/compose/compose.yaml
curl -o .env https://raw.githubusercontent.com/suitenumerique/meet/refs/heads/main/env.d/production.dist/hosts
curl -o env.d/common https://raw.githubusercontent.com/suitenumerique/meet/refs/heads/main/env.d/production.dist/common
curl -o env.d/postgresql https://raw.githubusercontent.com/suitenumerique/meet/refs/heads/main/env.d/production.dist/postgresql
curl -o livekit-server.yaml https://raw.githubusercontent.com/suitenumerique/meet/refs/heads/main/docs/examples/livekit/server.yaml
curl -o default.conf.template https://raw.githubusercontent.com/suitenumerique/meet/refs/heads/main/docker/files/production/default.conf.template

为了后续部署工作的顺利进行,这里先解决一些目前官方文档里面的错误,编辑compose文件:

nano compose.yaml

后端容器设置的env配置文件是错的,根本没有backend这个文件,取而代之的是.env文件,所以这里注释掉不存在的backend文件,添加.env文件:

...
  backend:
    image: lasuite/meet-backend:latest
    ...
    restart: always
    env_file:
    - env.d/common
#    - env.d/backend
    - .env
    - env.d/postgresql
    ...

前端容器又缺少.env文件,这里加上,同时将前端容器的8083端口暴露出来(不是官方文档说的8086端口)方便后续配置反向代理:

...
  frontend:
    image: lasuite/meet-frontend:latest
    ...
    env_file:
    - .env
    - env.d/common
    ...
    ports:
    - "127.0.0.1:8086:8083"

将LiveKit容器的7880端口暴露出来,这是Likvkit的“信号”端口,是Meet与Livekit通信的关键:

...
  livekit:
    image: livekit/livekit-server:latest
    command: --config /config.yaml
    ports:
    - 127.0.0.1:7880:7880
    - 7881:7881/tcp
    - 7882:7882/udp
    ...

编辑供前端容器内部使用的NGINX配置文件:

nano default.conf.template

将这两个错误的环境变量:BACKEND_HOST/FRONTEND_HOST修改为如下内容:

upstream meet_backend {
    server ${BACKEND_INTERNAL_HOST}:8000 fail_timeout=0;
}
upstream meet_frontend {
    server ${FRONTEND_INTERNAL_HOST}:8080 fail_timeout=0;
}

编辑.env文件:

nano .env

这里只列出需要修改的内容:

MEET_HOST=meet.example.com
#KEYCLOAK_HOST=id.domain.tld # 注释掉这个配置,我们不使用KEYCLOAK
LIVEKIT_HOST=livekit.example.com
#REALM_NAME=meet # 注释掉这个配置,我们不使用KEYCLOAK

编辑common文件:

nano env.d/common

这里只列出需要修改的内容:

# Django
DJANGO_SECRET_KEY= # 使用openssl rand -hex 32生成

# Mail
DJANGO_EMAIL_HOST=mail.example.com
DJANGO_EMAIL_HOST_USER=smtp
DJANGO_EMAIL_HOST_PASSWORD=smtppassword
DJANGO_EMAIL_PORT=587
[email protected]
DJANGO_EMAIL_USE_TLS=true

# OIDC
OIDC_OP_JWKS_ENDPOINT=https://voidauth.example.com/oidc/jwks
OIDC_OP_AUTHORIZATION_ENDPOINT=https://voidauth.example.com/oidc/auth
OIDC_OP_TOKEN_ENDPOINT=https://voidauth.example.com/oidc/token
OIDC_OP_USER_ENDPOINT=https://voidauth.example.com/oidc/me
OIDC_OP_LOGOUT_ENDPOINT=https://voidauth.example.com/oidc/session/end
OIDC_RP_CLIENT_ID=
OIDC_RP_CLIENT_SECRET=

# Livekit Token settings
LIVEKIT_API_SECRET= # 使用openssl rand -hex 32生成

编辑postgresql文件,设置PostgreSQL数据库密码:

nano env.d/postgresql

这里只列出需要修改的内容:

DB_PASSWORD=setyourdbpassword # 设置你的数据库密码。

编辑livekit-server.yaml:

nano livekit-server.yaml

将keys的值设置成和LIVEKIT_API_SECRET相同的内容:

port: 7880
redis:
  address: redis:6379
keys:
  meet: # 把这里的值设置成和LIVEKIT_API_SECRET相同的内容
# WebRTC configuration
rtc:
  # # when set, LiveKit will attempt to use a UDP mux so all UDP traffic goes through
  # # listed port(s). To maximize system performance, we recommend using a range of ports
  # # greater or equal to the number of vCPUs on the machine.
  # # port_range_start & end must not be set for this config to take effect
  udp_port: 7882
  # when set, LiveKit enable WebRTC ICE over TCP when UDP isn't available
  # this port *cannot* be behind load balancer or TLS, and must be exposed on the node
  # WebRTC transports are encrypted and do not require additional encryption
  # only 80/443 on public IP are allowed if less than 1024
  tcp_port: 7881
  # use_external_ip should be set to true for most cloud environments where
  # the host has a public IP address, but is not exposed to the process.
  # LiveKit will attempt to use STUN to discover the true IP, and advertise
  # that IP with its clients
  use_external_ip: true

启动全部容器:

docker compos up -d

运行数据库迁移并创建Django管理员用户:

docker compose run --rm backend python manage.py migrate
docker compose run --rm backend python manage.py createsuperuser --email [email protected] --password adminpassword

稍后你可以使用这个URL访问Docs的Django后台:meet.example.com/admin。在这个后台你可以管理用户创建的房间。

请注意这里创建的用户只拥有Django管理员权限,最终实际可供用户使用的账号必须使用OIDC创建。

配置Ferron反向代理:

nano /etc/ferron.kdl

写入如下内容:

meet.example.com {
   proxy "http://127.0.0.1:8086/"
   proxy_request_header_replace "Host" "{header:Host}"
}

livekit.example.com {
   proxy "http://127.0.0.1:7880/"
   proxy_request_header_replace "Host" "{header:Host}"
}

如果你使用的是别的反向代理,则必须为LiveKit配置WebSocket和长连接支持。Ferron默认支持这些,所以不必写在配置文件内。

重载Ferron:

systemctl reload ferron

效果:

看着这个经典的蓝白配色UI,还有这几个按钮的造型,然后还是法国出品,瞬间就觉得好似一位故人:OVH!

简单测试,在电脑上启用OBS虚拟摄像头,在手机上加入房间,看看双方能不能正常视频通话:

功能还是很全面的,共享浏览器屏幕、发表情、拍手、甚至还有虚拟背景和聊天功能。唯独在国内使用的话可能要注意连通性问题,国内的网络嘛,懂的都懂,如果你按照这篇文章部署后连不上,则可能还需要在LiveKit配置TURN服务。

由法国政府开源的笔记软件:Docs

2026-01-28 19:12:14

Docs这个项目我一直都在关注,奈何之前的部署方式只支持k8s,如果只是为了部署一个笔记软件去搭一个k8s的话,那真的是有点拿大炮打蚊子那味了= =最近发现这个项目支持用docker compose部署了,遂记录下部署过程与遇到的一些问题。

不得不说国家队还是牛B!这个笔记软件第一次用就感觉挺顺手的,前端UI简洁大气,自带AI功能,可以帮你美化、改写、总结、修正错别字、翻译等。自托管的实例所有功能都能使用,与官方实例1:1还原,而不是像某些“开源笔记”那样吃相难看。

缺点也还是有的,没有十全十美的东西= =目前虽然支持docker compose部署了,但部署起来还是比较麻烦。另外我在使用中发现一些小bug,例如:上传的文件名不能包含中文,有中文就会导致上传失败。导出的PDF文件显示中文是乱码,且不支持代码块等。如果你不介意这些问题的话,可以尝试一下。

本文根据Docs官方的文档编写,进行了一些修改:

1.将Keycloak更换为VoidAuth,因为Keycloak部署和配置都过于复杂。

2.将MinIO更换为Garage,因为开源的MinIO已经名存实亡了。

3.不使用官方的NGINX反向代理配置,因为我的服务器已经运行Ferron Web Server了。

如果你完全遵循本文的步骤来部署,则在开始前需要做好以下准备工作:

1.一个域名做好解析,本文示例域名:docs.example.com

2.部署Garage S3对象存储。本文示例域名:s3-garage.example.com

注:如果你使用Garage S3则无法使用Docs的历史版本与回退功能,这是由于目前Garage的S3实现不支持“版本控制”功能导致的,并不是Docs的问题。

3.部署VoidAuth OIDC身份验证服务。本文示例域名:voidauth.example.com

4.创建一个OPENAI的API KEY。

在Garage S3创建存储桶和key并授权:

docker exec -ti garage /garage bucket create docs-media-storage
docker exec -ti garage /garage key create docs-media-storage-app-key
docker exec -ti garage /garage bucket allow --read --write --owner docs-media-storage --key docs-media-storage-app-key

在VoidAuth创建OIDC APP:

务必将Redirect URLs设置为:

https://docs.example.com/api/v1.0/callback/

务必将PostLogout URL设置为:

https://docs.example.com/api/v1.0/logout-callback/

做好上面的准备工作后,现在可以正式部署Docs了,先在服务器内安装Docker:

apt -y update
apt -y install curl
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

下载compose文件以及需要用到的环境变量配置文件、NGINX配置文件:

cd /opt
mkdir -p docs/env.d
cd docs
curl -o compose.yaml https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/docs/examples/compose/compose.yaml
curl -o env.d/common https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/common
curl -o env.d/backend https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/backend
curl -o env.d/yprovider https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/yprovider
curl -o env.d/postgresql https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/env.d/production.dist/postgresql
curl -o default.conf.template https://raw.githubusercontent.com/suitenumerique/docs/refs/heads/main/docker/files/production/etc/nginx/conf.d/default.conf.template

设置PostgreSQL数据库密码:

nano env.d/postgresql

这里只列出需要修改的内容:

DB_PASSWORD=setyourdbpassword # 设置你的数据库密码。

设置YPROVIDER API KEY/COLLABORATION SECRET:

nano env.d/yprovider

这里只列出需要修改的内容:

Y_PROVIDER_API_KEY=randomkey # 使用openssl rand -hex 32生成
COLLABORATION_SERVER_SECRET=randomkey # 使用openssl rand -hex 32生成

编辑common环境变量配置文件:

nano env.d/common

这里只列出需要修改的内容:

DOCS_HOST=docs.example.com # 设置你的Docs实例域名
#KEYCLOAK_HOST=id.domain.tld # 注释掉这个变量,因为我们不使用KEYCLOAK
S3_HOST=s3-garage.example.com # 设置你的Garage S3端点域名
BUCKET_NAME=docs-media-storage # 如果你的S3桶名不是docs-media-storage请修改
#REALM_NAME=docs # 注释掉这个变量,因为我们不使用KEYCLOAK

编辑backend环境变量配置文件:

nano env.d/backend

这里只列出需要修改和增加的内容:

## Django
DJANGO_SECRET_KEY= # 使用openssl rand -hex 32生成
DOCUMENT_IMAGE_MAX_SIZE=2048000000 # 增加这个配置,修改默认文件上传大小到2048MB

# Mail
DJANGO_EMAIL_HOST=mail.example.com
DJANGO_EMAIL_HOST_USER=smtp
DJANGO_EMAIL_HOST_PASSWORD=smtppassword
DJANGO_EMAIL_PORT=587
[email protected]
DJANGO_EMAIL_USE_TLS=true

# Media
AWS_S3_REGION_NAME=garage # 因Garage S3强制要求区域,增加这个配置以适配Garage S3
AWS_S3_ACCESS_KEY_ID=
AWS_S3_SECRET_ACCESS_KEY=

# OIDC
OIDC_OP_JWKS_ENDPOINT=https://voidauth.example.com/oidc/jwks
OIDC_OP_AUTHORIZATION_ENDPOINT=https://voidauth.example.com/oidc/auth
OIDC_OP_TOKEN_ENDPOINT=https://voidauth.example.com/oidc/token
OIDC_OP_USER_ENDPOINT=https://voidauth.example.com/oidc/me
OIDC_OP_LOGOUT_ENDPOINT=https://voidauth.example.com/oidc/session/end
OIDC_RP_CLIENT_ID=
OIDC_RP_CLIENT_SECRET=

# AI
AI_FEATURE_ENABLED=true # is false by default
AI_BASE_URL=https://api.openai.com/v1
AI_API_KEY=sk-proj-3aFFuEBT...
AI_MODEL=gpt-4o-mini

编辑NGINX配置文件:

nano default.conf.template

修改上传大小与之前的配置对应:

# increase max upload size
client_max_body_size 2048m;

为了避免混淆,请注意这里的NGINX配置文件是给前端容器在容器内部使用的,并不是给主机NGINX用的。无论你用不用NGINX反代,都必须要有这个文件。

编辑compose文件:

nano compose.yaml

将前端容器的8083端口暴露出来:

...
  frontend:
    image: lasuite/impress-frontend:latest
    ...
    volumes:
      - ./default.conf.template:/etc/nginx/templates/docs.conf.template
    ports:
      - 127.0.0.1:8083:8083
...

启动Docs:

docker compose up -d

运行数据库迁移并创建Django管理员用户:

docker compose run --rm backend python manage.py migrate
docker compose run --rm backend python manage.py createsuperuser --email [email protected] --password adminpassword

稍后你可以使用这个URL访问Docs的Django后台:docs.example.com/admin。请注意这里创建的用户仅作为Django管理员账号,与实际的用户账号不相关,用户账号始终使用OIDC登录。

配置Ferron反向代理:

nano /etc/ferron.kdl

写入如下内容:

docs.example.com {
   proxy "http://127.0.0.1:8083/"
   proxy_request_header_replace "Host" "{header:Host}"
}

重载Ferron:

systemctl reload ferron

看下使用效果,和AFFiNE一样,支持使用/命令呼出菜单:

选中一段内容可以使用AI功能:

AI改写:

用作提示:

gpt-4o-mini这排版感觉比我写的还好啊= =我艹了个DJ!把功能都试的差不多了,最后再补充点不太满意的地方。搜索功能弱了点,似乎不支持全文搜索。不支持密码分享文档。没有个人账号的信息页面,缺少上传头像之类的功能,这方面有点过于简洁了= =总的来说很牛B,给我一种很丝滑的体验。

由AdGuard开源的VPN协议:TrustTunnel

2026-01-25 21:32:12

TrustTunnel可以将任意网络流量(TCP/UDP/ICMP)通过加密的HTTP/2或HTTP/3连接进行隧道传输。该协议的设计目标如下:

隐蔽性:流量显示为标准的HTTPS,难以与常规网页浏览区分开来。
高性能:在单个传输会话上高效复用多个连接。
可靠性:内置会话恢复和健康检查机制。
灵活性:同时支持 HTTP/2(基于TLS)和HTTP/3(基于QUIC)传输协议。

TrustTunnel还有iOS/Android的GUI客户端,Windows和Linux目前只有CLI客户端,但是这个CLI也支持TUN模式。我部署试了一下,目前感觉分流不太行,要是官方能支持GeoIP之类的数据库就好了,现在只能用IPCIDR= =

开始部署前你需要先准备一个域名,做好解析记录,例如:giatunnel.example.com。一台Debian x64服务器(VPS)。

Debian服务器端安装:

cd /opt
wget https://github.com/TrustTunnel/TrustTunnel/releases/download/v0.9.115/trusttunnel-v0.9.115-linux-x86_64.tar.gz
tar -xzvf trusttunnel-v0.9.115-linux-x86_64.tar.gz
mv trusttunnel-v0.9.115-linux-x86_64 trusttunnel
cd trusttunnel/

直接运行这个二进制文件开始配置向导,这个向导会协助你配置服务端的内容:

./setup_wizard

1.服务端监听的地址和端口,默认:0.0.0.0:443,但是考虑到443端口可能会被Web Server等软件占用,本文配置为:0.0.0.0:8443。

2.设置用户账号和密码,这里的账号和密码用于客户端连接。TrustTunnel是支持多用户的,这可能为后续的机场服务铺路= =

3.创建一个规则配置文件(rules.toml)如果你是一个人使用,那么服务器端不需要配置这个,一路回车下一步即可。

4.创建一个核心配置文件(vpn.toml)所有与VPN相关的配置都在这个配置文件内。一路回车下一步即可!

5.协助你配置域名证书,可使用Let’s Encrypt自动申请证书,支持HTTP-01/DNS-01模式。如果服务器80端口被Web Server等软件占用,可以选择DNS-01模式。

如果选择DNS-01模式,则需要在DNS解析提供商处添加相应解析记录:

配置完成后,复制一份systemd服务配置文件:

cp trusttunnel.service.template /etc/systemd/system/trusttunnel.service

启动TrustTunnel服务并设置开机自启:

systemctl enable --now trusttunnel

检查运行状态,确保正常运行:

systemctl status --now trusttunnel

[可选]导出客户端配置文件,方便客户端配置,例如本文之前配置的用户账号是imlala,服务器IP是89.64.19.37,端口为8443,那么执行如下命令:

./trusttunnel_endpoint vpn.toml hosts.toml -c imlala -a 89.64.19.37:8443

会输出类似如下内容,这些是配置客户端连接需要的,可以复制保存下来:

# Endpoint host name, used for TLS session establishment
hostname = "giatunnel.exampel.com"
# Endpoint addresses.
addresses = ["89.64.19.37:8443"]
# Whether IPv6 traffic can be routed through the endpoint
has_ipv6 = true
# Username for authorization
username = "imlala"
# Password for authorization
password = "yourvpnpassword"
# Skip the endpoint certificate verification?
# That is, any certificate is accepted with this one set to true.
skip_verification = false
upstream_protocol = "http2"
upstream_fallback_protocol = ""
anti_dpi = false

服务器端的配置就全部完成了,接下来配置客户端。这里我以Linux的CLI客户端为例。

下载客户端压缩包解压进入到目录:

cd /home/imlala/桌面
wget https://github.com/TrustTunnel/TrustTunnelClient/releases/download/v0.99.93/trusttunnel_client-v0.99.93-linux-x86_64.tar.gz
tar -xzvf trusttunnel_client-v0.99.93-linux-x86_64.tar.gz
cd trusttunnel_client-v0.99.93-linux-x86_64

执行配置向导,协助你配置客户端:

./setup_wizard

1.配置VPN的运行模式,目前支持general和selective模式。general是指加入排除列表的都走直连,其他走代理。而selective是加入排除列表的走代理,其他走直连。本文使用的是general模式。

2.配置连接到VPN服务器的IP地址/端口/账号密码,对于本文而言端口号是8443。

3.配置证书,直接回车下一步。但是请不要启用跳过证书验证,这可能会导致安全问题,如果你是自签证书的话就无所谓了。

4.配置服务端的域名,本文示例:giatunnel.example.com

5.配置客户端监听类型,支持Socks5和TUN,本文使用的是TUN。

接下来使用文本编辑器打开向导生成的客户端配置文件:

nano trusttunnel_client.toml

配置一个DNS服务器:

dns_upstreams = ["tls://1.1.1.1"]

[可选]配置分流,下载中国的IP列表,然后新建一个Python脚本,内容如下:

with open("chnroute.txt", "r") as f:
    ips = [f'"{line.strip()}"' for line in f if line.strip()]

with open("config.toml", "w") as f:
    f.write("exclusions = [\n  ")
    f.write(",\n  ".join(ips))
    f.write("\n]")

print("处理完成,结果已保存至 config.toml")

运行脚本,把IP转换成TrustTunnel需要的格式:

python3 ipcidr.py

把转换好的内容全选复制粘贴到trusttunnel_client.toml:

exclusions = [
  "1.0.1.0/24",
  "1.0.2.0/23",
  "1.0.8.0/21",
  "1.0.32.0/19",
  "1.1.0.0/24",
  "1.1.2.0/23",
  "1.1.4.0/22",
  "1.1.8.0/24",
  "1.1.9.0/24",
  "1.1.10.0/23",
  "1.1.12.0/22",
  "1.1.16.0/20",
  "1.1.32.0/19",
  "1.2.0.0/23",
  "1.2.2.0/24",
  ...
]

下载中国域名列表,然后新建一个Python脚本,内容如下:

import json

def extract_domain_suffixes(input_file, output_file):
    try:
        # 1. 读取并解析 JSON 文件
        with open(input_file, 'r', encoding='utf-8') as f:
            data = json.load(f)
        
        all_suffixes = []
        
        # 2. 遍历 rules 提取所有的 domain_suffix
        rules = data.get("rules", [])
        for rule in rules:
            if "domain_suffix" in rule:
                all_suffixes.extend(rule["domain_suffix"])

        if not all_suffixes:
            print("未找到任何 domain_suffix 数据。")
            return

        # 3. 格式化处理
        formatted_list = []
        total_count = len(all_suffixes)
        
        for i, item in enumerate(all_suffixes):
            # 在最前面添加两个空格
            line = f'  "{item}"'
            
            # 如果不是最后一项,则在末尾加逗号
            if i 

运行脚本,把域名转换成TrustTunnel需要的格式:

python3 cndomain.py

把转换好的内容全选复制粘贴到trusttunnel_client.toml:

exclusions = [
  ...
  "zzzla.com",
  "zzzlsh.com",
  "zzznkq.com",
  "zzzppp.com",
  "zzzqqp.com",
  "zzzsxx.com",
  "zzzxwh.net",
  "zzzyb.com",
  "zzzymjg.com",
  "zzzyy.com",
  "zzzyyy.com",
  "zzzzaaaa.com",
  "zzzzzz.me"
]

启动TrustTunnel客户端:

sudo ./trusttunnel_client -c trusttunnel_client.toml

使用TUN模式请使用sudo提升权限,以允许TrustTunnel创建TUN0虚拟网卡及配置路由表。

简单说一下使用体验(分流效果)。。如果客户端使用:

upstream_protocol = "http2"

访问国外的站点很快,但是国内站点比mihomo/sing-box慢多了,分流是生效了的,不知道是不是DNS的问题。。如果客户端使用:

upstream_protocol = "http3"

则访问国外也慢的一匹,应该是奠信限制udp导致的= =,另外请不要把油管4k/8k视频当作测速工具,即便要测也请关闭浏览器的quic(血泪史):

chrome://flags/#enable-quic

Docker部署PowerDNS Authoritative Server

2026-01-19 17:12:01

我几年前写过一篇部署PowerDNS权威服务器的文章,最近需要搭建一个,然后翻出来看了下发现写的不够完善,而且纯手动部署太麻烦了,遂决定重新记录下使用Docker部署的步骤,另外主要补充一下:主从同步、DNSSEC的配置。

首先还是需要到域名注册商添加胶水记录(Glue Record),我使用的是spaceship,这家的用户面板不叫胶水记录,叫个人名称服务器,说实话有时候挺烦这种自己瞎起名字的行为。。害我在他们的这个面板里面找半天:

由于spaceship的限制,这里至少要添加2条胶水记录,如果你不打算部署2台服务器(主从同步),可以把两条记录的值都指向同一台服务器的IP,之后更改域名的NS服务器为刚设置的“个人名称服务器”:

本文示例:91.99.72.72为主(primary)服务器,49.13.168.202为从(secondary)服务器,在两台服务器内都安装Docker:

apt -y update
apt -y install curl
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

在主(primary)服务器创建目录新建compose文件:

mkdir /opt/pdns-mysql && cd /opt/pdns-mysql && nano docker-compose.yml

写入如下内容,需要修改的地方写了注释:

services:
  mariadb:
    image: mariadb:lts
    container_name: pdns-mariadb
    restart: unless-stopped
    networks:
      - pdns
    environment:
      - MARIADB_ROOT_PASSWORD=setyourpdnsmasterdbpassword # 设置数据库ROOT用户的密码
    volumes:
      - ./mariadb-data:/var/lib/mysql:Z
    healthcheck:
      test: ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized']
      timeout: 10s
      retries: 5

  phpmyadmin:
    image: phpmyadmin
    restart: unless-stopped
    networks:
      - pdns
    ports:
      - 8988:80
    environment:
      - PMA_HOST=mariadb

  pdns-master:
    image: pschiffe/pdns-mysql:latest
    container_name: pdns-master
    hostname: ns1.ohsb.cc # 设置PDNS主服务器的主机名,务必与你的胶水记录保持一致
    restart: unless-stopped
    networks:
      pdns:
        ipv4_address: 172.89.64.74
    depends_on:
      mariadb:
        condition: service_healthy
    environment:
      - PDNS_gmysql_host=mariadb
      - PDNS_gmysql_port=3306
      - PDNS_gmysql_user=root
      - PDNS_gmysql_password=setyourpdnsmasterdbpassword # 设置连接数据库ROOT用户的密码
      - PDNS_gmysql_dbname=powerdns
      - PDNS_gmysql_dnssec=yes
      - PDNS_primary=yes
      - PDNS_api=yes
      - PDNS_api_key=setyourpdnsapikey # 设置PDNS API KEY
      - PDNS_webserver=yes
      - PDNS_webserver_address=0.0.0.0
      - PDNS_webserver_allow_from=0.0.0.0/0,::/0
      - PDNS_webserver_password=setyourwebserverpassword # 设置PDNS WEB密码
      - PDNS_version_string=anonymous
      - PDNS_default_ttl=1500
      - PDNS_allow_axfr_ips=49.13.168.202 # 设置为从服务器的公网IP
      - PDNS_only_notify=49.13.168.202 # 设置为从服务器的公网IP
    ports:
      - '53:53'
      - '53:53/udp'
      - '8081:8081'
    volumes:
      - /etc/localtime:/etc/localtime:ro

  pdns-admin:
    image: pschiffe/pdns-admin
    container_name: pdns-admin
    restart: unless-stopped
    depends_on:
      mariadb:
        condition: service_healthy
    networks:
      - pdns
    ports:
      - '8989:8080'
    environment:
      - PDNS_ADMIN_SQLA_DB_HOST=mariadb
      - PDNS_ADMIN_SQLA_DB_PORT=3306
      - PDNS_ADMIN_SQLA_DB_USER=root
      - PDNS_ADMIN_SQLA_DB_PASSWORD=setyourpdnsmasterdbpassword # 设置连接数据库ROOT用户的密码
      - PDNS_ADMIN_SQLA_DB_NAME=powerdnsadmin
      - PDNS_API_URL="http://pdns-master:8081/"
      - PDNS_API_KEY=setyourpdnsapikey # 设置连接到PDNS Master的API KEY
      - PDNS_VERSION=5.0
    volumes:
      - /etc/localtime:/etc/localtime:ro

networks:
  pdns:
    ipam:
      config:
        - subnet: 172.89.0.0/16
          gateway: 172.89.0.1

在从(secondary)服务器创建目录新建compose文件:

mkdir /opt/pdns-slave && cd /opt/pdns-slave && nano docker-compose.yml

写入如下内容,需要修改的地方写了注释:

services:
  mariadb:
    image: mariadb:lts
    container_name: pdns-mariadb
    restart: unless-stopped
    networks:
      - pdns
    environment:
      - MARIADB_ROOT_PASSWORD=setyourpdnsmasterdbpassword # 设置数据库ROOT用户的密码
    volumes:
      - ./mariadb-data:/var/lib/mysql:Z
    healthcheck:
      test: ['CMD', 'healthcheck.sh', '--connect', '--innodb_initialized']
      timeout: 10s
      retries: 5

  phpmyadmin:
    image: phpmyadmin
    restart: unless-stopped
    networks:
      - pdns
    ports:
      - 8988:80
    environment:
      - PMA_HOST=mariadb

  pdns-slave:
    image: pschiffe/pdns-mysql:latest
    container_name: pdns-slave
    hostname: ns2.ohsb.cc # 设置PDNS从服务器的主机名,务必与你的胶水记录保持一致,从服务器必须设置,否则无法与主服务器同步!
    restart: unless-stopped
    networks:
      pdns:
        ipv4_address: 172.89.64.75
    depends_on:
      mariadb:
        condition: service_healthy
    environment:
      - PDNS_gmysql_host=mariadb
      - PDNS_gmysql_port=3306
      - PDNS_gmysql_user=root
      - PDNS_gmysql_password=setyourpdnsmasterdbpassword # 设置连接数据库ROOT用户的密码
      - PDNS_gmysql_dbname=powerdnsslave
      - PDNS_gmysql_dnssec=yes
      - PDNS_secondary=yes
      - PDNS_autosecondary=yes
      - PDNS_webserver=yes
      - PDNS_webserver_address=0.0.0.0
      - PDNS_webserver_allow_from=0.0.0.0/0,::/0
      - PDNS_webserver_password=setyourwebserverpassword # 设置PDNS WEB密码
      - PDNS_version_string=anonymous
      - PDNS_default_ttl=1500
      - PDNS_disable_axfr=yes
      - PDNS_allow_notify_from=91.99.72.72 # 设置为主服务器的公网IP
      - SUPERMASTER_IPS=91.99.72.72 # 设置为主服务器的公网IP
    ports:
      - '53:53'
      - '53:53/udp'
      - '8081:8081'
    volumes:
      - /etc/localtime:/etc/localtime:ro

networks:
  pdns:
    ipam:
      config:
        - subnet: 172.89.0.0/16
          gateway: 172.89.0.1

配置项太多,这里我也懒得详细说明了,打字太累= =为了方便理解,我没有给敏感内容(域名、服务器IP等信息)脱敏,这套配置是我目前从测试服务器1:1复制下来的。只要你按照注释来配置,肯定能跑起来的,并且功能都是正常的。

启动主、从服务器的所有服务:

docker compose up -d

配置DNSSEC,首先打开PowerDNS-Admin(91.99.72.72:8989)注册一个账号,第一个注册的账号自动成为管理员。

在PowerDNS-Admin添加Zone,Zone Name:你的域名,Zone Type选择:Primary,一定要选择Primary,Primary,Primary!

按如图所示添加2条NS记录以及2条A记录:

启用DNSSEC:

会回显类似如图的信息:

DNSKEY不用管,你可以简单理解为这是公钥。我们需要注意的是DS下面的内容,这实际上代表两条DS记录:

41411 13 2 48e9394892ee2da8...
41411 13 4 9a9382822735e648...

41411是“密钥标签”,13是“算法”,2和4是“摘要类型”,后面一长串是“摘要”。按照这个格式在spaceship内添加两条DS记录:

实际上只添加一条DS记录也是可以的,这个取决于你自己。检查DNSSEC是否生效,可以安装如下软件包:

apt install bind9-dnsutils

测试:

delv ns1.ohsb.cc
delv ns2.ohsb.cc

如果输出的内容有fully validated,则说明DNSSEC工作正常:

检查主从同步是否正常,可以使用compose内部署的phpmyadmin登录到服务器数据库,查看两个数据库内的数据是否一致:

总结下部署过程中遇到的问题。从服务器无法同步,报错:

Unable to find backend willing to host ohsb.cc for potential autoprimary 91.99.72.72. Remote nameservers

这是从服务器的Docker容器没有设置正确的hostname导致的,见此issue

在spaceship设置了DNSSEC的DS记录后,spaceship面板的DNS传播状态异常。这是由于PowerDNS内的NS记录配置错误导致的。我在spaceship配置了两个NS服务器,那么PowerDNS-Admin内也应该有两条NS记录,必须要保持一致。

参考资料:

https://hub.docker.com/r/pschiffe/pdns-mysql
https://github.com/pschiffe/docker-pdns/blob/master/docker-compose-mysql.yml
https://doc.powerdns.com/authoritative/settings.html
https://doc.powerdns.com/authoritative/backends/generic-mysql.html#gmysql-dnssec

自建开源SSO(单点登录)身份验证服务:VoidAuth

2026-01-12 16:49:46

VoidAuth是一款开源的SSO身份验证和用户管理软件,可为您的自托管应用程序保驾护航,并支持诸多实用功能,例如Passkey登录、邀请注册、自助注册、电子邮件支持等等。

VoidAuth特点(摘自项目文档):

🌐 OpenID Connect (OIDC) Provider
🔄 Proxy ForwardAuth
👤 User and Groups Management
📨 User Self-Registration and Invitations
🎨 Customizable (Logo, Title, Theme Color, Email Templates)
🔑 Multi-factor Authentication, Passkeys, and Passkey-Only Accounts
📧 Secure Password Reset with Email Verification
🔒 Encryption-At-Rest with Postgres or SQLite Database

其实类似VoidAuth这样开源并且支持自建的SSO程序有很多,在接触VoidAuth之前,我部署过很多个,这里就不详细说了。我只想简单谈一下个人体验,我用过的这些软件里面或多或少都有这样的问题:安装和配置非常复杂、程序本身设计的过于臃肿,对于个人自托管爱好者而言(个人用户),甚至有很多用不到的功能,而VoidAuth完美的解决了上述问题,它非常轻量且易于使用。

VoidAuth最让我觉得好用的一个功能是ProxyAuth(转发认证),我自建的这些服务里面并不是所有都原生支持OIDC的,对于那些不支持OIDC的应用程序,我现在可以通过ProxyAuth来实现SSO,真正做到了一个账号登录所有服务。

这篇文章记录下VoidAuth安装以及OIDC、ProxyAuth的配置。

安装Docker:

apt -y update
apt -y install curl
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

创建目录新建compose文件:

mkdir /opt/voidauth && cd /opt/voidauth && nano docker-compose.yml

写入如下内容:

services:
  voidauth: 
    image: voidauth/voidauth:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:3001:3001"
    volumes:
      - ./voidauth/config:/app/config
    environment:
      APP_URL: https://voidauth.example.com # 设置你的域名
      APP_PORT: 3001
      STORAGE_KEY: JW8G+gr2sa8vuStV2F/6rR7VeqvarijvogwvE8jIDD0= # 使用openssl rand -base64 32命令生成
      DB_PASSWORD: yourdbpassword # 设置数据库密码
      DB_HOST: voidauth-db
      SIGNUP: false
      SIGNUP_REQUIRES_APPROVAL: true
      ENABLE_DEBUG: false
    depends_on:
      voidauth-db:
        condition: service_healthy

  voidauth-db:
    image: postgres:18
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: yourdbpassword # 设置数据库密码
    volumes:
      - db:/var/lib/postgresql/18/docker
    healthcheck:
      test: "pg_isready -U postgres -h localhost"

volumes:
  db:

启动:

docker compose up -d

默认的管理员账号与密码可通过查看容器日志获取:

docker compose logs -f

注:仅容器第一次启动会输出管理员账号与密码,后续不再显示,务必保存好。

配置Ferron反向代理:

nano /etc/ferron.kdl

写入如下内容:

voidauth.example.com {
   header "Access-Control-Allow-Origin" "*"
   proxy "http://127.0.0.1:3001/"
}

重载Ferron:

systemctl reload ferron

现在来配置ProxyAuth,让不支持OIDC的服务接入VoidAuth,实现单点登录。开始前先简单介绍一下这个功能是怎么实现的。

我现在的自托管环境,基本都是用Docker启动的服务,直接暴露服务的地址和端口,例如:127.0.0.1:5030,然后通过主机的Web Server反向代理127.0.0.1:5030,实现域名绑定、SSL证书申请、服务对外的发布(公网访问)。

VoidAuth的ProxyAuth其实就是ForwardAuth(转发认证),这个功能是需要与反向代理配合使用的,也就是说需要Web Server软件支持才行。我们配置Web Server,让服务在公网访问的时候先跳转到VoidAuth进行身份认证,认证完成后再跳转回源服务,这就是大致的流程。

现在主流的NGINX、Caddy、Traefik Web Server都是支持ForwardAuth的,如果您使用的是这类软件,可以参考VoidAuth官方的文档来配置。我目前使用的是Ferron Web Server,官方没有相应的文档,所以这里我只记录与Ferron相关的内容。

编辑Ferron配置文件:

nano /etc/ferron.kdl

加入如下配置,建议直接配置在全局(*):

* {
    trust_x_forwarded_for #true
}

根据Ferron 2.2.1版本的发布记录可以得知,这将让Ferron在默认情况下信任“X-Forwarded-For”标头,且不再覆盖X-Forwarded-Host、X-Forwarded-Proto标头,这个配置非常关键,没有这个配置Ferron将无法与VoidAuth配合使用。

假设我要保护的服务域名是:slskd.example.com,写入如下配置:

slskd.example.com {
   auth_to "https://voidauth.example.com/api/authz/forward-auth"
   auth_to_no_verification #false
   auth_to_copy "Remote-User" "Remote-Email" "Remote-Name" "Remote-Groups"
   proxy "http://127.0.0.1:5030/"
}

重载Ferron使新配置生效:

systemctl reload ferron

在VoidAuth添加需要保护的服务域名:slskd.example.com:

这样就配置好了,是不是特别简单,当用户访问slskd.example.com时,会先跳转到VoidAuth进行身份认证。

现在简单介绍一下OIDC的配置,您在VoidAuth的管理员后台点击OIDC Apps,可以查看对接服务需要用到的各种OIDC Endpoints:

然后您可以在VoidAuth的管理员后台创建一个OIDC App,这里我以Arcane Docker容器管理平台为例:

Arcane配置:

这里需要注意的是适用范围需要加上:groups,管理员声明需要配置为:groups,值配置为:auth_admins。因为我没有在VoidAuth创建新的管理员账号,默认的管理员账号(auth_admin)所属的组就是auth_admins,这样配置就可以让您以管理员的身份通过OIDC登录到Arcane。

最后,也许您可以看看VoidAuth官方的文档,他们提供了众多服务的OIDC接入指南可供参考。

Arcane:高颜值的Docker容器管理平台

2026-01-10 11:12:33

作为一个颜控,不得不说这个Arcane的前端设计的是真好看,尤其是在设置内打开了玻璃特效后,就一个词形容:精美。

其实这个项目刚出来没多久我就部署过,好像当时Gayhub的Star还没过500,确实哈,当时这个项目的完成度很低,而且有很多BUG,前端也没有现在好看。

但是但是但是,自从1.0版本作者把后端用Go重写后,这个项目似乎步入正轨了,我最近又重新部署了一遍,试用了一下,发现这个项目确实比之前强太多了,用在生产环境完全没问题。

当然就目前而言,我个人认为Arcane还是有一些小瑕疵的,比如中文翻译,有些地方翻译的不准确,但这问题不大。目前最让我不爽的是还不支持compose build指令,这意味着只能使用预构建的image,我有点纳闷的是前两天发布的新版本都支持Git Sync了为啥还不支持compose build=-=,但是看这个issue应该是计划上了,如果需要的人多,作者会考虑开发。

安装Docker:

apt -y update
apt -y install curl
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

创建目录新建compose文件:

mkdir /opt/arcane && cd /opt/arcane && nano docker-compose.yml

写入如下内容:

services:
  arcane:
    image: ghcr.io/getarcaneapp/arcane:latest
    container_name: arcane
    restart: unless-stopped
    environment:
      - APP_URL=https://arcane.example.com
      - PUID=1000
      - PGID=1000
      - ENCRYPTION_KEY=
      - JWT_SECRET=
    ports:
      - '127.0.0.1:3552:3552'
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - arcane-data:/app/data

volumes:
  arcane-data:

ENCRYPTION_KEY、JWT_SECRET可使用如下命令启动一个临时容器(运行完毕自动删除)生成:

docker run --rm ghcr.io/getarcaneapp/arcane:latest /app/arcane generate secret

启动:

docker compose up -d

配置Ferron反向代理:

nano /etc/ferron.kdl

写入如下内容:

arcane.example.com {
   proxy "http://127.0.0.1:3552/"
}

重载Ferron:

systemctl reload ferron

默认的管理员账号:arcane,密码:arcane-admin

Arcane还支持“远程环境”,也就是说你可以通过Arcane管理多台服务器的Docker,只需要在每台服务器内部署一个arcane-agent即可,具体操作见:

https://getarcane.app/docs/features/environments

如果你觉得让Arcane直接连接到Docker套接字这种部署方法不安全,也可以改为使用套接字代理,详细信息见:

https://getarcane.app/docs/setup/socket-proxy