AMD GPU部署LLM推理框架

基础环境

CPU: Intel(R) Xeon(R) Platinum 8358P * 2
内存:32GB * 16
显卡:AMD Instinct MI210 * 8
操作系统:CentOS Linux release 8.4.2105
内核:4.18.0-305.3.1.el8.x86_64

部署结果

vllm+Qwen3-32B,运行成功
sglang+Qwen3-32B,运行失败,所部署的sglang版本暂时不支持Qwen3,详细说明

部署过程

安装驱动和rocm:

rocm目前的最新版本是6.4.1,但截止到本文编写时间,vllm和sglang暂时还只是适配了6.3.x版本,因此建议安装6.3.x的最新版本(本文以6.3.3为例)
可以在此URL:https://repo.radeon.com/amdgpu-install/6.3.3/下找到对应的安装源,本文是安装了amdgpu-install-6.3.60303-1.el8.noarch.rpm

wget https://repo.radeon.com/amdgpu-install/6.3.3/el/8.10/amdgpu-install-6.3.60303-1.el8.noarch.rpm
rpm -ivh amdgpu-install-6.3.60303-1.el8.noarch.rpm

安装repo后,再执行以下命令安装驱动及rocm:

amdgpu-install
amdgpu-install --usecase=rocm

运行dkms status和rocm-smi命令验证安装成功。

部署vllm

直接拉起vllm镜像

拉取镜像(国内需要从国内的镜像源拉取或使用代理)

docker pull rocm/vllm:rocm6.3.1_vllm_0.8.5_20250521

更多版本见这里,https://hub.docker.com/r/rocm/vllm/tags

拉起vllm容器

docker run -it \
  --network=host \
  --group-add=video \
  --ipc=host \
  --cap-add=SYS_PTRACE \
  --security-opt seccomp=unconfined \
  --device /dev/kfd \
  --device /dev/dri \
  -v /public/models:/root/.cache/huggingface \
  rocm/vllm:rocm6.3.1_vllm_0.8.5_20250521 \
  bash

自己构建vllm镜像

直接从docker hub拉取的镜像,是vllm 0.8.5版本,如果想要较新版本,可以自己构建。
目前构建起来的版本是0.9.1

下载rocm版本的Dockerfile,https://github.com/vllm-project/vllm/blob/main/docker/Dockerfile.rocm,运行以下命令进行构建

DOCKER_BUILDKIT=1 docker build -f Dockerfile.rocm -t vllm-rocm .

如果构建失败,把Dockerfile.rocm中的ARG REMOTE_VLLM=”0″改为”1″

构建完成后,拉起容器

docker run -it \
  --network=host \
  --group-add=video \
  --ipc=host \
  --cap-add=SYS_PTRACE \
  --security-opt seccomp=unconfined \
  --device /dev/kfd \
  --device /dev/dri \
  -v /public/models:/root/.cache/huggingface \
  vllm-rocm \
  bash

运行vllm

运行vllm服务端(在容器内运行)

#已下载好模型文件,本地离线运行
vllm serve /root/.cache/huggingface/Qwen3-32B \     #目录路径是模型文件夹本身的路径
--served-model-name Qwen3-32B \
--tensor-parallel-size 8 \
--gpu-memory-utilization 0.95 \
--trust-remote-code

#在线运行,从huggingface下载模型文件
vllm serve Qwen/Qwen3-32B \       #用huggingface格式填写模型名称
--tensor-parallel-size 8 \
--gpu-memory-utilization 0.95 \
--trust-remote-code

部署sglang

用于rocm的sglang,目前最新版是v0.4.7-rocm630,同样可以从docker hub拉取,也可以自己构建。但最新版不支持MI210(gfa90a),建议使用”lmsysorg/sglang:v0.4.3.post2-rocm630″,来源

直接拉起sglang镜像

部署lmsysorg/sglang:v0.4.3.post2-rocm630版本

拉取镜像(国内需要从国内的镜像源拉取或使用代理)

docker pull lmsysorg/sglang:v0.4.7-rocm630

更多版本见这里,https://hub.docker.com/r/lmsysorg/sglang/tags

拉起sglang容器

