個人電腦也能做服務器

一般家庭網絡是沒有固定 ip 的,這就導致了外部無法方便地訪問家裏電腦上的文件或網絡服務。花生殼等內網穿透工具免費的又不好使,收費的又划不來,怎麼辦?今天我來給大家分享一個方法,輕鬆搞定。

準備

  • 阿里雲賬號
  • 阿里雲域名
  • 一臺路由器

思路

阿里雲解析DNS提供接口可以讓我們通過程序更新域名設置,這是核心要點。查看文檔
另外我們還需要知道家裏的IP地址。
然後只要我們根據運營商跟換ip的頻率(一般一天換一個)定時執行任務,進行更新域名指向,這樣就能實現只要訪問固定域名就能指向指定IP了。
然後再設置一下路由器,映射到內網ip地址(即提供網路服務的主機地址),可以使用樹莓派、老舊電腦或者NAS作爲主機,搭建自己的博客或者提供簡單的網絡服務。
大功告成!

widows 可以利用計劃任務,Linux 可以利用 crontab,來完成定時任務。

話不多說,都在代碼裏:

import logging
import requests
import hmac
import random
import string
from datetime import datetime, timezone
import base64

logger = logging.getLogger('test')
logger.setLevel(logging.DEBUG)

# 控制檯輸出
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# 輸出格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)

logger.addHandler(ch)


class DynamicRouter:
    """ 利用阿里雲解析接口,將域名動態解析到指定 ip

    適用於家庭寬帶的IP是公網IP的小夥伴,配合路由器的轉發功能對外提供服務。類似花生殼的功能。
    注意:80 端口一般被運營商封掉,在可以嘗試其他端口。
    """

    def __init__(self, access_key_id, access_key_secret):
        self.APP_ID = access_key_id
        self.APP_SECRET = access_key_secret
        self.base_host = "https://alidns.aliyuncs.com/"
        self._common_req_params = {
            "Format": "JSON",
            "Version": "2015-01-09",
            "AccessKeyId": self.APP_ID,
            "SignatureMethod": "HMAC-SHA1",
            "Timestamp": datetime.now(tz=timezone.utc).isoformat().split('.')[0] + 'Z',
            "SignatureVersion": "1.0",
            "SignatureNonce": ''.join([random.choice(string.ascii_letters + string.digits) for i in range(10)]),
        }

    def get_signature(self, **kwargs) -> bytes:
        """ 根據規則生成簽名

        :return  signature
        """
        signature_string_base = 'POST' + '&' + '%2F' + '&'
        signature_string_to_params = ''
        for key in sorted(kwargs):
            if key == "Timestamp":
                kwargs[key] = kwargs[key].replace(':', '%253A')
            signature_string_to_params += f'{key}%3D{kwargs[key]}%26'
        signature_string_to_sign = signature_string_base + signature_string_to_params.rstrip('%26')

        signature = hmac.new(key=(self.APP_SECRET + '&').encode(), msg=signature_string_to_sign.encode(),
                             digestmod="SHA1").digest()
        return base64.b64encode(signature)

    def get_record_id(self, domain_name: str, rr: str) -> str:
        """ 獲取該域名下二級域名的解析記錄 id

        :param domain_name:域名名稱
        :param rr:主機記錄(二級域名,若沒有,默認爲'@')
        :return record_id or None
        """
        data = {}
        data.update(self._common_req_params)
        data.update({'Action': 'DescribeDomainRecords', "DomainName": domain_name})
        signature = self.get_signature(**data)
        data['Signature'] = signature
        res = requests.post(self.base_host, data=data).json()

        records = res['DomainRecords']['Record']
        for i in records:
            if i['RR'] == rr:
                return i['RecordId']
        else:
            logger.error('未獲取到解析記錄,檢查參數是否正確。')
            raise Exception("can't get value")

    def update_domain_record(self, record_id: str, rr, value: str, ttl: int = 600, rtype: str = 'A') -> None:
        """ 更新解析記錄爲 record_id 的設置,包括但不限於ip地址、主機記錄、解析類型等

        :param record_id : 解析記錄
        :param rr : 主機記錄(二級域名)
        :param value : 解析記錄(若是 記錄類型 A,則爲 ip地址)
        :param ttl:解析生效時間
        :param rtype:記錄類型(默認爲'A',即跳轉到 ip4 地址)
        :return None
        """
        data = {
            'Action': 'UpdateDomainRecord',
            'RecordId': record_id,
            "RR": rr,
            "Type": rtype,
            "Value": value,
            "TTL": ttl
        }
        data.update(self._common_req_params)

        signature = self.get_signature(**data)
        data['Signature'] = signature
        res = requests.post(self.base_host, data=data)
        logger.info("更新域名記錄結果:" + res.text)
        return None

    @staticmethod
    def get_ip():
        """
        獲取本機外網ip
        接口是利用阿里雲函數計算服務(有免費額度)提供,比爬取網絡獲取方便。
        """
        req_url = 'https://1142905836248003.cn-shanghai.fc.aliyuncs.com/2016-08-15/proxy/musicApi/get_ip/'
        return requests.get(req_url).text


if __name__ == "__main__":
    eg = DynamicRouter(access_key_id='your-appid', access_key_secret='your-secret')
    record_id = eg.get_record_id('your-DomainName', 'your-RR')
    eg.update_domain_record(record_id=record_id, rr='blog', value=eg.get_ip())
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章