【运维】Wireguard+OpenVPN解决跨地区VPN的连接稳定性问题

首先我们要搞清楚一个问题,Wireguard和OpenVPN的区别在哪里

  1. Wireguard基于UDP协议,继承于内核中,由于加密协议简单(但安全),开销较小,性能较高

  2. OpenVPN基于TCP或UDP协议,由SSL/TLS实现身份加密,没有Wireguard效率高,但是支持多种管理方式

在实际使用上,TCP和UDP也有较大区别

  1. TCP:可以提供更可靠的连接,因为它具有确认和重传机制,能够处理丢包和错误。适用于对数据完整性和可靠性要求较高的场景。

  2. UDP:UDP可以提供更快的速度和较低的延迟,适用于实时应用程序和视频流等对延迟敏感的情况。UDP模式还可以避免TCP拥塞控制的限制,适用于高带宽环境

UDP在实际使用上可能会被QOS限速,但是在长距离、高延迟的VPN环境中还是可以发挥不错的效果,不容易出现TCP经常断连的情况。

实现方案

在某个实际应用场景中,我需要将在B地不同地区访问位于A地的局域网,A地与B地物理相隔较远并且网络条件较差,但是对业务实时性没有太多要求,并且A地存在NAT

方案一

全部走OpenVPN,对A-B两地互联的机器使用UDP协议,确保可以通讯
B地对B地其他地区使用TCP协议,确保连接稳定性
方案一可以参考
Windows上使用OpenVPN实现于异地访问公司内网资源(Tunnel方式、公网服务器frp转发)

方案二

在A-B两地之间使用Wireguard
在B地服务器是用OpenVPN供B地其他地区使用
网络结构如下

A地内网<--->A地服务器<- Wireguard-UDP ->B地服务器<- OpenVPN TCP/UCP ->B地其他地区用户

两方案相比,方案一更加简单,但是没有方案二稳定,并且AB两地如果存在高带宽情况用OpenVPN可能会消耗大量资源,在技术难度上方案二要设置转发,需要对两个VPN进行分别配置
最终选择方案二进行

Wireguard部分

脚本安装(建议)

安装OpenVPN(好像Wireguard也可以这样用,但是是端对端的,配置转发也很麻烦,所以不建议使用脚本了)

wget https://git.io/wireguard -O wireguard-install.sh && bash wireguard-install.sh

安装后我们直接导入服务端即可,然后在服务端执行

\#/etc/wireguard/wg0.conf
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0

如果出现有转发问题可以手动加入下方手动安装中的

PreUp = iptables -A FORWARD -i tun0 -j ACCEPT; iptables -A FORWARD -o tun0 -j ACCEPT; iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE

手动安装

安装wireguard并开启内核转发,其中在linux内核版本大于5.6时(Ubuntu为大于5.4)wireguard-dkms有可能已经继承进内核中,就无需再安装了

sudo apt-get update
sudo apt-get install wireguard wireguard-dkms wireguard-tools -y
sudo vi /etc/sysctl.conf
#将net.ipv4.ip_forward=0改成net.ipv4.ip_forward=1
#或者将net.ipv4.ip_forward=1注释去除
sysctl -w net.ipv4.ip_forward=1

生成密钥并且写入配置文件(注意最后出来的公钥)
在正常的Peer(对等)模式下,需要定义每个对等方的配置信息,包括公钥、IP地址、端口号等

对等端不能使用同样的密钥,不然会和我一样debug一晚上

(umask 077 && printf "[Interface]\nPrivateKey = " | sudo tee /etc/wireguard/wg0.conf > /dev/null)
wg genkey | sudo tee -a /etc/wireguard/wg0.conf | wg pubkey | sudo tee /etc/wireguard/publickey

将配置文件补充完整,端口默认就是51820,记得在防火墙放行对应端口,由于我们其中一方无法访问到另一方,我们就将在公网的当作服务端,NAT后的为客户端,服务端可以不设置EndPoint

sudo vi /etc/wireguard/wg0.conf
#/etc/wireguard/wg0.conf
[Interface]
PrivateKey = <自动生成的不用手动填写>
Address = 10.0.0.1/24
#客户端则为Address = 10.0.0.2/24
PreUp = iptables -A FORWARD -i tun0 -j ACCEPT; iptables -A FORWARD -o tun0 -j ACCEPT; iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE
#自动设置网卡转发
ListenPort = 51820

[Peer]
PublicKey = <填写对等端的公钥,或者cat /etc/wireguard/publickey>
AllowedIPs = 10.0.0.2/32,<要转发的网段>
#客户端则为Address = 10.0.0.1/32,10.8.0.0/24(下方OpenVPN的网段)
Endpoint = <服务端的IP地址>:51820
#上面的Endpoint服务端不用写
PersistentKeepalive = 25
#保持NAT映射关系

