WordPress 全栈 DDNS 托管系统技术手册

本方案旨在通过 WordPress 搭建一个面向多用户的 Cloudflare DDNS 托管平台。支持自动分配二级域名、API 权限隔离、动态环境适配以及自动化邮件系统。
一、 环境适配:Rockylinux9系统,动态域名与 Cloudflare 代理感知

为了让 WordPress 能够同时在内网、外网及 Cloudflare 代理下正常加载资源,必须解决“固定 URL”和“HTTPS 无限重定向”问题。

操作: 修改网站根目录 wp-config.php,在 /* That’s all, stop editing! */ 上方加入:
PHP

/* 1. 识别 Cloudflare HTTPS 代理头,解决子目录/后台无法跳转 HTTPS 问题 */
if (isset($_SERVER[‘HTTP_X_FORWARDED_PROTO’]) && $_SERVER[‘HTTP_X_FORWARDED_PROTO’] == ‘https’) {
$_SERVER[‘HTTPS’] = ‘on’;
}

/* 2. 动态获取当前访问协议 */
$http_type = ((isset($_SERVER[‘HTTPS’]) && $_SERVER[‘HTTPS’] == ‘on’) || (isset($_SERVER[‘HTTP_X_FORWARDED_PROTO’]) && $_SERVER[‘HTTP_X_FORWARDED_PROTO’] == ‘https’)) ? ‘https://’ : ‘http://’;

/* 3. 强制 WordPress 使用当前请求的域名(适配多域名/IP/内网访问) */
$current_domain = $_SERVER[‘HTTP_HOST’];
define(‘WP_HOME’, $http_type . $current_domain);
define(‘WP_SITEURL’, $http_type . $current_domain);

/* 4. 自动修复数据库中的绝对路径链接(仅输出层替换) */
ob_start( ‘ob_replace_home_url’ );
function ob_replace_home_url( $content ) {
$home_url = get_option( ‘home’ );
return str_replace( $home_url, WP_HOME, $content );
}

二、 核心插件:Cloudflare 多类型 DDNS 服务 (v3.2)

该插件负责与 Cloudflare API 交互,为每个注册用户提供专属的 API Key 和二级域名更新权限。

插件路径: /wp-content/plugins/cf-ddns-service/cf-ddns-service.php

<?php
/*
Plugin Name: Cloudflare 多类型 DDNS 服务 (专业版)
Description: 支持 A/AAAA/CNAME 自动更新,带一键复制功能的实时管理控制台。已集成越权防护、速率限制、最小长度限制及物理查重功能。
Version: 3.2
Author: Gemini Thought Partner erthanleo
*/

if (!defined('ABSPATH')) exit;

/**
 * ==========================================================
 * 配置区:请确保以下信息准确
 * ==========================================================
 */
define('CF_DDNS_TOKEN', 'yourCFtoken'); 
define('CF_DDNS_ZONE_ID', 'yourCFzoneid');
define('CF_DDNS_DOMAIN', 'yourdomain');

/**
 * 1. 注册验证逻辑(加固:长度、格式、黑名单、物理查重)
 */
add_filter('registration_errors', 'cf_ddns_full_registration_check', 15, 3);
function cf_ddns_full_registration_check($errors, $sanitized_user_login, $user_email) {
    
    // 长度检查:不得小于 4 个字符
    if (strlen($sanitized_user_login) < 4) {
        $errors->add('username_too_short', '<strong>错误</strong>:用户名长度不得少于 4 个字符。');
    }

    // 格式检查:仅小写和数字
    if (!preg_match('/^[a-z0-9]+$/', $sanitized_user_login)) {
        $errors->add('username_invalid', '<strong>错误</strong>:用户名只能包含小写字母和数字。');
    }

    // 后台设置的黑名单检查
    $keywords_str = get_option('cf_ddns_reserved_keywords', 'admin,www,api,root,blog');
    $reserved = array_map('trim', explode(',', strtolower($keywords_str)));
    if (in_array(strtolower($sanitized_user_login), $reserved)) {
        $errors->add('username_reserved', '<strong>错误</strong>:该用户名受系统保护,不可注册。');
    }

    // Cloudflare 物理查重
    $full_domain = $sanitized_user_login . '.' . CF_DDNS_DOMAIN;
    $check_url = "https://api.cloudflare.com/client/v4/zones/" . CF_DDNS_ZONE_ID . "/dns_records?name=$full_domain";
    $res = wp_remote_get($check_url, ['headers' => ['Authorization' => 'Bearer ' . CF_DDNS_TOKEN], 'timeout' => 5]);
    if (!is_wp_error($res)) {
        $body = json_decode(wp_remote_retrieve_body($res), true);
        if (!empty($body['result'])) {
            $errors->add('domain_taken', '<strong>错误</strong>:该二级域名在 Cloudflare 中已被占用。');
        }
    }

    return $errors;
}

