Obsidian Docker 容器浏览器访问完整部署记录
环境:飞牛OS (fnOS) + 1Panel + Docker + Nginx Proxy Manager 2.15.1 目标:在局域网内通过浏览器访问 Obsidian 笔记(无公网域名) 最终访问地址:
https://obsidian.local:30443
一、背景说明
为什么要用 Docker 部署 Obsidian?
Obsidian 没有官方 Web 版,只有桌面客户端(Windows/Mac/Linux)和移动端 App。LinuxServer 的镜像方案是:
完整 Linux 桌面环境(Xfce)
+ Selkies(WebRTC 远程桌面引擎,原 Google 工程师项目)
+ GStreamer 媒体编解码库
+ Obsidian 桌面应用程序
通过 Selkies 把容器内的 Obsidian 桌面以 WebRTC 方式串流到浏览器,变相实现"网页访问"。这也解释了为什么镜像体积高达 3GB+,以及为什么强制要求 HTTPS(WebRTC 安全上下文限制)。
访问链路:
浏览器 → HTTPS/WebSocket → NPM 反向代理 → 容器内 Selkies 引擎 → 容器内 Obsidian 桌面
环境约束
二、最终生效配置
2.1 Obsidian 容器(docker-compose)
networks:
1panel-network:
external: true
services:
obsidian:
image: lscr.io/linuxserver/obsidian:latest
container_name: ${CONTAINER_NAME}
security_opt:
- seccomp:unconfined # 官方要求,桌面环境需要更多系统调用
deploy:
resources:
limits:
cpus: ${CPUS}
memory: ${MEMORY_LIMIT}
environment:
- HTTPS=false # 容器内部关闭 HTTPS,由 NPM 对外提供
- PUID=1000
- PGID=1000
- TZ=${TIME_ZONE}
volumes:
- ./config:/config
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- ${HOST_IP}:${PANEL_APP_PORT_HTTP}:3000
restart: on-failure:5
networks:
- 1panel-network
2.2 NPM Proxy Host 配置
2.3 端口映射
宿主机 30443 → NPM 容器 443 → Obsidian 容器 3000
三、遇到的问题与解决过程
问题 1:ERR_SSL_UNRECOGNIZED_NAME_ALERT — TLS 握手直接失败
现象:浏览器和 curl 均报此错误,连 TLS 握手都无法完成。
排查:
curl -vk --resolve "192.168.5.224:30443:192.168.5.224" https://192.168.5.224:30443/
# 输出:TLSv1.3 (IN), TLS alert, unrecognized name (624)
根本原因:IP 直连时浏览器不发送 SNI(SNI 是域名专用机制),Nginx 收不到 SNI 就匹配不到任何 server_name,落入 fallback server block,而该 block 配置了:
# /etc/nginx/conf.d/default.conf(NPM 内置)
server {
listen 443 ssl;
server_name localhost;
ssl_reject_handshake on; # ← 直接拒绝所有不匹配的握手
return 444;
}
尝试过的无效方案:
NPM 界面设置 Default Site → 对 SSL 握手阶段无效
手动修改
3.conf加default_server→ NPM 每次保存 Proxy Host 会覆盖
最终解决:放弃 IP 直连,改用本地假域名 obsidian.local,彻底绕开 SNI 问题。
问题 2:第一版自签名证书导致 ERR_SSL_UNRECOGNIZED_NAME_ALERT
现象:从 Obsidian 容器内部提取的自带证书,浏览器报错。
原因:该证书未包含 subjectAltName(SAN),现代浏览器要求证书必须有 SAN,仅有 CN 字段不被接受。
解决:在宿主机用 OpenSSL 手动生成包含 IP SAN 的证书(此为过渡方案,后被域名方案替代):
cat > /tmp/openssl-ip.cnf <<EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = 192.168.5.224
[v3_req]
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = IP:192.168.5.224
EOF
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /tmp/obsidian-ip.key \
-out /tmp/obsidian-ip.crt \
-config /tmp/openssl-ip.cnf
问题 3:改用域名后证书报 ERR_SSL_KEY_USAGE_INCOMPATIBLE
现象:curl 已能正常握手并返回 HTTP 200,但浏览器仍然报错。
原因:第一版证书的 keyUsage 字段为:
keyUsage = keyEncipherment, dataEncipherment
TLS 1.3 要求证书必须包含 digitalSignature,浏览器比 curl 更严格地执行此检查。
解决:重新生成证书,修正 keyUsage:
cat > /tmp/openssl-local.cnf <<EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = obsidian.local
[v3_req]
keyUsage = digitalSignature, keyEncipherment # ← 关键:加上 digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = DNS:obsidian.local
EOF
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /tmp/obsidian-local.key \
-out /tmp/obsidian-local.crt \
-config /tmp/openssl-local.cnf
验证:
openssl x509 -in /tmp/obsidian-local.crt -text -noout | grep -A3 "Key Usage"
# 期望输出:
# X509v3 Key Usage:
# Digital Signature, Key Encipherment
四、完整操作步骤(可复现)
Step 1:生成正确的自签名证书
cat > /tmp/openssl-local.cnf <<EOF
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = obsidian.local
[v3_req]
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = DNS:obsidian.local
EOF
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /tmp/obsidian-local.key \
-out /tmp/obsidian-local.crt \
-config /tmp/openssl-local.cnf
# 验证 SAN
openssl x509 -in /tmp/obsidian-local.crt -text -noout | grep -A1 "Subject Alternative Name"
# 验证 KeyUsage
openssl x509 -in /tmp/obsidian-local.crt -text -noout | grep -A3 "Key Usage"
Step 2:在 NPM 上传证书
打开
http://192.168.5.224:30081SSL Certificates → Add SSL Certificate → Custom
名称填
obsidian-local,上传.crt和.key,保存
Step 3:配置 NPM Proxy Host
Hosts → Proxy Hosts → 新建或编辑
Details 标签:
Domain Names:
obsidian.localForward Scheme:
httpForward Hostname:
1Panel-obsidianForward Port:
3000✅ Websocket Support
SSL 标签:选择
obsidian-local证书保存
Step 4:添加 hosts 记录(每台访问设备都要做)
Windows(管理员权限编辑 C:\Windows\System32\drivers\etc\hosts):
192.168.5.224 obsidian.local
Mac/Linux:
echo "192.168.5.224 obsidian.local" | sudo tee -a /etc/hosts
Step 5:验证
# 服务端验证
curl -vk --resolve "obsidian.local:30443:192.168.5.224" https://obsidian.local:30443/
# 期望:HTTP/1.1 200 OK,subject: CN=obsidian.local
浏览器访问 https://obsidian.local:30443,首次出现证书警告,点击"高级"→"继续前往"即可。
五、关键知识点总结
六、已知局限与注意事项
hosts 文件需要在每台设备上单独配置,新设备接入局域网时需重复操作(可考虑在路由器/内网 DNS 上统一配置
obsidian.local解析)NPM 每次在界面保存 Proxy Host 都会重新生成 Nginx 配置文件,手动修改的
listen ... default_server等改动会丢失自签名证书浏览器会持续显示警告,可将
obsidian-local.crt导入系统受信任根证书库消除警告Obsidian 容器内运行完整 Linux 桌面 + Selkies,资源占用较重(镜像 3GB+,运行时内存 400MB+)