然后启用wireguard

sudo wg-quick up wg0

OpenVPN部分

如果使用UDP网络较差建议更换成TCP

UDP相比于TCP连接稳定性相对较差,但是为什么wireguard要用UDP呢。
因为相比于连接稳定性差,我更在意能不能连上!

脚本安装(建议)

安装OpenVPN(好像Wireguard也可以这样用,但是是端对端的,配置转发也很麻烦,所以不建议使用脚本了)

wget https://git.io/vpn -O openvpn-install.sh && bash openvpn-install.sh
#wget https://git.io/wireguard -O wireguard-install.sh && bash wireguard-install.sh

下载下来后直接设置,全部默认后修改配置

vi /etc/openvpn/server/server.conf
#v/etc/openvpn/server/server.conf
push "route 10.0.0.0 255.255.0.0"
push "route <要转发的网段> <网段对应的掩码>"
#增加上述两句即可

新建的ovpn文件可以把remote修改成自己的域名,方便随时修改dns记录

手动安装

其实上方的Wireguard是我在写博客的中途手动安装的,吃了不少屎,所以我就不再吃一次了
所以我放下几个链接
OpenVPN配置使用
OpenVPN服务部署及使用文档
基于 WireGuard 和 OpenVPN 的混合云基础架构建设

成果

通过OpenVPN成功连接并且访问学校内网

碎碎念

在那天晚上,我调代码调到了5点多,由于转发一直不生效,我在怀疑是不是不应该使用Wireguard+OpenVPN这种组合方式进行,一度想转为全OpenVPN形式。
Tracert也没有消息,服务端在两协议上都是能连通的,让人百思不得其解。
头疼(生理上的),吃药(赶紧睡觉)
睡到7点多,起来发现,挂在后台的ping居然ping通了,tracert也能正常跟踪网关了,重启了一下也正常。
莫非是遇上了自己会修bug的linux了吗

如何快速搭建一个镜像源

引言

其实不少开源镜像站给出了他们的开源代码,例如清华大学镜像管理器tunasync中科大镜像Docker
当时思考了很久,没有使用他们的代码,主要是认为,没什么必要,做一个简单的源没必要那么复杂,于是自己仿照着写了个Demo

实现

Github-SZUmirrors
暂时来说,我们使用的仓库只有少部分几个,同步方式较为单一,pypi为bandersnatch同步,其余系统软件源为rsync同步,这里借用了ustcmirror-images的rsync镜像,其实就是一句rsync指令和一些配置了
守护进程采用service实现,能够开机启动,也能查看状态

流程如下

service(守护进程)->python(分配进程)->docker(工作单元)

这里还需要加上一些前端,一些数据库之类的同步信息,不过作为demo已经足够了,剩下的需要的交给各位自己完善了
TODO:增加Docker反代

注意

  1. bandersnatch同步python源时可以做一些设置,减小同步的大小(Python全部库同步下来要15T),下文范例为只同步100G以下包
[plugins]
enabled =
    size_project_metadata
[size_project_metadata]
max_package_size = 100G
  1. 要进行nginx调优,以提高负载量
    Nginx调优可以参考此文档
    具体可以进行百度,唯一难以解决的问题时https中tls握手造成的高负载和高延迟(响应速度慢)情况。
    下图为对比


    效率上有将近十倍的区别,延迟也显著提升,不过好在公布在外网的时候https握手可以由转发机实现,并且可以一次握手传输多个包(链接复用?)
  2. pypi可以给单独的域名指向pypi/web/simple方便访问,但是同时也要注意python只支持https形式访问
    虽然其他软件源http也行,但是https还是安全不少,性能却跟不上,也是恨头疼的一件事

【Web】Anaconda介绍、安装及使用

介绍

Anaconda是Python和Conda的组合包,里面附带了不少科学计算使用的Python依赖,并且可以通过Conda进行版本管理,能够便携获得管理包
Conda不仅支持Python,还支持R, Ruby, Lua, Scala, Java, JavaScript, C/C++, FORTRAN语言(虽然大部分都用不上)

继续阅读【Web】Anaconda介绍、安装及使用

【WechatBot】基于内存注入下的微信机器人

本文仅作技术分享,提醒各位注意网络应用安全性,请勿用于其他用途,否则后果自负。
前几天写过一篇这样的文章,但是耐不住WgpSecBot总是崩溃,于是打算自己写一个
【脚本】基于WgpSecBot的比赛推送
但是问题又来了,自从腾讯封了Web和UOS协议后,就再也弄不到机器人了。
但是苍天不负有心人,我找到了这个Github-wechat-bot
这个版本是基于对Windows下的微信进行内存注入实现的
继续阅读【WechatBot】基于内存注入下的微信机器人