docker run -it \
  --network=host \
  --device=/dev/kfd \
  --device=/dev/dri \
  --ipc=host \
  --shm-size 16G \
  --group-add video \
  --cap-add=SYS_PTRACE \
  --security-opt seccomp=unconfined \
  -v /public/models:/root/.cache/huggingface \
  --privileged \
  -w /workspace \
  lmsysorg/sglang:v0.4.3.post2-rocm630

运行sglang

运行sglang服务端(在容器内运行)

#已下载好模型文件,本地离线运行
python3 -m sglang.launch_server \
  --model-path /root/.cache/huggingface/DeepSeek-R1-Distill-Qwen-7B \   #目录路径是模型文件夹本身的路径
  --host 0.0.0.0 \
  --port 30000 \
  --tp 4 \
  --context-len 8192 \
  --max-prefill-tokens 8192 \
  --chunked-prefill-size 2048

#在线运行,从huggingface下载模型文件
python3 -m sglang.launch_server \
  --model-path deepseek-ai/DeepSeek-R1-Distill-Qwen-7B \       #用huggingface格式填写模型名称
  --host 0.0.0.0 \
  --port 30000 \
  --tp 4

测试vllm模型运行效果:

curl -X POST -H "Content-Type: application/json" -d '{"model": "Qwen3-32B", "messages": [{"role": "user", "content": "你好"}], "max_tokens": 10}' http://localhost:8000/v1/chat/completions

其它

sglang支持qwen3问题

因为目前的硬件环境是MI210(gfx90a),只能使用”lmsysorg/sglang:v0.4.3.post2-rocm630″这个版本,而这个版本是不支持qwen3。
最新版lmsysorg/sglang:v0.4.7-rocm630目前还没支持MI210(gfx90a),所以暂时也没法测试最新版是否支持qwen3。

下载模型

huggingface命令下载

huggingface-cli login
huggingface-cli download deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --local-dir /root/.cache/huggingface/DeepSeek-R1-Distill-Qwen-7B --local-dir-use-symlinks False

国内代理站

https://hf-mirror.com/

相关资料

AMD

驱动、rocm等: https://repo.radeon.com/
rocm相关镜像: https://hub.docker.com/u/rocm

vllm

github: https://github.com/vllm-project/vllm
Dockerfile: https://github.com/vllm-project/vllm/blob/main/docker/Dockerfile.rocm
部署指引: https://docs.vllm.ai/en/latest/getting_started/installation/gpu.html#amd-rocm
镜像: https://hub.docker.com/r/rocm/vllm/tags

sglang

github: https://github.com/sgl-project/sglang
Dockerfile: https://github.com/sgl-project/sglang/blob/main/docker/Dockerfile.rocm
部署指引: https://docs.sglang.ai/start/install.html
镜像: https://hub.docker.com/r/lmsysorg/sglang/tags

监控相关

  • device-metrics-exporter
    github: https://github.com/ROCm/device-metrics-exporter
    镜像: https://hub.docker.com/r/rocm/device-metrics-exporter/tags
    运行命令:
docker run -d \
  --device=/dev/dri \
  --device=/dev/kfd \
  -p 5000:5000 \
  --name device-metrics-exporter \
  rocm/device-metrics-exporter:v1.2.1
  • amd_smi_exporter
    github: https://github.com/amd/amd_smi_exporter

  • grafana模板
    https://grafana.com/grafana/dashboards/23434-amd-instinct-single-node-dashboard/

HA配置使用微软Azure STT

准备工作

在开始配置之前,您需要先:

  1. 注册Microsoft Azure账户
  2. 创建Speech Service资源
  3. 获取Speech Service的API密钥和区域信息

详细步骤:
1. 访问 Azure Portal
2. 注册/登录您的Microsoft账户
3. 在Azure门户中创建新的Speech Service资源
4. 创建完成后,在资源的”Keys and Endpoint”页面获取:
– API Key (密钥)
– Region (区域)

请妥善保存这些信息,后续配置会用到。

