docker部署vaultwarden+Caddy+FRP(TCP)+CF tunnel(HTTP)的记录
系统环境准备:
安装docker:
sh <(curl -sSL https://linuxmirrors.cn/docker.sh)
安装Caddy:
直接
apt install caddy,或者yum install caddy,或者dnf install caddy,这取决于你的系统。
Caddy配置:
先在
cloudflare的DNS控制台记录上配置CNAME域名映射(或者A/AAAA记录)到FRP服务器的地址。
然后是
Caddy需要有cloudflare的dns模块,就能使用cloudflare的API_TOKEN自动创建更新非443标准端口的TLS证书。将此
API_TOKEN替换到Caddy配置文件内FRP站点的<CF_DNS_API_TOKEN>位置。
root@NAS:/etc/caddy# caddy list-modules | grep cloudflare
dns.providers.cloudflare
然后是
Caddy需要有能解析FRP(TCP)高级参数proxy_protocol_version = v2的模块,就能通过proxy_protocol获取访问者IP。
root@NAS:/etc/caddy# caddy list-modules | grep proxy_
caddy.listeners.proxy_protocol
layer4.handlers.proxy_protocol
layer4.matchers.proxy_protocol
1、Caddy配置实现了从
FRP隧道来的访问转发到vaultwarden容器,并获取真实访问者IP给vaultwarden。但是禁止访问/admin2、Caddy配置实现了从
CF Tunnel隧道来的访问转发到到vaultwarden容器,并获取真实访问者IP给vaultwarden。可以访问/admin,但是需要通过邮箱一次性验证码来验证。CF Tunnel自带TLS,无需配置证书。3、Caddy配置实现了来自本地的指定访问IP访问,使用自签证书。
Caddy安装模块问一下AI或者到Caddy官网https://caddyserver.com/download下载,这里就不啰嗦了。
Caddy配置文件如下:
cat > /opt/caddy/Caddyfile <<"EOF"
{
# FRP 站点解析 proxy_protocol_version = v2 参数,仅在1200端口(来自FRP的访问)的站点生效。
servers :1200 {
listener_wrappers {
proxy_protocol {
timeout 2s
allow 127.0.0.1/32
}
tls
}
}
}
# ------------------------------------------------------------
# 共享安全 Header
(shared_header) {
header {
# 启用 HTTP Strict Transport Security (HSTS)
Strict-Transport-Security "max-age=31536000;"
# 禁用 cross-site filter (XSS)
X-XSS-Protection "0"
# 禁止在框架内呈现网站 (clickjacking protection)
# X-Frame-Options "SAMEORIGIN"
# 阻止搜索引擎建立索引(可选)
X-Robots-Tag "noindex, nofollow"
# 禁止嗅探 X-Content-Type-Options
X-Content-Type-Options "nosniff"
# 服务器名称移除
-Server
# 移除 X-Powered-By,虽然这不应该是一个问题,但最好移除
-X-Powered-By
# 移除 Last-Modified,因为 etag 相同并且同样有效
-Last-Modified
}
}
# ------------------------------------------------------------
# FRP(TCP + Proxy Protocol v2)站点
vaultwarden.域名地址.xyz:1200 {
encode gzip
tls {
# 根据实际情况更改此处的 <CF_DNS_API_TOKEN>
dns cloudflare <CF_DNS_API_TOKEN>
propagation_timeout 120s
resolvers 1.1.1.1 1.0.0.1
}
handle /admin* {
respond "小黑子你想干什么?!" 403
}
handle {
import shared_header
reverse_proxy 127.0.0.1:1199 {
header_up X-Real-IP {remote_host}
}
}
}
# ------------------------------------------------------------
# Cloudflare Tunnel 站点,这里有必要指明http协议,否则大概率会自签内部证书导致无法正常访问。
http://vaultwarden-cf.域名地址.xyz:1201 {
encode gzip
handle {
import shared_header
reverse_proxy 127.0.0.1:1199 {
trusted_proxies 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22 2400:cb00::/32 2606:4700::/32 2803:f800::/32 2405:b500::/32 2405:8100::/32 2a06:98c0::/29 2c0f:f248::/32
header_up X-Real-IP {http.request.header.CF-Connecting-IP}
}
}
}
#假设我的客户端设备局域网IP是10.126.126.1,vaultwarden服务器的IP是10.126.126.193,则可以如下配置,然后通过https://10.126.126.193:1202来访问vaultwarden服务。
#如果是通过组网的形式去访问,有些组网软件会默认NAT后去访问,就需要把vaultwarden的IP(10.126.126.193)也加到允许的列表中去
10.126.126.193:1202 {
encode gzip
tls internal
# 1️⃣ 仅允许指定 IP
@allow_ip {
remote_ip 10.126.126.1/32 10.126.126.193/32
}
handle @allow_ip {
reverse_proxy 127.0.0.1:1199 {
header_up X-Real-IP {remote_host}
}
}
# 2️⃣ 其余来源全部拒绝
handle {
respond "Forbidden" 403
}
}
EOF
然后标准化一下配置文件后载入配置文件到Caddy:
caddy fmt --overwrite /etc/caddy/Caddyfile && caddy reload --config /etc/caddy/Caddyfile
正常来说没错的话应该是这个情况
root@NAS:~# caddy fmt --overwrite /etc/caddy/Caddyfile && caddy reload --config /etc/caddy/Caddyfile
2026/02/04 08:03:57.713 INFO using config from file {"file": "/etc/caddy/Caddyfile"}
2026/02/04 08:03:57.744 INFO adapted config to JSON {"adapter": "caddyfile"}
root@NAS:~# ss -ntlp | grep caddy
LISTEN 0 4096 127.0.0.1:2019 0.0.0.0:* users:(("caddy",pid=2830955,fd=24))
LISTEN 0 4096 *:80 *:* users:(("caddy",pid=2830955,fd=31))
LISTEN 0 4096 *:1202 *:* users:(("caddy",pid=2830955,fd=29))
LISTEN 0 4096 *:1200 *:* users:(("caddy",pid=2830955,fd=30))
LISTEN 0 4096 *:1201 *:* users:(("caddy",pid=2830955,fd=25))
安装vaultwarden:
docker run --detach --name vaultwarden \
-e DOMAIN='https://<用来访问的域名>:<用来访问的端口>' \
-e TZ='Asia/Shanghai' \
-p 127.0.0.1:1199:80 \
-v /opt/vw-data:/data \
--restart unless-stopped \
vaultwarden/server:latest
这里主要是
FRP不能使用标准443端口,否则-e DOMAIN=参数不需要指定端口。
-e DOMAIN=这个参数用来自定义访问的地址,也可以不设置。
-e DOMAIN=在 vaultwarden 中只能有一个生效值,vaultwarden 本身不支持同时配置多个访问域名。多域名时,可以配置其他域名 301 重定向 到这个主域名,但不是必要的。
因为FRP如果不能访问了,我们要手动使用CF tunnel这个备用路径,所以可以不搞301重定向这一步。
这个参数不是访问白名单,而是一个对外公布的主域名,主要用于:
1️⃣ 生成对外 URL
邀请邮件里的链接
Web Vault 中的一些跳转链接
API 返回的绝对 URL
2️⃣ Web Vault 的 CSP / WebSocket
WebSocket 连接地址
某些前端资源引用
-p 127.0.0.1:1199:80是将容器内的80端口映射到本地1199端口,仅监听在127.0.0.1上。
-v /opt/vw-data:/data是将数据库文件挂载出来,方便后面备份或者迁移,即使容器删除,数据依旧存在。
配置FRP服务:
先创建一条TCP隧道,需要有高级参数 proxy_protocol_version = v2才能获取真实访问者IP:

然后去下载 frpc客户端程序到 /opt/Frp_linux_arm64/frpc,我使用的是某FRP服务网站提供的,也可自建。
使用下列命令创建systemd服务,以实现开机自启。
cat > /etc/systemd/system/frpc.service <<"EOF"
[Unit]
Description=Frp Client
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
Group=root
# 根据实际情况更改 <USER_TOKEN_KEY> 和 <SERVER_ID>
ExecStart=/opt/Frp_linux_arm64/frpc -u <USER_TOKEN_KEY> -p <SERVER_ID>
WorkingDirectory=/opt/Frp_linux_arm64/
Restart=always
RestartSec=5
# 日志优化(可选)
StandardOutput=journal
StandardError=journal
# 安全加固(可选)
ProtectSystem=full
PrivateTmp=true
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
EOF
服务文件创建好之后,刷新一下systemd,然后设置开机自启,并启动服务:
命令:systemctl daemon-reload && systemctl enable frpc && systemctl start frpc
如果手动指定,则
frpc的配置文件大致如下。命令查看:
cat /opt/Frp_linux_arm64/frpc.ini
[common]
server_addr = frp.server.com
server_port = 7000
tcp_mux = true
protocol = tcp
user = <USER_KEY>
token = <TOKEN_KEY>
dns_server = 223.6.6.6
tls_enable = false
[vaultwarden]
privilege_mode = true
type = tcp
local_ip = 127.0.0.1
local_port = 1200
remote_port = 32213
use_encryption = false
use_compression = false
proxy_protocol_version = v2
大致意思就是
用TCP协议
type = tcp,将本地local_ip = 127.0.0.1的local_port = 1200端口,映射到FRP服务器的remote_port = 32213端口后面就可以通过FRP服务器的
https://<用来访问的域名>:32213进行访问。
配置CF Tunnel服务:
在 https://one.dash.cloudflare.com/控制台的【网络】-【连接器】中,创建一个【隧道】,在【概述】里有部署方式,推荐使用docker的方式部署,命令参考:
docker run -d --network host --name cfd_tunnel cloudflare/cloudflared:latest tunnel run --token <你的隧道token>
然后到【隧道】的配置里,增加增加一个【已发布应用程序路由】,【子域】部分填 vaultwarden-cf,就是Caddy配置文件里的CF tunnel站点。【域】就是你的域名地址。【路径】为空。服务类型为http,对应Caddy配置文件中的 http://vaultwarden-cf.域名地址.xyz:1201 站点块。【URL】填 127.0.0.1:1201,将来自 CF Tunnel的数据转发到 Caddy的 1201端口。