【WSL】WSL2-Ubuntu安装CUDA

某一天,在摸鱼的时候被人拍了一下,叫我用Kali跑一下hashcat,因为hashcat可以调用CUDA(显卡)模块,加速爆破 虽然实际上,我的CPU跑起来也很快 file 但是,既然来了就研究一下。但是我又不想装多系统,那么就该想想怎么在WSL里面调用CUDA了。

Update: 其实做到最后我又重新做了一遍。原因在于,我的linux核心其实不支持CUDA。 GPU_CUDA_IN_WSL 在安装前,你需要确认一下你的内核版本,只有5.10.43.3以上的版本才是默认支持的

PS C:\Users\hz2016> wsl cat /proc/version
Linux version 5.10.16.3-microsoft-standard-WSL2 (oe-user@oe-host) (x86_64-msft-linux-gcc (GCC) 9.3.0, GNU ld (GNU Binutils) 2.34.0.20200220) #1 SMP Fri Apr 2 22:23:49 UTC 2021

你需要打开下面的功能,并且把内核更新到最新版 file

  1. 安装Ubuntu的WSL版并换源

由于WSL版的Ubuntu不自带gcc,所以我们在安装CUDA前要自己装一个

apt-get install gcc -y
  1. 安装CUDA for WSL-Ubuntu

CUDA Toolkit官网下载 我安装的十CUDA Toolkit 11.6版本,选择的是Runfile(可执行文件)安装 别问为什么,只要知道我翻车很多次就是了。 file

wget https://developer.download.nvidia.com/compute/cuda/11.6.2/local_installers/cuda_11.6.2_510.47.03_linux.run
sudo sh cuda_11.6.2_510.47.03_linux.run

千万别点进去Options的Drives,别问我为什么问就是我在来了一次 file 安装完成

===========
= Summary =
===========

Driver:   Not Selected
Toolkit:  Installed in /usr/local/cuda-11.6/

Please make sure that
 -   PATH includes /usr/local/cuda-11.6/bin
 -   LD_LIBRARY_PATH includes /usr/local/cuda-11.6/lib64, or, add /usr/local/cuda-11.6/lib64 to /etc/ld.so.conf and run ldconfig as root

To uninstall the CUDA Toolkit, run cuda-uninstaller in /usr/local/cuda-11.6/bin
***WARNING: Incomplete installation! This installation did not install the CUDA Driver. A driver of version at least 510.00 is required for CUDA 11.6 functionality to work.
To install the driver using this installer, run the following command, replacing with the name of this run file:
    sudo .run --silent --driver 
  1. 添加PATH路径
export PATH=/usr/local/cuda-11.6/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-11.6/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
  1. 验证是否更新成功
root@hz2016-pc:~# nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2022 NVIDIA Corporation
Built on Tue_Mar__8_18:18:20_PST_2022
Cuda compilation tools, release 11.6, V11.6.124
Build cuda_11.6.r11.6/compiler.31057947_0
  1. 更新你的显卡驱动

A driver of version at least 510.00 is required for CUDA 11.6 functionality to work.

打开GPU-Z查看一下 file 发现自己是497.29版本的显卡驱动,于是更新一下 file

然后你就可以在你的WSL里面跑CUDA了~

  1. 安装OpenCL相关(翻车)
apt-get install beignet clinfo
apt-get install beignet-dev
apt-cache search opencl

运行clinfo测试一下

root@hz2016-pc:~# clinfo
······
clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU)  No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_ACCELERATOR)  No devices found in platform
clCreateContextFromType(NULL, CL_DEVICE_TYPE_CUSTOM)  No devices found in platform
······

还是找不到GPU,翻了下文档,还是我想多了

OpenGL-CUDA Interop is not yet supported. Applications relying on OpenGL will not work.

要用GPU跑hashcat还是去win版跑吧 file 实测GPU跑比CPU跑快130倍

【脚本】Push镜像到Dockerhub

首先你要自己制作一个Docker镜像,这个就不再赘述了,相信各位都会了

  1. COMMIT你的镜像,-p可选,为commit时暂停容器
    docker commit <容器ID> <镜像名:版本号>

    file

  2. 登录你的Dockerhub
    按提示输入账号密码

    docker login
  3. 修改规范你的镜像名
    规范为<注册用户名/镜像名>
    可以通过tag指令修改镜像名

    docker tag <旧镜像名> <新镜像名>
  4. 推送至仓库,版本号可填latest,意思是最新的容器
    docker push <镜像名:版本号>

    file
    登录Dockerhub就确认已经推送上了
    file
    如果你在windows下,且有Docker on desktop,你可以通过这样操作登录,直接push
    file

梅开二度:记得给Docker换源,不然慢死,参考脚本如下
【脚本】Linux换源汇总