/**
 * 2. 初始化 API Key
 */
add_action('user_register', function($user_id) {
    $api_key = wp_generate_password(20, false);
    update_user_meta($user_id, 'cf_ddns_user_key', $api_key);
});

/**
 * 3. REST API 核心处理器 (加固:越权防护 + 速率限制)
 */
add_action('rest_api_init', function () {
    register_rest_route('cf-ddns/v1', '/update', [
        'methods' => 'GET',
        'callback' => 'cf_ddns_api_handler',
        'permission_callback' => '__return_true',
    ]);
});

function cf_ddns_api_handler($request) {
    $user_login_param = sanitize_user($request->get_param('user'));
    $key_param = sanitize_text_field($request->get_param('key'));
    $type = strtoupper($request->get_param('type') ?: 'A');
    $ip = $request->get_param('ip') ?: $_SERVER['REMOTE_ADDR'];

    if (!in_array($type, ['A', 'AAAA', 'CNAME'])) {
        return new WP_REST_Response(['status' => 'error', 'message' => '不支持的记录类型'], 400);
    }

    $user = get_user_by('login', $user_login_param);
    $stored_key = $user ? get_user_meta($user->ID, 'cf_ddns_user_key', true) : '';
    if (!$user || $stored_key !== $key_param) {
        return new WP_REST_Response(['status' => 'error', 'message' => '身份验证失败'], 403);
    }

    // 速率限制:每 5 分钟 10 次
    $limit_key = 'cf_limit_' . $user->ID;
    $count = get_transient($limit_key) ?: 0;
    if ($count >= 10) {
        return new WP_REST_Response(['status' => 'error', 'message' => '请求频繁:5分钟内限10次'], 429);
    }
    set_transient($limit_key, $count + 1, 300);

    $full_domain = strtolower($user->user_login) . '.' . CF_DDNS_DOMAIN;

    $query_url = "https://api.cloudflare.com/client/v4/zones/" . CF_DDNS_ZONE_ID . "/dns_records?name=$full_domain&type=$type";
    $query_res = wp_remote_get($query_url, ['headers' => ['Authorization' => 'Bearer ' . CF_DDNS_TOKEN]]);
    $query_data = json_decode(wp_remote_retrieve_body($query_res), true);
    $record_id = (!empty($query_data['result'])) ? $query_data['result'][0]['id'] : null;

    $api_url = "https://api.cloudflare.com/client/v4/zones/" . CF_DDNS_ZONE_ID . "/dns_records" . ($record_id ? "/$record_id" : "");
    $method = $record_id ? 'PUT' : 'POST';

    $response = wp_remote_request($api_url, [
        'method' => $method,
        'headers' => ['Authorization' => 'Bearer ' . CF_DDNS_TOKEN, 'Content-Type' => 'application/json'],
        'body' => json_encode(['type' => $type, 'name' => $full_domain, 'content' => $ip, 'ttl' => 120, 'proxied' => false])
    ]);

    $res_data = json_decode(wp_remote_retrieve_body($response), true);
    if (!empty($res_data['success'])) {
        return new WP_REST_Response(['status' => 'success', 'domain' => $full_domain, 'remaining' => (10 - ($count + 1))], 200);
    }
    return new WP_REST_Response(['status' => 'error', 'message' => 'Cloudflare 交互失败'], 500);
}

