当前位置: 首页 > news >正文

ZeroTier虚拟局域网内搭建DNS服务器

一、搭建本地 DNS 服务器(适合多设备共享)

如果需要让局域网内所有设备(电脑、手机、智能家居等)都能使用自定义域名,推荐搭建本地 DNS 服务器,统一管理域名解析。

推荐工具:dnsmasq(轻量易用,适合 Linux 服务器)

步骤 1:配置 dnsmasq 解析虚拟局域网内的域名

  1. 安装 dnsmasq(以 Ubuntu 为例):

    sudo apt update && sudo apt install dnsmasq -y
    
  2. 配置自定义域名解析:编辑配置文件:

    sudo nano /etc/dnsmasq.conf
    

    添加以下内容(根据你的虚拟局域网节点信息修改)

  3. # 监听虚拟局域网的 IP(确保 dnsmasq 能被虚拟局域网内的其他节点访问)
    listen-address=127.0.0.1,10.144.0.10  # 10.144.0.10 是 dnsmasq 所在服务器的虚拟 IP# 允许所有设备查询(虚拟局域网内信任环境下可用)
    interface=ztxxxxxx  # 替换为 ZeroTier 在服务器上的虚拟网卡名称(可通过 `ip addr` 查看,如 zt0)
    bind-interfaces  # 仅绑定到指定网卡,增强安全性# 自定义域名映射(虚拟局域网内的节点)
    address=/nas.vlan/10.144.0.20  # 例如:nas.vlan → 节点1的虚拟 IP
    address=/server.vlan/10.144.0.30  # 例如:server.vlan → 节点2的虚拟 IP
    address=/printer.vlan/10.144.0.40  # 例如:printer.vlan → 节点3的虚拟 IP# 可选:设置上游 DNS 服务器(用于解析虚拟局域网外的公网域名,如 www.baidu.com)
    server=8.8.8.8  # 谷歌 DNS
    server=223.5.5.5  # 阿里云 DNS
    
  4. 关键配置说明
    • listen-address 必须包含 dnsmasq 服务器的虚拟 IP,否则其他节点无法访问该 DNS 服务。
    • interface 指定 ZeroTier 的虚拟网卡(如 zt0),确保 DNS 服务仅在虚拟局域网内提供。
    • address 规则中的域名可自定义(如 .vlan 后缀),方便区分虚拟局域网内资源。
  5. 重启 dnsmasq 生效

    sudo systemctl restart dnsmasq
可能存在的问题:dnsmasq 服务启动失败,原因是 端口 53 被占用failed to create listening socket for port 53: Address already in use)。端口 53 是 DNS 服务的默认端口,可能系统中已有其他程序(如 systemd-resolved)占用了该端口。以下是解决步骤:

步骤 1:查找占用端口 53 的进程

执行命令,查看哪个进程在使用端口 53:

sudo netstat -tulpn | grep :53

或者用 lsof 命令(如果没安装,先执行 sudo apt install lsof):

sudo lsof -i :53

步骤 2:停止占用端口的服务

假设是 systemd-resolved 占用(Ubuntu 常见情况),执行以下命令停止并禁用该服务:

sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved

如果是其他服务(如 bind9 等),则执行 sudo systemctl stop 服务名 和 sudo systemctl disable 服务名 来停止禁用。

步骤 3:重启 dnsmasq 服务

sudo systemctl restart dnsmasq

步骤 4:验证 dnsmasq 是否正常运行

执行命令查看 dnsmasq 服务状态:

sudo systemctl status dnsmasq

如果显示 active (running),则说明 dnsmasq 已成功启动。

步骤 2:让虚拟局域网内的所有节点使用该 dnsmasq 服务器作为 DNS

需要为虚拟局域网内的每台节点配置 DNS 服务器地址为 dnsmasq 所在服务器的虚拟 IP(即 10.144.0.10),确保节点的 DNS 请求会被发送到 dnsmasq 处理。

方法 1:在 ZeroTier 控制器中统一配置(推荐,批量生效)

