Featured image of post 家庭网络建站

家庭网络建站

家庭网络建站具体实现方法

前提条件

  1. 小型服务器
  2. 公网ip
  3. 备案的域名

最近随着云服务器陆续的到期,续费价格有点高,想着能不用家庭网络自己搭建一个低功耗的服务器,用于自己的博客日志的记录和游戏服务器的测试。说干就干,硬件装备先要搞到手,打开淘宝搜了一圈,低功耗linux主机,发现一款升腾的c92廋客户机看着还不错,cpu是j1900四核4进程,tdp 10w,这功耗看着挺香。一举拿下,内存8g,固态硬盘250G,完全够用了。 Alt text

安装ubuntu操作系统

商家默认安装了win7系统,如果用来做服务器,那就重装系统吧,我使用了Ubuntu20.4版本,去清华镜像网或者其他网站下载ios镜像,使用rufus制作启动盘 Alt text 启动盘制作完毕就可以安装系统了,在安装linux系统过程中遇到个坑,就是升腾c92开机会遇到进不去系统,一值显示下面的页面 Alt text 这个在bios中关闭nc即可,被这个折腾了很久。 进入Ubuntu系统后,即可安装hugo了,这里不介绍hugo的安装,参考另一篇hugo教程。 最后启动hugo测试

1
hugo server

这样hugo就运行起来了,

1
curl 127.0.0.1:1313

能看到数据的返回就说明服务器已经启动了,那么如何在外网访问到这个网站呢,前提条件是像运营商申请公网ip(公网ip地址是会变的这里要用到ddns,后面介绍)。说到公网ip,那就用到端口映射了,不然内部的服务器在外部是访问不到的,将光猫模式设置为桥接模式,光猫只负责光信号的处理,路由器负责拨号上网。 Alt text 一般在高级设置里设置端口映射, Alt text

ip地址写局域网服务器的ip地址,比如192.168.7.230 内部端口号,https的话写443,外部端口一般不能写443了,因为营运商会禁用80,443,8080等端口,那么只有写其他的端口比如1010… (可以用nginx反向代理或url转发实现去掉端口号),到这步不出意外的话可以用公网ip+端口号可以访问内部服务器了。

设置域名解析

上面已经能够用ip+端口号访问内部服务器了,现在设置dns域名解析, Alt text
记录类型:A记录
主机记录:写域名前缀,如www
记录值:写公网ip
保存设置等待一会dns解析就会生效了

设置ddns

运营商的公网ip是会变化的,这时候我们就要不时的修改域名解析的ip地址了,有没有其他办法实现ip变化自动更新解析呢,如果用的是阿里云的dns 解析,可以用阿里提供的api自动更新。下面是更新代码:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env python3
#coding=gbk
 
# 加载核心SDK
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
 
# 加载获取 、 新增、 更新、 删除接口
from aliyunsdkalidns.request.v20150109 import DescribeSubDomainRecordsRequest, AddDomainRecordRequest, UpdateDomainRecordRequest, DeleteDomainRecordRequest
 
# 加载内置模块
import json,urllib
 
# AccessKey 和 Secret 建议使用 RAM 子账户的 KEY 和 SECRET 增加安全性
ID = '**********'
SECRET = '********'
 
# 地区节点 可选地区取决于你的阿里云帐号等级,普通用户只有四个,分别是杭州、上海、深圳、河北,具体参考官网API
regionId = 'cn-hangzhou'
 
# 配置认证信息
client = AcsClient(ID, SECRET, regionId)
 
# 设置主域名
DomainName = 'spidernote.cn'
 
# 子域名列表 列表参数可根据实际需求增加或减少值
SubDomainList = ['logon','www']
 
# 获取外网IP  三个地址返回的ip地址格式各不相同,3322 的是最纯净的格式, 备选1为 json格式 备选2 为curl方式获取 两个备选地址都需要对获取值作进一步处理才能使用
def getIp():
  # 备选地址: 1, http://pv.sohu.com/cityjson?ie=utf-8  2,curl -L tool.lu/ip
  with urllib.request.urlopen('http://www.3322.org/dyndns/getip') as response:
    html = response.read()
    ip = str(html, encoding='utf-8').replace("\n", "")
  return ip
 
# 查询记录
def getDomainInfo(SubDomain):
  request = DescribeSubDomainRecordsRequest.DescribeSubDomainRecordsRequest()
  request.set_accept_format('json')
 
  # 设置要查询的记录类型为 A记录  官网支持A / CNAME / MX / AAAA / TXT / NS / SRV / CAA / URL隐性(显性)转发 如果有需要可将该值配置为参数传入
  request.set_Type("A")
 
  # 指定查记的域名 格式为 'test.example.com'
  request.set_SubDomain(SubDomain)
 
  response = client.do_action_with_exception(request)
  response = str(response, encoding='utf-8')
 
  # 将获取到的记录转换成json对象并返回
  return json.loads(response)
 
