【无标题】

家庭宽带建站指南

众所周知,家庭宽带虽然可以获取公网IP并通过DDNS的方式建站,但是运营商把80/443端口ban了,导致访问服务必须加端口号,十分丑陋且不方便

使用CloudFlare代理非80/443端口,实现http/https直接通过域名访问家庭宽带部署的服务,不再需要拼端口号

由于所有流量都会经过CloudFlare,延迟会直接起飞,不适用于对延迟敏感的服务,例如teamspeak

0.准备工作:

  • 一台物理机:闲置的PC、Mac;Nas;软路由;树莓派等等
  • 公网IP:找家庭网所在的运营商开通
  • 域名:一个一级域名

1.测试

  • 将服务部署在物理机中并使用局域网IP+端口成功访问

  • 在路由器中配置端口转发,将服务的端口转发到公网,并在公网成功访问

2.CloudFlare

  • 注册一个账号并在右上角切换到【简体中文】
  • 将域名添加到CloudFlare,计划选择【Free】即可
  • 出现提示 删除以下名称服务器 添加Cloudflare名称服务器
  • 登录到域名注册机构平台,修改DNS服务器,将默认的DNS服务器删除,添加CloudFlare给的服务器,修改完成后回到CloudFlare检查是否成功解析
  • 成功解析后,我们先手动配一个服务进行尝试:
    1. 在CloudFlare的【DNS记录】中添加一条:【类型:A;名称:二级域名,比如域名为baidu.com,这里填map,最终访问的地址就是map.baidu.com;IPv4 地址:你的公网IP;代理状态:开启】
    2. 在左侧导航栏找到【规则】,选择【Origin Rules】
    3. 配置一个规则:【字段:SSL/HTTPS,:否,重写到:你本地服务映射的公网端口】,部署
    4. 使用这里上面配置的完整域名访问服务
  • 如果上一步成功访问,你的服务已经初步脱离了家庭宽带端口的限制

3.DDNS

  • 由于家庭宽带公网IP会变化,需要一个脚本更新CloudFlare中的DNS配置

  • 在CloudFlare右上角点击【我的个人资料】,找到【API令牌】,找到【Global API Key】,点击查看

  • 这里提供一个Python脚本来更新IP,你也可以使用自己熟悉的语言来请求CloudFlare API

    import requests
    import json
    import datetime
    
    
    def check_ip():
        with open("./ip.txt", "r+") as f:
            lines = f.readlines()
            last_line = lines[-1]
            now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            if last_line != ip:
                print(f"{now}:ip changed to {ip}")
                f.write(f"\n{ip}")
                return False
            else:
                print(f"{now}:ip not change")
                return True
    
    
    def get_ipv4():
        res = requests.get("https://ident.me")
        return res.text
    
    
    class CloudFlareDDNSUpdater:
        def __init__(self):
            self.headers = {
                "X-Auth-Email": Auth_Email,
                "X-Auth-Key": Auth_Key,
                "Content-Type": "application/json",
            }
            self.login_verify()
    
        def login_verify(self):
            url = "https://api.cloudflare.com/client/v4/user/"
            res = requests.get(url=url, headers=self.headers)
            data = json.loads(res.text)
            if not data["success"]:
                print(data["errors"])
                exit()
    
        def list_zone_identifier(self):
            url = "https://api.cloudflare.com/client/v4/zones"
            res = requests.get(url=url, headers=self.headers)
            data = json.loads(res.text)
            return data["result"]
    
        def list_zone_record(self, domain_id):
            url = f"https://api.cloudflare.com/client/v4/zones/{domain_id}/dns_records?page=1&per_page=20&order=type&direction=asc"
            res = requests.get(url=url, headers=self.headers)
            data = json.loads(res.text)
            return data["result"]
    
        def update_A_record(self, domain_name):
            domains = self.list_zone_identifier()
            target_domain = list(filter(lambda x: x["name"] in domain_name, domains))[0]
            records = self.list_zone_record(target_domain["id"])
            target_record = list(filter(lambda x: x["name"] == domain_name, records))[0]
    
            domain_id, record_id = target_domain["id"], target_record["id"]
    
            url = f"https://api.cloudflare.com/client/v4/zones/{domain_id}/dns_records/{record_id}"
            data = {
                "type": "A",
                "name": domain_name,
                "content": ip,
                "ttl": 1,
                "proxied": True,
            }
            res = requests.put(url=url, headers=self.headers, data=json.dumps(data))
            data = json.loads(res.text)
            if data["success"]:
                print(f"[+] Now {data['result']['name']} {data['result']['type']} record is {data['result']['content']}")
                print(f"[i] May will take effect in {int(data['result']['ttl'] / 60)} minutes")
            else:
                print(data["errors"])
                exit()
            return data["result"]
    
    
    if __name__ == "__main__":
        ip = get_ipv4()
        if not check_ip():
            Auth_Email = ""  # 你的CloudFlare邮箱
            Auth_Key = ""  # 你的CloudFlare API Key
            updater = CloudFlareDDNSUpdater()
            updater.update_A_record("")  # 你的完整域名,例如:map.baidu.com
    
  • 在脚本最后填写你的信息,如果配置了多个二级域名DNS记录,可以复制多次最后一行填写不同的域名

  • 把脚本放在任意目录,并创建一个ip.txt用来记录历史ip

  • 创建一个一分钟执行一次的定时任务来执行该脚本,根据不同的设备自行搜索实现方式