通过 ZeroTier 私有控制器(即你搭建的 http://ip:3443 管理界面)为虚拟局域网内的所有节点分配 DNS 服务器,无需逐个节点手动设置:

  1. 登录 ZeroTier 控制器管理界面,进入你的虚拟局域网(如网络 ID 为 8056c2e21cxxxxxx)。
  2. 进入 “设置” 或 “网络配置” 页面,找到 DNS 配置 选项(通常在 “Advanced” 或 “DHCP” 部分):
    • 设置 DNS 服务器 为 10.144.0.10dnsmasq 服务器的虚拟 IP)。
    • 可选:设置 DNS 搜索域(如 vlan,这样访问 nas 即可自动补全为 nas.vlan)。
  3. 保存配置后,虚拟局域网内的节点会自动获取该 DNS 服务器(可能需要重启节点的 ZeroTier 服务生效)。
方法 2:手动为单个节点配置 DNS(适合少量节点)

如果无法通过控制器统一配置,可在每个节点上手动指定 DNS 服务器为 10.144.0.10

  • Linux 节点:编辑网络配置文件(以 Ubuntu 为例):

    sudo nano /etc/systemd/resolved.conf
    

    修改 DNS 字段:

    [Resolve]
    DNS=10.144.0.10  # dnsmasq 服务器的虚拟 IP
    

    重启解析服务:

    sudo systemctl restart systemd-resolved
    
  • Windows 节点:进入 “网络连接”→ 找到 ZeroTier 虚拟网卡 → 右键 “属性”→ 双击 “Internet 协议版本 4 (TCP/IPv4)”→ 设置 “首选 DNS 服务器” 为 10.144.0.10

  • macOS 节点:进入 “系统设置”→“网络”→ 选择 ZeroTier 虚拟网卡 →“详细信息”→“DNS”→ 点击 “+” 添加 10.144.0.10

步骤 3:测试虚拟局域网内的域名访问

在虚拟局域网内的任意节点上,通过以下方式验证域名解析是否生效:

  1. 使用 ping 或 nslookup 测试

    # 测试自定义域名解析
    ping nas.vlan  # 应能 ping 通 10.144.0.20
    nslookup server.vlan  # 应返回 10.144.0.30# 测试公网域名解析(验证上游 DNS 是否生效)
    nslookup www.baidu.com  # 应返回百度的公网 IP
    
  2. 通过浏览器或应用访问:若节点上运行着 Web 服务(如 nas.vlan 的 80 端口),在浏览器中输入 http://nas.vlan 应能访问到对应服务。

注意事项

执行后,防火墙会允许虚拟局域网内的其他节点通过 zt0 网卡访问这台服务器的 53 端口(dnsmasq 的 DNS 服务端口)。

如果需要同时允许 TCP 协议(某些 DNS 场景可能用到 TCP,如长查询),可以再补充一条命令:

sudo ufw allow in on zt0 to any port 53 proto tcp

  1. 防火墙设置:确保 dnsmasq 所在服务器的 53/udp 端口(DNS 服务端口)在虚拟局域网中放行(可通过 ufw allow in on zt0 to any port 53/udp 配置)。
  2. sudo ufw allow in on zt0 to any port 53 proto udp
    
  3. zt0 替换为你的 ZeroTier 虚拟网卡名称。
  4. port 53 proto udp 表示允许 53 端口的 UDP 协议(DNS 服务默认用 UDP 协议)。
  5. 域名冲突:避免自定义域名与公网域名重复(如不要用 baidu.vlan),防止解析混乱。
  6. 节点 IP 固定:若虚拟局域网内的节点 IP 是动态分配的,建议在 ZeroTier 控制器中为节点设置 “固定 IP”(Static IP),避免 IP 变化导致域名映射失效。

可能存在的问题:DNS设置了10.11.12.35,但是依然显示
服务器: 192.168.0.1
Address: 192.168.0.1

出现这种情况,说明 Windows 节点实际使用的 DNS 服务器仍为路由器的 192.168.0.1,而非你设置的 10.11.12.35dnsmasq 服务器的虚拟 IP)。问题根源在于 DNS 配置未真正生效,可能是 ZeroTier 虚拟网卡的 DNS 设置被其他网络优先级覆盖,或配置步骤有误。以下是具体解决方法:

尝试通过 PowerShell 命令 来调整网络适配器优先级,步骤如下:

步骤 1:查看网卡名称和当前优先级

以管理员身份打开 PowerShell(右键点击开始菜单,选择 “Windows PowerShell(管理员)”),执行以下命令,列出所有网络适配器及其优先级(InterfaceMetric 数值越小,优先级越高):

Get-NetIPInterface | Where-Object {$_.InterfaceAlias -like "*"} | Select-Object InterfaceAlias, InterfaceMetric

执行后会看到类似输出(找到 ZeroTier 虚拟网卡、以太网、WLAN 对应的条目):

InterfaceAlias       InterfaceMetric
--------------       ---------------
以太网                  25
WLAN                    35
ZeroTier Virtual Port #2  45  # 假设 ZeroTier 网卡当前优先级较低
步骤 2:降低其他网卡的优先级(提升 ZeroTier 优先级)

假设 以太网 的 InterfaceMetric 是 25WLAN 是 35,而 ZeroTier 是 45。我们需要提高其他网卡的数值(如设为 50)。

  • 提高其他网卡的 InterfaceMetric(以 以太网 为例):

  • Set-NetIPInterface -InterfaceAlias "以太网" -InterfaceMetric 50
    

    对 WLAN 等其他网卡重复此操作,确保它们的 InterfaceMetric 大于 45

步骤 3:刷新 DNS 缓存并测试
  1. 刷新 Windows DNS 缓存:

    ipconfig /flushdns
    
  2. 再次测试 nslookup,强制使用 ZeroTier 网卡的 DNS:

    nslookup server.symboland 10.11.12.35
    
    • 如果返回 server.symboland 对应的 IP,说明 dnsmasq 解析正常,只是 Windows 优先级配置问题。
    • 如果仍返回错误,需检查 dnsmasq 服务器是否运行正常,以及域名 server.symboland 是否在 dnsmasq 中正确配置。
步骤 4:最终验证

执行普通 nslookup,确认 Windows 自动选择 ZeroTier 的 DNS:

nslookup server.symboland

如果输出的「服务器」是 10.11.12.35,且解析到正确 IP,说明优先级调整成功。

通过以上配置,ZeroTier 虚拟局域网内的所有节点即可通过自定义域名互相访问,无需记忆复杂的虚拟 IP。

扩展:在宝塔面板中部署 DNS 域名注册系统

1. 准备环境

1.1 确保 dnsmasq 正常运行

在终端中检查:

bash

systemctl status dnsmasq
# 如果未安装,使用以下命令安装
# apt update && apt install dnsmasq -y

1.2 检查 dnsmasq 配置

确保 /etc/dnsmasq.conf 包含:

bash

# 加载自定义配置目录
conf-dir=/etc/dnsmasq.d/,*.conf
# 本地域名后缀
local=/symboland/
domain=symboland

2. 宝塔面板部署步骤

2.1 创建网站

  1. 登录宝塔面板

  2. 点击「网站」→「添加站点」

  3. 填写站点信息:

    • 域名:nas.symboland

    • 根目录:/www/wwwroot/nas.symboland

    • PHP版本:选择纯静态(因为我们将使用Python)

    • 其他保持默认

2.2 上传文件

在 /www/wwwroot/nas.symboland 目录下创建以下文件:

文件结构:

text

/www/wwwroot/nas.symboland/
├── app.py                 # Flask 应用
├── config.py              # 配置文件
├── requirements.txt       # Python依赖
├── static/
│   └── index.html        # 前端页面
├── logs/                  # 日志目录
└── dnsmasq/              # DNS配置目录(软链接)
2.2.1 创建 Flask 应用 (app.py)

python