/**
 * 4. 前端 UI 管理控制台 [display_ddns_info]
 */
add_shortcode('display_ddns_info', 'cf_ddns_render_ui');
function cf_ddns_render_ui() {
    if (!is_user_logged_in()) return '<p>请先<a href="'.wp_login_url(get_permalink()).'">登录</a>查看解析信息。</p>';
    
    $user = wp_get_current_user();
    $key = get_user_meta($user->ID, 'cf_ddns_user_key', true);
    $subdomain = $user->user_login . '.' . CF_DDNS_DOMAIN;

    $res = wp_remote_get("https://api.cloudflare.com/client/v4/zones/".CF_DDNS_ZONE_ID."/dns_records?name=$subdomain", [
        'headers' => ['Authorization' => 'Bearer ' . CF_DDNS_TOKEN]
    ]);
    $records = json_decode(wp_remote_retrieve_body($res), true)['result'] ?? [];

    ob_start(); ?>
    <div style="border: 1px solid #e1e4e8; padding: 25px; border-radius: 12px; background: #fff; box-shadow: 0 4px 12px rgba(0,0,0,0.05); margin: 20px 0;">
        <h3 style="margin-top:0; color:#24292e;">域名管理控制台</h3>
        <p><strong>分配域名:</strong> <code style="color:#0366d6; font-size:16px;"><?php echo $subdomain; ?></code></p>
        <p><strong>您的 API Key:</strong> <code style="background:#fff5b1; padding:2px 5px; border-radius:3px;"><?php echo $key; ?></code></p>
        
        <table style="width:100%; border-collapse: collapse; margin-top: 20px;">
            <tr style="background: #f6f8fa;">
                <th style="padding:12px; border: 1px solid #d1d5da; text-align: left;">记录类型</th>
                <th style="padding:12px; border: 1px solid #d1d5da; text-align: left;">当前解析值</th>
                <th style="padding:12px; border: 1px solid #d1d5da; text-align: left;">快捷操作</th>
            </tr>
            <?php foreach(['A', 'AAAA', 'CNAME'] as $t): 
                $val = '<span style="color:#ccc;">未设置</span>';
                foreach($records as $rec) {
                    if($rec['type'] === $t) {
                        $val = '<strong style="color:#22863a;">' . $rec['content'] . '</strong>';
                        break;
                    }
                }
                $link = home_url("/wp-json/cf-ddns/v1/update?user={$user->user_login}&key={$key}&type={$t}&ip=你的IP");
            ?>
            <tr>
                <td style="padding:12px; border: 1px solid #d1d5da;"><strong><?php echo $t; ?></strong></td>
                <td style="padding:12px; border: 1px solid #d1d5da;"><?php echo $val; ?></td>
                <td style="padding:12px; border: 1px solid #d1d5da;">
                    <button style="cursor:pointer; background:#2ea44f; color:#fff; border:none; padding:6px 12px; border-radius:6px;" 
                            onclick="navigator.clipboard.writeText('<?php echo $link; ?>').then(()=>alert('接口链接已复制'))">复制链接</button>
                </td>
            </tr>
            <?php endforeach; ?>
        </table>

        <div style="margin-top:25px; font-size:13px; color:#586069; border-top:1px solid #eaecef; padding-top:15px; line-height:1.6;">
            <h4 style="margin-top:0; color:#24292e;">使用指南:</h4>
            1. 点击<strong>“复制链接”</strong>获取更新地址。<br>
            2. <strong>手动更新:</strong>将链接末尾加上 <code>&ip=你的IP</code> 访问即可。<br>
            3. <strong>路由器/脚本:</strong>如果不带 <code>&ip=</code> 参数,系统将自动识别设备出口 IP。<br>
            4. <strong>生效时间:</strong>Cloudflare 解析通常在 2-5 分钟内生效。<br>
            5. <strong>快捷查询:</strong>您可以在本地终端使用以下命令测试是否更新成功:<br>
            &nbsp;&nbsp;<code>nslookup <?php echo $subdomain; ?> 1.1.1.1</code><br>
			&nbsp;&nbsp;<code>nslookup <?php echo $subdomain; ?> 2606:4700:4700::1111</code>
        </div>
    </div>
    <?php return ob_get_clean();
}

