接下来开始安装 Netmaker。
🔐 安全 :
我本人非常重视安全,买了 NAS 后,你会在 NAS 上看到海量的被攻击日志,所以不要心存侥幸。
最基础的实现安全的方式就是:SSL + 认证 + 防火墙。
所以以上 3 块我都会默认启用,当然,由此也必然会带来了一些安装、配置上的复杂度。
本次 Netmaker 安装会启用所有相关的安全特性。为了启用安全特性,你至少需要有属于自己的 域名。
〇、前提条件
- 来自公有云的云服务器
- 具有公网静态 IP
- 最小 1C1G
- 2GB+ 的存储空间
- 安装 Ubuntu 20.04 操作系统
- 域名
- 公网域名(如我的域名是
ewhisper.cn
)并备案(备案过程就略过了) - 允许和访问通过 DNS 服务(如我的 DNS 供应商是 DNSPod) 修改 DNS 记录
一、准备 DNS
创建一条指向你云服务器的公网 IP 的通配符记录,例如,*.netmaker.ewhisper.cn
。
如我在 DNSPod 控制台上的 DNS 记录配置如下:
Netmaker 通配符记录
后面的过程会用这个通配符创建 3 个子域名:
dashboard.netmaker.ewhisper.cn
api.netmaker.ewhisper.cn
grpc.netmaker.ewhisper.cn
二、安装依赖项
包括:
- docker
- docker-compose
- wireguard
ssh root@your-host sudo apt-get update sudo apt-get install -y docker.io docker-compose wireguard BASH |
三、打开防火墙
确保在云服务器和云安全组上为 Netmaker 设置了防火墙设置。
确保以下端口在 VM 和云安全组中都是打开的:
- 443(tcp): 用于 Dashboard、REST API 和 gRPC
- 355(udp 和 tcp):用于 CoreDNS
- 51820-51830:对于 WireGuard-Netmaker,每个网络需要一个端口,从 51821 开始(Wireguard 默认是 51820),因此根据计划拥有的网络数量开放一个范围。例如,51820-51830。
- ICMP:允许 ICMP
云服务器上的防火墙,开启命令如下:
1 |
sudo ufw allow proto tcp from any to any port 443 && sudo ufw allow 53/udp && sudo ufw allow 53/tcp && sudo ufw allow 51820:51830/udp BASH |
同样,基于您的云提供商,您可能还需要为您的服务器设置入站安全规则。这将取决于您的云供应商。
以天翼云 / 华为云为例,云安全组配置如下:
Netmaker 云安全组配置
四、安装 Netmaker
⚠️ 警告:
COREDNS_IP:根据您的云提供商,公网 IP 可能不会直接绑定到您正在运行的 VM。在这种情况下,CoreDNS 不能绑定到这个 IP,您应该使用计算机上默认接口的 IP 来代替 COREDNS_IP。在很多情况下,这个命令会为你提供正确的 CoreDNS IP: (就是云服务器的内网 IP)
ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'
现在,插入基本域(通配符)(domain)、公网 ip(public ip) 和 coredns ip 的值。
wget -O docker-compose.yml https://raw.githubusercontent.com/gravitl/netmaker/master/compose/docker-compose.contained.yml sed -i 's/NETMAKER_BASE_DOMAIN/<your base domain>/g' docker-compose.yml sed -i 's/SERVER_PUBLIC_IP/<your server ip>/g' docker-compose.yml sed -i 's/COREDNS_IP/<default interface ip>/g' docker-compose.yml BASH |
在这里:
<your base domain>
:是类似这种:netmaker.ewhisper.cn
<your server ip>
:就是公网 IP<default interface ip>
: 就是私网 IP,如:192.168.1.226
docker-compose 内容如下(基于原始内容做了部分调整,调整内容见注释):
version: "3.4" services: netmaker: container_name: netmaker image: gravitl/netmaker:v0.9.1 volumes: - ./dnsconfig:/root/config/dnsconfig # 将 dnsconfig 直接放到当前目录 - /usr/bin/wg:/usr/bin/wg - ./sqldata:/root/data # 将数据库数据也放到当前目录 - /etc/netclient/config:/etc/netclient/config # Netmaker Server 所在的主机会作为 netclient 的一员,将 netclient config 的配置文件放到主机的 /etc/netclient/config 目录 cap_add: - NET_ADMIN restart: always privileged: true environment: SERVER_HOST: "SERVER_PUBLIC_IP" SERVER_API_CONN_STRING: "api.NETMAKER_BASE_DOMAIN:443" SERVER_GRPC_CONN_STRING: "grpc.NETMAKER_BASE_DOMAIN:443" COREDNS_ADDR: "SERVER_PUBLIC_IP" GRPC_SSL: "on" DNS_MODE: "on" SERVER_HTTP_HOST: "api.NETMAKER_BASE_DOMAIN" SERVER_GRPC_HOST: "grpc.NETMAKER_BASE_DOMAIN" API_PORT: "8081" GRPC_PORT: "50051" CLIENT_MODE: "on" MASTER_KEY: "REPLACE_MASTER_KEY" SERVER_GRPC_WIREGUARD: "off" CORS_ALLOWED_ORIGIN: "*" DISPLAY_KEYS: "on" DATABASE: "sqlite" NODE_ID: "netmaker-server-1" network_mode: host # 这里直接使用 host 网络模式 netmaker-ui: container_name: netmaker-ui depends_on: - netmaker image: gravitl/netmaker-ui:v0.9.1 links: - "netmaker:api" ports: - "8082:80" environment: BACKEND_URL: "https://api.NETMAKER_BASE_DOMAIN" restart: always coredns: depends_on: - netmaker image: coredns/coredns command: -conf /root/dnsconfig/Corefile container_name: coredns restart: always ports: - "COREDNS_IP:53:53/udp" - "COREDNS_IP:53:53/tcp" volumes: - ./dnsconfig:/root/dnsconfig # 我的 DNS 域名托管在 DNSPod 上,无法通过默认方式自动申请证书,所以不使用容器方式的 caddy,而是使用 安装了 dnspod 插件的 apt 安装的 caddy # caddy: # image: caddy:latest # container_name: caddy # restart: unless-stopped # network_mode: host # Wants ports 80 and 443! # volumes: # - /root/Caddyfile:/etc/caddy/Caddyfile # # - $PWD/site:/srv # you could also serve a static site in site folder # - caddy_data:/data # - caddy_conf:/config # 都指定了具体的目录,所以 volumes 也不需要了 # volumes: # caddy_data: {} # caddy_conf: {} # sqldata: {} # dnsconfig: {} YAML |
生成一个唯一的主密钥并插入它:
tr -dc A-Za-z0-9 </dev/urandom | head -c 30 ; echo '' sed -i 's/REPLACE_MASTER_KEY/<your generated key>/g' docker-compose.yml BASH |
⚠️ 重要 :
保存好这个密钥,以便将来与 API 一起使用。
4.1 准备 Caddy
⚠️ 注意 :
我的 DNS 域名托管在 DNSPod 上,无法通过默认方式自动申请证书,所以不使用容器方式的 caddy,而是使用 安装了 dnspod 插件的 apt 安装的 caddy。
另一种可行的方式是自行 docker build 将 dnspod 插件编译到容器中并使用。
安装这个包时,Caddy 会自动启动并作为一个名为 Caddy 的 systemd 服务运行。
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/caddy-stable.asc curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install caddy BASH |
4.1.1 Caddy 使用 DNSPod 模块
Caddy 2 使用了一个 新的和改进的 DNS 提供者接口 来解决 ACME DNS 的 challenge。
所有您需要做的就是将您需要的服务提供商(如 DNSPod)插入到您的构建中,然后将 DNS challenge 添加到您的配置中!
获得 DNSPod DNS 插件
- 访问 Caddy 下载
- 在模块列表中找到您的 DNS 提供程序
- 下载,比如我的 linux amd64 版本的 dnspod 插件下载地址为:https://caddyserver.com/api/download?os=linux&arch=amd64&p=github.com%2Fcaddy-dns%2Fdnspod&idempotency=14234280192478
4.1.2 将默认安装的 Caddy 替换为下载的带有 dnspod 插件的 caddy
这个过程旨在简化运行定制的 caddy 二进制文件,同时保留 caddy 包中的支持文件。
此过程允许用户利用官方包中的默认配置、 systemd 服务文件和 bash-completion。
前提:
- 已安装
caddy
- 已下载好带有 dns (本次是 dnspod) 插件的
caddy
步骤:
dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy mv ./caddy /usr/bin/caddy.custom update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10 update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50 BASH |
dpkg-divert
将 /usr/bin/caddy
二进制文件移动到 /usr/bin/caddy.default
,并在任何包想要在这个位置安装文件的情况下放置一个转移。
update-alternatives
将创建一个从所需的 caddy 二进制到 /usr/bin/caddy
的符号链接
通过执行下面命令,可以在自定义二进制代码和默认二进制代码之间进行更改
update-alternatives --config caddy BASH |
并在屏幕上做出选择。
4.1.3 创建 Caddyfile 并启动 Caddy
下面创建 Caddyfile 并启动 Caddy,这里以通过 dnspod 自动向 LetsEncrypt 或 ZeroSSL 申请免费 SSL 证书为例:
前提条件:
- 买个域名(这个是必须要花钱的,但是一些冷门域名很便宜)
- 知道自己的域名是哪个 dns 提供商并拥有相应的 token。以 dnspod 为例,从这里申请 token
vi /etc/caddy/Caddyfile
{ # LetsEncrypt account email cuikaidong@foxmail.com acme_dns dnspod <dnspod_id>,<dnspod_token> # 将 <> 中的内容替换为对应的 dnspod id 和 token } # Dashboard https://dashboard.netmaker.ewhisper.cn { reverse_proxy http://127.0.0.1:8082 } # API https://api.netmaker.ewhisper.cn { reverse_proxy http://127.0.0.1:8081 } # gRPC https://grpc.netmaker.ewhisper.cn { reverse_proxy h2c://127.0.0.1:50051 } NGINX |
上面配置很通俗易懂,就不做解释了。
启动 Caddy:
systemctl start caddy.service BASH |
4.1.4 Caddy 自动申请证书并对外服务
然后,Caddy 会通过 LetsEncrypt 或 ZeroSSL 自动申请证书并定期续约。通过向 dnspod 增加我的域名的 dns 解析来验证这个域名确实属于我(这种证书申请方式就是下面日志中提到的:"challenge_type":"dns-01"
)。如下图:
通过 DNSPod token 添加 dns 记录的操作日志
之后会获得 LetsEncrypt 或 ZeroSSL 颁发的证书,如下:
Dec 06 16:05:46 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806746.1932435,"logger":"tls.issuance.acme.acme_client","msg":"trying to solve challenge","identifier":"dashboard.netmaker.ewhisper.cn","challenge_type":"dns-01","ca":"http> Dec 06 16:05:53 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806752.9999793,"logger":"tls.issuance.acme.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-staging-v02.api.letsencrypt.org/acme/order/360> Dec 06 16:05:53 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806753.1332862,"logger":"tls.issuance.acme.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-staging-v02.api.letsencrypt.org/acme/order/360> Dec 06 16:05:53 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806753.6776898,"logger":"tls.issuance.acme.acme_client","msg":"successfully downloaded available certificate chains","count":1,"first_url":"https://acme-staging-v02.api.let> Dec 06 16:05:53 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806753.6779523,"logger":"tls.issuance.acme","msg":"waiting on internal rate limiter","identifiers":["grpc.netmaker.ewhisper.cn"],"ca":"https://acme-v02.api.letsencrypt.org/> Dec 06 16:05:53 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806753.677963,"logger":"tls.issuance.acme","msg":"done waiting on internal rate limiter","identifiers":["grpc.netmaker.ewhisper.cn"],"ca":"https://acme-v02.api.letsencrypt.> Dec 06 16:05:56 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806756.0425541,"logger":"tls.issuance.acme.acme_client","msg":"trying to solve challenge","identifier":"grpc.netmaker.ewhisper.cn","challenge_type":"dns-01","ca":"https://a> Dec 06 16:05:59 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806759.301592,"logger":"tls.issuance.acme.acme_client","msg":"successfully downloaded available certificate chains","count":1,"first_url":"https://acme-staging-v02.api.lets> Dec 06 16:05:59 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806759.3018231,"logger":"tls.issuance.acme","msg":"waiting on internal rate limiter","identifiers":["dashboard.netmaker.ewhisper.cn"],"ca":"https://acme-v02.api.letsencrypt> Dec 06 16:05:59 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806759.3018348,"logger":"tls.issuance.acme","msg":"done waiting on internal rate limiter","identifiers":["dashboard.netmaker.ewhisper.cn"],"ca":"https://acme-v02.api.letsen> Dec 06 16:06:00 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806760.909151,"logger":"tls.issuance.acme.acme_client","msg":"trying to solve challenge","identifier":"dashboard.netmaker.ewhisper.cn","challenge_type":"dns-01","ca":"https> Dec 06 16:06:08 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806768.1700737,"logger":"tls.issuance.acme.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-v02.api.letsencrypt.org/acme/order/310057420/4> Dec 06 16:06:09 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806769.6764278,"logger":"tls.issuance.acme.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-v02.api.letsencrypt> Dec 06 16:06:09 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806769.67741,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"grpc.netmaker.ewhisper.cn"} Dec 06 16:06:09 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806769.6776047,"logger":"tls.obtain","msg":"releasing lock","identifier":"grpc.netmaker.ewhisper.cn"} Dec 06 16:06:14 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806774.210461,"logger":"tls.issuance.acme.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-v02.api.letsencrypt.org/acme/order/310057420/45> Dec 06 16:06:15 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806775.165971,"logger":"tls.issuance.acme.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-v02.api.letsencrypt.> Dec 06 16:06:15 09b2brd7robnn5zi-1106883 caddy[119805]: {"level":"info","ts":1638806775.1666183,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"dashboard.netmaker.ewhisper.cn"} D |
ℹ️ 提示 :
生成的证书位于:/var/lib/caddy/.local/share/caddy/
目录
4.2 启动 Netmaker
终于到 Netmaker 了,通过如下命令启动:
sudo docker-compose up -d BASH |
然后访问:dashboard.<your base domain>
(本例中是:dashboard.netmaker.ewhisper.cn
) 开始使用 Netmaker。
五、Netmaker 基本界面及使用
访问后,首先创建管理员。创建后会进入首页,如下:
Netmaker 首页
左侧依次为:
- 仪表板
- 网络
- 节点
- 访问密钥
- 外部客户端
- DNS
- 文档
- 管理员账号
- 登出
- 用户
- 版本信息
仪表板主要有 6 大部分内容:
- 网络
- 节点
- 访问密钥
- 外部客户端
- DNS
- 用户
要创建 Full Mesh 网络,基本的操作流程为:
- 在 Network 页面,填入网络基本信息,创建网络;
- 创建网络的同时,默认会将 Netmaker 所在主机加入到 Node 中,可以在 Nodes 和 DNS 页面看到该节点状态;
- 创建 Access Key,指定该 Key 会被多少个 Netclient 客户端使用;同时页面会弹出通过 netclient 加入网络的指令
- 在其他节点上,执行对应的指令,即可完成 Full Mesh 网络的组建;此后 WireGuard 的 peer 等配置会由 Netmaker 统一管理;
- 对于 Android 等尚不支持 Netclient 的客户端,可以先将上面的一个节点指定为 Ingress Gateway(可以理解为是 WireGuard 的中继服务器),然后创建 External Client,自动生成配置及配置二维码,安卓手机可以扫码添加配置并加入网络