DefGuard 2.1.1 Docker Compose 部署指南
Ubuntu 22.04 + Docker Compose 从零部署 DefGuard 2.1.1 实测指南:PostgreSQL 初始化、Core/Edge/Gateway 三组件编排、首启向导、管理员创建、WireGuard 网关对接与端到端 VPN 连通性实测、数据持久化与常见问题排障。
DefGuard 2.1.1 Docker Compose 部署指南
目标:在 Ubuntu 22.04 服务器上用 Docker Compose 从零部署 DefGuard 2.1.1(开源 WireGuard VPN + 身份认证一体化平台),覆盖 PostgreSQL 初始化、Core/Edge/Gateway 三组件编排、首启向导、管理员创建、WireGuard 网关对接与端到端 VPN 连通性实测、数据持久化、环境变量、运维命令与排障实录。文中全部命令与回显均在真实部署环境实测,取材日期 2026-10-25。项目定位与选型对比见《DefGuard 2.1.1 介绍与选型指南》。
一、环境信息
本篇的实测环境与部署目标如下,读者操作时把路径、端口与口令换成自己的取值即可:
- 操作系统:Ubuntu 22.04 LTS,x86_64
- Docker 引擎:29.x(Compose v2 插件)
- 应用版本:DefGuard
2.1.1(运行时defguard --version回显defguard 2.1.1+bbc29a1) - 数据库:PostgreSQL 18(官方编排使用
postgres:18-alpine) - 组件镜像:
ghcr.io/defguard/defguard:2(Core)、ghcr.io/defguard/defguard-proxy:2(Edge)、ghcr.io/defguard/gateway:2(Gateway) - 对外端口:Core 管理台 8000、Edge 8080/443/80、Gateway WireGuard UDP 51820
- 部署目录:
/opt/defguard - 编排项目名:
defguard-2.1.1-stack(由编排文件name:字段固定)
版本取证:
docker compose exec core /app/defguard --version
实测回显:
defguard 2.1.1+bbc29a1
二、部署形态说明
官方给出两种部署入口:
| 形态 | 组成 | 适用场景 | 本文是否实测 |
|---|---|---|---|
| 一键脚本 | bash <(curl -sSL .../setup.sh) 自动生成编排与 .env 并启动 | 快速评估、演示 | 否(脚本会占用 80/443 端口且不可定制) |
| Docker Compose 手编 | Core + Edge + Gateway + PostgreSQL 四个服务,自行编排 | 生产、需要定制端口与持久化 | 是,全文以此为主线 |
DefGuard 是四组件架构,缺一不可:
- Core:控制面,提供 Web UI 与 REST API,管理身份、设备、网络策略;
- Edge:公网边缘代理,处理用户自助注册与客户端配置下发;
- Gateway:WireGuard 数据面,落地 VPN 隧道与 ACL;
- PostgreSQL:持久化全部数据。
组件间通过**自动采纳(auto-adoption)**建立 mTLS 信任:Core 启动时连接 Edge(50051)与 Gateway(50066)的 setup 端口,交换 CSR 并签发证书,无需手工拷贝密钥。
三、前置条件
3.1 宿主机资源
- CPU/内存:建议 2 核 4 GiB 起步;PostgreSQL 与 Core 同机运行需余量。
- 磁盘:镜像合计约 600 MB,数据库与日志建议预留 10 GB。
- 内核:Gateway 优先使用内核态 WireGuard;需内核模块
wireguard(版本 1.0.0)。无内核模块时回退用户态 boringtun,性能下降。 - 端口:需放行 UDP 51820(WireGuard)与管理台端口(默认 8000)。
⚠️ 注意:DefGuard 官方明确说明不能在 LXC 容器内运行(缺少 WireGuard 内核能力与 systemd)。本文部署在支持 Docker 的 Ubuntu 裸机或 KVM 虚拟机上。
3.2 内核模块核验
cat /sys/module/wireguard/version
实测回显(内核态可用):
1.0.0
若该文件不存在,说明内核未加载 WireGuard 模块,Gateway 将自动回退用户态实现。
四、部署步骤
4.1 准备部署目录与环境变量
mkdir -p /opt/defguard && cd /opt/defguard
mkdir -p .volumes/db .volumes/certs/edge .volumes/certs/gateway
生成数据库口令并写入 .env:
DB_PASS=$(openssl rand -hex 12)
cat > .env << EOF
DEFGUARD_CORE_TAG=2
DEFGUARD_PROXY_TAG=2
DEFGUARD_GATEWAY_TAG=2
POSTGRES_DB=defguard
POSTGRES_USER=defguard
POSTGRES_PASSWORD=${DB_PASS}
DEFGUARD_DB_NAME=defguard
DEFGUARD_DB_USER=defguard
DEFGUARD_DB_PASSWORD=${DB_PASS}
DEFGUARD_MASQUERADE=true
EOF
💡 说明:
DEFGUARD_MASQUERADE=true让 Gateway 对 VPN 流量做源地址伪装,使客户端能访问 Gateway 所在主机可达的任意网络;不需要时设为false并自行配置 ACL。
4.2 编写编排文件
在 /opt/defguard/docker-compose.yaml 写入:
name: defguard-2.1.1-stack
services:
db:
restart: unless-stopped
image: postgres:18-alpine
container_name: defguard-2.1.1-db
env_file: .env
volumes:
- ./.volumes/db:/var/lib/postgresql
core:
restart: unless-stopped
image: ghcr.io/defguard/defguard:${DEFGUARD_CORE_TAG}
container_name: defguard-2.1.1-core
env_file: .env
environment:
DEFGUARD_DB_HOST: db
DEFGUARD_DB_PORT: 5432
DEFGUARD_ADOPT_EDGE: "edge:50051"
DEFGUARD_ADOPT_GATEWAY: "gateway:50066"
depends_on:
- db
- edge
- gateway
ports:
- "8000:8000"
edge:
restart: unless-stopped
image: ghcr.io/defguard/defguard-proxy:${DEFGUARD_PROXY_TAG}
container_name: defguard-2.1.1-edge
env_file: .env
volumes:
- ./.volumes/certs/edge:/etc/defguard/certs
ports:
- "8080:8080"
- "443:443"
- "80:80"
gateway:
restart: unless-stopped
image: ghcr.io/defguard/gateway:${DEFGUARD_GATEWAY_TAG}
container_name: defguard-2.1.1-gateway
env_file: .env
cap_add:
- NET_ADMIN
volumes:
- ./.volumes/certs/gateway:/etc/defguard/certs
environment:
DEFGUARD_STATS_PERIOD: 10
HEALTH_PORT: 55003
ports:
- "51820:51820/udp"
关键配置项说明:
DEFGUARD_ADOPT_EDGE/DEFGUARD_ADOPT_GATEWAY:Core 启动时自动采纳 Edge 与 Gateway 的地址,格式<主机名>:<端口>;cap_add: NET_ADMIN:Gateway 需要此能力创建 WireGuard 接口与管理路由;DEFGUARD_STATS_PERIOD: 10:Gateway 每 10 秒向 Core 上报一次流量统计。
4.3 启动服务
cd /opt/defguard
docker compose pull
docker compose up -d
启动后查看状态:
docker compose ps
实测回显(节选):
NAME STATUS
defguard-2.1.1-db Up
defguard-2.1.1-core Up
defguard-2.1.1-edge Up
defguard-2.1.1-gateway Up
4.4 观察 Core 启动日志(自动采纳过程)
docker compose logs core | tail -20
实测回显(节选):
INFO defguard_setup::auto_adoption: Auto-adoption: created proxy record name=Edge address=edge:50051
INFO defguard_setup::auto_adoption: Startup auto-adoption for Edge component completed endpoint=edge:50051
INFO defguard_setup::auto_adoption: Auto-adoption: created network location name=Gateway id=1
INFO defguard_setup::auto_adoption: Auto-adoption: created gateway record name=Gateway address=gateway:50066 network_id=1
INFO defguard_setup::auto_adoption: Startup auto-adoption for Gateway component completed endpoint=gateway:50066
INFO run_setup_web_server: Starting initial setup web server on port 8000
日志表明 Edge 与 Gateway 已被 Core 自动采纳,初始配置向导已在 8000 端口启动。
4.5 首启向导与管理员创建
浏览器打开 http://<服务器IP>:8000,进入初始化向导,依次完成:
- 创建管理员:填写姓名、用户名(
admin)、邮箱、密码。密码需满足 8 位以上,含大小写字母、数字与特殊字符。 - 内部 URL:填写 Core 管理台对外可达的 URL(须用主机名,不能用 IP),例如
http://defguard.example.com:8000;SSL 选项选「Do not configure SSL」(生产环境应配置反向代理 + TLS)。 - 外部 URL:填写 Edge 的公网 URL(用于用户自助注册),例如
http://defguard.example.com:8080;SSL 同样选不配置。 - 首个 VPN 位置:填写 VPN 公网地址(域名或公网 IP)、WireGuard 端口(默认 51820)、内网 VPN 网段(如
10.10.0.1/24)、Allowed IPs、DNS。 - MFA:选择是否对该 VPN 位置强制多因素认证(评估环境可选「Do not enforce MFA」)。
- 汇总:确认配置,点击「Go to Defguard」进入登录页。
向导完成后,用刚创建的管理员账号登录管理台。
4.6 验证管理台可访问
curl -sI http://127.0.0.1:8000 | head -3
实测回显:
HTTP/1.1 200 OK
content-type: text/html
content-length: 4981
4.7 验证 WireGuard 网关已就绪
docker compose exec gateway wg show wg0
实测回显:
interface: wg0
public key: jTuESOQHFTNz4YYRf9dST9UdmMUuUs5IhBCHAodUfks=
private key: (hidden)
listening port: 51820
wg0 接口已起来、监听 51820,公钥与管理台「Locations」页面显示的一致。
五、WireGuard 端到端连通性实测
本节用一台客户端验证从设备注册到隧道握手的完整链路,证明 VPN 数据面可用。
5.1 为用户添加设备
在管理台「Users」中为目标用户添加设备,输入设备名与 WireGuard 公钥。公钥由客户端生成:
# 在客户端生成密钥对
PRIVKEY=$(wg genkey)
PUBKEY=$(echo "$PRIVKEY" | wg pubkey)
echo "公钥: $PUBKEY"
将 $PUBKEY 填入管理台设备表单。添加成功后,管理台为该设备分配 VPN 内网 IP(如 10.10.0.2)。
也可通过 REST API 创建设备(详见《DefGuard 2.1.1 API 使用详解》):
curl -s -X POST "http://<core>:8000/api/v1/device/<用户名>" \
-H "Cookie: defguard_session=<会话>" -H "Content-Type: application/json" \
-d '{"name":"laptop","wireguard_pubkey":"<客户端公钥>"}'
5.2 下载客户端 WireGuard 配置
在管理台设备详情页或 API 获取该设备的 WireGuard 配置:
curl -s "http://<core>:8000/api/v1/device/1/config" \
-H "Cookie: defguard_session=<会话>"
实测回显:
[{"config":"[Interface]\nPrivateKey = YOUR_PRIVATE_KEY\nAddress = 10.10.0.2\nDNS = 8.8.8.8\n\n[Peer]\nPublicKey = jTuESOQHFTNz4YYRf9dST9UdmMUuUs5IhBCHAodUfks=\nAllowedIPs = 10.10.0.0/24\nEndpoint = <VPN公网地址>:51820\nPersistentKeepalive = 25","network_name":"Gateway"}]
把 YOUR_PRIVATE_KEY 替换为第 5.1 步生成的客户端私钥,保存为客户端 wg0.conf。
5.3 客户端连接并验证握手
# 客户端
sudo wg-quick up ./wg0.conf
sudo wg show wg0
实测回显(客户端侧):
interface: wg0
public key: ZZjfYdR0Kop/WrhgO8dIkyJoUaVnzYmPYrq3GVT0wgg=
private key: (hidden)
listening port: 41784
peer: jTuESOQHFTNz4YYRf9dST9UdmMUuUs5IhBCHAodUfks=
endpoint: <服务器IP>:51820
allowed ips: 10.10.0.0/24
latest handshake: Now
transfer: 92 B received, 180 B sent
persistent keepalive: every 25 seconds
latest handshake: Now 且有 transfer 字节数,说明隧道握手成功、有数据收发。
5.4 服务端确认对端上线
在服务器上查看 Gateway 的对端列表:
docker compose exec gateway wg show wg0
实测回显(服务端侧):
peer: ZZjfYdR0Kop/WrhgO8dIkyJoUaVnzYmPYrq3GVT0wgg=
endpoint: <客户端出口IP>:50563
allowed ips: 10.10.0.2/32
latest handshake: 11 seconds ago
transfer: 360 B received, 248 B sent
persistent keepalive: every 25 seconds
服务端已看到客户端对端,allowed IP 为 10.10.0.2/32,握手时间正常更新。
5.5 连通性验证
从客户端 ping Gateway 的 VPN 内网地址 10.10.0.1:
ping -c 3 10.10.0.1
实测回显(节选):
PING 10.10.0.1 (10.10.0.1) 56(84) bytes of data.
64 bytes from 10.10.0.1: icmp_seq=1 ttl=64 time=1.23 ms
64 bytes from 10.10.0.1: icmp_seq=2 ttl=64 time=0.98 ms
64 bytes from 10.10.0.1: icmp_seq=3 ttl=64 time=1.02 ms
隧道端到端连通,VPN 数据面完全可用。
六、数据持久化说明
| 目录(宿主机) | 挂载到(服务内) | 内容 |
|---|---|---|
.volumes/db | /var/lib/postgresql(db) | PostgreSQL 数据文件 |
.volumes/certs/edge | /etc/defguard/certs(edge) | Edge 的 gRPC TLS 证书 |
.volumes/certs/gateway | /etc/defguard/certs(gateway) | Gateway 的 gRPC TLS 证书 |
证书由 Core 在自动采纳时签发并下发,切勿手工删除,否则 Edge/Gateway 与 Core 的 gRPC 信道会中断。
数据库备份:
docker compose exec db pg_dump -U defguard defguard > /opt/defguard/backup_$(date +%Y%m%d).sql
恢复:
docker compose exec -T db psql -U defguard defguard < /opt/defguard/backup_YYYYMMDD.sql
七、环境变量速查
.env 中由编排文件读取的变量:
| 变量 | 作用 | 示例 |
|---|---|---|
DEFGUARD_CORE_TAG | Core 镜像标签 | 2 |
DEFGUARD_PROXY_TAG | Edge 镜像标签 | 2 |
DEFGUARD_GATEWAY_TAG | Gateway 镜像标签 | 2 |
POSTGRES_DB / POSTGRES_USER / POSTGRES_PASSWORD | PostgreSQL 库名/用户/口令 | defguard |
DEFGUARD_DB_NAME / DEFGUARD_DB_USER / DEFGUARD_DB_PASSWORD | Core 连接数据库的凭据(须与上一行一致) | defguard |
DEFGUARD_MASQUERADE | Gateway 是否对 VPN 流量做源伪装 | true |
Core 还支持大量运行时环境变量(数据库、JWT/OIDC 签名密钥、URL、超时、限流等),完整清单见《DefGuard 2.1.1 配置参数详解》。
八、配置文件挂载
官方编排以环境变量为主要配置方式,不挂载额外配置文件。如需自定义:
- Core 环境变量在
core.environment中追加; - Gateway 的 WireGuard 行为(接口名、MTU、masquerade 等)通过环境变量控制,见配置篇;
- TLS 证书由自动采纳机制管理,一般无需手工挂载。
九、常用运维命令
# 查看四服务状态
docker compose ps
# 查看某服务日志
docker compose logs core --tail 50
# 重启单个服务
docker compose restart gateway
# 停止并移除服务(保留数据卷)
docker compose down
# 停止并移除服务与数据卷(危险!清空数据)
docker compose down -v
# 进入 Core 执行管理命令(如创建管理员)
docker compose exec core /app/defguard manage create-admin \
--username admin --password 'Q1w2e3r4!' \
--first-name Admin --last-name User --email admin@example.com
💡 说明:
defguard manage create-admin可在命令行直接创建管理员,无需走 Web 向导;适用于自动化部署或重置管理员场景。
十、常见问题
10.1 端口 80/443 被占用
Edge 默认映射 80 与 443(用于 Let's Encrypt 证书签发)。若宿主机已有 Web 服务占用这些端口,可只保留 8080 映射并在前置反向代理上终止 TLS:
edge:
ports:
- "8080:8080"
# 去掉 443 与 80 映射
10.2 内部 URL 不能填 IP 地址
向导「Internal URL Settings」要求 URL 使用主机名,不能直接填 IP。若只有 IP 没有域名,可在客户端 /etc/hosts 或内网 DNS 中把一个主机名指向服务器 IP,再在向导中填该主机名。
实测报错:
Defguard URL must use a hostname, not an IP address
10.3 Gateway 无法创建 wg0 接口
若 Gateway 日志出现 Operation not permitted 或 RTNETLINK answers: Operation not permitted,通常是缺少 NET_ADMIN 能力。确认编排文件中 gateway 服务有:
cap_add:
- NET_ADMIN
10.4 客户端无法握手
- 检查服务器 UDP 51820 是否放行(云服务商安全组 / 防火墙);
- 检查客户端配置中的
Endpoint是否为服务器公网可达地址; - 检查客户端公钥是否已在管理台添加、且与配置中私钥匹配。
10.5 升级版本
修改 .env 中的镜像标签(如 DEFGUARD_CORE_TAG=2.1.1),然后:
docker compose pull
docker compose up -d
数据库迁移由 Core 启动时自动执行。降级可能因数据库 schema 变更而不可逆,升级前务必备份数据库。