配置步骤

  1. 在Home Assistant的Add-on Store中添加新的仓库:
    • 打开Home Assistant
    • 进入Settings -> Add-ons
    • 点击右下角的”Add-on Store”
    • 点击右上角的菜单按钮(⋮)
    • 选择”Repositories”
    • 添加仓库URL: https://github.com/hugobloem/homeassistant-addons
    • 点击”Add”确认添加
  2. 在Add-on Store中安装Microsoft STT:
    • 刷新Add-on Store页面
    • 找到并点击”Microsoft STT”
    • 点击”Install”按钮安装插件
    • 等待安装完成后启动插件
  3. 点击进入Microsoft STT的配置页面,在设置页面中输入您的API密钥、区域和语言信息。

  1. 可识别的语言清单及相关配置,请参考Azure Speech Service语言支持文档

  2. 在装置与服务中会发现新的服务Microsoft STT,添加并启用,即可在语音助手中等场景使用微软STT服务。

粤语输入输出

粤语TTS配置:

homeassistant自带的google translate tts,默认自带有粤语,只要语言选择yue,即可使用粤语。

粤语STT配置:

配置微软的STT,区域选择:eastasia,语言选择:zh-HK

参考资料

自建ChatGPT服务

前言

ChatGPT免费版,如果多聊几句,gpt-4/4o的quota的不够用;但如果开通Plus,每个月$20美元也不便宜,如果用得不够多总觉得很亏。

还是通过api部署自己的服务比较好,用多少算多少,而且现在Azure中申请4/4o的API也很容易,不用一等再等了。

通过部署ChatGPT-Next-Web来实现自建ChatGPT服务ChatGPT-Next-Web

提前条件

本篇中ChatGPT-Next-Web服务是通过微软Azure OpenAI API + docker部署的,所以你必须先拥有以下两样:
– Azure账户。最好是非国内的,国内的账户的没试过。
– 公网上的虚拟机。同样,最好是非国内的,虽然目前可以直接Azure API,但不知以后怎样;另外,国内的主机要开web访问也非常麻烦。

创建Azure OpenAI服务

  1. 找到Azure OpenAI(没看到的话直接搜索),然后按”创建”
    创建Azure OpenAI服务

  2. 订阅账户、资源群组、名称、定价层等,按照自身实际情况选择或填写就可以。这里最重要的选择是区域,因为不同区域提供的模型是不一样的,详细可以参考这里 ,还有价格
    选择区域

  3. 网络和tag根据自身情况选择,本例中是对所有网络开放存取,提交后后台会进行部署,约1、2分钟就能创建完成。

  4. 点击”Azure OpenAI”的图标,就能看到刚才创建的服务。
    AzureAI服务清单
  5. 点击进去,在”资源管理”->”金钥与端点”可以看到API的key和url
    key&endpoint
  6. 还需要部署模型,点击“模型部署”->“管理部署”,部署新的模型(会打开新的页面)。
    管理部署模型
  7. 点击”部署模型”->”部署基本模型”,选择要部署的模型(不同区域这里的选项会有不同)
    选择模型
  8. 下一步要输入部署名称,点击”确定”即部署完成。需要注意,调用是以”部署名称”为准,不是模型名称(本例中部署名称跟模型名称一样)。
    部署名称

容器部署ChatGPT-Next-Web

确保虚拟机已经安装好docker相关组件,运行以下命令就可以直接部署完成(相关变量替换为实际参数):

docker run \
  --name=nextchat \
  -p 3000:3000 \
  -e CODE=xxx \
  -e AZURE_URL=https://fortestme.openai.azure.com/openai \
  -e AZURE_API_KEY=xxx \
  -e AZURE_API_VERSION=2024-06-01 \
  -e CUSTOM_MODELS="-all,+gpt-4o-mini@Azure=gpt-4o-mini" \
  -e DEFAULT_MODEL="gpt-4o-mini@Azure" \
  --privileged \
  --restart unless-stopped \
  -d yidadaa/chatgpt-next-web

环境变量说明:

  • CODE,访问密码
  • AZURE_URL,AZURE API接口URL,在endpoint的url后再加上openai就可以
  • AZURE_API_KEY,API key,页面中看到的key1、key2通用
  • AZURE_API_VERSION,API版本,详细参考这里
  • CUSTOM_MODELS,自定义模型。ChatGPT-Next-Web支持多家公司的多种模型,都内置到选项中,不便于选择使用,可以自定义需要的选项。
  • DEFAULT_MODEL,默认使用哪个模型

