连接自定义域名
使用 Cloudflare 作为反向代理,将你自己的域名指向 Daki 上托管的 Web 应用 — 免费 HTTPS 和自定义端口转发。包含高级的 Cloudflare Tunnel(cloudflared)替代方案。
想让你的 Web 应用可以通过 yourdomain.com 访问,而不是 hostname:port 地址?本指南将向你展示如何使用 Cloudflare 作为免费反向代理,把你自己的域名指向 Daki 服务器。Cloudflare 会为你处理 HTTPS,并把访问者转发到你的应用所监听的自定义端口。
你将学到
- 为什么 Daki 上的自定义域名需要 Cloudflare 这样的反向代理
- 如何通过已代理的 DNS 记录将域名指向你的服务器
- 如何为你的域名启用免费 HTTPS
- 如何使用 Origin Rule 将流量转发到应用的端口
- 使用 Cloudflare Tunnel(
cloudflared)的高级替代方案
前提条件
- 一台带有公网端口分配的付费套餐服务器 — 参见付费套餐
- 一个你拥有的域名(在任意注册商注册,例如 Namecheap、GoDaddy、IONOS、Cloudflare Registrar)
- 一个免费的 Cloudflare 账户
- 一个正在运行、并监听服务器分配端口的 Web 应用(HTTP/HTTPS)
你的应用必须在分配端口上绑定到 0.0.0.0(所有接口),而不是 127.0.0.1 / localhost。只绑定到 localhost 的应用无法从容器外部访问,代理将无法连接。大多数框架都接受 host 参数(例如 Flask 中的 app.run(host="0.0.0.0", port=...),或许多 Node.js 应用中的 HOST=0.0.0.0)。
为什么需要 Cloudflare
Daki 的各个节点共享 IP 地址,而你的应用监听的是非标准端口(分配给你服务器的端口)。由此会产生两个问题:
- 访问者希望通过标准 HTTPS 端口(443)访问
https://yourdomain.com— 而不是yourdomain.com:4129。 - 你希望获得有效的 HTTPS 证书,而无需自己管理。
在你的服务器前面放置 Cloudflare,可以同时解决这两个问题。Cloudflare 充当反向代理:浏览器通过 443 端口的 HTTPS 连接 Cloudflare,再由 Cloudflare 把请求转发到你服务器的自定义端口。你将获得免费 SSL 和简洁的 URL,同时服务器的真实 IP 保持隐藏。
此方法适用于 HTTP/HTTPS Web 应用(网站、API、仪表板、Webhook)。它不适用于大多数游戏服务器等原始 TCP/UDP 服务 — Cloudflare 的标准代理只处理 HTTP(S)。对于非 HTTP 服务,请使用下方的 Cloudflare Tunnel 方法,或联系支持。
查找服务器的 IP 和端口
你需要从 门户 的 Network 标签页中获取两个值:
| 值 | 获取位置 | 示例 |
|---|---|---|
| 服务器 IP | 服务器主机名解析到的 IP 地址(显示在 Network 标签页中)。如果只显示主机名,你可以自行解析 — 例如 ping eu-node1.daki.cc — 或询问支持。 | 203.0.113.10 |
| 分配端口 | Network 标签页中主机名旁显示的端口。你的应用必须监听此端口。 | 4129 |
本指南全程使用这些示例值。出现的地方都请替换为你自己的值。关于分配的更多信息,参见网络与端口分配。
第 1 部分:Cloudflare 设置
将你的域名添加到 Cloudflare
- 在 dash.cloudflare.com 创建一个免费账户(或登录)。
- 点击 Add a site,输入你的域名(例如
yourdomain.com)。 - 出现提示时,选择 Free 套餐。
- Cloudflare 会提供两个 nameserver(例如
xxx.ns.cloudflare.com)。 - 登录你的域名注册商,找到该域名的 nameserver / DNS 设置,并将现有的 nameserver 替换为 Cloudflare 提供的两个。
nameserver 的更改可能需要几分钟到 24 小时才能生效。域名激活后,Cloudflare 会发邮件通知你。在此期间,你可以继续后面的步骤。
创建 DNS 记录
在你的域名的 Cloudflare 控制台中,进入 DNS → Records,然后点击 Add record:
字段 值 Type AName @(表示根域名yourdomain.com)IPv4 address 你的服务器 IP(示例: 203.0.113.10)Proxy status Proxied(橙色云朵 ☁️) 点击 Save。
橙色云朵(Proxied)状态至关重要 — 它让流量经过 Cloudflare,使 SSL 和第 2 部分中的端口重写得以生效。灰色云朵(DNS only)会完全绕过 Cloudflare,并暴露你服务器的 IP。若还要提供
www.yourdomain.com,请再添加一条名为www的已代理记录。配置 SSL/TLS
- 进入 SSL/TLS → Overview。
- 将加密模式设置为 Flexible。
Flexible 表示访问者与 Cloudflare 之间的流量是加密的(HTTPS),而 Cloudflare 通过明文 HTTP 连接你自定义端口上的应用。当你的应用提供明文 HTTP 时(大多数运行在自定义端口上的应用都是如此),这是正确的选择。
如果你的应用自行终止 TLS(即它在自己的端口上直接提供 HTTPS),请改选 Full。注意,Flexible 不会加密 Cloudflare 与你服务器之间的连接;对于敏感流量,请优先使用 Full 并在应用中启用 HTTPS。
第 2 部分:将流量转发到应用端口
由于你的应用运行在自定义端口(例如 4129)而不是标准的 80/443,你需要告诉 Cloudflare 在连接你的服务器时使用哪个端口。Origin Rule 正好能做到这一点 — 它会重写传入请求的目标端口。
创建 Origin Rule
- 在 Cloudflare 控制台中,进入 Rules → Origin Rules。
- 点击 Create Origin Rule。
- 配置规则:
设置 值 When incoming requests match Hostname equals yourdomain.comThen... Rewrite to Destination Port → 4129(你的分配端口)- 点击 Save(或 Deploy)。
DNS 生效后,你的应用即可通过 https://yourdomain.com 访问 — Cloudflare 通过 HTTPS 提供服务,并把流量转发到你服务器的 4129 端口。
验证是否生效
- 确保你的服务器正在运行,并且应用在分配端口上监听(在 Console 标签页中检查)。
- 在浏览器中打开
https://yourdomain.com。 - 你应该能看到应用通过 HTTPS 正常加载,并显示有效的锁形图标。
如果不能立即加载,请稍等片刻让 DNS 生效,然后参见下方的常见问题。
高级替代方案:Cloudflare Tunnel(cloudflared)
除了开放公网端口并将 A 记录指向你的服务器,你还可以在应用旁运行 cloudflared — Cloudflare 的隧道客户端。它会向 Cloudflare 建立一个出站连接,并在本地把流量转发到你的应用,因此你服务器的 IP 和端口保持隐藏,既不需要 DNS A 记录,也不需要 Origin Rule。
Daki 环境如何影响此方法。 Startup 标签页提供两个命令 — 安装命令(在首次设置或重新安装时运行一次)和启动命令(每次启动时运行)。你也可以临时把启动命令设为 bash 来打开一个 Shell。但你的服务器是容器,而不是完整的 Linux 虚拟机:没有 apt,你无法注册系统服务,而你在控制台中手动启动的隧道会在服务器重启时终止。因此,可靠的做法是把隧道作为应用自身启动流程的一部分 — 在运行时下载 cloudflared 二进制文件,并通过环境变量控制,将其作为子进程与应用一同启动。
创建隧道
- 在 Cloudflare Zero Trust 控制台中,进入 Networks → Tunnels,点击 Create a tunnel,然后选择 Cloudflared。
- 为隧道命名,并复制 Cloudflare 显示的隧道令牌(即安装命令中
--token后面的长字符串)。 - 为隧道添加一个 Public Hostname:
- Domain:
yourdomain.com - Service:
http://localhost:4129(你应用的本地端口)
- Domain:
将令牌保存到 .env
将令牌添加到服务器的
.env文件中(参见环境变量),这样它就不会出现在你的源代码里:.envCLOUDFLARE_TUNNEL_TOKEN=your_tunnel_token_here从代码中启动隧道
添加一个小型启动脚本:它会在首次运行时下载
cloudflared,并在你的应用旁边启动它,然后把该脚本设为你的启动命令。只有设置了CLOUDFLARE_TUNNEL_TOKEN时才会启动隧道,因此同一份代码在本地没有令牌时也能正常运行。保存为
start.js,然后将启动命令设为node start.js:JavaScript// start.js — starts your app and, if a token is set, a Cloudflare tunnel. require("dotenv").config(); const fs = require("fs"); const path = require("path"); const { spawn, spawnSync } = require("child_process"); const CLOUDFLARED_URL = "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64"; const binaryPath = path.join(__dirname, "cloudflared"); const children = []; // The container has no apt — download the binary on first run, reuse it after. function ensureCloudflared() { if (fs.existsSync(binaryPath)) return binaryPath; console.log("[tunnel] downloading cloudflared..."); const dl = spawnSync("curl", ["-fsSL", "-o", binaryPath, CLOUDFLARED_URL], { stdio: "inherit", }); if (dl.status !== 0) return null; fs.chmodSync(binaryPath, 0o755); return binaryPath; } // Spawn a child process; if any child exits, stop the rest and quit. function start(name, command, args) { const child = spawn(command, args, { stdio: "inherit", env: process.env }); child.on("exit", (code) => { console.error(`[${name}] exited (${code}); shutting down`); for (const c of children) if (!c.killed) c.kill("SIGTERM"); process.exit(code ?? 1); }); children.push(child); } const token = process.env.CLOUDFLARE_TUNNEL_TOKEN?.trim(); if (token) { const binary = ensureCloudflared(); if (binary) start("tunnel", binary, ["tunnel", "run", "--token", token]); } else { console.log("[tunnel] CLOUDFLARE_TUNNEL_TOKEN not set; skipping tunnel"); } // Start your app — change this to your real entry point. start("app", "node", ["index.js"]);保存为
start.sh,然后将启动命令设为bash start.sh:Shell#!/usr/bin/env bash # Load variables from .env into the environment. set -a; [ -f .env ] && . ./.env; set +a # The container has no apt — download cloudflared on first run, reuse it after. if [ ! -x ./cloudflared ]; then curl -fsSL -o ./cloudflared \ https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 chmod +x ./cloudflared fi # Start the tunnel in the background only if a token is set. if [ -n "$CLOUDFLARE_TUNNEL_TOKEN" ]; then ./cloudflared tunnel run --token "$CLOUDFLARE_TUNNEL_TOKEN" & fi # Start your app in the foreground — change this to your real command. exec python main.py为避免每次启动都重新下载,你可以把下载步骤移到安装命令中,只在启动命令里保留启动逻辑。上面的示例每次启动时运行也是安全的 — 二进制文件存在后会跳过下载。
取舍:
| Cloudflare 代理(第 1–2 部分) | Cloudflare Tunnel(cloudflared) | |
|---|---|---|
| 设置难度 | 较简单(仅需控制台) | 较高级(需整合进应用的启动流程) |
| 暴露服务器 IP/端口 | 隐藏在代理之后 | 完全隐藏(仅出站) |
| 需要公网端口 / Origin Rule | 需要 | 不需要 |
| 占用服务器资源 | 服务器上无额外占用 | 运行一个额外进程 |
常见问题
网站完全无法加载
DNS 可能仍在生效中。nameserver 的更改最长可能需要 24 小时(通常远少于此)。请在 Cloudflare 中确认你的域名状态为 Active,并且 A 记录 已存在且为 Proxied(橙色云朵)。你可以使用 dnschecker.org 之类的工具检查生效情况。
错误 522 / 523 — 连接超时 / 源站不可达
Cloudflare 无法连接到你的应用。请按以下顺序检查:
- 你的服务器正在运行,并且应用已完全启动(在 Console 标签页中检查)。
- Origin Rule 把端口重写为你准确的分配端口。
- A 记录的 IP 与你服务器的 IP 一致。
- 你的应用绑定到
0.0.0.0,而不是127.0.0.1/localhost。
重定向次数过多 / ERR_TOO_MANY_REDIRECTS
这通常是 SSL 模式不匹配导致的。如果你的应用强制使用 HTTPS,而 Cloudflare 通过 HTTP 连接它,就会形成重定向循环。你可以让应用提供明文 HTTP(并使用 Flexible),或让应用提供 HTTPS,并在 SSL/TLS → Overview 中把 Cloudflare 切换为 Full。
http:// 可以访问,但 https:// 不行
确保你的 DNS 记录为 Proxied(橙色云朵),并且已设置 SSL/TLS 模式(Flexible 或 Full)。如果是灰色云朵(DNS only),Cloudflare 的 SSL 会被绕过。
我的游戏服务器 / 非 HTTP 服务无法工作
必须使用 Cloudflare 吗?
不必。Cloudflare 是最简单的免费选项,但任何能转发到自定义端口的反向代理都可以使用(例如通过 cloudflared 的隧道,或在应用前自行部署的 Nginx/Caddy)。推荐使用 Cloudflare,因为它提供免费 SSL、隐藏你的服务器 IP,并且在代理方式下无需在服务器上安装额外软件。