# 新增记录 (默认都设置为A记录,通过配置set_Type可设置为其他记录)
def addDomainRecord(client,value,rr,domainname):
  request = AddDomainRecordRequest.AddDomainRecordRequest()
  request.set_accept_format('json')
 
  # request.set_Priority('1') # MX 记录时的必选参数
  request.set_TTL('600')    # 可选值的范围取决于你的阿里云账户等级,免费版为 600 - 86400 单位为秒 
  request.set_Value(value)   # 新增的 ip 地址
  request.set_Type('A')    # 记录类型
  request.set_RR(rr)      # 子域名名称 
  request.set_DomainName(domainname) #主域名
 
  # 获取记录信息,返回信息中包含 TotalCount 字段,表示获取到的记录条数 0 表示没有记录, 其他数字为多少表示有多少条相同记录,正常有记录的值应该为1,如果值大于1则应该检查是不是重复添加了相同的记录
  response = client.do_action_with_exception(request)
  response = str(response, encoding='utf-8')
  relsult = json.loads(response)
  return relsult
 
# 更新记录
def updateDomainRecord(client,value,rr,record_id):
  request = UpdateDomainRecordRequest.UpdateDomainRecordRequest()
  request.set_accept_format('json')
 
  # request.set_Priority('1')
  request.set_TTL('600')
  request.set_Value(value) # 新的ip地址
  request.set_Type('A')
  request.set_RR(rr)
  request.set_RecordId(record_id) # 更新记录需要指定 record_id ,该字段为记录的唯一标识,可以在获取方法的返回信息中得到该字段的值
 
  response = client.do_action_with_exception(request)
  response = str(response, encoding='utf-8')
  return response
 
# 删除记录
def delDomainRecord(client,subdomain):
  info = getDomainInfo(subdomain)
  if info['TotalCount'] == 0:
    print('没有相关的记录信息,删除失败!')
  elif info["TotalCount"] == 1:
    print('准备删除记录')
    request = DeleteDomainRecordRequest.DeleteDomainRecordRequest()
    request.set_accept_format('json')
 
    record_id = info["DomainRecords"]["Record"][0]["RecordId"]
    request.set_RecordId(record_id) # 删除记录需要指定 record_id ,该字段为记录的唯一标识,可以在获取方法的返回信息中得到该字段的值
    result = client.do_action_with_exception(request)
    print('删除成功,返回信息:')
    print(result)
  else:
    # 正常不应该有多条相同的记录,如果存在这种情况,应该手动去网站检查核实是否有操作失误
    print("存在多个相同子域名解析记录值,请核查后再操作!")
 
# 有记录则更新,没有记录则新增
def setDomainRecord(client,value,rr,domainname):
  info = getDomainInfo(rr + '.' + domainname)
  if info['TotalCount'] == 0:
    print('准备添加新记录')
    add_result = addDomainRecord(client,value,rr,domainname)
    print(add_result)
  elif info["TotalCount"] == 1:
    print('准备更新已有记录')
    record_id = info["DomainRecords"]["Record"][0]["RecordId"]
    cur_ip = getIp()
    old_ip = info["DomainRecords"]["Record"][0]["Value"]
    if cur_ip == old_ip:
      print ("新ip与原ip相同,无法更新!")
    else:
      update_result = updateDomainRecord(client,value,rr,record_id)
      print('更新成功,返回信息:')
      print(update_result)
  else:
    # 正常不应该有多条相同的记录,如果存在这种情况,应该手动去网站检查核实是否有操作失误
    print("存在多个相同子域名解析记录值,请核查删除后再操作!")
 
 
IP = getIp()
 
# 循环子域名列表进行批量操作
for x in SubDomainList:
  setDomainRecord(client,IP,x,DomainName)
 
# 删除记录测试
# delDomainRecord(client,'b.jsoner.com')
 
# 新增或更新记录测试
# setDomainRecord(client,'192.168.3.222','a',DomainName)
 
# 获取记录测试
# print (getDomainInfo(DomainName, 'y'))
 
# 批量获取记录测试
# for x in SubDomainList:
#   print (getDomainInfo(DomainName, x))
 
# 获取外网ip地址测试
# print ('(' + getIp() + ')')

这里主要要修改的部分

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# AccessKey 和 Secret 建议使用 RAM 子账户的 KEY 和 SECRET 增加安全性
ID = '**********'
SECRET = '********'
 
# 地区节点 可选地区取决于你的阿里云帐号等级,普通用户只有四个,分别是杭州、上海、深圳、河北,具体参考官网API
regionId = 'cn-hangzhou'
 
# 配置认证信息
client = AcsClient(ID, SECRET, regionId)
 
# 设置主域名
DomainName = 'spidernote.cn'
 
# 子域名列表 列表参数可根据实际需求增加或减少值
SubDomainList = ['logon','www']

Alt text
AccessKey 和 Secret 获取填入,修改完毕保存后,运行这个脚本 python3 ddns.py 可以看到会

1
2
3
4
5
6

asdxet@asdxet:~$ python3 ddns.py
准备更新已有记录
新ip与原ip相同,无法更新!
准备更新已有记录
新ip与原ip相同,无法更新!

如果有这个显示,就可以了,脚本会自动获取本机的公网ip并通过阿里的api修改解析,问题又来了,怎么知道ip变化又去执行修改dns解析呢,这里可以使用linux的定时任务,让脚本定时运行。 输入命令:

1
 crontab -e

输入:
Alt text
脚本将会每5分钟执行一次,到此设置完毕。

结束

到此家庭网络建站基本实现,假设过程中如果有问题可以百度查询。