#!/usr/bin/env python3
"""
DNS 域名注册系统 - 宝塔面板版本
"""from flask import Flask, request, jsonify, send_file
import subprocess
import os
import re
from pathlib import Path
import logging
from datetime import datetimeapp = Flask(__name__, static_folder='static', static_url_path='')# 配置 - 宝塔面板适配
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DNSMASQ_CONF_DIR = "/etc/dnsmasq.d"
CUSTOM_DNS_FILE = os.path.join(DNSMASQ_CONF_DIR, "custom_domains.conf")
DOMAIN_SUFFIX = "symboland"
LOG_FILE = os.path.join(BASE_DIR, "logs", "dns_register.log")# 创建必要的目录
os.makedirs(os.path.join(BASE_DIR, "logs"), exist_ok=True)# 设置日志
logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s - %(message)s',handlers=[logging.FileHandler(LOG_FILE),logging.StreamHandler()]
)def validate_domain(domain):"""验证域名格式"""if not domain or len(domain) < 2 or len(domain) > 63:return False# 只允许字母、数字和连字符if not re.match(r'^[a-zA-Z0-9-]+$', domain):return False# 不能以连字符开头或结尾if domain.startswith('-') or domain.endswith('-'):return Falsereturn Truedef get_client_ip():"""获取客户端真实IP - 适配宝塔Nginx"""if request.headers.get('X-Forwarded-For'):ip = request.headers.get('X-Forwarded-For').split(',')[0]elif request.headers.get('X-Real-IP'):ip = request.headers.get('X-Real-IP')else:ip = request.remote_addrreturn ipdef read_existing_domains():"""读取已存在的域名配置"""domains = {}if os.path.exists(CUSTOM_DNS_FILE):with open(CUSTOM_DNS_FILE, 'r', encoding='utf-8') as f:for line in f:line = line.strip()if line and not line.startswith('#'):# 解析 dnsmasq 配置格式if line.startswith('address=/'):parts = line.split('/')if len(parts) >= 4:domain = parts[2]ip = parts[3]domains[domain] = ipreturn domainsdef write_domain_config(domain, ip):"""写入域名配置到dnsmasq配置文件"""try:# 确保配置目录存在Path(DNSMASQ_CONF_DIR).mkdir(parents=True, exist_ok=True)# 读取现有配置existing_domains = read_existing_domains()# 更新或添加新域名full_domain = f"{domain}.{DOMAIN_SUFFIX}"existing_domains[full_domain] = ip# 写入新配置with open(CUSTOM_DNS_FILE, 'w', encoding='utf-8') as f:f.write("# 自动生成的域名配置 - 请勿手动修改\n")f.write(f"# 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")f.write(f"# 总记录数: {len(existing_domains)}\n\n")for dom, dom_ip in existing_domains.items():f.write(f"address=/{dom}/{dom_ip}\n")logging.info(f"域名配置已更新: {full_domain} -> {ip}")return Trueexcept Exception as e:logging.error(f"写入配置文件失败: {e}")return Falsedef reload_dnsmasq():"""重新加载dnsmasq配置"""try:result = subprocess.run(['systemctl', 'reload', 'dnsmasq'],capture_output=True,text=True,timeout=10)if result.returncode == 0:logging.info("dnsmasq 重新加载成功")return Trueelse:logging.error(f"dnsmasq 重新加载失败: {result.stderr}")return Falseexcept subprocess.TimeoutExpired:logging.error("dnsmasq 重新加载超时")return Falseexcept Exception as e:logging.error(f"重新加载dnsmasq时发生错误: {e}")return False@app.route('/')
def index():"""主页面"""return send_file('static/index.html')@app.route('/api/get-ip')
def get_ip():"""获取客户端IP API"""client_ip = get_client_ip()return jsonify({'ip': client_ip})@app.route('/api/register-domain', methods=['POST'])
def register_domain():"""注册域名API"""try:data = request.get_json()if not data:return jsonify({'success': False,'message': '无效的请求数据'}), 400domain = data.get('domain', '').strip().lower()client_ip = get_client_ip()# 验证域名if not validate_domain(domain):return jsonify({'success': False,'message': '域名格式无效。只能使用字母、数字和连字符,长度2-63个字符'}), 400# 检查域名是否已存在existing_domains = read_existing_domains()full_domain = f"{domain}.{DOMAIN_SUFFIX}"if full_domain in existing_domains:existing_ip = existing_domains[full_domain]if existing_ip == client_ip:return jsonify({'success': True,'message': f'域名 {full_domain} 已指向您的IP'})else:return jsonify({'success': False,'message': f'域名 {full_domain} 已被IP {existing_ip} 使用'}), 400# 写入配置if not write_domain_config(domain, client_ip):return jsonify({'success': False,'message': '配置文件更新失败'}), 500# 重新加载dnsmasqif not reload_dnsmasq():return jsonify({'success': False,'message': 'DNS服务重载失败,请联系管理员'}), 500# 记录注册日志logging.info(f"域名注册成功: {full_domain} -> {client_ip}")return jsonify({'success': True,'message': f'域名 {full_domain} 注册成功!现在可以通过该域名访问您的设备。','domain': full_domain,'ip': client_ip})except Exception as e:logging.error(f"域名注册过程出错: {e}")return jsonify({'success': False,'message': '服务器内部错误,请稍后重试'}), 500@app.route('/api/domains')
def list_domains():"""列出所有已注册的域名"""domains = read_existing_domains()return jsonify({'success': True,'domains': domains,'count': len(domains)})@app.route('/api/status')
def system_status():"""系统状态检查"""try:# 检查dnsmasq服务状态dnsmasq_status = subprocess.run(['systemctl', 'is-active', 'dnsmasq'],capture_output=True,text=True)domains_count = len(read_existing_domains())return jsonify({'success': True,'dnsmasq_status': dnsmasq_status.stdout.strip(),'domains_count': domains_count,'config_file': CUSTOM_DNS_FILE,'config_exists': os.path.exists(CUSTOM_DNS_FILE)})except Exception as e:return jsonify({'success': False,'error': str(e)}), 500if __name__ == '__main__':app.run(host='0.0.0.0', port=5000, debug=False)
2.2.2 创建前端页面 (static/index.html)