CUSTOM_MODELS语法简要说明,详细见项目文档

-all, 禁用所有模型
+gpt-4o-mini@azure=gpt-4o-mini,增加一个Azure的模型,’@’前面的是模型的部署名称,’=’后面的是使用时选项中显示的名称

ChatGPT-Next-Web的容器正常运行后,浏览器输入http://ip:3000就访问自己的ChatGPT服务,如果访问不了,注意虚拟机上的防火墙配置。

web

服务发布

完成以上步骤,虽然已经可以正常使用,但基于安全性等种种原因,还是不建议直接3000端口进行访问。以下提供几种对外发布的方案供参考(不作详细展开说明)。

  1. 安装nginx,以反代方式进行部署,再把DNS指向过来就可以通过域名访问;
  2. 通过caddy来进行反代部署,原理跟nginx一样,但caddy能自动申请免费证书并自动续期,省事并提高安全性。
  3. 在主机上安装cloudflared,再通过Tunnels发布,天然享有ssl和cdn,但前提是你的域名托管在CF。

2024年暑假青甘大环线非主流自驾游记

行程概要

9天假期,除去从居住城市到西宁一来一回的行程,有7天时间是在青甘线的旅程上。
青甘环线

行程:西宁->茶卡镇->大柴旦->敦煌->玉门->张掖->青海湖东(金沙湾)->西宁

到西宁后是租车自驾,上图是主要行程路线,行程线路中每一站,就是住宿点1。我自己核算过,共开了约2550公里。

每一天车程平均约400公里,最长茶卡-大柴旦(有兜路)约540公里,最短青海湖东-西宁约125公里。

旅程

既然是非主流游记,就不会逐一介绍景点。主要说一下旅途中遇到一些特别事情,并且8月是属于当地的旅游旺季,在淡季中也未必完全一样。

西宁-茶卡

从西宁到倒湖茶公路(青海湖旅游专线),直接走G6高速从倒淌河收费站出,这里有可能会塞车。倒湖茶公路正在建收费口(2024年8月初),未来走这段也需要收费。

在倒湖茶公路上,有一些私人出租骑马、骑耗牛,相比景区内会便宜一些,一匹马走一圈一般¥50,一大人一小孩同骑一匹也是¥50。

经过二郎剑景区门口路段,有可能也会塞车。我当天在这段路上,高德提示会塞50分钟,就调头走G6直接去茶卡了。

茶卡的民宿,都集中在茶卡镇幸福路西边的一条村内,订民宿的都是在这一带了。
茶卡

茶卡-大柴旦

我的行程是茶卡直接去315的U型公路,再调头去翡翠湖,所以中间会经过小柴旦湖。
小柴旦湖
从S20经过小柴旦湖,在大概上图所示的位置上,有一个紧急停车带,有洗手间,也可以走近小柴旦湖观光拍照2

小柴旦湖景
315的U型公路,从2024年7月中开始禁止停车,其实也只是针对网红点周边,其它地方还是可以停的。

在大柴旦翡翠湖游玩,如果坐景区内的小火车,它的去程是直接开到最里面的站点,游客全下车游玩;回程的时候才会每个站点停车,游客可以在每个站点上下车。

晚上我住的是雪山温泉酒店,这里比大柴旦镇高了约400米(海拔3600左右),要注意高反。温泉里有卖10元3只的温泉蛋,但我去时说蛋卖完了,如果有自带蛋可以直接放进去泡。这里都真天然温泉,连在酒店门前流过的小溪水都是暖的。
温泉蛋

大柴旦-敦煌

走G3011,从大柴旦出去去敦煌,会经过鱼卡收费站,这里会要求所有人员(司机除外)下车安检,不清楚是常规还是旺季才这样。在收费站前几百米有鱼卡服务区,如果看到塞车太长,可以走服务区的路去收费区,会快一点(一样要安检)。

高速进入甘肃当金山路段后,终于又是全封闭路段,并且见到平时常见的服务区。

到敦煌西收费站出高速,去往月牙泉的方向,如果走景观大道,路的两旁会有很多农民摆摊卖水果的,价钱也不贵。

鸣沙山

关于鸣沙山月牙泉的东、西、中门,简单来说就是这样:

鸣沙山门票是有三天有效期的

  • 中门,停好车后,到大门检票自己走进去景区。
  • 西门,在离景区西边一两公里的地方开辟一块停车场,那里停车、检票后,再坐摆渡车送你到景区,¥10/人,包来回(我自己就是从西门进)。
  • 东门,综合了解到的信息就是类似西门那样,只是在东边。
  • 无论中门(检票进去后),还是东、西门(下摆渡车后),进到景区的地点都是鸣月广场,不会有很大的距离变化。

在敦煌住宿选择了包晚包早沙漠露营。因为是露营,一开始降低了心理预期,但现实还把预期打破了。

缺点:

  • 塞车,其实所有的露营基地,都是集中那一带(鸣沙山西南方5、6公里)。那天我从鸣沙山西门去露营基地,短短几公里路,走了2个多小时,这可能是旺季问题。
  • 晚餐,并不是你去到了,想什么时候吃就吃。是等营地准备好,认为人员到得差不多了,大家一起边看表演边吃的,而且因为是打火锅,不一定全是自己一围的,有可能会拼台。食材嘛,妥妥的合成肉,工业食品。
  • 吵,整个场地(不同营地其实就在旁边)都是不同的表演,烟花声、摩托声、吵闹声不断,想要早点休息,或者静静发呆是很难的。那天晚上我大概看了下,到凌晨两点半后才迎来真正的安静。不过,这对有些朋友来说可能是优点。
  • 洗澡和洗手间,这个是预期内的问题,都是公共的,洗澡要额外给钱,也有些房型是有独立沐浴间的。

优点:

  • 骑骆驼便宜,¥50一次,一大一小同坐算一次,但兜的圈没鸣沙山那边那么大。
  • 免费坐沙漠摩托,订房有送几张票,虽然不是兜很大的圈,但够玩了。
  • 免费滑沙,营地有滑沙板,自己拿了就可以去玩。

与其他游客交流中得知,有些人只是过来营地吃饭看表演,玩玩娱乐活动,再回市区酒店睡的,营地包接送,这样也是不错的。

营地区域

另外,预订时要注意,如果它显示的营地地点不在鸣沙山西南,而是在市区的,这些有可能二道贩子。我订的就是这样,预订的名称,跟去到实际营地的名称不同,接待我们的人,对营地那边的人都是哈腰点头的。

敦煌-玉门

上午去参观莫高窟,有分正常票和应急票,这个没什么好说的了,网上一堆说明的。如果是正常票,你什么时候去都行;如果是应急票,就老老实实早点去排队。
那天我10点到停车场,排队入门坐摆渡车,12点多才到景区;你以为到景区就可以参观应急票的4个窟,太天真了,排队入窟参观的长龙,目测最少要等2小时,遂放弃。
莫高窟这个正常票和应急票也真高端,不叫VIP票,让大家心里都舒坦多了。

九层塔

很多行程都会在敦煌住两晚,但因为我在敦煌是沙漠露营,第二晚都一定换酒店的,索性就推进一点行程,目标是瓜州或玉门。最后选择了玉门,因为离嘉峪关近一点,第二天可以迟一点出发,休息得更好。

从敦煌去玉门,经过瓜州后就会转入G30连霍高速,直至去到张掖都会走这条高速。这条高速大货车、半挂车巨多,开车一定要注意小心

玉门-张掖

去张掖的途中,会去嘉峪关游玩。嘉峪关其实包括了三个景点:悬壁长城、关城(最常讲的嘉峪关)、第一墩。在关城买¥110的票(网上买是¥108),就会包括悬壁长城和第一墩。如果单独去悬壁长城和第一墩,是要单独买票的。
悬壁长城
从玉门(敦煌)去嘉峪关,推荐的游玩顺序是:悬壁长城->关城->第一墩

张掖-青海湖东(金沙湾)

从张掖去青海湖东,要走G0611张汶高速。但高速没全通,有一段要下来走国道,那天在这国道上有车祸,塞了我三个小时。

中途会经过祁连山草原祁连大草原(在高德上可以分别搜到两个地点的)。我从网上找资料时,说祁连大草原会有卖食和玩的,但我实际去到是什么都没有,而门前的国道在维护,也不知是不是这个原因。
祁连山草原是在鹅堡镇,吃、喝、玩、乐相对齐全方便;祁连大草原在较高点,在国道的一个拐弯处,门前停车位较少,里面人也少,拍照比较好。
祁连大草原