/**
 * 5. 后台管理与安全权限
 */
add_action('admin_init', function() {
    if (!current_user_can('administrator') && !(defined('DOING_AJAX') && DOING_AJAX)) {
        wp_safe_redirect(home_url()); exit;
    }
});
add_action('after_setup_theme', function() {
    if (!current_user_can('administrator')) show_admin_bar(false);
});
add_action('admin_menu', function() {
    add_options_page('DDNS 拦截设置', 'DDNS 拦截设置', 'manage_options', 'cf-ddns-settings', function() {
        ?>
        <div class="wrap"><h1>DDNS 拦截设置</h1><form method="post" action="options.php">
        <?php settings_fields('cf_ddns_settings_group'); do_settings_sections('cf-ddns-settings'); submit_button(); ?>
        </form></div>
        <?php
    });
});
add_action('admin_init', function() {
    register_setting('cf_ddns_settings_group', 'cf_ddns_reserved_keywords');
    add_settings_section('cf_ddns_main', '注册安全控制', null, 'cf-ddns-settings');
    add_settings_field('keywords', '保留关键词(逗号分隔)', function() {
        $val = get_option('cf_ddns_reserved_keywords', 'admin,www,api,root');
        echo '<textarea name="cf_ddns_reserved_keywords" rows="5" class="large-text">' . esc_textarea($val) . '</textarea>';
    }, 'cf-ddns-settings', 'cf_ddns_main');
});

/**
 * 6. 用户删除清理
 */
add_action('delete_user', function($user_id) {
    $user = get_userdata($user_id);
    if (!$user) return;
    $domain = $user->user_login . '.' . CF_DDNS_DOMAIN;
    $res = wp_remote_get("https://api.cloudflare.com/client/v4/zones/".CF_DDNS_ZONE_ID."/dns_records?name=$domain", ['headers'=>['Authorization'=>'Bearer '.CF_DDNS_TOKEN]]);
    $data = json_decode(wp_remote_retrieve_body($res), true);
    if (!empty($data['result'])) {
        foreach($data['result'] as $r) {
            wp_remote_request("https://api.cloudflare.com/client/v4/zones/".CF_DDNS_ZONE_ID."/dns_records/".$r['id'], ['method'=>'DELETE', 'headers'=>['Authorization'=>'Bearer '.CF_DDNS_TOKEN]]);
        }
    }
});

三、 辅助配套设置

用户管理优化:

    启用注册:设置 -> 常规 -> 成员资格(勾选“任何人都可以注册”)。

    固定链接:设置 -> 固定链接(选择“文章名”),确保 REST API 路由正常工作。

安全性补丁:

    禁止普通用户访问 /wp-admin(已包含在插件逻辑中)。

    隐藏前台管理工具栏。

邮件系统 (Gmail API):

    需求原因:解决服务器 PHP 邮件由于拦截率高无法发送激活链接的问题。

    核心流程:Google Cloud Console -> 启用 Gmail API -> 创建 OAuth 2.0 凭据 -> 插件授权接入。

四、 关键检查清单

Cloudflare 层面:

    SSL 模式:源站有证书建议 Full (完全),无证书选Flexible (灵活),配合 wp-config.php 的代理感知。

    Always Use HTTPS:开启。
    Automatic HTTPS Rewrites(自动 HTTPS 重写)

    页面规则:确保没有针对根目录设置导致子目录失效的规则。

插件层面:

    确保 CF_DDNS_DOMAIN 不包含协议头(如 yourdoamin.com 而非 http://...)。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部