html

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>NAS 域名注册系统 - 宝塔面板版</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);min-height: 100vh;display: flex;justify-content: center;align-items: center;padding: 20px;}.container {background: white;border-radius: 15px;box-shadow: 0 20px 40px rgba(0,0,0,0.1);padding: 40px;width: 100%;max-width: 500px;}.header {text-align: center;margin-bottom: 30px;}.header h1 {color: #333;margin-bottom: 10px;font-size: 28px;}.header p {color: #666;font-size: 16px;}.form-group {margin-bottom: 20px;}label {display: block;margin-bottom: 8px;color: #333;font-weight: 500;}input[type="text"] {width: 100%;padding: 12px 15px;border: 2px solid #e1e5e9;border-radius: 8px;font-size: 16px;transition: all 0.3s ease;}input[type="text"]:focus {outline: none;border-color: #667eea;box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);}.domain-suffix {color: #667eea;font-weight: 600;}.btn {width: 100%;padding: 14px;background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);color: white;border: none;border-radius: 8px;font-size: 16px;font-weight: 600;cursor: pointer;transition: all 0.3s ease;}.btn:hover {transform: translateY(-2px);box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);}.btn:active {transform: translateY(0);}.message {margin-top: 20px;padding: 12px;border-radius: 8px;text-align: center;display: none;}.success {background: #d4edda;color: #155724;border: 1px solid #c3e6cb;}.error {background: #f8d7da;color: #721c24;border: 1px solid #f5c6cb;}.info {background: #cce7ff;color: #004085;border: 1px solid #b3d7ff;}.current-ip {background: #f8f9fa;padding: 15px;border-radius: 8px;margin-bottom: 20px;text-align: center;border: 1px solid #e9ecef;}.ip-address {font-weight: 600;color: #667eea;font-size: 18px;}.system-info {background: #fff3cd;padding: 10px 15px;border-radius: 8px;margin-bottom: 20px;border: 1px solid #ffeaa7;font-size: 14px;color: #856404;}</style>
</head>
<body><div class="container"><div class="header"><h1>🚀 域名注册系统</h1><p>宝塔面板版 - 为您的设备注册专属域名</p></div><div class="system-info">💡 系统提示:请确保您的设备与DNS服务器在同一局域网内</div><div class="current-ip"><div>您的当前 IP 地址:</div><div class="ip-address" id="currentIp">检测中...</div></div><form id="domainForm"><div class="form-group"><label for="domainName">请输入域名:</label><input type="text" id="domainName" placeholder="例如:mydevice" required><div style="margin-top: 5px; color: #666; font-size: 14px;">完整域名:<span id="fullDomain" class="domain-suffix">输入域名.symboland</span></div></div><button type="submit" class="btn">注册域名</button></form><div id="message" class="message"></div><div style="margin-top: 20px; text-align: center;"><button type="button" class="btn" οnclick="checkSystemStatus()" style="background: #6c757d; margin-bottom: 10px;">检查系统状态</button><button type="button" class="btn" οnclick="listDomains()" style="background: #17a2b8;">查看已注册域名</button></div></div><script>// 获取客户端IP地址async function getClientIP() {try {const response = await fetch('/api/get-ip');const data = await response.json();document.getElementById('currentIp').textContent = data.ip;return data.ip;} catch (error) {document.getElementById('currentIp').textContent = '获取失败';return null;}}// 更新完整域名显示function updateFullDomain() {const domainName = document.getElementById('domainName').value;const fullDomainElement = document.getElementById('fullDomain');if (domainName) {fullDomainElement.textContent = domainName + '.symboland';} else {fullDomainElement.textContent = '输入域名.symboland';}}// 显示消息function showMessage(message, type) {const messageElement = document.getElementById('message');messageElement.textContent = message;messageElement.className = 'message ' + type;messageElement.style.display = 'block';// 自动隐藏成功消息if (type === 'success') {setTimeout(() => {messageElement.style.display = 'none';}, 5000);}}// 检查系统状态async function checkSystemStatus() {try {const response = await fetch('/api/status');const data = await response.json();if (data.success) {showMessage(`系统状态正常 | DNS服务: ${data.dnsmasq_status} | 已注册域名: ${data.domains_count}个`, 'info');} else {showMessage('系统状态检查失败', 'error');}} catch (error) {showMessage('系统状态检查失败', 'error');}}// 列出已注册域名async function listDomains() {try {const response = await fetch('/api/domains');const data = await response.json();if (data.success) {const domains = data.domains;if (Object.keys(domains).length === 0) {showMessage('暂无已注册域名', 'info');} else {let domainsList = '已注册域名:\n';for (const [domain, ip] of Object.entries(domains)) {domainsList += `${domain} -> ${ip}\n`;}showMessage(domainsList, 'info');}} else {showMessage('获取域名列表失败', 'error');}} catch (error) {showMessage('获取域名列表失败', 'error');}}// 处理表单提交document.getElementById('domainForm').addEventListener('submit', async function(e) {e.preventDefault();const domainName = document.getElementById('domainName').value.trim();if (!domainName) {showMessage('请输入域名', 'error');return;}// 简单的域名格式验证if (!/^[a-zA-Z0-9-]+$/.test(domainName)) {showMessage('域名只能包含字母、数字和连字符', 'error');return;}if (domainName.length < 2 || domainName.length > 63) {showMessage('域名长度必须在2-63个字符之间', 'error');return;}try {const response = await fetch('/api/register-domain', {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify({domain: domainName})});const data = await response.json();if (data.success) {showMessage(`✅ ${data.message}`, 'success');document.getElementById('domainName').value = '';updateFullDomain();} else {showMessage(`❌ ${data.message}`, 'error');}} catch (error) {showMessage('网络错误,请检查连接', 'error');}});// 初始化document.getElementById('domainName').addEventListener('input', updateFullDomain);getClientIP();// 页面加载时检查系统状态setTimeout(checkSystemStatus, 1000);</script>
</body>
</html>
2.2.3 创建依赖文件 (requirements.txt)

txt

Flask==2.3.3
gunicorn==21.2.0

2.3 配置 Python 项目

  1. 在宝塔面板中安装 Python 项目管理器

    • 进入「软件商店」

    • 搜索「Python 项目管理器」并安装

  2. 添加 Python 项目

    • 进入「软件商店」→「Python 项目管理器」

    • 点击「添加项目」

    • 配置如下:

      • 项目名称:dns-register

      • 路径:/www/wwwroot/nas.symboland

      • Python 版本:选择 3.7+

      • 框架:Flask

      • 启动方式:gunicorn

      • 启动文件:app.py

      • 运行用户:root(需要修改DNS配置,所以需要root权限)

      • 端口:5001(避免冲突)

2.4 配置网站反向代理

  1. 进入「网站」→ 选择 nas.symboland 站点

  2. 点击「设置」→「反向代理」

  3. 添加反向代理:

    • 代理名称:python_app

    • 目标URL:http://127.0.0.1:5001

2.5 设置权限

在终端中执行:

bash

# 确保应用目录权限
chown -R www:www /www/wwwroot/nas.symboland
chmod -R 755 /www/wwwroot/nas.symboland# 创建日志文件并设置权限
touch /www/wwwroot/nas.symboland/logs/dns_register.log
chown www:www /www/wwwroot/nas.symboland/logs/dns_register.log
chmod 644 /www/wwwroot/nas.symboland/logs/dns_register.log

2.6 重启服务

bash

# 重启 dnsmasq
systemctl restart dnsmasq# 在宝塔Python项目管理器中重启项目

3. 验证部署

  1. 访问系统:在浏览器中打开 http://nas.symboland

  2. 测试功能

    • 系统应该显示你的IP地址

    • 尝试注册一个测试域名

    • 检查系统状态

  3. 验证DNS

    bash

    nslookup 你注册的域名.symboland
    ping 你注册的域名.symboland

4. 故障排除

如果遇到问题,检查以下位置:

  1. 日志文件

    • 应用日志:/www/wwwroot/nas.symboland/logs/dns_register.log

    • Python项目日志:在宝塔Python项目管理器中查看

    • Nginx日志:在宝塔网站设置中查看

  2. 常见问题

    • 权限问题:确保Python项目以root用户运行

    • 端口冲突:检查5001端口是否被占用

    • DNS缓存:重启dnsmasq或清除DNS缓存

  3. 手动测试API

    bash

    curl http://127.0.0.1:5001/api/status

这样就完成了在宝塔面板中的部署。系统现在可以通过 http://nas.symboland 访问,用户可以在网页上注册自己的域名了。

http://www.dtcms.com/a/512484.html

相关文章:

  • 网络与通信安全课程复习汇总3——身份认证
  • 诸城网站做的好的创网站 灵感
  • C++多线程、STL
  • 自己做的网站怎么加入微信支付哪个网站做五金冲压的
  • MySQL数据库05:DQL查询运算符
  • 橙米网站建设网站建设合同制人员招聘
  • 织梦网站图片修改文化墙 北京广告公司
  • VTK——双重深度剥离
  • Linux小课堂: 软件安装与源码编译实战之从 RPM 到源码构建的完整流程
  • 【Python编程】之面向对象
  • Day67 Linux I²C 总线与设备驱动架构、开发流程与调试
  • 【AI增强质量管理体系结构】AI+自动化测试引擎 与Coze
  • 音频共享耳机专利拆解:碰击惯性数据监测与阈值减速识别机制研究
  • 青岛专业网站设计公司网站后台程序怎么做
  • MySQL创建用户、权限分配以及添加、修改权限
  • 【循环神经网络基础】
  • 郑州网站建设与设计校园网站建设年度总结
  • 中国新冠一共死去的人数网站优化和提升网站排名怎么做
  • 太仓手机网站建设阿里云如何做网站
  • 第二篇:按键交互入门:STM32 GPIO输入与消抖处理
  • JSP九大内置对象
  • 如何选择大良网站建设网站建设插件代码大全
  • 卡码网语言基础课(Python) | 17.判断集合成员
  • 温州专业网站建设成都营销推广公司
  • 淘客做网站还是做app佛山seo网站优化
  • 组合数常见的四种计算方法
  • 美容医疗服务小程序:功能集成,解锁一站式变美新体验
  • 网站建设的展望 视频搭建公司内部网站
  • Mac 从零开始配置 VS Code + Claude/Codex AI 协同开发环境教程
  • 鸿蒙flutter 老项目到新项目的遇到迁移坑点