继续走高速,会经过门源县,那是一个非常美丽的县。如果有时间走国道可以慢慢欣赏,走高速的话会经过一个花海服务区,可以在那里停车拍照,视野也十分好的。
花海服务区门源县

青海湖金沙湾露营基地,食宿方便,一边是青海湖,另一边是沙漠。住宿的话可以免费坐摆渡车,否则是有偿乘坐。营地有很多野生小动物,狐狸、小兔、土拨鼠(反正会打洞的),走几百米就到沙漠,可以玩沙、滑沙。

青海湖东-西宁

回市区就没什么好说的了,在西宁买手信的话可以去莫家街那边,品类较多,相比在茶卡、大柴旦等也便宜。
莫家街

其它建议

  • 海西州大部分高速,都不是全封闭道路,高速行车要注意
  • 海西州的高速收费站,大多都是收一段路的费用,不用拿卡的
  • 在海西州的高速上如果人有三急,停在紧急停车带上解决,会比在服务区上去更好,原因你懂的。
  • 尽量不在高速服务区加油
  • 海西州的平均海拔是3200米左右,西宁2200米,到甘肃就是1200米左右。这一圈下来,最高就是在祁连大草原,3700米。
  • 这边夏季日照时间长,普遍都是8点半后才开始天黑,所以就算5点多,景区还有很多人排队进场,里面的人也很多,每日行程规划可以适当延长。

  1. 图片中的途经点,不一定是行程的经停点,只是为了使高德显示出路线而插入 ↩︎
  2. 从停车点走到湖边也有几百米 ↩︎

2024年暑假-青海行程

规划行程

D1(08.03,星期六)

行程:去程火车(需中转)

中转:广州南->郑州(中转)->西宁
– 方案:G696(06:23-13:56) -> K177(15:30-次日09:36),中间换乘时间约1小时34分(已购)
早上约4点50分从家自驾出发,先到西出发口,我再去停车场停车,后再自行进站。

餐食:

早餐(预计):火车
午餐(预计):火车
晚餐(预计):火车

住宿:K177火车

D2(08.04,星期日)

行程:西宁站->青海湖->茶卡盐湖->茶卡镇,310KM

09:36到达西宁站,取车出发
途经:
青海湖
茶卡盐湖

餐食:

早餐(预计):火车
午餐(预计):西宁
晚餐(预计):茶卡镇

住宿:茶卡镇

乌兰悦客之家家庭宾馆

行程路线

西宁到茶卡路线

D3(08.05,星期一)

行程:茶卡镇->U型公路(G315)->大柴旦翡翠湖->大柴旦行委柴旦镇,540KM

08:30左右从茶卡镇出发
途经:
U型公路
大柴旦翡翠湖

餐食:

早餐(预计):茶卡镇
午餐(预计):服务区
晚餐(预计):大柴旦行委柴旦镇

住宿:大柴旦行委柴旦镇

大柴旦雪山温泉度假酒店,¥557+¥553+¥128

行程路线

茶卡到大柴旦路线

D4(08.06,星期二)

行程:大柴旦行委柴旦镇->月牙泉->沙州夜市->敦煌,370KM

08:30左右从大柴旦出发
途经:
鸣沙山月牙泉
沙州夜市

餐食:

早餐(预计):大柴旦行委柴旦镇
午餐(预计):敦煌
晚餐(预计):敦煌

住宿:敦煌

敦煌国际沙漠露营基地

行程路线

大柴旦到敦煌路线

D5(08.07,星期三)

行程:敦煌->莫高窟->大地之子->玉门,270KM

敦煌周边游,出发时间待定
莫高窟(参观时间:12:00)
大地之子

餐食:

早餐(预计):敦煌
午餐(预计):敦煌
晚餐(预计):玉门

住宿:玉门

玉门宾馆

行程路线

敦煌到玉门路线

D6(08.08,星期四)

行程:玉门->嘉峪关->张掖,355KM

08:30左右从玉门出发
途经:
悬壁长城
嘉峪关关城景区
第一墩

