同步更新 微信公众号【爱写代码的小任】 欢迎关注
背景
在工作中,内网中的服务,想要暴露出去(公网),给不在内网的伙伴访问。要实现这些,我归结一下几个常见的问题。
- 发现公司的公网IP是不固定的;
- 使用第三方花生壳面临收费,限速的问题;
- 若IP变更,对应的DNS解析也需要变化,同时如果能有通知(如钉钉)最好了
- 使用哪一个开发语言(技术栈)开发 能够更容易理解
解决方案准备
- 语言首选 Go,因为之前开发命令行工具, Go语言比较适合, 但其次考虑到语言理解度上, 最后还是选择的NodeJS,搜索了下,NodeJs相关的库也足够用了。
实施过程
1. 创建Node 命令行项目
# 1. 创建目录
$ mkdir auto-change
# 2. 初始化
$ cd auto-change
$ npm init --yes
# 3. 创建 bin 目录
$ mkdir bin
$ vim bin/main.js
# 4. nodejs 启动 bin 下面是 package.json内容 主要是 bin那块的配置
{
"name": "auto-change",
"version": "1.0.0",
"description": "",
"bin": {
"auto-change": "bin/main.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"dingding-robot-sdk": "^1.0.0",
"nodejs-publicip": "^2.1.2"
}
}
2. 使用获取公网IP的库
/**
* 1. 获取公网IP https://blog.csdn.net/hua_thirteen/article/details/125016420
*/
async function main() {
try {
const ipAddress = await new PublicIp().queryPublicIPAddresses()
let previousIp = readIpFromFile();
if (ipAddress.ipv4 !== previousIp) {
console.log(`捕获IP变更: ${previousIp} -- ${ipAddress.ipv4}`)
const msgInfo = `优秀: 捕获IP地址变更 ${previousIp} -- ${ipAddress.ipv4}}`
sendDingMsg(msgInfo)
updateDnsRecord(ipAddress.ipv4);
} else {
console.log("IP没有变更, 不执行任何操作")
}
writeIpToFile(ipAddress.ipv4);
} catch (error) {
console.error(error);
}
}
3. 使用文件库,主要用于记录变化前的IP地址
function readIpFromFile(){
try {
return fs.readFileSync("/tmp/auto-change.txt","utf-8");
} catch (error) {
console.error(error);
return "";
}
}
function writeIpToFile(ipv4){
fs.writeFileSync("/tmp/auto-change.txt", ipv4);
}
4. 使用钉钉机器人库
/**
* 钉钉消息回调 https://open.dingtalk.com/document/robots/custom-robot-access
* https://gitee.com/yunsin/dingding_robot_sdk
*/
const webhookURL = "https://oapi.dingtalk.com/robot/send?access_token=";
async function sendDingMsg(msgInfo){
try {
const robot = new Robot(webhookURL);
const sendRes = await robot.sendText({
content: msgInfo,
atMobiles: "",
isAtAll: true,
});
console.log(`发送钉钉消息结果是: ${JSON.stringify(sendRes)}`);
} catch (error) {
console.error(error);
}
}
5. 调用DNS解析库
这里主要是通过调用aliyun 命令行工具,更新DNS解析
/**
* https://next.api.aliyun.com/api/Alidns/2015-01-09/UpdateDomainRecord
* 3. 通过阿里云CLI命令修改解析即可
*/
const util = require('util');
const exec = util.promisify(require('child_process').exec);
async function updateDnsRecord(ipv4) {
const dnsRecordArr = [];
for(var i=0;i< dnsRecordArr.length;i++) {
const dnsRecord = dnsRecordArr[i];
try {
const command = `aliyun alidns UpdateDomainRecord --profile dns --region cn-hangzhou --RecordId ${dnsRecord.recordId} --RR ${dnsRecord.rr} --Type A --Value '${ipv4}'`
const { stdout, stderr } = await exec(command);
console.log('stdout:', stdout);
console.log('stderr:', stderr);
await sleep(10000)
} catch (error) {
console.log("更新异常")
console.error(error);
}
}
}
6. 配置定时任务
定时任务借助Linux自带的非常稳的 crontab实现
# 添加用户级的定时任务
$ crontab -e
# 追加一下内容,这里面需要注意,这里面的命令他不会调用环境变量, 需要手动让环境变量生效
27 11 * * * source $HOME/.bashrc && auto-change & >> ~/auto-change.out 2>&1
总结
通过以上代码,完整的实现了,公网IP地址变更, 造成DNS解析问题,间接实现了内网穿透的问题,这让我后面也不需要持续关注因为IP地址变更,造成每次手动修改DNS问题, 期望你读到这篇文章后,能有实质收获.
关注我,实时获取我的更新动态,和我一起讨论