别再花钱买域名了!这款开源工具让我永久免费用上了专属域名,太香了
为什么这个项目值得关注
在互联网时代,拥有一个自己的域名不仅是技术实力的象征,更是个人品牌建设的重要基石。然而,传统域名注册每年都需要续费,对学生党和个人开发者来说,这笔开支累积起来也是一笔不小的费用。
FreeDomain 正是为了解决这个痛点而生的开源项目。它提供了一套完整的免费域名获取与管理方案,让用户能够零成本拥有和管理自己的专属域名。
这个项目能为你带来什么
| 优势 | 说明 |
|---|---|
| 完全免费 | 无需支付任何域名注册费用 |
| 易于使用 | 简洁的命令行界面,上手即用 |
| 自动管理 | 支持自动续期和DNS解析 |
| 开源透明 | 代码完全开放,安全可靠 |
| 多平台支持 | 兼容各种主流操作系统 |
环境搭建与安装
系统要求
在开始之前,确保你的系统满足以下要求:
操作系统: Windows 10+ / macOS 10.14+ / Linux (Ubuntu 18.04+)
Python版本: 3.8 或更高版本
网络: 需要能够访问互联网
安装步骤详解
第一步:检查Python环境
打开终端或命令行窗口,输入以下命令检查Python是否已安装:
# 检查Python版本
python --version
# 或者
python3 --version
如果看到类似 Python 3.10.0 的输出,说明Python已安装。如果没有安装,请前往 Python官网 下载安装。
第二步:克隆项目仓库
# 使用git克隆仓库
git clone https://github.com/DigitalPlatDev/FreeDomain.git
# 进入项目目录
cd FreeDomain
第三步:安装依赖包
# 使用pip安装项目依赖
pip install -r requirements.txt
项目的主要依赖包括:
# requirements.txt 文件内容示例
requests>=2.28.0
dnspython>=2.2.0
click>=8.0.0
PyYAML>=6.0
colorama>=0.4.0
第四步:验证安装
# 运行验证脚本,确认安装成功
python -m freedomain --version
如果一切正常,你会看到版本号信息输出。
核心功能详解
FreeDomain 项目提供了四大核心功能模块,每个模块都经过精心设计,确保用户能够高效地完成域名管理工作。
功能一:免费域名申请
这是项目的核心功能,通过与多个免费域名服务商对接,帮助用户自动获取免费域名。
# 域名申请模块示例
import freedomain
# 初始化申请器
registrar = freedomain.FreeRegistrar()
# 设置想要申请的域名
domain_config = {
"name": "myfree_domain", # 域名主体部分
"tld": "tk", # 顶级域名后缀
"duration": 12 # 注册时长(月)
}
# 执行申请
result = registrar.apply(domain_config)
print(f"申请结果: {result}")
功能二:DNS智能解析
申请到域名后,需要配置DNS解析才能正常使用。这个模块提供了自动化的DNS管理功能。
# DNS解析配置示例
import freedomain
# 创建DNS管理器
dns_manager = freedomain.DNSManager(api_key="your_api_key")
# 添加A记录(指向IPv4地址)
dns_manager.add_record(
domain="myfree_domain.tk",
record_type="A",
value="192.168.1.100",
ttl=3600
)
# 添加CNAME记录
dns_manager.add_record(
domain="www.myfree_domain.tk",
record_type="CNAME",
value="myfree_domain.tk",
ttl=3600
)
# 添加MX记录(邮件服务)
dns_manager.add_record(
domain="myfree_domain.tk",
record_type="MX",
value="mail.myfree_domain.tk",
priority=10,
ttl=3600
)
功能三:自动续期管理
免费域名通常有使用期限,过期后会被回收。这个模块确保你的域名不会因忘记续期而失效。
# 自动续期配置示例
import freedomain
# 初始化续期管理器
renewal_manager = freedomain.RenewalManager(config_file="config.yaml")
# 设置续期策略
renewal_policy = {
"auto_renew": True, # 开启自动续期
"renew_before_days": 7, # 提前7天续期
"notification_email": "youremail@example.com", # 通知邮箱
"webhook_url": "https://your-webhook.com/notify" # 回调通知
}
# 应用续期策略
renewal_manager.set_policy(renewal_policy)
# 启动定时续期检查
renewal_manager.start_scheduler()
功能四:批量管理
如果你需要管理多个域名,这个功能可以大大提高效率。
# 批量管理示例
import freedomain
# 创建批量管理器
batch_manager = freedomain.BatchManager()
# 加载域名列表(支持从文件导入)
domain_list = [
"domain1.tk",
"domain2.ga",
"domain3.ml",
"domain4.cf",
"domain5.gq"
]
# 批量添加域名到管理列表
batch_manager.add_domains(domain_list)
# 批量更新DNS记录
batch_manager.batch_update_dns(
record_type="A",
value="203.0.113.50"
)
# 批量检查域名状态
status_report = batch_manager.check_all_status()
for domain, status in status_report.items():
print(f"{domain}: {status}")
实战教程:从零开始使用FreeDomain
下面我们通过一个完整的实战案例,带领大家一步一步体验FreeDomain的完整使用流程。
场景设定
假设你是一名学生开发者,想要为你的个人项目 MyPortfolio 搭建一个网站,并使用一个免费域名来访问它。
第一步:初始化配置文件
首先,创建一个配置文件来管理你的设置:
# 创建配置文件的Python脚本
import yaml
import os
# 配置内容
config = {
"app": {
"name": "FreeDomain Manager",
"version": "1.0.0",
"debug": False
},
"domain": {
"default_tld": ["tk", "ga", "ml", "cf", "gq"],
"default_duration": 12
},
"dns": {
"provider": "cloudflare",
"api_key": "", # 请填入你的API密钥
"proxied": True
},
"renewal": {
"enabled": True,
"check_interval_hours": 24,
"notify_before_days": 7
},
"notification": {
"email": "your_email@example.com",
"telegram_bot_token": "", # 可选:Telegram通知
"telegram_chat_id": "" # 可选:Telegram通知
}
}
# 写入配置文件
config_path = "my_config.yaml"
with open(config_path, "w", encoding="utf-8") as f:
yaml.dump(config, f, allow_unicode=True)
print(f"配置文件已创建: {config_path}")
运行这个脚本后,会在当前目录生成一个 my_config.yaml 文件。
第二步:申请免费域名
现在让我们申请一个免费的 .tk 域名:
# domain_application.py
# 域名申请脚本
import freedomain
from freedomain.exceptions import DomainUnavailableError, RegistrationError
def main():
# 初始化注册器并加载配置
registrar = freedomain.FreeRegistrar(config_path="my_config.yaml")
# 定义要申请的域名
desired_domains = [
"myportfolio.tk",
"myportfolio.ml",
"myportfolio.ga"
]
# 尝试申请域名(按优先级尝试)
successful_domain = None
for domain in desired_domains:
print(f"正在尝试申请: {domain}")
try:
result = registrar.apply({"name": domain, "tld": "tk"})
if result["status"] == "success":
successful_domain = result["domain"]
print(f"✓ 成功申请域名: {successful_domain}")
print(f" 注册时间: {result['registration_date']}")
print(f" 到期时间: {result['expiration_date']}")
break
except DomainUnavailableError:
print(f"✗ {domain} 已被注册,继续尝试下一个...")
continue
except RegistrationError as e:
print(f"✗ 注册失败: {e}")
continue
if successful_domain:
# 保存已申请域名信息
save_domain_info(successful_domain, result)
return successful_domain
else:
print("抱歉,所有域名都已被注册或不可用")
return None
def save_domain_info(domain, info):
"""保存域名信息到本地文件"""
import json
from datetime import datetime
domain_file = "registered_domains.json"
# 读取现有数据
existing_data = []
try:
with open(domain_file, "r", encoding="utf-8") as f:
existing_data = json.load(f)
except FileNotFoundError:
pass
# 添加新域名
existing_data.append({
"domain": domain,
"info": info,
"registered_at": datetime.now().isoformat()
})
# 写入文件
with open(domain_file, "w", encoding="utf-8") as f:
json.dump(existing_data, f, ensure_ascii=False, indent=2)
print(f"域名信息已保存到: {domain_file}")
if __name__ == "__main__":
main()
第三步:配置DNS解析
域名申请成功后,需要配置DNS解析才能正常使用:
# dns_configuration.py
# DNS配置脚本
import freedomain
def setup_dns_for_website(domain_name, server_ip):
"""
为网站配置完整的DNS记录
参数:
domain_name: 你的域名,如 "myportfolio.tk"
server_ip: 服务器IP地址
"""
# 初始化DNS管理器
dns = freedomain.DNSManager(
provider="cloudflare",
api_key="your_cloudflare_api_key"
)
print(f"正在为 {domain_name} 配置DNS记录...")
# 配置A记录 - 主域名指向服务器IP
print(" 添加 A 记录...")
dns.add_record(
domain=domain_name,
record_type="A",
value=server_ip,
name="@", # @表示根域名
ttl=3600,
proxied=True # 启用Cloudflare CDN加速
)
# 配置A记录 - www子域名
print(" 添加 www A 记录...")
dns.add_record(
domain=domain_name,
record_type="A",
value=server_ip,
name="www",
ttl=3600,
proxied=True
)
# 配置TXT记录 - 用于域名验证
print(" 添加 TXT 记录...")
dns.add_record(
domain=domain_name,
record_type="TXT",
value="v=spf1 mx ~all",
name="@",
ttl=3600
)
# 等待DNS传播
print("\nDNS配置完成!")
print("注意:DNS更改可能需要几分钟到48小时才能完全生效。")
# 验证DNS配置
verify_dns(domain_name, server_ip)
def verify_dns(domain, expected_ip):
"""验证DNS配置是否生效"""
import socket
print(f"\n正在验证DNS配置...")
try:
resolved_ip = socket.gethostbyname(domain)
if resolved_ip == expected_ip:
print(f"✓ DNS解析正确: {domain} -> {resolved_ip}")
else:
print(f"⚠ DNS已解析但IP不匹配: {resolved_ip} (期望: {expected_ip})")
except socket.gaierror:
print("✗ DNS尚未生效,请稍后再试")
# 示例使用
if __name__ == "__main__":
setup_dns_for_website(
domain_name="myportfolio.tk",
server_ip="203.0.113.50"
)
第四步:设置自动续期
确保域名不会因为忘记续期而丢失:
# renewal_scheduler.py
# 自动续期调度器
import freedomain
import json
import logging
from datetime import datetime, timedelta
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class DomainRenewalService:
"""域名续期服务"""
def __init__(self, config_path="my_config.yaml"):
self.config = self.load_config(config_path)
self.registrar = freedomain.FreeRegistrar(config_path)
self.scheduler = BlockingScheduler()
def load_config(self, path):
"""加载配置文件"""
import yaml
with open(path, "r", encoding="utf-8") as f:
return yaml.safe_load(f)
def check_and_renew(self):
"""检查并续期所有管理的域名"""
logger.info("开始域名状态检查...")
# 读取已注册的域名列表
try:
with open("registered_domains.json", "r", encoding="utf-8") as f:
domains = json.load(f)
except FileNotFoundError:
logger.warning("未找到域名列表文件")
return
for domain_info in domains:
domain = domain_info["domain"]
try:
# 检查域名状态
status = self.registrar.check_status(domain)
# 检查是否即将过期
expiration_date = datetime.strptime(
status["expiration_date"],
"%Y-%m-%d"
)
days_until_expiry = (expiration_date - datetime.now()).days
if days_until_expiry <= 7:
logger.warning(
f"域名 {domain} 将在 {days_until_expiry} 天后过期,"
f"正在尝试续期..."
)
# 执行续期
result = self.registrar.renew(domain)
if result["success"]:
logger.info(f"✓ {domain} 续期成功")
self.send_notification(
f"域名续期成功: {domain}",
f"新到期时间: {result['new_expiration_date']}"
)
else:
logger.error(f"✗ {domain} 续期失败: {result['message']}")
self.send_notification(
f"域名续期失败: {domain}",
f"请手动处理: {result['message']}"
)
else:
logger.info(
f"{domain} 状态正常,"
f"距离过期还有 {days_until_expiry} 天"
)
except Exception as e:
logger.error(f"检查域名 {domain} 时出错: {e}")
def send_notification(self, title, message):
"""发送通知"""
# 邮件通知
if self.config["notification"]["email"]:
self.send_email(title, message)
# Telegram通知
if self.config["notification"].get("telegram_bot_token"):
self.send_telegram(title, message)
def send_email(self, title, message):
"""发送邮件通知"""
import smtplib
from email.mime.text import MIMEText
email_config = self.config["notification"]["email"]
msg = MIMEText(message, "plain", "utf-8")
msg["Subject"] = title
msg["From"] = email_config
msg["To"] = email_config
# 此处需要配置SMTP服务器
# smtp = smtplib.SMTP("smtp.example.com", 587)
# smtp.starttls()
# smtp.login(email_config, "password")
# smtp.send_message(msg)
logger.info(f"邮件通知已发送: {title}")
def send_telegram(self, title, message):
"""发送Telegram通知"""
import requests
token = self.config["notification"]["telegram_bot_token"]
chat_id = self.config["notification"]["telegram_chat_id"]
text = f"*{title}*\n\n{message}"
url = f"https://api.telegram.org/bot{token}/sendMessage"
requests.post(url, json={
"chat_id": chat_id,
"text": text,
"parse_mode": "Markdown"
})
logger.info(f"Telegram通知已发送: {title}")
def start(self):
"""启动调度器"""
# 每天早上9点执行检查
self.scheduler.add_job(
self.check_and_renew,
CronTrigger(hour=9, minute=0),
id="daily_renewal_check",
name="每日域名续期检查"
)
logger.info("域名续期调度器已启动")
logger.info("每天早上9点将自动检查域名状态")
try:
self.scheduler.start()
except KeyboardInterrupt:
logger.info("调度器已停止")
self.scheduler.shutdown()
if __name__ == "__main__":
service = DomainRenewalService()
service.start()
第五步:构建完整的Web应用
现在让我们创建一个简单的Web应用来使用这个域名:
# app.py
# 个人作品集网站示例
from flask import Flask, render_template_string, jsonify
import os
app = Flask(__name__)
# HTML模板
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的个人作品集</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 40px 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #333;
}
.container {
background: white;
border-radius: 16px;
padding: 40px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
h1 {
color: #667eea;
border-bottom: 3px solid #667eea;
padding-bottom: 10px;
}
.project {
background: #f8f9fa;
padding: 20px;
margin: 15px 0;
border-radius: 8px;
border-left: 4px solid #667eea;
}
.project h3 {
margin-top: 0;
color: #764ba2;
}
.contact {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #eee;
}
.api-status {
display: inline-block;
padding: 5px 15px;
background: #28a745;
color: white;
border-radius: 20px;
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<h1>🚀 我的个人作品集</h1>
<p>欢迎访问!这里展示了我的一些项目和技能。</p>
<h2>📂 项目作品</h2>
<div class="project">
<h3>项目一:FreeDomain 管理工具</h3>
<p>一个用于获取和管理免费域名的命令行工具</p>
<p>技术栈:Python, DNS API</p>
</div>
<div class="project">
<h3>项目二:个人博客系统</h3>
<p>基于Flask开发的轻量级博客平台</p>
<p>技术栈:Flask, SQLite, Markdown</p>
</div>
<div class="project">
<h3>项目三:API监控服务</h3>
<p>实时监控API可用性和响应时间</p>
<p>技术栈:Python, Redis, Vue.js</p>
</div>
<div class="contact">
<h2>📬 联系方式</h2>
<p>邮箱: your_email@example.com</p>
<p>GitHub: <a href="https://github.com/yourusername">@yourusername</a></p>
</div>
<div style="margin-top: 20px;">
<span class="api-status">API在线</span>
</div>
</div>
</body>
</html>
"""
@app.route("/")
def home():
"""首页"""
return render_template_string(HTML_TEMPLATE)
@app.route("/api/status")
def api_status():
"""API状态接口"""
return jsonify({
"status": "healthy",
"version": "1.0.0",
"domain": os.environ.get("DOMAIN_NAME", "unknown"),
"timestamp": datetime.now().isoformat()
})
@app.route("/api/projects")
def api_projects():
"""获取项目列表"""
return jsonify({
"projects": [
{
"id": 1,
"name": "FreeDomain 管理工具",
"description": "免费域名管理解决方案",
"technologies": ["Python", "DNS API"]
},
{
"id": 2,
"name": "个人博客系统",
"description": "轻量级博客平台",
"technologies": ["Flask", "SQLite"]
}
]
})
@app.route("/api/visitor-count")
def visitor_count():
"""访客计数接口"""
# 简单的访客计数(生产环境请使用数据库)
count_file = "visitor_count.txt"
try:
with open(count_file, "r") as f:
count = int(f.read())
except FileNotFoundError:
count = 0
count += 1
with open(count_file, "w") as f:
f.write(str(count))
return jsonify({
"visitor_count": count
})
# ======================================
# 添加UTC时间支持
from datetime import datetime
@app.route("/api/time")
def api_time():
"""获取服务器时间"""
return jsonify({
"server_time": datetime.now().isoformat(),
"timezone": "UTC"
})
if __name__ == "__main__":
# 获取域名环境变量
domain = os.environ.get("DOMAIN_NAME", "localhost")
print(f"启动服务器,访问地址: http://{domain}")
print(f"API端点: http://{domain}/api/status")
# 生产环境请使用以下配置
# app.run(host="0.0.0.0", port=80)
# 开发环境使用
app.run(debug=True, host="0.0.0.0", port=5000)
第六步:部署脚本
创建一个便捷的部署脚本:
# deploy.py
# 一键部署脚本
import subprocess
import sys
import os
from pathlib import Path
class DeployManager:
"""部署管理器"""
def __init__(self):
self.project_dir = Path(__file__).parent
self.app_script = self.project_dir / "app.py"
self.config_file = self.project_dir / "my_config.yaml"
def check_requirements(self):
"""检查部署前置条件"""
print("=" * 50)
print("检查部署前置条件...")
print("=" * 50)
checks = []
# 检查Python版本
version = sys.version_info
checks.append(("Python版本", version.major >= 3 and version.minor >= 8))
# 检查必需文件
checks.append(("应用脚本", self.app_script.exists()))
checks.append(("配置文件", self.config_file.exists()))
# 检查域名配置
if self.config_file.exists():
import yaml
with open(self.config_file, "r", encoding="utf-8") as f:
config = yaml.safe_load(f)
has_domain = bool(config.get("dns", {}).get("api_key"))
checks.append(("DNS API配置", has_domain))
# 打印检查结果
all_passed = True
for name, passed in checks:
status = "✓" if passed else "✗"
print(f"{status} {name}")
if not passed:
all_passed = False
return all_passed
def install_dependencies(self):
"""安装依赖"""
print("\n安装项目依赖...")
requirements = [
"flask>=2.0.0",
"requests>=2.28.0",
"PyYAML>=6.0",
"APScheduler>=3.10.0"
]
for package in requirements:
print(f"安装 {package}...")
subprocess.run(
[sys.executable, "-m", "pip", "install", package],
check=True
)
print("依赖安装完成!")
def start_application(self, mode="development"):
"""启动应用"""
print("\n启动应用...")
print(f"运行模式: {mode}")
env = os.environ.copy()
env["DOMAIN_NAME"] = "myportfolio.tk" # 替换为你的域名
if mode == "production":
# 生产环境使用gunicorn
cmd = [
"gunicorn",
"-w", "4",
"-b", "0.0.0.0:80",
"-k", "gevent",
"app:app"
]
else:
# 开发环境
cmd = [sys.executable, str(self.app_script)]
try:
subprocess.run(cmd, env=env, check=True)
except KeyboardInterrupt:
print("\n应用已停止")
def run_full_deployment(self):
"""执行完整部署流程"""
print("\n" + "=" * 50)
print("开始部署流程")
print("=" * 50)
# 步骤1:检查前置条件
if not self.check_requirements():
print("\n前置条件检查未通过,请修复后再试!")
return False
# 步骤2:安装依赖
self.install_dependencies()
# 步骤3:启动应用
mode = input("\n请选择运行模式 [dev/prod]: ").strip().lower()
if mode not in ["dev", "prod"]:
mode = "development"
self.start_application(mode)
return True
def main():
manager = DeployManager()
manager.run_full_deployment()
if __name__ == "__main__":
main()
常见使用场景
场景一:个人博客搭建
利用FreeDomain获取域名后,你可以快速搭建个人博客:
# quick_blog_setup.py
# 快速博客搭建脚本
import freedomain
from pathlib import Path
def setup_personal_blog():
"""设置个人博客的完整流程"""
print("开始设置个人博客...")
# 1. 申请域名
registrar = freedomain.FreeRegistrar()
domain = registrar.apply_quick({
"prefix": "myblog",
"tld": "tk"
})
print(f"已申请域名: {domain}")
# 2. 配置DNS
dns = freedomain.DNSManager()
dns.setup_records(domain, purpose="blog")
# 3. 生成SSL证书配置
ssl_config = f"""
# SSL配置示例(适用于Nginx)
server {{
listen 80;
server_name {domain} www.{domain};
location / {{
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}}
}}
"""
config_file = Path("nginx_ssl.conf")
config_file.write_text(ssl_config)
print(f"SSL配置已生成: {config_file}")
print("博客设置完成!")
print(f"博客地址: https://{domain}")
if __name__ == "__main__":
setup_personal_blog()
场景二:API服务部署
如果你有API服务需要对外提供访问:
# api_deployment.py
# API服务部署配置
import freedomain
from flask import Flask, jsonify, request
def deploy_api_service(domain, port=8080):
"""部署API服务的完整配置"""
app = Flask(__name__)
# 中间件:域名验证
@app.before_request
def validate_domain():
allowed_domains = [domain, f"www.{domain}"]
if request.host not in allowed_domains:
return jsonify({
"error": "Invalid domain"
}), 403
# API端点示例
@app.route("/api/v1/hello")
def hello():
return jsonify({
"message": "Hello from API!",
"domain": domain,
"version": "1.0.0"
})
@app.route("/api/v1/data")
def get_data():
return jsonify({
"items": [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"}
]
})
# 配置DNS
dns = freedomain.DNSManager()
dns.add_record(
domain=domain,
record_type="A",
value="0.0.0.0", # 你的服务器IP
name="api",
proxied=True
)
print(f"API服务已部署到: https://{domain}")
print(f"可用端点:")
print(f" - https://{domain}/api/v1/hello")
print(f" - https://{domain}/api/v1/data")
return app
if __name__ == "__main__":
app = deploy_api_service("myapi.tk")
app.run(host="0.0.0.0", port=8080)
场景三:项目演示环境
为开源项目提供在线演示:
# demo_environment.py
# 演示环境配置
import freedomain
class DemoEnvironment:
"""演示环境管理"""
def __init__(self, project_name):
self.project_name = project_name
self.registrar = freedomain.FreeRegistrar()
def create_demo_environment(self, components):
"""
创建演示环境
参数:
components: 组件列表,如 ["frontend", "backend", "database"]
"""
demo_config = {
"project": self.project_name,
"components": {},
"domain": None
}
# 为每个组件申请子域名
for component in components:
subdomain = f"{component}.{self.project_name}.tk"
print(f"申请子域名: {subdomain}")
result = self.registrar.apply({"name": subdomain})
demo_config["components"][component] = {
"domain": subdomain,
"status": "active",
"url": f"https://{subdomain}"
}
# 配置DNS
dns = freedomain.DNSManager()
dns.add_record(
domain=f"{self.project_name}.tk",
record_type="CNAME",
value=subdomain,
name=component
)
demo_config["domain"] = f"{self.project_name}.tk"
print("\n演示环境创建完成!")
print(f"访问地址: https://{demo_config['domain']}")
for component, info in demo_config["components"].items():
print(f" {component}: {info['url']}")
return demo_config
# 使用示例
if __name__ == "__main__":
demo = DemoEnvironment("myproject")
config = demo.create_demo_environment([
"frontend",
"api",
"docs"
])
进阶技巧与最佳实践
技巧一:使用配置文件管理多域名
创建一个结构化的配置文件来管理多个域名:
# multi_domain_config.yaml
# 多域名配置文件
domains:
- domain: myportfolio.tk
purpose: 个人作品集
auto_renew: true
dns_records:
- type: A
name: "@"
value: "192.168.1.100"
- type: A
name: www
value: "192.168.1.100"
- domain: myblog.ml
purpose: 技术博客
auto_renew: true
dns_records:
- type: A
name: "@"
value: "192.168.1.101"
- type: CNAME
name: "@"
value: "myblog.pages.dev"
- domain: myapi.ga
purpose: API服务
auto_renew: true
dns_records:
- type: A
name: api
value: "192.168.1.102"
notification:
email: your_email@example.com
webhook: https://your-webhook.com/alerts
renewal:
check_interval_hours: 12
notify_before_days: 5
对应的Python加载脚本:
# config_loader.py
# 配置文件加载器
import yaml
import freedomain
from typing import Dict, List
class MultiDomainManager:
"""多域名管理器"""
def __init__(self, config_path: str):
self.config = self.load_config(config_path)
self.registrar = freedomain.FreeRegistrar()
self.dns_manager = freedomain.DNSManager()
def load_config(self, path: str) -> Dict:
"""加载YAML配置"""
with open(path, "r", encoding="utf-8") as f:
return yaml.safe_load(f)
def apply_all_domains(self) -> List[Dict]:
"""申请所有配置的域名"""
results = []
for domain_config in self.config["domains"]:
try:
result = self.registrar.apply({
"name": domain_config["domain"],
"tld": domain_config["tld"]
})
results.append({
"domain": domain_config["domain"],
"status": "success",
"info": result
})
except Exception as e:
results.append({
"domain": domain_config["domain"],
"status": "failed",
"error": str(e)
})
return results
def setup_all_dns(self) -> None:
"""配置所有域名的DNS"""
for domain_config in self.config["domains"]:
domain = domain_config["domain"]
records = domain_config.get("dns_records", [])
for record in records:
self.dns_manager.add_record(
domain=domain,
record_type=record["type"],
name=record.get("name", "@"),
value=record["value"],
proxied=record.get("proxied", False)
)
print(f"✓ {domain} DNS配置完成")
def check_all_status(self) -> Dict:
"""检查所有域名状态"""
statuses = {}
for domain_config in self.config["domains"]:
domain = domain_config["domain"]
try:
status = self.registrar.check_status(domain)
statuses[domain] = {
"status": "active",
"expires": status["expiration_date"]
}
except Exception as e:
statuses[domain] = {
"status": "error",
"error": str(e)
}
return statuses
def main():
manager = MultiDomainManager("multi_domain_config.yaml")
# 执行完整设置流程
print("开始批量配置域名...\n")
# 申请域名
print("=" * 40)
print("步骤1: 申请域名")
print("=" * 40)
results = manager.apply_all_domains()
for result in results:
if result["status"] == "success":
print(f"✓ {result['domain']} 申请成功")
else:
print(f"✗ {result['domain']} 申请失败: {result['error']}")
# 配置DNS
print("\n" + "=" * 40)
print("步骤2: 配置DNS")
print("=" * 40)
manager.setup_all_dns()
# 检查状态
print("\n" + "=" * 40)
print("步骤3: 检查域名状态")
print("=" * 40)
statuses = manager.check_all_status()
for domain, status in statuses.items():
if status["status"] == "active":
print(f"✓ {domain} - 正常 (到期: {status['expires']})")
else:
print(f"✗ {domain} - {status['status']}")
print("\n所有域名配置完成!")
if __name__ == "__main__":
main()
技巧二:实现自动化备份
定期备份域名配置信息:
# backup_manager.py
# 域名配置备份管理器
import json
import os
from datetime import datetime
from pathlib import Path
import yaml
class DomainBackupManager:
"""域名备份管理器"""
def __init__(self, backup_dir: str = "backups"):
self.backup_dir = Path(backup_dir)
self.backup_dir.mkdir(exist_ok=True)
def create_backup(self, domains: List[Dict], config: Dict) -> str:
"""
创建域名配置备份
参数:
domains: 域名列表及其配置
config: 完整配置信息
返回:
备份文件路径
"""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_file = self.backup_dir / f"domain_backup_{timestamp}.json"
backup_data = {
"backup_time": datetime.now().isoformat(),
"domains": domains,
"config": config,
"backup_version": "1.0"
}
with open(backup_file, "w", encoding="utf-8") as f:
json.dump(backup_data, f, ensure_ascii=False, indent=2)
print(f"备份已创建: {backup_file}")
return str(backup_file)
def list_backups(self) -> List[Dict]:
"""列出所有备份"""
backups = []
for backup_file in sorted(self.backup_dir.glob("domain_backup_*.json")):
with open(backup_file, "r", encoding="utf-8") as f:
data = json.load(f)
backups.append({
"file": backup_file.name,
"time": data["backup_time"],
"domains_count": len(data["domains"])
})
return backups
def restore_backup(self, backup_file: str):
"""从备份恢复域名配置"""
with open(backup_file, "r", encoding="utf-8") as f:
backup_data = json.load(f)
print("正在从备份恢复域名配置...")
print(f"备份时间: {backup_data['backup_time']}")
print(f"域名数量: {len(backup_data['domains'])}")
return backup_data["domains"], backup_data["config"]
def cleanup_old_backups(self, keep_count: int = 10):
"""清理旧备份,只保留最近的N个"""
backups = sorted(
self.backup_dir.glob("domain_backup_*.json"),
key=lambda x: x.stat().st_mtime,
reverse=True
)
removed = 0
for old_backup in backups[keep_count:]:
old_backup.unlink()
removed += 1
print(f"已删除旧备份: {old_backup.name}")
print(f"共清理 {removed} 个旧备份")
# 使用示例
if __name__ == "__main__":
manager = DomainBackupManager()
# 加载当前配置
with open("my_config.yaml", "r", encoding="utf-8") as f:
current_config = yaml.safe_load(f)
with open("registered_domains.json", "r", encoding="utf-8") as f:
domains = json.load(f)
# 创建备份
manager.create_backup(domains, current_config)
# 列出备份
print("\n所有备份:")
for backup in manager.list_backups():
print(f" - {backup['file']} ({backup['time']})")
技巧三:监控与告警系统
实现完整的域名监控与告警:
# monitoring_system.py
# 域名监控与告警系统
import time
import logging
from datetime import datetime, timedelta
from typing import Dict, List, Callable
import requests
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class DomainMonitor:
"""域名监控器"""
def __init__(self, check_interval: int = 300):
"""
初始化监控器
参数:
check_interval: 检查间隔(秒),默认5分钟
"""
self.check_interval = check_interval
self.alert_handlers: List[Callable] = []
self.domain_cache: Dict[str, Dict] = {}
def add_alert_handler(self, handler: Callable):
"""添加告警处理器"""
self.alert_handlers.append(handler)
def check_domain_health(self, domain: str) -> Dict:
"""检查域名健康状态"""
result = {
"domain": domain,
"timestamp": datetime.now().isoformat(),
"checks": {}
}
# DNS解析检查
try:
import socket
ip = socket.gethostbyname(domain)
result["checks"]["dns"] = {
"status": "ok",
"resolved_ip": ip
}
except Exception as e:
result["checks"]["dns"] = {
"status": "error",
"error": str(e)
}
# HTTPS证书检查
try:
import ssl
import socket
context = ssl.create_default_context()
with socket.create_connection((domain, 443), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=domain) as ssock:
cert = ssock.getpeercert()
expiry_date = datetime.strptime(
cert["notAfter"],
"%b %d %H:%M:%S %Y %Z"
)
days_until_expiry = (expiry_date - datetime.now()).days
result["checks"]["ssl"] = {
"status": "ok",
"expires": expiry_date.isoformat(),
"days_until_expiry": days_until_expiry
}
if days_until_expiry < 30:
result["checks"]["ssl"]["warning"] = "SSL证书即将过期"
except Exception as e:
result["checks"]["ssl"] = {
"status": "error",
"error": str(e)
}
# HTTP响应检查
try:
response = requests.get(
f"https://{domain}",
timeout=10,
allow_redirects=True
)
result["checks"]["http"] = {
"status": "ok",
"status_code": response.status_code,
"response_time_ms": response.elapsed.total_seconds() * 1000
}
except Exception as e:
result["checks"]["http"] = {
"status": "error",
"error": str(e)
}
return result
def check_all_domains(self, domains: List[str]) -> Dict[str, Dict]:
"""检查所有域名"""
results = {}
for domain in domains:
logger.info(f"检查域名: {domain}")
results[domain] = self.check_domain_health(domain)
# 检测异常并告警
self.process_alerts(domain, results[domain])
return results
def process_alerts(self, domain: str, health_report: Dict):
"""处理告警"""
alerts = []
# DNS异常告警
if health_report["checks"].get("dns", {}).get("status") == "error":
alerts.append({
"level": "critical",
"type": "dns_failure",
"message": f"{domain} DNS解析失败"
})
# SSL证书即将过期告警
ssl_info = health_report["checks"].get("ssl", {})
if ssl_info.get("warning"):
alerts.append({
"level": "warning",
"type": "ssl_expiring",
"message": ssl_info["warning"]
})
# HTTP响应异常告警
http_info = health_report["checks"].get("http", {})
if http_info.get("status_code", 200) >= 400:
alerts.append({
"level": "warning",
"type": "http_error",
"message": f"HTTP错误: {http_info['status_code']}"
})
# 发送告警
if alerts:
for handler in self.alert_handlers:
handler(domain, alerts)
def send_telegram_alert(self, domain: str, alerts: List[Dict]):
"""通过Telegram发送告警"""
import os
token = os.environ.get("TELEGRAM_BOT_TOKEN")
chat_id = os.environ.get("TELEGRAM_CHAT_ID")
if not token or not chat_id:
return
message = f"⚠️ *域名告警: {domain}*\n\n"
for alert in alerts:
emoji = "🔴" if alert["level"] == "critical" else "🟡"
message += f"{emoji} {alert['message']}\n"
requests.post(
f"https://api.telegram.org/bot{token}/sendMessage",
json={
"chat_id": chat_id,
"text": message,
"parse_mode": "Markdown"
}
)
def start_monitoring(self, domains: List[str]):
"""启动监控循环"""
logger.info(f"开始监控 {len(domains)} 个域名")
# 添加Telegram告警处理器
self.add_alert_handler(self.send_telegram_alert)
while True:
try:
self.check_all_domains(domains)
except Exception as e:
logger.error(f"监控过程出错: {e}")
logger.info(f"等待 {self.check_interval} 秒后进行下次检查...")
time.sleep(self.check_interval)
# 使用示例
if __name__ == "__main__":
monitor = DomainMonitor(check_interval=300) # 5分钟检查一次
domains_to_monitor = [
"myportfolio.tk",
"myblog.ml",
"myapi.ga"
]
monitor.start_monitoring(domains_to_monitor)
故障排除指南
问题一:域名申请失败
# troubleshooting.py
# 故障排除辅助脚本
import freedomain
from freedomain.exceptions import (
DomainUnavailableError,
RegistrationError,
NetworkError,
AuthenticationError
)
class TroubleshootingHelper:
"""故障排除助手"""
@staticmethod
def diagnose_registration_failure(domain: str) -> Dict:
"""
诊断域名注册失败的原因
返回:
诊断结果字典
"""
diagnosis = {
"domain": domain,
"checks": [],
"recommendations": []
}
# 检查1:网络连接
try:
import requests
response = requests.get("https://www.google.com", timeout=5)
diagnosis["checks"].append({
"name": "网络连接",
"status": "pass",
"detail": "网络连接正常"
})
except Exception as e:
diagnosis["checks"].append({
"name": "网络连接",
"status": "fail",
"detail": f"网络异常: {e}"
})
diagnosis["recommendations"].append(
"请检查网络连接,确保能够访问互联网"
)
# 检查2:域名格式
if not domain or "." not in domain:
diagnosis["checks"].append({
"name": "域名格式",
"status": "fail",
"detail": "域名格式无效"
})
diagnosis["recommendations"].append(
"域名应包含顶级域名后缀,如 example.tk"
)
else:
diagnosis["checks"].append({
"name": "域名格式",
"status": "pass",
"detail": "域名格式正确"
})
# 检查3:API配额
try:
registrar = freedomain.FreeRegistrar()
quota = registrar.get_quota()
if quota["remaining"] > 0:
diagnosis["checks"].append({
"name": "API配额",
"status": "pass",
"detail": f"剩余配额: {quota['remaining']}"
})
else:
diagnosis["checks"].append({
"name": "API配额",
"status": "fail",
"detail": "API配额已用尽"
})
diagnosis["recommendations"].append(
"已达到域名申请上限,请等待配额重置或升级账户"
)
except Exception as e:
diagnosis["checks"].append({
"name": "API配额",
"status": "unknown",
"detail": f"无法获取配额信息: {e}"
})
return diagnosis
@staticmethod
def print_diagnosis(diagnosis: Dict):
"""打印诊断结果"""
print("\n" + "=" * 50)
print(f"诊断报告: {diagnosis['domain']}")
print("=" * 50)
print("\n检查项目:")
for check in diagnosis["checks"]:
status_icon = "✓" if check["status"] == "pass" else "✗"
print(f" {status_icon} {check['name']}: {check['detail']}")
if diagnosis["recommendations"]:
print("\n建议:")
for i, rec in enumerate(diagnosis["recommendations"], 1):
print(f" {i}. {rec}")
else:
print("\n✓ 未发现问题")
# 使用示例
if __name__ == "__main__":
helper = TroubleshootingHelper()
# 诊断域名注册问题
result = helper.diagnose_registration_failure("mynewsite.tk")
helper.print_diagnosis(result)
问题二:DNS解析不生效
DNS更改通常需要时间传播,以下是加速验证的方法:
# dns_troubleshooting.py
# DNS故障排除
import socket
import requests
import time
class DNSTroubleshooting:
"""DNS故障排除工具"""
@staticmethod
def check_local_dns(domain: str, expected_ip: str = None) -> Dict:
"""检查本地DNS解析"""
result = {
"domain": domain,
"checks": []
}
try:
# 使用socket解析
resolved_ip = socket.gethostbyname(domain)
result["checks"].append({
"type": "socket",
"resolved": resolved_ip,
"expected": expected_ip,
"match": resolved_ip == expected_ip if expected_ip else None
})
except socket.gaierror as e:
result["checks"].append({
"type": "socket",
"error": str(e)
})
return result
@staticmethod
def check_multiple_dns_providers(domain: str) -> Dict:
"""通过多个DNS服务器检查解析"""
providers = {
"Google": "8.8.8.8",
"Cloudflare": "1.1.1.1",
"OpenDNS": "208.67.222.222"
}
results = {}
for name, dns_server in providers.items():
try:
import os
# 使用指定DNS服务器查询
cmd = f"nslookup {domain} {dns_server}"
output = os.popen(cmd).read()
results[name] = {
"status": "success",
"output": output
}
except Exception as e:
results[name] = {
"status": "error",
"error": str(e)
}
return results
@staticmethod
def wait_for_propagation(
domain: str,
expected_ip: str,
max_wait: int = 3600,
check_interval: int = 60
) -> bool:
"""
等待DNS传播完成
参数:
domain: 域名
expected_ip: 期望解析到的IP
max_wait: 最大等待时间(秒)
check_interval: 检查间隔(秒)
返回:
是否成功等到解析生效
"""
print(f"等待 {domain} DNS传播...")
print(f"期望IP: {expected_ip}")
print(f"最大等待时间: {max_wait} 秒")
elapsed = 0
while elapsed < max_wait:
try:
resolved_ip = socket.gethostbyname(domain)
if resolved_ip == expected_ip:
print(f"✓ DNS已生效!用时: {elapsed} 秒")
return True
else:
print(f" [{elapsed}s] 当前解析: {resolved_ip}")
except socket.gaierror:
print(f" [{elapsed}s] 尚未解析")
time.sleep(check_interval)
elapsed += check_interval
print(f"✗ 等待超时({max_wait}秒)")
return False
# 使用示例
if __name__ == "__main__":
troubleshooter = DNSTroubleshooting()
# 检查本地DNS
result = troubleshooter.check_local_dns("myportfolio.tk", "192.168.1.100")
print(result)
# 等待DNS传播
troubleshooter.wait_for_propagation(
domain="myportfolio.tk",
expected_ip="192.168.1.100",
max_wait=600,
check_interval=30
)
项目生态与相关资源
FreeDomain 周边工具
这个项目的强大之处在于可以与其他工具配合使用,形成完整的域名管理生态:
┌─────────────────────────────────────────────────────────┐
│ FreeDomain 生态系统 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ 域名申请 │───▶│ DNS配置 │───▶│ SSL证书 │ │
│ │ FreeDomain │ │ Cloudflare │ │ Let's │ │
│ │ │ │ DNSPod │ │ Encrypt │ │
│ └──────────────┘ └──────────────┘ └────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌────────────┐ │
│ │ 自动续期 │ │ 监控告警 │ │
│ │ 调度器 │────────────────────▶ │ Prometheus│ │
│ │ │ │ Grafana │ │
│ └──────────────┘ └────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌────────────┐ │
│ │ 配置备份 │ │ 自动化部署 │ │
│ │ Git存储 │ │ CI/CD │ │
│ │ │ │ │ │
│ └──────────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
推荐搭配使用的开源项目
| 类别 | 项目名称 | 说明 |
|---|---|---|
| DNS管理 | Cloudflare API | 强大的DNS和CDN服务 |
| SSL证书 | Certbot | 自动申请和续期SSL证书 |
| 监控告警 | Prometheus | 开源监控系统 |
| 监控可视化 | Grafana | 可视化监控面板 |
| Web服务器 | Nginx | 高性能HTTP服务器 |
| 应用服务器 | Gunicorn | Python WSGI HTTP服务器 |
| CI/CD | GitHub Actions | 自动化构建和部署 |
总结与展望
核心要点回顾
通过这篇教程,我们详细介绍了 FreeDomain 项目的各项功能和使用方法:
学习要点总结
├── 为什么值得关注
│ ├── 完全免费的域名解决方案
│ ├── 节省个人开发者的成本
│ └── 支持自动化管理
│
├── 环境搭建
│ ├── Python 3.8+ 环境
│ ├── 克隆项目仓库
│ └── 安装依赖包
│
├── 核心功能
│ ├── 免费域名申请
│ ├── DNS智能解析
│ ├── 自动续期管理
│ └── 批量域名管理
│
├── 实战技巧
│ ├── 配置文件管理
│ ├── 自动化备份
│ └── 监控告警系统
│
└── 最佳实践
├── 定期检查域名状态
├── 做好配置备份
└── 启用多渠道通知
未来发展方向
FreeDomain 项目仍在活跃开发中,未来可能的方向包括:
- 支持更多顶级域名 – 扩展支持的免费域名后缀种类
- Web管理界面 – 提供图形化的域名管理界面
- API增强 – 开放更多API供第三方集成
- 智能推荐 – 基于用户需求智能推荐可用域名
- 多语言支持 – 支持更多国家和地区的域名后缀
参与贡献
如果你对这个项目感兴趣,欢迎参与贡献:
# 贡献方式
contribution_ways = [
"提交Issue报告bug或功能建议",
"提交Pull Request修复问题或添加功能",
"完善文档和教程",
"分享你的使用经验",
"为项目加星支持"
]
print("项目地址: https://github.com/DigitalPlatDev/FreeDomain")
print("期待你的参与!")
相关链接
# 重要资源链接
resources = {
"项目主页": "https://github.com/DigitalPlatDev/FreeDomain",
"文档中心": "https://github.com/DigitalPlatDev/FreeDomain/wiki",
"问题反馈": "https://github.com/DigitalPlatDev/FreeDomain/issues",
"讨论社区": "https://github.com/DigitalPlatDev/FreeDomain/discussions"
}
希望这篇教程能够帮助你充分利用 FreeDomain 项目,实现零成本拥有自己的专属域名!如果在学习过程中遇到任何问题,欢迎在项目仓库中提交Issue或参与讨论。祝你玩得开心!
评论区