餐食:

早餐(预计):玉门
午餐(预计):嘉峪关
晚餐(预计):张掖

住宿:张掖

西北民谷客栈(张掖国家湿地公园店)

行程路线

玉门到张掖路线

D7(08.09,星期五)

行程:张掖->祁连大草原->青海湖东(金沙湾),380KM

08:30左右从张掖出发
途经:
祁连大草原

餐食:

早餐(预计):张掖
午餐(预计):祁连大草原周边
晚餐(预计):青海湖周边

住宿:青海湖周边

青海湖金沙湾露营基地

行程路线

张掖到青海湖北路线

D8(08.10,星期六):

行程:青海湖东->西宁,125KM

出发时间待定
青海湖游玩
西宁市区内游玩

餐食:

早餐(预计):青海湖周边
午餐(预计):西宁
晚餐(预计):西宁

住宿:西宁

青海白云翔羚酒店

行程路线

青海湖到西宁路线

D9(08.11,星期日):

行程:回程火车 D2656 ¥1188

中转:西宁->西安北(中转)->广州南
– 方案1:D2656(07:50-12:06) -> G1166(13:23-22:46),中间换乘时间约1小时17分(已购)
– 方案2:D2736(08:45-12:41) -> G848(14:01-23:06),中间换乘时间约1小时20分
– 方案3:D2656(07:50-12:06) -> G848(14:01-23:06),中间换乘时间约1小时55分
– 方案4:D2736(08:45-12:41) -> G1166(13:23-22:46),中间换乘时间约42分
一起坐停车场的接送到停车场,拿车后自驾回家

餐食:

早餐(预计):火车
午餐(预计):火车
晚餐(预计):火车

费用

交通

去程费用

G696,合计:¥3405
K177,合计:¥1668
共:¥5073

回程费用

D2656,合计:¥1188
G1166,合计:¥3645
共:¥4833

当地用车

租车:¥3643
油费:¥1210
路费:¥904
共:¥5757

住宿

乌兰悦客之家家庭宾馆,¥188+¥197
大柴旦雪山温泉度假酒店,¥557+¥553+¥128
敦煌国际沙漠露营基地,¥1156
玉门宾馆,¥445
西北民谷客栈(张掖国家湿地公园店),¥204
青海湖金沙湾露营基地 ¥682
青海白云翔羚酒店 ¥456
共:¥4566

午餐:西宁午餐 ¥208
晚餐:茶卡镇¥132
晚餐:大柴旦行委柴旦镇 ¥322.80
早餐:玉门 ¥80
晚餐:张掖 ¥288
晚餐:青海湖周边 ¥294
早餐:青海湖周边¥20
午餐:西宁 ¥198
共:¥1542.8

景区

大柴旦翡翠湖:¥510
鸣沙山月牙泉:¥330
莫高窟应急票:¥350
嘉峪关关城景区:¥326
共:¥1516

使用tailscale打通两个Lan之间互访(VPN)

背景

一直有使用tailscale,在外访问家里的nas都很方便。后来在看资料时,发现可以用tailscale打通两个lan之间的site to site互访,lan内的non-tailscale设备(没安装tailscale)也可以直接访问另一个lan内的non-tailscale设备。

简单来说,其实就是在每个lan中找一台设备安装tailscale,用来承载vpn(跨lan)流量,其它non-tailscale设备就是通过它来访问另一个lan的设备。

刚才好手头上也有环境,决定测试部署一下。


测试环境

  • LAN1, 192.168.100.0/24, tailscale设备:ubuntu(虚拟机), IP:192.168.100.201
  • LAN2, 192.168.101.0/24, tailscale设备:Netgear WNDR4300,刷openwrt 22.03.5, IP:192.168.101.201

部署tailscale

LAN1:ubuntu安装tailscale

linux安装很简单,就一行命令,更详细的可以看官方资料:https://tailscale.com/download/linux

curl -fsSL https://tailscale.com/install.sh | sh

LAN1:配置并运行

启用ip forward功能

echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf

启动tailscale

tailscale up --advertise-routes=192.168.100.0/24 --accept-routes --snat-subnet-routes=false
  • –advertise-routes=192.168.100.0/24, 公告本节点代理的路由网段(网段信息以实际为准)。
  • –accept-routes, 接受其它节点公告的路由信息
  • –snat-subnet-routes=false, 通过本节点访问局域网设备时,不做源地址转换,默认为true