4.Nginx

  • 当服务较多时,可以使用Nginx作为入口网关进行反向代理,使用同一个CloudFlare规则,只暴露一个端口,通过配置路由来区分不同服务
  • 可以先通过端口转发用IP+端口测试Nginx服务是否正常
  • 在局域网中部署一个Nginx服务
  • 在Nginx目录的conf.d中添加【完整域名.conf】,listen任意端口,并配置需要反代的服务
  • 将Nginx配置中listen的端口转发到公网
  • 修改CloudFlare配置,将Origin Rules中的端口改为上一步转发的端口
  • 使用域名访问服务
  • 如果成功访问,建议将其他暴露的端口关闭

5.SSL/HTTPS

  • 在阿里云或腾讯云申请免费SSL证书

  • 创建证书,填入完整域名,选择手工DNS认证,获取到DNS信息后返回CloudFlare,在DNS配置中配置一个类型为TXT的DNS解析记录,名称和内容按申请证书提示的填

  • 申请完耐心等待,通过后下载证书,类型选择Nginx,pem/key

  • 在Nginx目录中创建新目录ssl,将下载的pem文件和key文件重命名为【完整域名.pem】和【完整域名.key】后放入ssl目录中

  • 编辑3中conf.d目录下的【完整域名.conf】,SSL相关配置去网上抄一下

  • 这里提供一段我自己的Nginx配置

    server {
        listen 443 ssl;
        server_name  i.potato.com;
    
        # 增加ssl
        ssl_certificate /ssl/i.potato.com.pem;
        ssl_certificate_key /ssl/i.potato.com.key;
     
        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;
     
        # 指定密码为openssl支持的格式
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        
        # 密码加密方式
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        # 依赖SSLv3和TLSv1协议的服务器密码将优先于客户端密码
        ssl_prefer_server_ciphers on;
    
        access_log  /var/log/nginx/host.access.log  main;
    
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    
        error_page  404              /404.html;
        location = /404.html {
            root   /usr/share/nginx/html;
        }
    
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }
    
        # 配置自己的服务
        location /api/ {
            proxy_pass    http://192.168.31.254:8000;
        }
    }
    
  • 重启Nginx服务

  • 将【2】中【Origin Rules】配置的【SSL/HTTPS】改为【是】

  • 在CloudFlare的左侧导航栏找到【SSL/TLS】,将加密模式改为【严格

  • 使用【https://完整域名/】访问服务

以上为2023年5月10日的配置过程

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值