配置 /admin控制台访问的邮件令牌验证:
在 https://one.dash.cloudflare.com/控制台的【访问控制】中增加一个【策略】,名称自定义,例如叫【允许列表内邮件验证码认证访问】,【操作】选 Allow,【会话持续时间】自定义,添加一个规则,【选择器】为 Emails,【值】则是自己的邮箱,这个邮箱将用来接受验证码,通过验证就能访问 /admin

将策略应用:
在 https://one.dash.cloudflare.com/控制台的【访问控制】中增加一个【应用程序】,名称自定义,例如叫【管理员控制台】,【会话持续时间】自定义,默认的输入方法,【子域】填 vaultwarden-cf,对应Caddy配置文件中的 http://vaultwarden-cf.域名地址.xyz:1201 站点块。【域】就是你的域名地址。【路径】则是 admin,这里很重要,无需加 /,直接填 admin

验证:
当去访问 http://vaultwarden-cf.域名地址.xyz/admin的时候,就会自动跳转到验证。

输入策略里存在的邮箱,就会收到类似于以下的验证码,验证后就能访问 /admin控制台了。

开启vaultwarden的admin控制台:
接下来关闭注册功能,然后开启vaultwarden的邮件功能,以实现邀请用户。
使用 openssl rand -base64 48命令创建 admin访问的 token它看起来像这样:yi7GmMLGWaTo5OJdmALHL4eajv+rh3G7eVtaXJCxylvcF6+B7vbhh0HWACZdeAQl
此token需要牢记,登录admin后台使用。
然后将此明文的token转成密文,利用vaultwarden容器自带的hash工具,目前vaultwarden容器已经在正常运行了,那么执行 docker exec -it vaultwarden /vaultwarden hash命令,然后隐性输入token两次(建议复制粘贴),若两次输输入token不一致则不会生成密文。看起来会像这样:
Generate an Argon2id PHC string using the 'bitwarden' preset:
Password: <-----------隐性输入
Confirm Password: <-----------隐性输入
ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$RtC7dEU7RacyN6v0oUM2nVu9f3rI9OjaFA1S2sWXJLg$4j0HHDGop+71A2dxtco7JuO7UEV2js4wgojPsiETeU8' <-----------密文生成成功
Generation of the Argon2id PHC string took: 142.1447ms
重建容器,开启admin管理页面(启用变量 -e ADMIN_TOKEN=)带入密文 token,然后关闭注册功能(启用变量 -e SIGNUPS_ALLOWED=false),
docker stop vaultwarden && docker rm vaultwarden && docker run --detach --name vaultwarden \
-e SIGNUPS_ALLOWED=false \
-e DOMAIN='https://<用来访问的域名>:<用来访问的端口>' \
-e ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$RtC7dEU7RacyN6v0oUM2nVu9f3rI9OjaFA1S2sWXJLg$4j0HHDGop+71A2dxtco7JuO7UEV2js4wgojPsiETeU8' \
-e TZ='Asia/Shanghai' \
-v /opt/vw-data:/data \
-p 127.0.0.1:1199:80 \
--restart unless-stopped \
vaultwarden/server:latest
然后去访问 http://vaultwarden-cf.域名地址.xyz/admin就能进admin后台了。
开启SMTP邮件服务(以163为例):
添加一点SMTP参数,参考:
docker stop vaultwarden && docker rm vaultwarden && docker run --detach --name vaultwarden \
-e SIGNUPS_ALLOWED='false' \
-e DOMAIN='https://<用来访问的域名>:<用来访问的端口>' \
-e ADMIN_TOKEN='$argon2id$v=19$m=65540,t=3,p=4$RtC7dEU7RacyN6v0oUM2nVu9f3rI9OjaFA1S2sWXJLg$4j0HHDGop+71A2dxtco7JuO7UEV2js4wgojPsiETeU8' \
-e TZ='Asia/Shanghai' \
-e ADMIN_SESSION_LIFETIME='60' \
-e SMTP_FROM='邮箱账号@163.com' \
-e SMTP_HOST='smtp.163.com' \
-e SMTP_PORT=465 \
-e SMTP_SECURITY=force_tls \
-e SMTP_USERNAME='邮箱账号@163.com' \
-e SMTP_PASSWORD='POP3/SMTP密码' \
-e HELO_NAME='vaultwarden-selfhosted' \
-p 127.0.0.1:1199:80 \
-v /opt/vw-data:/data \
--restart unless-stopped \
vaultwarden/server:latest
本文来自博客园,作者:Ojox,转载请注明原文链接:https://www.cnblogs.com/Ojox/p/19574261

浙公网安备 33010602011771号