如果是首次运行,会提示先验证登录;需要在浏览器中打开指定URL。

LAN1:Approvers路由信息

在启动时公告了路由信息后,还需要在machines page中确认启用,console的machines page

节点公告了代理路由网段,但没在console启用,subnets旁边会有叹号

点击节点最后的三个点点“…”,选择“Edit route settings…”,启用公告的网段

启用后subnets旁边的叹号就会消失

LAN2:openwrt安装tailscale

openwrt可以通过opkg安装,如果是22.03及之后的版本,还需要安装iptables-nft,否则会运行失败

opkg update
opkg install tailscale
opkg install iptables-nft

LAN2:配置并运行

启动方式与ubuntu的类似,只是openwrt 22.03及之后的版本,要增加–netfilter-mode=off参数

tailscale up --advertise-routes=192.168.101.0/24 --accept-routes --snat-subnet-routes=false --netfilter-mode=off

还需要在luci添加接口和防火墙规则

添加接口:Network → Interfaces → Add new interface

  • Name: tailscale
  • Protocol: Unmanaged
  • Device: tailscale0

添加防火墙规则:Network → Firewall → Zones → Add

  • Name: tailscale
  • Input: ACCEPT (default)
  • Output: ACCEPT (default)
  • Forward: ACCEPT
  • Masquerading: on
  • MSS Clamping: on
  • Covered networks: tailscale
  • Allow forward to destination zones: Select your LAN
  • Allow forward from source zones: Select your LAN

LAN2:Approvers路由信息

与LAN1一样,参考:LAN1:Approvers路由信息

non-tailscale设备配置

在non-tailscale设备,只需要添加对应的静态路由就可以

LAN1 non-tailscale设备配置

#linux
ip route add 100.64.0.0/10 via 192.168.100.201    #此为tailscale vpn的网段
ip route add 192.168.101.0/24 via 192.168.100.201    #此为LAN2的网段
#windows
route add 100.64.0.0 mask 255.192.0.0 192.168.100.201    #此为tailscale vpn的网段
route add 192.168.101.0 mask 255.255.255.0 192.168.100.201    #此为LAN2的网段

LAN2 non-tailscale设备配置

#linux
ip route add 100.64.0.0/10 via 192.168.100.201    #此为tailscale vpn的网段
ip route add 192.168.100.0/24 via 192.168.100.201    #此为LAN1的网段
#windows
route add 100.64.0.0 mask 255.192.0.0 192.168.100.201    #此为tailscale vpn的网段
route add 192.168.100.0 mask 255.255.255.0 192.168.100.201    #此为LAN1的网段

连通测试

直接从LAN1的non-tailscale设备ping去LAN2的non-tailscale设备

可以ping通,测试成功。

其它问题

通过dhcp为客户端下发静态路由

所有要跨lan访问的non-tailscale设备,都要添加对应的静态路由,如果逐一在各客户端上操作会十分麻烦,这个可以通过dhcp解决。

dhcp中的option 121,可以为dhcp客户端添加静态路由。格式:121,目标网络/掩码,网关

以下是我在openwrt的配置,供参考:

openwrt下为tailscale配置接口后,ip消失

在openwrt安装并启动tailscale后,还要添加对应的接口,协议为“Unmanaged”。添加这个接口后,有可能会出现系统内tailscale的ip消失的情况,但实际上,从admin console查看,这个设备还是在tailscale的网络中的。

如果出现这种情况,可以把tailscale接口的协议改为静态,手动把tailscale的ip配上(可以在console上确认ip),掩码需要写为10位。

我自己在测试过程中,也出现过很多次这种情况。后来不知怎样,终于在配置接口协议为“Unmanaged”,ip也没有消失。

这个问题解决方法暂时未明确。

iptables配置

在官方的配置指引文档中,还需要配置iptables,配置命令如下:

iptables -t mangle -A FORWARD -i tailscale0 -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu

根据指引说明,就是把最大分段大小限制在mtu的大小之内。

我在测试部署中没有配置这项,目前使用暂没影响。

参考资料