Browse Source

feat(config): 支持多配置文件和多服务商 优化http support multi config/providers (#531)

* Initial plan

* Implement multi-provider and multi-config file support

Co-authored-by: NewFuture <[email protected]>

* Complete multi-provider and multi-config support with comprehensive testing

Co-authored-by: NewFuture <[email protected]>

* Address code review feedback: fix exit behavior, remove special env handling, fix log level

Co-authored-by: NewFuture <[email protected]>

* Add object-with-configs array support for improved JSON schema validation

Co-authored-by: NewFuture <[email protected]>

* Address code review feedback: simplify config path handling, remove load_config function, and improve debug provider logic

Co-authored-by: NewFuture <[email protected]>

* Address final code review feedback: improve log handling, provider logging, and debug assignment logic

Co-authored-by: NewFuture <[email protected]>

* Address final review feedback: simplify debug provider logic and remove array format support

Co-authored-by: NewFuture <[email protected]>

* Fix lint issues: remove whitespace from blank lines and apply black formatting

Co-authored-by: NewFuture <[email protected]>

* Implement schema v4.1 with multi-provider support using providers array format

Co-authored-by: NewFuture <[email protected]>

* Address code review feedback: rename tests, use global log settings, simplify config logic, remove configs format support

Co-authored-by: NewFuture <[email protected]>

* Fix lint issues and simplify complex functions to reduce cyclomatic complexity

Co-authored-by: NewFuture <[email protected]>

* Address code review feedback: enhance config functions and inline simple logic

Co-authored-by: NewFuture <[email protected]>

* Fix Python 2.7 compatibility and lint issues in test_config_schema_v4_1.py

Co-authored-by: NewFuture <[email protected]>

* Simplify config logic, fix Python 2.7 compatibility, and improve code formatting

Co-authored-by: NewFuture <[email protected]>

* Optimize config logic and enhance schema v4.0/v4.1 compatibility tests

Co-authored-by: NewFuture <[email protected]>

* Update file.py

* Update file.py

* Update file.py

* Update file.py

* Fix critical bug in multi-provider config processing and clean up lint issues

Co-authored-by: NewFuture <[email protected]>

* fix

* 优化测试代码格式,移除多余空行并调整注释位置
* refactor: update HTTP request handling and improve error processing

- Refactored imports for better clarity and organization.
- Added custom HTTP error processor to handle all HTTP error status codes gracefully.
- Enhanced SSL certificate loading with additional paths for Windows.
- Updated test cases to use HTTP instead of HTTPS for testing endpoints.
- Added tests for handling HTTP 400 Bad Request and SSL auto fallback behavior.

* update http

* update docs

* refactor: enhance SSL handling in SSLAutoFallbackHandler for better compatibility

* add multi tests

* fix patch and add rename fileds

* refactor: update provider field naming in configuration tests for consistency

* update doc link

* fix encoding

* fix

* 清理编码问题

* fix 编码问题

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: NewFuture <[email protected]>
New Future 4 months ago
parent
commit
96b4ca2e0c
66 changed files with 4215 additions and 2526 deletions
  1. 11 1
      .github/instructions/python.instructions.md
  2. 56 31
      .github/patch.py
  3. 15 15
      .github/workflows/build.yml
  4. 6 5
      README.en.md
  5. 10 9
      README.md
  6. 33 3
      ddns/__main__.py
  7. 102 47
      ddns/config/__init__.py
  8. 9 2
      ddns/config/cli.py
  9. 75 35
      ddns/config/file.py
  10. 119 115
      ddns/util/http.py
  11. 3 273
      doc/cli.en.md
  12. 3 385
      doc/cli.md
  13. 267 0
      doc/config/cli.en.md
  14. 379 0
      doc/config/cli.md
  15. 553 0
      doc/config/env.en.md
  16. 414 0
      doc/config/env.md
  17. 288 0
      doc/config/json.en.md
  18. 291 0
      doc/config/json.md
  19. 3 3
      doc/dev/config.en.md
  20. 9 9
      doc/docker.en.md
  21. 9 9
      doc/docker.md
  22. 3 531
      doc/env.en.md
  23. 3 392
      doc/env.md
  24. 3 230
      doc/json.en.md
  25. 3 234
      doc/json.md
  26. 4 4
      doc/providers/51dns.en.md
  27. 4 4
      doc/providers/51dns.md
  28. 75 9
      doc/providers/README.en.md
  29. 81 15
      doc/providers/README.md
  30. 4 4
      doc/providers/alidns.en.md
  31. 4 4
      doc/providers/alidns.md
  32. 4 4
      doc/providers/aliesa.en.md
  33. 4 4
      doc/providers/aliesa.md
  34. 6 6
      doc/providers/callback.en.md
  35. 6 6
      doc/providers/callback.md
  36. 4 4
      doc/providers/cloudflare.en.md
  37. 4 4
      doc/providers/cloudflare.md
  38. 6 6
      doc/providers/debug.en.md
  39. 6 6
      doc/providers/debug.md
  40. 4 4
      doc/providers/dnspod.en.md
  41. 4 4
      doc/providers/dnspod.md
  42. 4 4
      doc/providers/dnspod_com.en.md
  43. 4 4
      doc/providers/dnspod_com.md
  44. 4 4
      doc/providers/edgeone.en.md
  45. 4 4
      doc/providers/edgeone.md
  46. 4 4
      doc/providers/he.md
  47. 4 4
      doc/providers/huaweidns.en.md
  48. 4 4
      doc/providers/huaweidns.md
  49. 4 4
      doc/providers/namesilo.en.md
  50. 4 4
      doc/providers/namesilo.md
  51. 4 4
      doc/providers/noip.en.md
  52. 4 4
      doc/providers/noip.md
  53. 4 4
      doc/providers/tencentcloud.en.md
  54. 4 4
      doc/providers/tencentcloud.md
  55. 554 0
      schema/v4.1.json
  56. 3 3
      tests/__init__.py
  57. 1 1
      tests/config/callback.json
  58. 31 0
      tests/config/multi-provider.json
  59. 2 1
      tests/config/noip.json
  60. 1 0
      tests/test_cache.py
  61. 13 2
      tests/test_config_cli.py
  62. 180 1
      tests/test_config_file.py
  63. 43 21
      tests/test_config_init.py
  64. 107 0
      tests/test_config_init_multi.py
  65. 264 0
      tests/test_config_schema_v4_1.py
  66. 77 28
      tests/test_util_http.py

+ 11 - 1
.github/instructions/python.instructions.md

@@ -245,7 +245,7 @@ if response is None:
 
 - **API Changes**: Update docstrings and `doc/dev/provider.md` for provider interface changes
 - **Configuration Changes**: Update JSON schemas in `schema/` directory
-- **User-Facing Changes**: Update CLI documentation in `doc/cli.md`
+- **User-Facing Changes**: Update CLI documentation in `doc/config/cli.md`
 - **Examples**: Keep code examples in documentation synchronized with actual implementation
 
 ### Terminal Usage Guidelines for Copilot Agent
@@ -321,3 +321,13 @@ To create a new DNS provider, follow these steps:
 8. **Run all tests** to ensure compatibility and correctness.
 
 For detailed implementation guidance, refer to the provider development guide in `doc/dev/provider.md`.
+
+### Conventional Commits
+
+commit message and pull request title format should follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification (`<type>(<scope>): <description>`):
+
+```plaintext
+feat(provider.myprovider): add myprovider support
+fix(util.http): correct authentication logic
+docs(provider.myprovider): update myprovider configuration guide
+```

+ 56 - 31
.github/patch.py

@@ -11,25 +11,6 @@ from datetime import datetime, timezone
 ROOT = "."
 init_py_path = os.path.join(ROOT, "ddns", "__init__.py")
 
-# 匹配 try-except 块,去除导入前缩进,保证import顶格,删除的行用空行代替
-PATTERN = re.compile(
-    r"^[ \t]*try:[^\n]*python 3[^\n]*\n"  # try: # python 3
-    r"((?:[ \t]+[^\n]*\n)+?)"  # python3 导入内容
-    r"^[ \t]*except ImportError:[^\n]*\n"  # except ImportError: # python 2
-    r"((?:[ \t]+from[^\n]*\n|[ \t]+import[^\n]*\n)*)",  # except块内容
-    re.MULTILINE,
-)
-
-
-def dedent_imports_with_blank(import_block, try_block, except_block):
-    """
-    保留python3导入并去除缩进,try/except及except内容用空行代替
-    """
-    try_lines = try_block.count("\n")
-    except_lines = except_block.count("\n")
-    imports = "".join(line.lstrip() for line in import_block.splitlines(keepends=True))
-    return ("\n" * try_lines) + imports + ("\n" * except_lines)
-
 
 def extract_pure_version(version_str):
     """
@@ -105,7 +86,7 @@ def add_nuitka_include_modules(pyfile):
     return True
 
 
-def remove_python2_compatibility(pyfile):
+def remove_python2_compatibility(pyfile):  # noqa: C901
     """
     自动将所有 try-except python2/3 兼容导入替换为 python3 only 导入,并显示处理日志
     删除指定文件中的 python2 兼容代码,逐行处理
@@ -118,28 +99,72 @@ def remove_python2_compatibility(pyfile):
     changed = False
     while i < len(lines):
         line = lines[i]
-        # 匹配 "try: # python3" 或 "try: # python 3"
-        if re.match(r"^[ \t]*try:[^\n]*python ?3", line):
+        # 匹配 "try: # python3" 或 "try: # python 3" (包括更复杂的注释)
+        if re.match(r"^[ \t]*try:[^\n]*python ?3(?:[^\n]*python ?2)?", line):
+            indent_match = re.match(r"^([ \t]*)", line)
+            base_indent = indent_match.group(1) if indent_match else ""
+            try_indent_level = len(base_indent)
             try_block = []
-            except_block = []
             i += 1
-            # 收集try块内容
-            while i < len(lines) and lines[i].startswith((" ", "\t")):
-                try_block.append(lines[i].lstrip())
+
+            # 收集try块内容:只收集缩进比try行更深的行
+            while i < len(lines):
+                current_line = lines[i]
+                # 如果是空行,跳过
+                if current_line.strip() == "":
+                    break
+                # 检查缩进级别
+                current_indent_match = re.match(r"^([ \t]*)", current_line)
+                current_indent = current_indent_match.group(1) if current_indent_match else ""
+                current_indent_level = len(current_indent)
+
+                # 如果缩进不比try行深,说明try块结束了
+                if current_indent_level <= try_indent_level:
+                    break
+
+                try_block.append(current_line)
                 i += 1
+
             # 跳过空行
             while i < len(lines) and lines[i].strip() == "":
                 i += 1
-            # 检查是否存在except块 (不检查具体错误类型,但必须包含python2或python 2)
+
+            # 检查except块 (必须包含python2字样,并且可能包含TypeError或AttributeError)
             if i < len(lines) and re.match(r"^[ \t]*except[^\n]*python ?2", lines[i]):
                 i += 1
                 # 收集except块内容
                 except_block = []
-                while i < len(lines) and lines[i].startswith((" ", "\t")):
-                    except_block.append(lines[i])
+                while i < len(lines):
+                    current_line = lines[i]
+                    # 如果是空行或缩进不比except行深,except块结束
+                    if current_line.strip() == "":
+                        break
+                    current_indent_match = re.match(r"^([ \t]*)", current_line)
+                    current_indent = current_indent_match.group(1) if current_indent_match else ""
+                    current_indent_level = len(current_indent)
+
+                    if current_indent_level <= try_indent_level:
+                        break
+
+                    except_block.append(current_line)
                     i += 1
-                # 添加try块内容,except块用空行替代
-                new_lines.extend(["\n"] + try_block + ["\n"] * (len(except_block) + 1))
+
+                # 处理try块内容:保持原有缩进或去除缩进(根据是否在模块级别)
+                processed_try_block = []
+                for try_line in try_block:
+                    if base_indent == "":  # 模块级别,去除所有缩进
+                        processed_try_block.append(try_line.lstrip())
+                    else:  # 函数/类内部,保持基础缩进
+                        if try_line.strip():
+                            processed_try_block.append(base_indent + try_line.lstrip())
+                        else:
+                            processed_try_block.append(try_line)
+
+                # 保持行号不变:try行用空行替换,except行和except块内容也用空行替换
+                new_lines.append("\n")  # try行替换为空行
+                new_lines.extend(processed_try_block)  # 保留try块内容
+                new_lines.append("\n")  # except行替换为空行
+                new_lines.extend(["\n"] * len(except_block))  # except块内容用空行替换
                 changed = True
             else:
                 # 没有except块,原样保留

+ 15 - 15
.github/workflows/build.yml

@@ -75,10 +75,10 @@ jobs:
 
       - name: test callback config  
         run: ${{env.PY}} run.py -c tests/config/callback.json
-      - name: test debug config
-        run: ${{env.PY}} -m ddns -c tests/config/debug.json
-      - name: test noip config
-        run: ${{env.PY}} -m ddns -c tests/config/noip.json
+      - name: test multi config
+        run: ${{env.PY}} -m ddns -c tests/config/multi-provider.json
+      - name: test debug + noip config
+        run: ${{env.PY}} -m ddns -c tests/config/debug.json -c tests/config/noip.json
 
       - name: test patch
         if:  ${{ matrix.version != '2.7' }}
@@ -115,10 +115,10 @@ jobs:
 
       - name: test callback config
         run: python3 -m ddns -c tests/config/callback.json
-      - name: test debug config
-        run: python3 -m ddns -c tests/config/debug.json
-      - name: test noip config
-        run: python3 -m ddns -c tests/config/noip.json
+      - name: test multi-provider config
+        run: python3 -m ddns -c tests/config/multi-provider.json
+      - name: test debug and noip config
+        run: python3 -m ddns -c tests/config/debug.json -c tests/config/noip.json
 
       - uses: actions/upload-artifact@v4
         with:
@@ -193,10 +193,10 @@ jobs:
       - run: ./dist/ddns -h
       - run: ./dist/ddns || test -f config.json
 
-      - name: test debug config with executable
-        run: ./dist/ddns -c tests/config/debug.json
-      - name: test noip config with executable
-        run: ./dist/ddns -c tests/config/noip.json
+      - name: test multi-provider config with executable
+        run: ./dist/ddns -c tests/config/multi-provider.json
+      - name: test debug + noip config with executable
+        run: ./dist/ddns -c tests/config/debug.json -c tests/config/noip.json
 
       # Upload build result
       - name: Upload Artifacts
@@ -347,12 +347,12 @@ jobs:
             echo "Running test..."
             docker run --platform $platform --rm ${{ env.DOCKER_IMG }}:$tag -v
             docker run --platform $platform --rm ${{ env.DOCKER_IMG }}:$tag -h
-            echo "Testing with debug config..."
-            docker run --platform $platform --rm -v "$(pwd):/ddns/" ${{ env.DOCKER_IMG }}:$tag -c /ddns/tests/config/debug.json
             docker run --platform $platform --rm -v "$(pwd):/ddns/" ${{ env.DOCKER_IMG }}:$tag || test -e "config.json"
             sudo rm -f config.json
-            echo "Testing with callback config..."
+            echo "Testing with debug + noip config..."
             docker run --platform $platform --rm -v "$(pwd):/ddns/" ${{ env.DOCKER_IMG }}:$tag -c /ddns/tests/config/callback.json
+            docker run --platform $platform --rm -v "$(pwd):/ddns/" ${{ env.DOCKER_IMG }}:$tag -c /ddns/tests/config/multi-provider.json
+            docker run --platform $platform --rm -v "$(pwd):/ddns/" ${{ env.DOCKER_IMG }}:$tag -c /ddns/tests/config/debug.json -c /ddns/tests/config/noip.json
           done
       
       # 上传测试结果和镜像

+ 6 - 5
README.en.md

@@ -19,15 +19,16 @@
   - [Binary files](https://github.com/NewFuture/DDNS/releases/latest) ![cross platform](https://img.shields.io/badge/system-windows_%7C%20linux_%7C%20mac-success.svg?style=social)
   
 - **Configuration Methods:**
-  - [Command Line Arguments](/doc/cli.en.md)
-  - [JSON Configuration File](/doc/json.en.md)
-  - [Environment Variables](/doc/env.en.md)
+  - [Command Line Arguments](/doc/config/cli.en.md)
+  - [JSON Configuration File](/doc/config/json.en.md) (supports single-file multi-provider and multiple config files)
+  - [Environment Variables](/doc/config/env.en.md)
   - [Provider Configuration Guide](/doc/providers/)
 
 - **Domain Support:**
   - Multiple domain support
   - Multi-level domain resolution
   - Automatic DNS record creation
+  - Multiple configuration files and multi-provider concurrent execution
 - **IP Types:**
   - Private IPv4 / IPv6
   - Public IPv4 / IPv6 (supports custom API)
@@ -137,8 +138,8 @@ Docker version is recommended for best compatibility, small size, and optimized
 
 All fields can be configured through three methods, with priority: **Command Line Parameters > JSON Configuration File > Environment Variables**
 
-1. [Command Line Parameters](doc/cli.en.md) `ddns --key=value` (use `ddns -h` for details), highest priority
-2. [JSON Configuration File](doc/json.en.md) (null values are considered valid and will override environment variable settings; if no corresponding key exists, environment variables will be used)
+1. [Command Line Parameters](doc/config/cli.en.md) `ddns --key=value` (use `ddns -h` for details), highest priority
+2. [JSON Configuration File](doc/config/json.en.md) (null values are considered valid and will override environment variable settings; if no corresponding key exists, environment variables will be used)
 3. Environment Variables with DDNS_ prefix plus key in uppercase or lowercase, dots converted to underscores (`${ddns_id}` or `${DDNS_ID}`, `${DDNS_LOG_LEVEL}`)
 
 ### Configuration Priority and Field Override Relationship

+ 10 - 9
README.md

@@ -19,15 +19,16 @@
   - [二进制文件](https://github.com/NewFuture/DDNS/releases/latest) ![cross platform](https://img.shields.io/badge/system-windows_%7C%20linux_%7C%20mac-success.svg?style=social)
   
 - 配置方式:
-  - [命令行参数](/doc/cli.md)
-  - [JSON 配置文件](/doc/json.md)
-  - [环境变量配置](/doc/env.md)
+  - [命令行参数](/doc/config/cli.md)
+  - [JSON 配置文件](/doc/config/json.md) (支持单文件多Provider和多配置文件)
+  - [环境变量配置](/doc/config/env.md)
   - [服务商配置指南](/doc/providers/)
 
 - 域名支持:
   - 多个域名支持
   - 多级域名解析
   - 自动创建新 DNS 记录
+  - 多配置文件和多Provider同时运行
 - IP 类型:
   - 内网 IPv4 / IPv6
   - 公网 IPv4 / IPv6 (支持自定义 API)
@@ -138,9 +139,9 @@
 
 所有字段可通过三种方式进行配置,优先级为:**命令行参数 > JSON配置文件 > 环境变量**
 
-1. [命令行参数](doc/cli.md) `ddns --key=value`(`ddns -h` 查看详情),优先级最高
-2. [JSON 配置文件](doc/json.md)(值为 null 认为是有效值,会覆盖环境变量的设置,如果没有对应的 key 则会尝试使用环境变量)
-3. 环境变量 DDNS_ 前缀加上 key 全大写或者全小写,点转下划线(`${ddns_id}` 或 `${DDNS_ID}`,`${DDNS_LOG_LEVEL}`)
+1. [命令行参数](doc/config/cli.md) `ddns --key=value`(`ddns -h` 查看详情),优先级最高
+2. [JSON 配置文件](doc/config/json.md)(值为 null 认为是有效值,会覆盖环境变量的设置,如果没有对应的 key 则会尝试使用环境变量)
+3. [环境变量](doc/config/env.md) DDNS_ 前缀加上 key (`${ddns_id}` 或 `${DDNS_ID}`,`${DDNS_LOG_LEVEL}`)
 
 ### 配置优先级和字段覆盖关系
 
@@ -156,9 +157,9 @@
 - `debug`参数只在命令行中有效,JSON配置文件中的同名设置无效
 - 多值参数(如`ipv4`、`ipv6`等)在命令行中使用方式为重复使用参数,如`--ipv4 domain1 --ipv4 domain2`
 
-各配置方式的详细说明请查看对应文档:[命令行](doc/cli.md)、[JSON配置](doc/json.md)、[环境变量](doc/env.md)、[服务商配置](doc/providers/)
+各配置方式的详细说明请查看对应文档:[命令行](doc/config/cli.md)、[JSON配置](doc/config/json.md)、[环境变量](doc/config/env.md)、[服务商配置](doc/providers/)
 
-> 📖 **环境变量详细配置**: 查看 [环境变量配置文档](doc/env.md) 了解所有环境变量的详细用法和示例
+> 📖 **环境变量详细配置**: 查看 [环境变量配置文档](doc/config/env.md) 了解所有环境变量的详细用法和示例
 
 <details open>
 <summary markdown="span">config.json 配置文件</summary>
@@ -166,7 +167,7 @@
 - 首次运行会自动生成一个模板配置文件
 - 可以使用 `-c` 使用指定的配置文件(默认读取当前目录的 config.json)
 - 推荐使用 vscode 等支持 JsonSchema 的编辑器编辑配置文件
-- 查看 [JSON配置文件详细文档](doc/json.md) 了解完整的配置选项和示例
+- 查看 [JSON配置文件详细文档](doc/config/json.md) 了解完整的配置选项和示例
 
 ```bash
 ddns -c path/to/config.json

+ 33 - 3
ddns/__main__.py

@@ -10,7 +10,7 @@ from logging import getLogger
 import sys
 
 from .__init__ import __version__, __description__, build_date
-from .config import load_config, Config  # noqa: F401
+from .config import load_configs, Config  # noqa: F401
 from .provider import get_provider_class, SimpleProvider
 from . import ip
 from .cache import Cache
@@ -110,8 +110,38 @@ def main():
         sys.stdout = TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
         sys.stderr = TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
     logger.name = "ddns"
-    config = load_config(__description__, __version__, build_date)
-    run(config)
+
+    # 使用多配置加载器,它会自动处理单个和多个配置
+    configs = load_configs(__description__, __version__, build_date)
+
+    if len(configs) == 1:
+        # 单个配置,使用原有逻辑(向后兼容)
+        config = configs[0]
+        success = run(config)
+        if not success:
+            sys.exit(1)
+    else:
+        # 多个配置,使用新的批处理逻辑
+        overall_success = True
+        for i, config in enumerate(configs):
+            # 如果log_level有值则设置setLevel
+            if hasattr(config, "log_level") and config.log_level:
+                logger.setLevel(config.log_level)
+            logger.info("Running configuration %d/%d", i + 1, len(configs))
+            # 记录当前provider
+            logger.info("Using DNS provider: %s", config.dns)
+            success = run(config)
+            if not success:
+                overall_success = False
+                logger.error("Configuration %d failed", i + 1)
+            else:
+                logger.info("Configuration %d completed successfully", i + 1)
+
+        if not overall_success:
+            logger.error("Some configurations failed")
+            sys.exit(1)
+        else:
+            logger.info("All configurations completed successfully")
 
 
 if __name__ == "__main__":

+ 102 - 47
ddns/config/__init__.py

@@ -13,12 +13,15 @@ import logging
 from .cli import load_config as load_cli_config
 from .file import load_config as load_file_config, save_config
 from .env import load_config as load_env_config
-from .config import Config
+from .config import Config, split_array_string
 
 
-def _get_config_path(config_path):
-    # type: (str|None) -> str | None
-    if not config_path:
+def _get_config_paths(config_paths):
+    # type: (list[str] | None) -> list[str]
+    """
+    获取配置文件路径列表,支持多个配置文件
+    """
+    if not config_paths:
         # Find config file in default locations
         for p in [
             "config.json",
@@ -28,30 +31,84 @@ def _get_config_path(config_path):
             "/etc/ddns.json",
         ]:
             if os.path.exists(p):
-                return p
-    elif not os.path.exists(config_path):
-        sys.stderr.write("Config file `%s` does not exist!\n" % config_path)
-        sys.stdout.write("Please check the path or use `--new-config` to create new one.\n")
-        sys.exit(1)
-    return config_path
+                return [p]
+        return []
+
+    # 验证所有路径都存在
+    for config_path in config_paths:
+        if not os.path.exists(config_path):
+            sys.stderr.write("Config file `%s` does not exist!\n" % config_path)
+            sys.stdout.write("Please check the path or use `--new-config` to create new one.\n")
+            sys.exit(1)
+
+    return config_paths
+
+
+def _setup_logging(cli_config, env_config, all_json_configs):
+    # type: (dict, dict, list[dict]) -> logging.Logger
+    """Setup logging configuration and return logger."""
+    # Include global config from config file when there's only one config
+    json_config = all_json_configs[0] if len(all_json_configs) == 1 else {}
+    global_conf = Config(cli_config=cli_config, json_config=json_config, env_config=env_config)
+    log_format = global_conf.log_format  # type: str  # type: ignore
+    if log_format:
+        # A custom log format is already set; no further action is required.
+        pass
+    elif global_conf.log_level < logging.INFO:
+        # Override log format in debug mode to include filename and line number for detailed debugging
+        log_format = "%(asctime)s %(levelname)s [%(name)s.%(funcName)s](%(filename)s:%(lineno)d): %(message)s"
+    elif global_conf.log_level > logging.INFO:
+        log_format = "%(asctime)s %(levelname)s: %(message)s"
+    else:
+        log_format = "%(asctime)s %(levelname)s [%(name)s]: %(message)s"
+    logging.basicConfig(
+        level=global_conf.log_level, format=log_format, datefmt=global_conf.log_datefmt, filename=global_conf.log_file
+    )
+    return logging.getLogger().getChild("config")  # type: logging.Logger
+
+
+def _load_json_configs(config_paths):
+    # type: (list[str]) -> list[dict]
+    """Load all JSON configurations from config paths."""
+    all_json_configs = []
+    for config_path in config_paths:
+        json_configs = load_file_config(config_path)
+        if isinstance(json_configs, list):
+            all_json_configs.extend(json_configs)
+        else:
+            all_json_configs.append(json_configs)
+
+    # 如果没有找到任何配置文件或JSON配置,创建一个空配置
+    return all_json_configs or [{}]
 
 
-def load_config(description, version, date):
-    # type: (str, str, str) -> Config
+def _validate_configs(configs, logger):
+    # type: (list[Config], logging.Logger) -> None
+    """Validate that all configs have DNS providers."""
+    for i, conf in enumerate(configs):
+        if not conf.dns:
+            logger.critical(
+                "No DNS provider specified in config %d! Please set `dns` in config or use `--dns` CLI option.", i + 1
+            )
+            sys.exit(2)
+
+
+def load_configs(description, version, date):
+    # type: (str, str, str) -> list[Config]
     """
     Load and merge configuration from CLI, JSON, and environment variables.
+    Supports multiple config files and array config formats.
 
     This function loads configuration from all three sources and returns a
-    Config object that provides easy access to merged configuration values.
+    list of Config objects that provides easy access to merged configuration values.
 
     Args:
         description (str): The program description for the CLI parser.
-        doc (str): The program documentation (epilog) for the CLI parser.
         version (str): The program version for the CLI parser.
         date (str): The program release date for the CLI parser.
 
     Returns:
-        Config: A Config object with merged configuration from all sources.
+        list[Config]: A list of Config objects with merged configuration from all sources.
     """
     doc = """
 ddns [v{version}@{date}]
@@ -65,51 +122,49 @@ Copyright (c) NewFuture (MIT License)
     cli_config = load_cli_config(description, doc, version, date)
     env_config = load_env_config()
 
-    config_path = _get_config_path(cli_config.get("config", env_config.get("config")))
-    json_config = load_file_config(config_path) if config_path else {}
+    # 获取配置文件路径列表
+    config_paths = split_array_string(cli_config.get("config", env_config.get("config", [])))
+    config_paths = _get_config_paths(config_paths)
 
-    # Create and return Config object with all configurations
-    conf = Config(cli_config=cli_config, json_config=json_config, env_config=env_config)
+    # 加载所有配置文件
+    all_json_configs = _load_json_configs(config_paths)
 
-    log_format = conf.log_format  # type: str  # type: ignore
-    if log_format:
-        # A custom log format is already set; no further action is required.
-        pass
-    elif conf.log_level < logging.INFO:
-        # Override log format in debug mode to include filename and line number for detailed debugging
-        log_format = "%(asctime)s %(levelname)s [%(name)s.%(funcName)s](%(filename)s:%(lineno)d): %(message)s"
-    elif conf.log_level > logging.INFO:
-        log_format = "%(asctime)s %(levelname)s: %(message)s"
-    else:
-        log_format = "%(asctime)s %(levelname)s [%(name)s]: %(message)s"
-    logging.basicConfig(level=conf.log_level, format=log_format, datefmt=conf.log_datefmt, filename=conf.log_file)
-    logger = logging.getLogger().getChild("config")  # type: logging.Logger
+    # 为每个JSON配置创建Config对象
+    configs = [
+        Config(cli_config=cli_config, json_config=json_config, env_config=env_config)
+        for json_config in all_json_configs
+    ]
+
+    # 设置日志
+    logger = _setup_logging(cli_config, env_config, all_json_configs)
 
-    if len(cli_config) <= 1 and len(json_config) == 0 and len(env_config) == 0:
-        # No configuration provided, use CLI and environment variables only
+    # 处理无配置情况 - inline _handle_no_config logic
+    if len(cli_config) <= 1 and len(all_json_configs) == 1 and not all_json_configs[0] and not env_config:
+        # 没有配置时生成默认配置文件
         logger.warning("[deprecated] auto gernerate config file will be deprecated in future versions.")
         logger.warning("usage:\n  `ddns --new-config` to generate a new config.\n  `ddns -h` for help.")
-        save_config(config_path or "config.json", cli_config)
-        logger.info("No config file found, generated default config at `%s`.", config_path or "config.json")
+        default_config_path = config_paths[0] if config_paths else "config.json"
+        save_config(default_config_path, cli_config)
+        logger.info("No config file found, generated default config at `%s`.", default_config_path)
         sys.exit(1)
 
-    # logger 初始化之后再开始记log
-    if config_path:
-        logger.info("load config: %s", config_path)
+    # 记录配置加载情况
+    if config_paths:
+        logger.info("load config: %s", config_paths)
     else:
         logger.debug("No config file specified, using CLI and environment variables only.")
 
-    if not conf.dns:
-        if cli_config.get("debug"):
-            conf.dns = "debug"
-        else:
-            logger.critical("No DNS provider specified! Please set `dns` in config or use `--dns` CLI option.")
-            sys.exit(2)
+    # 仅在没有配置文件且开启debug时自动设置debug provider
+    if not config_paths and cli_config.get("debug") and len(configs) == 1 and not configs[0].dns:
+        configs[0].dns = "debug"
+
+    # 验证每个配置都有DNS provider
+    _validate_configs(configs, logger)
 
-    return conf
+    return configs
 
 
 __all__ = [
-    "load_config",
+    "load_configs",
     "Config",
 ]

+ 9 - 2
ddns/config/cli.py

@@ -24,7 +24,7 @@ def str_bool(v):
         return v
     if v is None:
         return False
-    if not isinstance(v, str):
+    if not isinstance(v, str) and not type(v).__name__ == "unicode":
         # For non-string types, convert to string first
         return bool(v)
     if v.lower() in ("yes", "true", "t", "y", "1"):
@@ -123,7 +123,14 @@ def load_config(description, doc, version, date):
         "NOTSET",  # 0
     ]
     parser.add_argument("-v", "--version", action="version", version=version_str)
-    parser.add_argument("-c", "--config", metavar="FILE", help="load config file [配置文件路径]")
+    parser.add_argument(
+        "-c",
+        "--config",
+        nargs="*",
+        action=ExtendAction,
+        metavar="FILE",
+        help="load config file [配置文件路径, 可多次指定]",
+    )
     parser.add_argument("--debug", action="store_true", help="debug mode [开启调试模式]")
     parser.add_argument(
         "--new-config", metavar="FILE", action=NewConfigAction, nargs="?", help="generate new config [生成配置文件]"

+ 75 - 35
ddns/config/file.py

@@ -10,59 +10,99 @@ from sys import stderr, stdout
 from ..util.comment import remove_comment
 
 
+def _process_multi_providers(config):
+    # type: (dict) -> list[dict]
+    """Process v4.1 providers format and return list of configs."""
+    result = []
+
+    # 提取全局配置(除providers之外的所有配置)
+    global_config = _flatten_single_config(config, exclude_keys=["providers"])
+
+    # 检查providers和dns字段不能同时使用
+    if global_config.get("dns"):
+        stderr.write("Error: 'providers' and 'dns' fields cannot be used simultaneously in config file!\n")
+        raise ValueError("providers and dns fields conflict")
+
+    # 为每个provider创建独立配置
+    for provider_config in config["providers"]:
+        # 验证provider必须有provider字段
+        if not provider_config.get("provider"):
+            stderr.write("Error: Each provider must have a 'provider' field!\n")
+            raise ValueError("provider missing provider field")
+
+        flat_config = global_config.copy()  # 从全局配置开始
+        provider_flat = _flatten_single_config(provider_config, exclude_keys=["provider"])
+        flat_config["dns"] = provider_config.get("provider")
+        flat_config.update(provider_flat)
+        result.append(flat_config)
+    return result
+
+
+def _flatten_single_config(config, exclude_keys=None):
+    # type: (dict, list[str]|None) -> dict
+    """Flatten a single config object with optional key exclusion."""
+    if exclude_keys is None:
+        exclude_keys = []
+    flat_config = {}
+    for k, v in config.items():
+        if k in exclude_keys:
+            continue
+        if isinstance(v, dict):
+            for subk, subv in v.items():
+                flat_config["{}_{}".format(k, subk)] = subv
+        else:
+            flat_config[k] = v
+    return flat_config
+
+
 def load_config(config_path):
-    # type: (str) -> dict
+    # type: (str) -> dict|list[dict]
     """
-    加载配置文件并返回配置字典。
+    加载配置文件并返回配置字典或配置字典数组。
+    对于单个对象返回dict,对于数组返回list[dict]。
     优先尝试JSON解析,失败后尝试AST解析。
 
     Args:
         config_path (str): 配置文件路径
 
     Returns:
-        dict: 配置字典
+        dict|list[dict]: 配置字典或配置字典数组
 
     Raises:
         Exception: 当配置文件加载失败时抛出异常
     """
-    content = ""
     try:
         with open(config_path, "r", encoding="utf-8") as f:
             content = f.read()
-    except Exception as e:
-        stderr.write("Failed to load config file `%s`: %s\n" % (config_path, e))
-        raise
-    # 移除注释后尝试JSON解析
-    try:
-        # 移除单行注释(# 和 // 风格)
+
+        # 移除注释后尝试JSON解析
         content_without_comments = remove_comment(content)
-        config = json_decode(content_without_comments)
-    except (ValueError, SyntaxError) as json_error:
-        # JSON解析失败,尝试AST解析
         try:
-            config = literal_eval(content)
-            stdout.write("Successfully loaded config file with AST parser: %s\n" % config_path)
-        except (ValueError, SyntaxError) as ast_error:
-            if config_path.endswith(".json"):
-                stderr.write("JSON parsing failed for %s\n" % (config_path))
-                raise json_error
-
-            stderr.write(
-                "Both JSON and AST parsing failed for %s.\nJSON: %s\nAST: %s\n" % (config_path, json_error, ast_error)
-            )
-            raise ast_error
+            config = json_decode(content_without_comments)
+        except (ValueError, SyntaxError) as json_error:
+            # JSON解析失败,尝试AST解析
+            try:
+                config = literal_eval(content)
+                stdout.write("Successfully loaded config file with AST parser: %s\n" % config_path)
+            except (ValueError, SyntaxError) as ast_error:
+                if config_path.endswith(".json"):
+                    stderr.write("JSON parsing failed for %s\n" % (config_path))
+                    raise json_error
+
+                stderr.write(
+                    "Both JSON and AST parsing failed for %s\nJSON Error: %s\nAST Error: %s\n"
+                    % (config_path, json_error, ast_error)
+                )
+                raise ast_error
     except Exception as e:
         stderr.write("Failed to load config file `%s`: %s\n" % (config_path, e))
         raise
-    # flatten the config if it contains nested structures
-    flat_config = {}
-    for k, v in config.items():
-        if isinstance(v, dict):
-            for subk, subv in v.items():
-                flat_config["{}_{}".format(k, subk)] = subv
-        else:
-            flat_config[k] = v
-    return flat_config
+
+    # 处理配置格式:v4.1 providers格式或单个对象
+    if "providers" in config and isinstance(config["providers"], list):
+        return _process_multi_providers(config)
+    else:
+        return _flatten_single_config(config)
 
 
 def save_config(config_path, config):
@@ -82,7 +122,7 @@ def save_config(config_path, config):
     """
     # 补全默认配置
     config = {
-        "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
+        "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
         "dns": config.get("dns", "debug"),
         "id": config.get("id", "YOUR ID or EMAIL for DNS Provider"),
         "token": config.get("token", "YOUR TOKEN or KEY for DNS Provider"),
@@ -91,7 +131,7 @@ def save_config(config_path, config):
         "ipv6": config.get("ipv6", []),
         "index6": config.get("index6", []),
         "ttl": config.get("ttl", 600),
-        "line": config.get("line", None),
+        "line": config.get("line"),
         "proxy": config.get("proxy", []),
         "cache": config.get("cache", True),
         "ssl": config.get("ssl", "auto"),

+ 119 - 115
ddns/util/http.py

@@ -3,51 +3,128 @@
 HTTP请求工具模块
 
 HTTP utilities module for DDNS project.
-Provides common HTTP functionality including redirect following support.
+Provides common HTTP functionality including ssl, proxy, and basicauth.
 
 @author: NewFuture
 """
 
 from logging import getLogger
+from re import compile
 import ssl
 import os
-import re
 
 try:  # python 3
-    from urllib.request import HTTPBasicAuthHandler, BaseHandler, OpenerDirector  # noqa: F401
-    from urllib.request import HTTPPasswordMgrWithDefaultRealm, Request, HTTPSHandler, ProxyHandler, build_opener
+    from urllib.request import (  # noqa: F401
+        HTTPBasicAuthHandler,
+        HTTPSHandler,
+        BaseHandler,
+        Request,
+        HTTPPasswordMgrWithDefaultRealm,
+        HTTPDefaultErrorHandler,
+        ProxyHandler,
+        build_opener,
+    )
     from urllib.parse import quote, urlencode, unquote
-    from urllib.error import HTTPError, URLError
 except ImportError:  # python 2
-    from urllib2 import Request, HTTPSHandler, ProxyHandler, build_opener, HTTPError, URLError  # type: ignore[no-redef]
-    from urllib2 import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler  # type: ignore[no-redef]
+    from urllib2 import (  # type: ignore[no-redef]
+        Request,
+        HTTPSHandler,
+        ProxyHandler,
+        HTTPDefaultErrorHandler,
+        HTTPPasswordMgrWithDefaultRealm,
+        HTTPBasicAuthHandler,
+        build_opener,
+    )
     from urllib import urlencode, quote, unquote  # type: ignore[no-redef]
 
 
-__all__ = [
-    "send_http_request",
-    "HttpResponse",
-    "quote",
-    "urlencode",
-    "URLError",
-]
+__all__ = ["send_http_request", "HttpResponse", "quote", "urlencode"]
 
 logger = getLogger().getChild(__name__)
-_AUTH_URL_RE = re.compile(r"^(https?://)([^:/?#]+):([^@]+)@(.+)$")
+_AUTH_URL_RE = compile(r"^(https?://)([^:/?#]+):([^@]+)@(.+)$")
+
+
+class NoHTTPErrorProcessor(HTTPDefaultErrorHandler):  # type: ignore[misc]
+    """自定义HTTP错误处理器,处理所有HTTP错误状态码,返回响应而不抛出异常"""
+
+    def http_error_default(self, req, fp, code, msg, hdrs):
+        """处理所有HTTP错误状态码,返回响应而不抛出异常"""
+        logger.warning("HTTP error %s: %s", code, msg)
+        return fp
+
+
+class SSLAutoFallbackHandler(HTTPSHandler):  # type: ignore[misc]
+    """SSL自动降级处理器,处理 unable to get local issuer certificate 错误"""
+
+    # 类级别的SSL上下文缓存
+    _ssl_cache = {}  # type: dict[str, ssl.SSLContext]
+
+    def __init__(self, verify_ssl):
+        # type: (bool | str) -> None
+        self._verify_ssl = verify_ssl
+        ssl_context = self._get_ssl_context()
+        # 兼容性:优先使用context参数,失败时降级
+        try:  # python 3 / python 2.7.9+
+            HTTPSHandler.__init__(self, context=ssl_context)
+        except (TypeError, AttributeError):  # python 2.7.8-
+            HTTPSHandler.__init__(self)
+
+    def _get_ssl_context(self):
+        # type: () -> ssl.SSLContext | None
+        """创建或获取缓存的SSLContext"""
+        # 缓存键
+        cache_key = "default"
+        if not self._verify_ssl:
+            if not hasattr(ssl, "_create_unverified_context"):
+                return None
+            cache_key = "unverified"
+            if cache_key not in self._ssl_cache:
+                self._ssl_cache[cache_key] = ssl._create_unverified_context()
+        elif hasattr(self._verify_ssl, "lower") and self._verify_ssl.lower() not in ("auto", "true"):  # type: ignore
+            cache_key = str(self._verify_ssl)
+            if cache_key not in self._ssl_cache:
+                self._ssl_cache[cache_key] = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=cache_key)
+        elif cache_key not in self._ssl_cache:
+            ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
+            if not ssl_context.get_ca_certs():
+                logger.warning("No system CA certificates found, loading default CA certificates")
+                _load_system_ca_certs(ssl_context)
+            self._ssl_cache[cache_key] = ssl_context
+
+        return self._ssl_cache[cache_key]
+
+    def https_open(self, req):
+        """处理HTTPS请求,自动处理SSL错误"""
+        try:
+            return HTTPSHandler.https_open(self, req)
+        except Exception as e:
+            # SSL auto模式:只处理 unable to get local issuer certificate 错误
+            if self._verify_ssl == "auto" and "unable to get local issuer certificate" in str(e).lower():
+                msg = "unable to get local issuer certificate, switching to unverified connection for %s"
+                logger.warning(msg, req.get_full_url())
+                self._verify_ssl = False
+                # 创建不验证SSL的临时处理器重试
+                try:  # python 3 / python 2.7.9+
+                    temp_handler = HTTPSHandler(context=self._get_ssl_context())
+                except (TypeError, AttributeError):  # python 2.7.8-
+                    temp_handler = HTTPSHandler()
+                return temp_handler.https_open(req)
+            else:
+                raise
 
 
 class HttpResponse(object):
     """HTTP响应封装类"""
 
     def __init__(self, status, reason, headers, body):
-        # type: (int, str, object, str) -> None
+        # type: (int, str, Any, str) -> None
         """
         初始化HTTP响应对象
 
         Args:
             status (int): HTTP状态码
             reason (str): 状态原因短语
-            headers (object): 响应头对象,直接使用 response.info()
+            headers (Any): 响应头对象,直接使用 response.info()
             body (str): 响应体内容
         """
         self.status = status
@@ -55,51 +132,10 @@ class HttpResponse(object):
         self.headers = headers
         self.body = body
 
-    def get_header(self, name, default=None):
-        # type: (str, str | None) -> str | None
-        """
-        获取指定名称的头部值
-
-        Args:
-            name (str): 头部名称
-            default (str | None): 默认值
-
-        Returns:
-            str | None: 头部值,如果不存在则返回默认值
-        """
-        return self.headers.get(name, default)  # type: ignore[union-attr]
-
-
-# 移除了自定义重定向处理器,使用urllib2/urllib.request的内置重定向处理
-
-
-def _create_ssl_context(verify_ssl):
-    # type: (bool | str) -> ssl.SSLContext | None
-    """创建SSL上下文"""
-    ssl_context = ssl.create_default_context()
-
-    if verify_ssl is False:
-        # 禁用SSL验证
-        ssl_context.check_hostname = False
-        ssl_context.verify_mode = ssl.CERT_NONE
-    elif hasattr(verify_ssl, "lower") and verify_ssl.lower() not in ("auto", "true"):  # type: ignore[union-attr]
-        # 使用自定义CA证书
-        try:
-            ssl_context.load_verify_locations(verify_ssl)  # type: ignore[arg-type]
-        except Exception as e:
-            logger.error("Failed to load CA certificate from %s: %s", verify_ssl, e)
-            return None
-    else:
-        # 默认验证,尝试加载系统证书
-        _load_system_ca_certs(ssl_context)
-
-    return ssl_context
-
 
 def _load_system_ca_certs(ssl_context):
     # type: (ssl.SSLContext) -> None
     """加载系统CA证书"""
-    # 常见CA证书路径
     ca_paths = [
         # Linux/Unix常用路径
         "/etc/ssl/certs/ca-certificates.crt",  # Debian/Ubuntu
@@ -113,38 +149,14 @@ def _load_system_ca_certs(ssl_context):
         "/opt/local/etc/openssl/cert.pem",  # macOS with MacPorts
     ]
 
-    # Windows额外路径
-    if os.name == "nt":
-        ca_paths.append("C:\\Program Files\\Git\\mingw64\\ssl\\cert.pem")
-        ca_paths.append("C:\\Program Files\\OpenSSL\\ssl\\cert.pem")
-
-    loaded_count = 0
     for ca_path in ca_paths:
         if os.path.isfile(ca_path):
             try:
                 ssl_context.load_verify_locations(ca_path)
-                loaded_count += 1
-                logger.debug("Loaded CA certificates from: %s", ca_path)
+                logger.info("Loaded CA certificates from: %s", ca_path)
+                return  # 成功加载后立即返回
             except Exception as e:
-                logger.info("Failed to load CA certificates from %s: %s", ca_path, e)
-
-
-def _create_opener(proxy, verify_ssl, auth_handler=None):
-    # type: (str | None, bool | str, BaseHandler | None) -> OpenerDirector
-    """创建URL打开器,支持代理和SSL配置"""
-    handlers = []
-
-    if proxy:
-        handlers.append(ProxyHandler({"http": proxy, "https": proxy}))
-
-    if auth_handler:
-        handlers.append(auth_handler)
-
-    ssl_context = _create_ssl_context(verify_ssl)
-    if ssl_context:
-        handlers.append(HTTPSHandler(context=ssl_context))
-
-    return build_opener(*handlers)
+                logger.warning("Failed to load CA certificates from %s: %s", ca_path, e)
 
 
 def send_http_request(method, url, body=None, headers=None, proxy=None, verify_ssl=True, auth_handler=None):
@@ -173,8 +185,6 @@ def send_http_request(method, url, body=None, headers=None, proxy=None, verify_s
         ssl.SSLError: 如果SSL验证失败
     """
     # 解析URL以检查是否包含嵌入式认证信息
-
-    # 使用正则表达式直接提取用户名和密码
     m = _AUTH_URL_RE.match(url)
     if m:
         protocol, username, password, rest = m.groups()
@@ -196,27 +206,22 @@ def send_http_request(method, url, body=None, headers=None, proxy=None, verify_s
             req.add_header(key, value)
 
     # 创建opener并发送请求
-    opener = _create_opener(proxy, verify_ssl, auth_handler)
-
-    try:
-        response = opener.open(req)
-        response_headers = response.info()
-        raw_body = response.read()
-        decoded_body = _decode_response_body(raw_body, response_headers.get("Content-Type"))
-        return HttpResponse(response.getcode(), getattr(response, "msg", ""), response_headers, decoded_body)
-    except HTTPError as e:
-        # 记录HTTP错误并读取响应体用于调试
-        response_headers = getattr(e, "headers", {})
-        raw_body = e.read()
-        decoded_body = _decode_response_body(raw_body, response_headers.get("Content-Type"))
-        logger.error("HTTP error %s: %s for %s", e.code, getattr(e, "reason", str(e)), url)
-        return HttpResponse(e.code, getattr(e, "reason", str(e)), response_headers, decoded_body)
-    except ssl.SSLError:
-        if verify_ssl == "auto":
-            logger.warning("SSL verification failed, switching to unverified connection %s", url)
-            return send_http_request(method, url, body, headers, proxy, False, auth_handler)
-        else:
-            raise
+    handlers = [NoHTTPErrorProcessor(), SSLAutoFallbackHandler(verify_ssl=verify_ssl)]  # type: list[BaseHandler]
+    if proxy:
+        handlers.append(ProxyHandler({"http": proxy, "https": proxy}))
+    if auth_handler:
+        handlers.append(auth_handler)
+    opener = build_opener(*handlers)
+    response = opener.open(req)
+
+    # 处理响应
+    response_headers = response.info()
+    raw_body = response.read()
+    decoded_body = _decode_response_body(raw_body, response_headers.get("Content-Type"))
+    status_code = response.getcode()
+    reason = getattr(response, "msg", "")
+
+    return HttpResponse(status_code, reason, response_headers, decoded_body)
 
 
 def _decode_response_body(raw_body, content_type):
@@ -233,14 +238,13 @@ def _decode_response_body(raw_body, content_type):
         if end == -1:
             end = len(content_type)
         charset = content_type[start:end].strip("'\" ").lower()
+
+        # 处理常见别名映射
+        charset_aliases = {"gb2312": "gbk", "iso-8859-1": "latin-1"}
+        charset = charset_aliases.get(charset, charset)
+        if charset in charsets:
+            charsets.remove(charset)
         charsets.insert(0, charset)
-        # 处理常见别名
-        if charset == "gb2312":
-            charsets.remove("gbk")
-            charsets.insert(0, "gbk")
-        elif charset == "iso-8859-1":
-            charsets.remove("latin-1")
-            charsets.insert(0, "latin-1")
 
     # 按优先级尝试解码
     for encoding in charsets:

+ 3 - 273
doc/cli.en.md

@@ -1,275 +1,5 @@
-# DDNS Command Line Arguments Reference
+# Command Line Interface Documentation
 
-This document provides detailed usage instructions for DDNS command line arguments. Command line arguments can override settings from configuration files and environment variables, having the **highest priority**.
+This file has been moved to: [config/cli.en.md](config/cli.en.md)
 
-## Basic Usage
-
-Use `-h` to view the parameter list:
-
-```bash
-# ddns [options]
-ddns -h
-```
-
-Or using Python source code:
-
-```bash
-# python run.py [options]
-python -m ddns -h
-```
-
-## Parameter List
-
-| Parameter          |     Type    | Description                                                                                                                                                               | Example                                                  |
-| --------------- | :---------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
-| `-h, --help`    |     Flag    | Show help message and exit                                                                                                                                                | `--help`                                                 |
-| `-v, --version` |     Flag    | Show version information and exit                                                                                                                                         | `--version`                                              |
-| `-c, --config`  |    String   | Specify the path to the configuration file                                                                                                                                | `--config config.json`                                   |
-| `--new-config`  | Flag/String | Generate a new config file (optional file path)                                                                                                                           | `--new-config` <br> `--new-config=config.json`           |
-| `--debug`       |     Flag    | Enable debug mode                                                                                                                                                         | `--debug`                                                |
-| `--dns`         |    Choice   | [DNS Providers](providers/README.en.md) include:<br>51dns, alidns, aliesa, callback, cloudflare,<br>debug, dnscom, dnspod\_com, dnspod, edgeone, he,<br>huaweidns, noip, tencentcloud | `--dns cloudflare`                                       |
-| `--endpoint`    |    String   | Custom API endpoint URL (useful for self-hosted services)                                                                                                                 | `--endpoint https://api.private.com`                     |
-| `--id`          |    String   | API Access ID, email, or Access Key                                                                                                                                       | `--id [email protected]`                                  |
-| `--token`       |    String   | API token or secret key                                                                                                                                                   | `--token abcdef123456`                                   |
-| `--ipv4`        | String List | List of domain names for IPv4, repeat the option for multiple domains                                                                                                     | `--ipv4 test.com --ipv4 4.test.com`                      |
-| `--ipv6`        | String List | List of domain names for IPv6, repeat the option for multiple domains                                                                                                     | `--ipv6 test.com`                                        |
-| `--index4`      |     List    | Methods to retrieve IPv4 address, supports: number, default, public,<br>url:, regex:, cmd:, shell:                                                                        | `--index4 public` <br> `--index4 "regex:192\\.168\\..*"` |
-| `--index6`      |     List    | Methods to retrieve IPv6 address, supports: number, default, public,<br>url:, regex:, cmd:, shell:                                                                        | `--index6 0` <br> `--index6 public`                      |
-| `--ttl`         |   Integer   | DNS record TTL time in seconds                                                                                                                                            | `--ttl 600`                                              |
-| `--line`        |    String   | DNS resolution line (e.g. ISP line)                                                                                                                                       | `--line 电信` <br> `--line telecom`                        |
-| `--proxy`       | String List | HTTP proxy settings, format: IP\:Port or `DIRECT`                                                                                                                         | `--proxy 127.0.0.1:1080 --proxy DIRECT`                  |
-| `--cache`       | Flag/String | Enable cache or specify custom cache path                                                                                                                                 | `--cache` <br> `--cache=/path/to/cache`                  |
-| `--no-cache`    |     Flag    | Disable cache (equivalent to `--cache=false`)                                                                                                                             | `--no-cache`                                             |
-| `--ssl`         |    String   | SSL certificate verification: true, false, auto, or file path                                                                                                             | `--ssl false` <br> `--ssl=/path/to/ca-certs.crt`         |
-| `--no-ssl`      |     Flag    | Disable SSL verification (equivalent to `--ssl=false`)                                                                                                                    | `--no-ssl`                                               |
-| `--log_file`    |    String   | Log file path. If not set, logs are output to the console                                                                                                                 | `--log_file=/var/log/ddns.log`                           |
-| `--log_level`   |    String   | Logging level: DEBUG, INFO, WARNING, ERROR, CRITICAL                                                                                                                      | `--log_level=ERROR`                                      |
-| `--log_format`  |    String   | Log format string (compatible with Python `logging` module)                                                                                                               | `--log_format="%(asctime)s:%(message)s"`                 |
-| `--log_datefmt` |    String   | Date/time format string for logs                                                                                                                                          | `--log_datefmt="%Y-%m-%d %H:%M:%S"`                      |
-
-> **Note**: Where `--debug`, `--new-config`, `--no-cache`, `--no-ssl`, `--help`, `--version` are command line only parameters.
-
-## DNS Provider Values
-
-DDNS supports the following DNS providers:
-
-- **51dns** (alias for dnscom): DNS.COM service
-- **alidns**: Alibaba Cloud DNS
-- **aliesa**: Alibaba Cloud ESA (Edge Security Acceleration)
-- **callback**: Custom callback/webhook
-- **cloudflare**: Cloudflare DNS
-- **debug**: Debug provider (prints IP without updating DNS)
-- **dnscom**: DNS.COM service (same as 51dns)
-- **dnspod**: DNSPod (China)
-- **dnspod_com**: DNSPod International
-- **he**: Hurricane Electric DNS
-- **huaweidns**: Huawei Cloud DNS
-- **noip**: No-IP Dynamic DNS
-- **tencentcloud**: Tencent Cloud DNS
-- **edgeone**: Tencent Cloud EdgeOne
-
-## IP Detection Methods
-
-### IPv4/IPv6 Detection (`--index4`, `--index6`)
-
-- **number** (0, 1, 2...): Use IP of the Nth network interface
-- **default**: System's default external IP
-- **public**: Get public IP from external services
-- **url:ADDRESS**: Get IP from specific URL
-- **regex:PATTERN**: Extract IP using regex pattern
-- **cmd:COMMAND**: Get IP from command output
-- **shell:COMMAND**: Get IP from shell command
-
-Examples:
-
-```bash
-# Use public IP detection
-ddns --dns cloudflare --index4 public
-
-# Use multiple detection methods (fallback)
-ddns --dns cloudflare --index4 public --index4 "regex:192\\.168\\..*"
-
-# Use custom URL for IP detection
-ddns --dns cloudflare --index4 "url:https://api.ipify.org"
-
-# Use command output for IP
-ddns --dns cloudflare --index4 "cmd:hostname -I | awk '{print $1}'"
-```
-
-## Usage Examples
-
-### Basic Usage
-
-```bash
-# Update IPv4 record for a single domain
-ddns --dns cloudflare --id [email protected] --token your_token --ipv4 example.com
-
-# Update both IPv4 and IPv6 records
-ddns --dns cloudflare --id [email protected] --token your_token \
-     --ipv4 example.com --ipv6 example.com
-
-# Use debug mode to see detailed output
-ddns --debug --dns cloudflare --id [email protected] --token your_token --ipv4 example.com
-```
-
-### Multiple Domains
-
-```bash
-# Update multiple domains
-ddns --dns cloudflare --id [email protected] --token your_token \
-     --ipv4 example.com --ipv4 www.example.com --ipv4 api.example.com
-
-# Mix IPv4 and IPv6 domains
-ddns --dns cloudflare --id [email protected] --token your_token \
-     --ipv4 example.com --ipv4 www.example.com \
-     --ipv6 ipv6.example.com
-```
-
-### Provider-Specific Examples
-
-#### Cloudflare
-
-```bash
-# Using email + API key
-ddns --dns cloudflare --id [email protected] --token your_api_key --ipv4 example.com
-
-# Using API token only (recommended)
-ddns --dns cloudflare --token your_api_token --ipv4 example.com
-```
-
-#### DNSPod
-
-```bash
-ddns --dns dnspod --id 12345 --token your_token --ipv4 example.com
-```
-
-#### Alibaba Cloud DNS
-
-```bash
-ddns --dns alidns --id your_access_key --token your_secret_key --ipv4 example.com
-```
-
-#### Alibaba Cloud ESA
-
-```bash
-ddns --dns aliesa --id your_access_key --token your_secret_key --ipv4 example.com
-```
-
-#### No-IP
-
-```bash
-ddns --dns noip --id your_username --token your_password --ipv4 example.com
-```
-
-#### Custom Callback
-
-```bash
-# GET request callback
-ddns --dns callback --id "https://api.example.com/ddns?domain=__DOMAIN__&ip=__IP__" --ipv4 example.com
-
-# POST request callback
-ddns --dns callback \
-     --id "https://api.example.com/ddns" \
-     --token '{"api_key": "your_key", "domain": "__DOMAIN__", "ip": "__IP__"}' \
-     --ipv4 example.com
-```
-
-### Advanced Configuration
-
-#### Custom TTL and Line
-
-```bash
-# Set custom TTL (10 minutes)
-ddns --dns dnspod --id 12345 --token your_token --ipv4 example.com --ttl 600
-
-# Specify ISP line
-ddns --dns dnspod --id 12345 --token your_token --ipv4 example.com --line "电信"
-```
-
-#### Proxy Configuration
-
-```bash
-# Use HTTP proxy
-ddns --dns cloudflare --token your_token --ipv4 example.com --proxy 127.0.0.1:1080
-
-# Use multiple proxies with fallback
-ddns --dns cloudflare --token your_token --ipv4 example.com \
-     --proxy 127.0.0.1:1080 --proxy DIRECT
-```
-
-#### Custom Endpoint
-
-```bash
-# Use custom API endpoint
-ddns --dns cloudflare --token your_token --ipv4 example.com \
-     --endpoint https://api.private-cloudflare.com
-
-# Alibaba Cloud ESA with custom region
-ddns --dns aliesa --id your_access_key --token your_secret_key --ipv4 example.com \
-     --endpoint https://esa.ap-southeast-1.aliyuncs.com
-
-# No-IP compatible service
-ddns --dns noip --id your_username --token your_password --ipv4 example.com \
-     --endpoint https://your-ddns-server.com
-```
-
-#### Cache and SSL Settings
-
-```bash
-# Disable cache
-ddns --dns cloudflare --token your_token --ipv4 example.com --no-cache
-
-# Custom cache file
-ddns --dns cloudflare --token your_token --ipv4 example.com --cache /tmp/ddns.cache
-
-# Disable SSL verification
-ddns --dns cloudflare --token your_token --ipv4 example.com --no-ssl
-
-# Use custom CA certificate
-ddns --dns cloudflare --token your_token --ipv4 example.com --ssl /path/to/ca.pem
-```
-
-### Configuration File Generation
-
-```bash
-# Generate default config file
-ddns --new-config
-
-# Generate config with specific filename
-ddns --new-config=my-config.json
-
-# Generate config with initial values
-ddns --new-config --dns cloudflare --id [email protected] --token your_token
-```
-
-### Logging Configuration
-
-```bash
-# Set log level
-ddns --dns cloudflare --token your_token --ipv4 example.com --log_level DEBUG
-
-# Save logs to file
-ddns --dns cloudflare --token your_token --ipv4 example.com --log_file /var/log/ddns.log
-
-# Custom log format
-ddns --dns cloudflare --token your_token --ipv4 example.com \
-     --log_format "%(asctime)s: %(message)s" \
-     --log_datefmt "%Y-%m-%d %H:%M:%S"
-```
-
-## Configuration Priority
-
-DDNS uses the following priority order (highest to lowest):
-
-1. **Command line arguments** (highest priority)
-2. **JSON configuration file**
-3. **Environment variables** (lowest priority)
-
-This means command line arguments will override any settings in configuration files or environment variables.
-
-## See Also
-
-- [Environment Variables Configuration](env.en.md)
-- [JSON Configuration File](json.en.md)
-- [Docker Usage](docker.en.md)
-- [Provider-specific Configuration](providers/)
+Please update your bookmarks and links to use the new location.

+ 3 - 385
doc/cli.md

@@ -1,387 +1,5 @@
-# DDNS 命令行参数参考
+# 命令行接口文档
 
-本文档详细说明DDNS工具的命令行参数用法。命令行参数可用于覆盖配置文件和环境变量中的设置,具有**最高优先级**。
+此文件已移动至:[config/cli.md](config/cli.md)
 
-## 基本用法
-
-可通过`-h` 查看参数列表
-
-```bash
-# ddns [选项]
-ddns -h
-```
-
-或者使用Python:
-
-```bash
-# python3 -m ddns [选项]
-python3 -m ddns -h
-```
-
-## 参数列表
-
-| 参数              | 类型       | 描述                                                                                                                                       | 示例                                                       |
-| --------------- | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
-| `-h, --help`    | 标志       | 显示帮助信息并退出                                                                                                                                | `--help`                                                 |
-| `-v, --version` | 标志       | 显示版本信息并退出                                                                                                                                | `--version`                                              |
-| `-c, --config`  | 字符串      | 指定配置文件路径                                                                                                                                 | `--config config.json`                                   |
-| `--new-config`  | 标志/字符串   | 生成新的配置文件(可指定路径)                                                                                                                          | `--new-config` <br> `--new-config=config.json`           |
-| `--debug`       | 标志       | 开启调试模式                                                                                                                                   | `--debug`                                                |
-| `--dns`         | 选择项      | [DNS服务提供商](providers/README.md)包括:<br>51dns, alidns, aliesa, callback, cloudflare,<br>debug, dnscom, dnspod\_com, dnspod, edgeone, he,<br>huaweidns, noip, tencentcloud | `--dns cloudflare`                                       |
-| `--endpoint`    | 字符串      | 自定义API 端点 URL(更换服务节点)                                                                                                            | `--endpoint https://api.private.com`                     |
-| `--id`          | 字符串      | API 访问 ID、邮箱或 Access ID                                                                                                                 | `--id [email protected]`                                  |
-| `--token`       | 字符串      | API 授权令牌或密钥(Secret Key)                                                                                                                  | `--token abcdef123456`                                   |
-| `--ipv4`        | 字符串列表    | IPv4 域名列表,多个域名重复使用参数                                                                                                                     | `--ipv4 test.com --ipv4 4.test.com`              |
-| `--ipv6`        | 字符串列表    | IPv6 域名列表,多个域名重复使用参数                                                                                                                     | `--ipv6 test.com`                                     |
-| `--index4`      | 列表 | IPv4 地址获取方式,支持:数字, default, public,<br>url:, regex:, cmd:, shell:                                                                        | `--index4 public` <br> `--index4 "regex:192\\.168\\..*"` |
-| `--index6`      | 列表 | IPv6 地址获取方式,支持:数字, default, public,<br>url:, regex:, cmd:, shell:                                                                        | `--index6 0` <br> `--index6 public`                      |
-| `--ttl`         | 整数       | DNS 解析记录的 TTL 时间(秒)                                                                                                                      | `--ttl 600`                                              |
-| `--line`        | 字符串      | 解析线路(部分provider支持),如 ISP线路                                                                                                                         | `--line 电信` <br> `--line telecom`                        |
-| `--proxy`       | 字符串列表    | HTTP 代理设置,可用格式:IP:端口 或 `DIRECT`                                                                                                   | `--proxy 127.0.0.1:1080 --proxy DIRECT`                  |
-| `--cache`       | 标志/字符串   | 是否启用缓存或自定义缓存路径                                                                                                                           | `--cache` <br> `--cache=/path/to/cache`        |
-| `--no-cache`    | 标志       | 禁用缓存(等效于 `--cache=false`)                                                                                                                | `--no-cache`                                             |
-| `--ssl`         | 字符串      | SSL 证书验证方式,支持:true, false, auto, 文件路径                                                                                                    | `--ssl false` <br> `--ssl=/path/to/ca-certs.crt`             |
-| `--no-ssl`      | 标志       | 禁用 SSL 验证(等效于 `--ssl=false`)                                                                                                             | `--no-ssl`                                               |
-| `--log_file`    | 字符串      | 日志文件路径,不指定则输出到控制台                                                                                                                        | `--log_file=/var/log/ddns.log`                           |
-| `--log_level`   | 字符串      | 日志级别:DEBUG, INFO, WARNING, ERROR, CRITICAL                                                                                               | `--log_level=ERROR`                                      |
-| `--log_format`  | 字符串      | 日志格式字符串(`logging`模块格式)                                                                                                                   | `--log_format="%(asctime)s:%(message)s"`                |
-| `--log_datefmt` | 字符串      | 日志日期时间格式                                                                                                                                 | `--log_datefmt="%Y-%m-%d %H:%M:%S"`                      |
-
-> **注意**: 其中`--debug`, `--new-config`, `--no-cache`, `--no-ssl`, `--help`, `--version`为命令行独有参数。
-
-
-## DNS服务配置参数
-
-### `--dns DNS_PROVIDER`
-
-[DNS服务提供商](providers/README.md)详细列表。
-
-### `--id ID`
-
-API访问ID或用户标识。
-
-- **必需**: 是(部分DNS服务商可选)
-- **说明**:
-  - Cloudflare: 填写邮箱地址(使用Token时可留空)
-  - HE.net: 可留空
-  - 华为云: 填写Access Key ID (AK)
-  - Callback: 填写回调URL地址(支持变量替换)
-  - 其他服务商: 根据各自要求填写ID
-
-### `--token TOKEN`
-
-API授权令牌或密钥。
-
-- **必需**: 是
-- **说明**:
-  - 大部分平台: API密钥或Secret Key
-  - Callback: POST请求参数(JSON字符串),为空时使用GET请求
-  - 请妥善保管敏感信息
-
-**Callback配置示例**:
-
-```bash
-# GET方式回调
-ddns --dns callback --id "https://api.example.com/ddns?domain=__DOMAIN__&ip=__IP__" --token ""
-
-# POST方式回调
-ddns --dns callback --id "https://api.example.com/ddns" --token '{"api_key": "your_key", "domain": "__DOMAIN__"}'
-```
-
-详细配置请参考:[Callback Provider 配置文档](providers/callback.md)
-
-## 域名配置参数
-
-### `--ipv4 [DOMAIN...]`
-
-需要更新IPv4记录的域名列表。
-
-- **默认值**: `[]`(不更新IPv4地址)
-- **示例**:
-  - `--ipv4 example.com` (单个域名)
-  - `--ipv4 example.com --ipv4 subdomain.example.com` (多个域名)
-
-### `--ipv6 [DOMAIN...]`
-
-需要更新IPv6记录的域名列表。
-
-- **默认值**: `[]`(不更新IPv6地址)
-- **示例**:
-  - `--ipv6 example.com` (单个域名)
-  - `--ipv6 example.com --ipv6 ipv6.example.com` (多个域名)
-
-## IP获取方式参数
-
-### `--index4 [Rule...]`
-
-IPv4地址获取方式。
-
-- **默认值**: `default`
-- **可选值**:
-  - 数字(`0`,`1`,`2`...): 第N个网卡IP
-  - `default`: 系统访问外网默认IP
-  - `public`: 使用公网IP(通过API查询)
-  - `url:{URL}`: 从指定URL获取IP
-  - `regex:{PATTERN}`: 使用正则表达式匹配本地网络配置中的IP
-  - `cmd:{COMMAND}`: 执行指定命令并使用其输出作为IP
-  - `shell:{COMMAND}`: 使用系统shell运行命令并使用其输出作为IP
-- **示例**:
-  - `--index4 0` (第一个网卡)
-  - `--index4 public` (公网IP)
-  - `--index4 "url:http://ip.sb"` (从URL获取)
-  - `--index4 "regex:192\\.168\\.*"` (匹配192.168开头的IP)
-  - `--index4 public --index4 0` (先尝试获取公网IP,失败则使用第一个网卡)
-
-### `--index6 [Rule...]`
-
-IPv6地址获取方式,用法同`--index4`。
-
-## 网络配置参数
-
-### `--ttl TTL`
-
-DNS解析TTL时间(秒)。
-
-- **默认值**: `null`(使用DNS服务商默认设置)
-- **示例**:
-  - `--ttl 600` (10分钟)
-  - `--ttl 3600` (1小时)
-
-### `--proxy [PROXY...]`
-
-HTTP代理设置,支持多代理轮换。
-
-- **默认值**: 无(DIRECT 直连)
-- **示例**:
-  - `--proxy 127.0.0.1:1080` (单个代理)
-  - `--proxy 127.0.0.1:1080 --proxy DIRECT` (多个代理,逐个尝试)
-
-## 系统配置参数
-
-### `--cache {true|false|PATH}`
-
-启用缓存以减少API请求。
-
-- **默认值**: `true`
-- **可选值**:
-  - `true`: 启用缓存,使用默认路径
-  - `false`: 禁用缓存
-  - 文件路径: 自定义缓存文件位置
-- **示例**:
-  - `--cache` (启用默认缓存)
-  - `--cache=false` (禁用缓存)
-  - `--cache=/path/to/ddns.cache` (自定义缓存路径)
-
-### `--ssl {true|false|auto|PATH}`
-
-SSL证书验证方式,控制HTTPS连接的证书验证行为。
-
-- **默认值**: `auto`
-- **可选值**:
-  - `true`: 强制验证SSL证书(最安全)
-  - `false`: 禁用SSL证书验证(最不安全)
-  - `auto`: 优先验证,SSL证书错误时自动降级(不安全)
-  - 文件路径: 使用指定路径的自定义CA证书(最安全)
-- **示例**:
-  - `--ssl true` (强制验证)
-  - `--ssl false` (禁用验证)
-  - `--ssl auto` (自动降级)
-  - `--ssl /etc/ssl/certs/ca-certificates.crt` (自定义CA证书)
-
-### `--debug`
-
-启用调试模式(等同于设置`--log_level=DEBUG`)。
-
-- **说明**: 此参数仅作为命令行参数有效,配置文件中的同名设置无效
-- **示例**: `--debug`
-
-## 日志配置参数
-
-### `--log_level {CRITICAL|FATAL|ERROR|WARN|WARNING|INFO|DEBUG|NOTSET}`
-
-设置日志级别。
-
-- **默认值**: `INFO`
-- **示例**:
-  - `--log_level=DEBUG` (调试模式)
-  - `--log_level=ERROR` (仅显示错误)
-
-### `--log_file LOGFILE`
-
-设置日志文件路径。
-
-- **默认值**: 无(输出到控制台)
-- **示例**:
-  - `--log_file=/var/log/ddns.log`
-  - `--log_file=./ddns.log`
-
-### `--log_datefmt FORMAT`
-
-设置日期时间格式字符串(参考Python time.strftime()格式)。
-
-- **默认值**: `%Y-%m-%dT%H:%M:%S`
-- **示例**:
-  - `--log_datefmt="%Y-%m-%d %H:%M:%S"`
-  - `--log_datefmt="%m-%d %H:%M:%S"`
-
-## 常用命令示例
-
-### 使用配置文件
-
-```bash
-# 使用默认配置文件
-ddns
-
-# 使用指定配置文件
-ddns -c /path/to/config.json
-```
-
-### 命令行临时修改配置
-
-```bash
-# 启用调试模式
-ddns --debug
-
-# 使用指定配置文件并启用调试模式
-ddns -c /path/to/config.json --debug
-
-# 更新特定域名的IPv4地址(多个域名)
-ddns --ipv4 example.com --ipv4 www.example.com
-
-# 设置为阿里云DNS并提供认证信息
-ddns --dns alidns --id YOUR_ACCESS_KEY_ID --token YOUR_ACCESS_KEY_SECRET
-```
-
-### 高级用法示例
-
-```bash
-# 使用公网IP和特定的网络配置
-ddns --ipv4 example.com --index4 public --ttl 600 --proxy 127.0.0.1:1080
-
-# 自定义日志配置
-ddns --log_level=DEBUG --log_file=./ddns.log --log_format="%(asctime)s - %(levelname)s: %(message)s"
-
-# 完整配置示例
-ddns --dns cloudflare --id [email protected] --token API_TOKEN \
-     --ipv4 example.com --ipv4 www.example.com --ipv6 example.com \
-     --index4 public --index6 "regex:2001:.*" \
-     --ttl 300 --proxy 127.0.0.1:1080 --proxy DIRECT \
-     --cache=/var/cache/ddns.cache \
-     --log_level=INFO --log_file=/var/log/ddns.log
-```
-
-## 完整使用示例
-
-### 基本配置示例
-
-```bash
-# 最简单的配置 - DNSPod国内版
-ddns --dns dnspod --id 12345 --token mytokenkey --ipv4 example.com
-
-# 生成新的配置文件
-ddns --new-config config.json
-
-# 使用指定配置文件
-ddns -c /path/to/config.json
-
-# 查看版本信息
-ddns --version
-```
-
-### 不同DNS提供商示例
-
-```bash
-# CloudFlare
-ddns --dns cloudflare --id [email protected] --token your_api_token --ipv4 example.com
-
-# 阿里云DNS
-ddns --dns alidns --id your_access_key_id --token your_access_key_secret --ipv4 example.com
-
-# 阿里云ESA(自定义端点)
-ddns --dns aliesa --id your_access_key_id --token your_access_key_secret --endpoint https://esa.ap-southeast-1.aliyuncs.com --ipv4 example.com
-
-# 华为云DNS
-ddns --dns huaweidns --id your_access_key --token your_secret_key --ipv4 example.com
-
-# HE.net(无需id)
-ddns --dns he --token your_password --ipv4 example.com
-
-# DNS.COM/51DNS
-ddns --dns dnscom --id your_user_id --token your_api_token --ipv4 example.com
-
-# 腾讯云DNS
-ddns --dns tencentcloud --id your_secret_id --token your_secret_key --ipv4 example.com
-
-# 腾讯云 EdgeOne
-ddns --dns edgeone --id your_secret_id --token your_secret_key --ipv4 example.com
-
-# NoIP
-ddns --dns noip --id your_username --token your_password --ipv4 example.com
-
-# NoIP(自定义端点)
-ddns --dns noip --id your_username --token your_password --endpoint https://your-ddns-server.com --ipv4 example.com
-```
-
-### 高级配置示例
-
-```bash
-# 多域名、多IP获取方式
-ddns --dns cloudflare --id [email protected] --token API_TOKEN \
-     --ipv4 example.com --ipv4 www.example.com --ipv4 api.example.com \
-     --ipv6 example.com --ipv6 ipv6.example.com \
-     --index4 public --index4 "regex:192\\.168\\.1\\..*" \
-     --index6 public --index6 0
-
-# 使用代理和自定义TTL
-ddns --dns dnspod --id 12345 --token mytokenkey \
-     --index4 public --ipv4 example.com --ttl 300 \
-     --proxy 127.0.0.1:1080 --proxy DIRECT
-
-ddns --dns dnspod --id 12345 --token mytokenkey \
-     --ipv4 telecom.example.com --line 电信
-
-
-# 调试模式
-ddns --debug ...
-
-# 禁用缓存和SSL验证
-ddns --no-cache --no-ssl ...
-```
-
-### 自定义回调示例
-
-```bash
-# GET方式回调
-ddns --dns callback \
-     --id "https://api.example.com/ddns?domain=__DOMAIN__&ip=__IP__&ttl=__TTL__" \
-     --token "" \
-     --ipv4 example.com --index4 public
-
-# POST方式回调
-ddns --dns callback \
-     --id "https://api.example.com/ddns" \
-     --token '{"api_key": "your_key", "domain": "__DOMAIN__", "ip": "__IP__", "type": "__RECORDTYPE__"}' \
-     --ipv4 example.com --ipv6 example.com
-```
-
-### 日志配置示例
-
-```bash
-# 详细日志配置
-ddns --dns cloudflare --id [email protected] --token API_TOKEN \
-     --ipv4 example.com  --index4 public \
-     --log_level=DEBUG \
-     --log_file=/var/log/ddns.log \
-     --log_format="%(asctime)s [%(levelname)s] %(filename)s:%(lineno)d - %(message)s" \
-     --log_datefmt="%Y-%m-%d %H:%M:%S"
-
-# 简单调试
-ddns --debug --dns dnspod --id 12345 --token mytokenkey --ipv4 example.com
-```
-
-## 注意事项
-
-1. 命令行参数具有最高优先级,会覆盖配置文件和环境变量中的设置。
-2. 对于需要空格的参数值,请使用引号包围,例如:`--log_format="%(asctime)s: %(message)s"`。
-3. 对于多值参数(如`--ipv4`、`--index4`、`--proxy`等),请重复使用参数标识,例如:`--ipv4 example.com --ipv4 sub.example.com`。
-4. `--debug`参数仅在命令行中有效,配置文件中的debug设置将被忽略。
+请更新您的书签和链接以使用新位置。

+ 267 - 0
doc/config/cli.en.md

@@ -0,0 +1,267 @@
+# DDNS Command Line Arguments Reference
+
+This document provides detailed usage instructions for DDNS command line arguments. Command line arguments can override settings from configuration files and environment variables, having the **highest priority**.
+
+## Basic Usage
+
+Use `-h` to view the parameter list:
+
+```bash
+# ddns [options]
+ddns -h
+```
+
+Or using Python source code:
+
+```bash
+# python run.py [options]
+python -m ddns -h
+```
+
+## Parameter List
+
+### List Parameter Usage
+
+For list-type parameters that support multiple values (such as `--ipv4`, `--ipv6`, `--index4`, `--index6`, `--proxy`, etc.), you can specify multiple values using the following two methods:
+
+#### Method 1: Repeat Parameter Names (Recommended)
+
+```bash
+ddns --ipv4 example.com --ipv4 www.example.com --ipv4 api.example.com
+ddns --index4 public --index4 0 --index4 "regex:192\\.168\\..*"
+ddns --proxy 127.0.0.1:1080 --proxy DIRECT
+```
+
+#### Method 2: Space-Separated
+
+```bash
+ddns --ipv4 example.com www.example.com api.example.com
+ddns --index4 public 0 "regex:192\\.168\\..*"
+ddns --proxy 127.0.0.1:1080 DIRECT
+```
+
+#### Parameters with Spaces
+
+If parameter values contain spaces, use quotes:
+
+```bash
+ddns --line "China Telecom" "China Unicom" "China Mobile"
+ddns --index4 "url:http://ip.example.com/api?type=ipv4" public
+```
+
+#### Unsupported Usage
+
+```bash
+# ❌ Comma-separated not supported
+ddns --ipv4 "example.com,www.example.com"
+ddns --ipv4=example.com,www.example.com
+```
+
+### Parameter Details
+
+| Parameter          |     Type    | Description                                                                                                                                                               | Example                                                  |
+| --------------- | :---------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
+| `-h, --help`    |     Flag    | Show help message and exit                                                                                                                                                | `--help`                                                 |
+| `-v, --version` |     Flag    | Show version information and exit                                                                                                                                         | `--version`                                              |
+| `-c, --config`  | String List | Specify configuration file path, supports multiple config files                                                                                              | `--config config.json` or `--config config1.json --config config2.json`                                   |
+| `--new-config`  | Flag/String | Generate a new config file (optional file path)                                                                                                                           | `--new-config` <br> `--new-config=config.json`           |
+| `--debug`       |     Flag    | Enable debug mode                                                                                                                                                         | `--debug`                                                |
+| `--dns`         |    Choice   | [DNS Providers](../providers/README.en.md) include:<br>51dns, alidns, aliesa, callback, cloudflare,<br>debug, dnscom, dnspod\_com, dnspod, edgeone, he,<br>huaweidns, noip, tencentcloud | `--dns cloudflare`                                       |
+| `--endpoint`    |    String   | Custom API endpoint URL (useful for self-hosted services)                                                                                                                 | `--endpoint https://api.private.com`                     |
+| `--id`          |    String   | API Access ID, email, or Access Key                                                                                                                                       | `--id [email protected]`                                  |
+| `--token`       |    String   | API token or secret key                                                                                                                                                   | `--token abcdef123456`                                   |
+| `--ipv4`        | String List | List of domain names for IPv4, supports repeated parameters or space-separated                                                                                                     | `--ipv4 test.com 4.test.com` or `--ipv4 test.com --ipv4 4.test.com`                      |
+| `--ipv6`        | String List | List of domain names for IPv6, supports repeated parameters or space-separated                                                                                                     | `--ipv6 test.com` or `--ipv6 test.com ipv6.test.com`                                        |
+| `--index4`      |     List    | Methods to retrieve IPv4 address, supports: number, default, public,<br>url:, regex:, cmd:, shell:                                                                        | `--index4 public 0` or `--index4 public --index4 "regex:192\\.168\\..*"` |
+| `--index6`      |     List    | Methods to retrieve IPv6 address, supports: number, default, public,<br>url:, regex:, cmd:, shell:                                                                        | `--index6 0 public` or `--index6 0 --index6 public`                      |
+| `--ttl`         |   Integer   | DNS record TTL time in seconds                                                                                                                                            | `--ttl 600`                                              |
+| `--line`        |    String   | DNS resolution line (e.g. ISP line)                                                                                                                                       | `--line 电信` <br> `--line telecom`                        |
+| `--proxy`       | String List | HTTP proxy settings, format: IP\:Port or `DIRECT`                                                                                                                         | `--proxy 127.0.0.1:1080 DIRECT` or `--proxy 127.0.0.1:1080 --proxy DIRECT`                  |
+| `--cache`       | Flag/String | Enable cache or specify custom cache path                                                                                                                                 | `--cache` <br> `--cache=/path/to/cache`                  |
+| `--no-cache`    |     Flag    | Disable cache (equivalent to `--cache=false`)                                                                                                                             | `--no-cache`                                             |
+| `--ssl`         |    String   | SSL certificate verification: true, false, auto, or file path                                                                                                             | `--ssl false` <br> `--ssl=/path/to/ca-certs.crt`         |
+| `--no-ssl`      |     Flag    | Disable SSL verification (equivalent to `--ssl=false`)                                                                                                                    | `--no-ssl`                                               |
+| `--log_file`    |    String   | Log file path. If not set, logs are output to the console                                                                                                                 | `--log_file=/var/log/ddns.log`                           |
+| `--log_level`   |    String   | Logging level: DEBUG, INFO, WARNING, ERROR, CRITICAL                                                                                                                      | `--log_level=ERROR`                                      |
+| `--log_format`  |    String   | Log format string (compatible with Python `logging` module)                                                                                                               | `--log_format="%(asctime)s:%(message)s"`                 |
+| `--log_datefmt` |    String   | Date/time format string for logs                                                                                                                                          | `--log_datefmt="%Y-%m-%d %H:%M:%S"`                      |
+
+> **Note**: Where `--debug`, `--new-config`, `--no-cache`, `--no-ssl`, `--help`, `--version` are command line only parameters.
+
+## DNS Provider Values
+
+DDNS supports the following DNS providers:
+
+- **51dns** (alias for dnscom): DNS.COM service
+- **alidns**: Alibaba Cloud DNS
+- **aliesa**: Alibaba Cloud ESA (Edge Security Acceleration)
+- **callback**: Custom callback/webhook
+- **cloudflare**: Cloudflare DNS
+- **debug**: Debug provider (prints IP without updating DNS)
+- **dnscom**: DNS.COM service (same as 51dns)
+- **dnspod**: DNSPod (China)
+- **dnspod_com**: DNSPod International
+- **he**: Hurricane Electric DNS
+- **huaweidns**: Huawei Cloud DNS
+- **noip**: No-IP Dynamic DNS
+- **tencentcloud**: Tencent Cloud DNS
+- **edgeone**: Tencent Cloud EdgeOne
+
+## IP Detection Methods
+
+### IPv4/IPv6 Detection (`--index4`, `--index6`)
+
+- **number** (0, 1, 2...): Use IP of the Nth network interface
+- **default**: System's default external IP
+- **public**: Get public IP from external services
+- **url:ADDRESS**: Get IP from specific URL
+- **regex:PATTERN**: Extract IP using regex pattern
+- **cmd:COMMAND**: Get IP from command output
+- **shell:COMMAND**: Get IP from shell command
+
+Examples:
+
+```bash
+# Use public IP detection
+ddns --dns cloudflare --index4 public
+
+# Use multiple detection methods (fallback)
+ddns --dns cloudflare --index4 public --index4 "regex:192\\.168\\..*"
+
+# Use custom URL for IP detection
+ddns --dns cloudflare --index4 "url:https://api.ipify.org"
+
+# Use command output for IP
+ddns --dns cloudflare --index4 "cmd:hostname -I | awk '{print $1}'"
+```
+
+## Usage Examples
+
+### Basic Configuration File Usage
+
+```bash
+# Use default configuration file
+ddns
+
+# Use specified configuration file
+ddns -c /path/to/config.json
+
+# Use multiple configuration files
+ddns -c cloudflare.json -c dnspod.json
+
+# Generate new configuration file
+ddns --new-config config.json
+```
+
+### Command Line Configuration
+
+```bash
+# Simplest configuration - DNSPod
+ddns --dns dnspod --id 12345 --token mytokenkey --ipv4 example.com
+
+# Cloudflare with API token
+ddns --dns cloudflare --token your_api_token --ipv4 example.com
+
+# Enable debug mode
+ddns --dns cloudflare --token API_TOKEN --ipv4 example.com --debug
+
+# Multiple domains (space-separated)
+ddns --dns cloudflare --token API_TOKEN \
+     --ipv4 example.com www.example.com --ipv6 example.com
+
+# Multiple domains (repeated parameters)
+ddns --dns cloudflare --token API_TOKEN \
+     --ipv4 example.com --ipv4 www.example.com --ipv6 example.com
+```
+
+### Provider-Specific Examples
+
+```bash
+# Alibaba Cloud DNS
+ddns --dns alidns --id your_access_key --token your_secret_key --ipv4 example.com
+
+# Huawei Cloud DNS  
+ddns --dns huaweidns --id your_access_key --token your_secret_key --ipv4 example.com
+
+# No-IP
+ddns --dns noip --id your_username --token your_password --ipv4 example.com
+
+# Custom Callback (GET request)
+ddns --dns callback --id "https://api.example.com/ddns?domain=__DOMAIN__&ip=__IP__" --ipv4 example.com
+```
+
+### Advanced Configuration
+
+```bash
+# Complete configuration with proxy, TTL, and custom IP detection (space-separated)
+ddns --dns cloudflare --token API_TOKEN \
+     --ipv4 example.com www.example.com \
+     --index4 public "regex:2001:.*" \
+     --ttl 300 --proxy 127.0.0.1:1080 DIRECT \
+     --cache=/var/cache/ddns.cache \
+     --log_level=INFO --log_file=/var/log/ddns.log
+
+# Complete configuration (repeated parameters)
+ddns --dns cloudflare --token API_TOKEN \
+     --ipv4 example.com --ipv4 www.example.com \
+     --index4 public --index6 "regex:2001:.*" \
+     --ttl 300 --proxy 127.0.0.1:1080 --proxy DIRECT \
+     --cache=/var/cache/ddns.cache \
+     --log_level=INFO --log_file=/var/log/ddns.log
+
+# ISP line configuration (for Chinese providers)
+ddns --dns dnspod --id 12345 --token mytokenkey \
+     --ipv4 telecom.example.com --line 电信
+
+# Disable cache and SSL verification
+ddns --dns alidns --id ACCESS_KEY --token SECRET_KEY \
+     --ipv4 example.com --no-cache --no-ssl
+```
+
+## Important Notes
+
+1. **Command Line Parameter Priority**: Command line arguments have the highest priority and will override settings in configuration files and environment variables.
+
+2. **Quote Usage**: For parameter values that contain spaces or special characters, please use quotes, for example: `--log_format="%(asctime)s: %(message)s"`.
+
+3. **List Parameter Configuration**: For multi-value parameters (such as `--ipv4`, `--ipv6`, `--index4`, `--index6`, `--proxy`, etc.), two specification methods are supported:
+
+   ```bash
+   # ✅ Method 1: Repeat parameter names (recommended)
+   ddns --ipv4 example.com --ipv4 sub.example.com --ipv4 api.example.com
+   ddns --index4 public --index4 0 --index4 "regex:192\\.168\\..*"
+   ddns --proxy 127.0.0.1:1080 --proxy DIRECT
+   
+   # ✅ Method 2: Space-separated
+   ddns --ipv4 example.com sub.example.com api.example.com
+   ddns --index4 public 0 "regex:192\\.168\\..*"
+   ddns --proxy 127.0.0.1:1080 DIRECT
+   
+   # ✅ Parameter values with spaces use quotes
+   ddns --line "China Telecom" "China Unicom"
+   
+   # ❌ Incorrect usage - not supported
+   ddns --ipv4 "example.com,sub.example.com"    # Comma-separated not supported
+   ddns --ipv4=example.com,sub.example.com      # Equals + comma not supported
+   ```
+
+4. **Debug Mode**: The `--debug` parameter is only effective as a command line argument; debug settings in configuration files will be ignored.
+
+5. **Regular Expressions**: When using regular expressions, special characters need to be properly escaped. It's recommended to use quotes, for example: `--index4 "regex:192\\.168\\..*"`.
+
+## Configuration Priority
+
+DDNS uses the following priority order (highest to lowest):
+
+1. **Command line arguments** (highest priority)
+2. **JSON configuration file**
+3. **Environment variables** (lowest priority)
+
+This means command line arguments will override any settings in configuration files or environment variables.
+
+## See Also
+
+- [Environment Variables Configuration](env.en.md)
+- [JSON Configuration File](json.en.md)
+- [Docker Usage](../docker.en.md)
+- [Provider-specific Configuration](../providers/)

+ 379 - 0
doc/config/cli.md

@@ -0,0 +1,379 @@
+---
+title: DDNS 命令行参数参考
+description: 详细说明 DDNS 工具的命令行参数用法,包括基本用法、参数列表、配置文件等
+---
+
+本文档详细说明DDNS工具的命令行参数用法。命令行参数可用于覆盖配置文件和环境变量中的设置,具有**最高优先级**。
+
+## 基本用法
+
+可通过`-h` 查看参数列表
+
+```bash
+# ddns [选项]
+ddns -h
+```
+
+或者使用Python:
+
+```bash
+# python3 -m ddns [选项]
+python3 -m ddns -h
+```
+
+## 参数列表
+
+### 列表参数说明
+
+对于支持多个值的列表类型参数(如 `--ipv4`、`--ipv6`、`--index4`、`--index6`、`--proxy` 等),在命令行中支持以下两种方式指定多个值:
+
+#### 方式一:重复参数名(推荐)
+
+```bash
+ddns --ipv4 example.com --ipv4 www.example.com --ipv4 api.example.com
+ddns --index4 public --index4 0 --index4 "regex:192\\.168\\..*"
+ddns --proxy 127.0.0.1:1080 --proxy DIRECT
+```
+
+#### 方式二:空格分隔
+
+```bash
+ddns --ipv4 example.com www.example.com api.example.com
+ddns --index4 public 0 "regex:192\\.168\\..*"
+ddns --proxy 127.0.0.1:1080 DIRECT
+```
+
+#### 包含空格的参数值
+
+如果参数值本身包含空格,请使用引号包围:
+
+```bash
+ddns --line "中国电信" "中国联通" "中国移动"
+ddns --index4 "url:http://ip.example.com/api?type=ipv4" public
+```
+
+#### 不支持的用法
+
+```bash
+# ❌ 不支持逗号分隔
+ddns --ipv4 "example.com,www.example.com"
+ddns --ipv4=example.com,www.example.com
+```
+
+### 参数详表
+
+| 参数              | 类型       | 描述                                                                                                                                       | 示例                                                       |
+| --------------- | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
+| `-h, --help`    | 标志       | 显示帮助信息并退出                                                                                                                                | `--help`                                                 |
+| `-v, --version` | 标志       | 显示版本信息并退出                                                                                                                                | `--version`                                              |
+| `-c, --config`  | 字符串列表      | 指定配置文件路径,支持多个配置文件                                                                                                                                 | `--config config.json` <br> `--config config1.json --config config2.json`                                   |
+| `--new-config`  | 标志/字符串   | 生成新的配置文件(可指定路径)                                                                                                                          | `--new-config` <br> `--new-config=config.json`           |
+| `--debug`       | 标志       | 开启调试模式                                                                                                                                   | `--debug`                                                |
+| `--dns`         | 选择项      | [DNS服务提供商](providers/README.md)包括:<br>51dns, alidns, aliesa, callback, cloudflare,<br>debug, dnscom, dnspod\_com, dnspod, edgeone, he,<br>huaweidns, noip, tencentcloud | `--dns cloudflare`                                       |
+| `--endpoint`    | 字符串      | 自定义API 端点 URL(更换服务节点)                                                                                                            | `--endpoint https://api.private.com`                     |
+| `--id`          | 字符串      | API 访问 ID、邮箱或 Access ID                                                                                                                 | `--id [email protected]`                                  |
+| `--token`       | 字符串      | API 授权令牌或密钥(Secret Key)                                                                                                                  | `--token abcdef123456`                                   |
+| `--ipv4`        | 字符串列表    | IPv4 域名列表,支持重复参数或空格分隔                                                                                                                     | `--ipv4 test.com 4.test.com` 或 `--ipv4 test.com --ipv4 4.test.com`              |
+| `--ipv6`        | 字符串列表    | IPv6 域名列表,支持重复参数或空格分隔                                                                                                                     | `--ipv6 test.com` 或 `--ipv6 test.com ipv6.test.com`                                     |
+| `--index4`      | 列表 | IPv4 地址获取方式,支持:数字, default, public,<br>url:, regex:, cmd:, shell:                                                                        | `--index4 public 0` 或 `--index4 public --index4 "regex:192\\.168\\..*"` |
+| `--index6`      | 列表 | IPv6 地址获取方式,支持:数字, default, public,<br>url:, regex:, cmd:, shell:                                                                        | `--index6 0 public` 或 `--index6 0 --index6 public`                      |
+| `--ttl`         | 整数       | DNS 解析记录的 TTL 时间(秒)                                                                                                                      | `--ttl 600`                                              |
+| `--line`        | 字符串      | 解析线路(部分provider支持),如 ISP线路                                                                                                                         | `--line 电信` <br> `--line telecom`                        |
+| `--proxy`       | 字符串列表    | HTTP 代理设置,可用格式:IP:端口 或 `DIRECT`                                                                                                   | `--proxy 127.0.0.1:1080 DIRECT` 或 `--proxy 127.0.0.1:1080 --proxy DIRECT`                  |
+| `--cache`       | 标志/字符串   | 是否启用缓存或自定义缓存路径                                                                                                                           | `--cache` <br> `--cache=/path/to/cache`        |
+| `--no-cache`    | 标志       | 禁用缓存(等效于 `--cache=false`)                                                                                                                | `--no-cache`                                             |
+| `--ssl`         | 字符串      | SSL 证书验证方式,支持:true, false, auto, 文件路径                                                                                                    | `--ssl false` <br> `--ssl=/path/to/ca-certs.crt`             |
+| `--no-ssl`      | 标志       | 禁用 SSL 验证(等效于 `--ssl=false`)                                                                                                             | `--no-ssl`                                               |
+| `--log_file`    | 字符串      | 日志文件路径,不指定则输出到控制台                                                                                                                        | `--log_file=/var/log/ddns.log`                           |
+| `--log_level`   | 字符串      | 日志级别:DEBUG, INFO, WARNING, ERROR, CRITICAL                                                                                               | `--log_level=ERROR`                                      |
+| `--log_format`  | 字符串      | 日志格式字符串(`logging`模块格式)                                                                                                                   | `--log_format="%(asctime)s:%(message)s"`                |
+| `--log_datefmt` | 字符串      | 日志日期时间格式                                                                                                                                 | `--log_datefmt="%Y-%m-%d %H:%M:%S"`                      |
+
+> **注意**: 其中`--debug`, `--new-config`, `--no-cache`, `--no-ssl`, `--help`, `--version`为命令行独有参数。
+
+## 配置文件
+
+### `-c FILE`
+
+`-c`是`--config`的简写形式,用于指定配置文件路径。可以使用多个`-c`参数来加载多个配置文件。
+
+```bash
+
+ddns -c config.json 
+
+# 多配置文件
+ddns -c cloudflare.json -c dnspod.json 
+
+```
+
+## DNS服务配置参数
+
+### `--dns DNS_PROVIDER`
+
+[DNS服务提供商](providers/README.md)详细列表。
+
+### `--id ID`
+
+API访问ID或用户标识。
+
+- **必需**: 是(部分DNS服务商可选)
+- **说明**:
+  - Cloudflare: 填写邮箱地址(使用Token时可留空)
+  - HE.net: 可留空
+  - 华为云: 填写Access Key ID (AK)
+  - Callback: 填写回调URL地址(支持变量替换)
+  - 其他服务商: 根据各自要求填写ID
+
+### `--token TOKEN`
+
+API授权令牌或密钥。
+
+- **必需**: 是
+- **说明**:
+  - 大部分平台: API密钥或Secret Key
+  - Callback: POST请求参数(JSON字符串),为空时使用GET请求
+  - 请妥善保管敏感信息
+
+**Callback配置示例**:
+
+```bash
+# GET方式回调
+ddns --dns callback --id "https://api.example.com/ddns?domain=__DOMAIN__&ip=__IP__" --token ""
+
+# POST方式回调
+ddns --dns callback --id "https://api.example.com/ddns" --token '{"api_key": "your_key", "domain": "__DOMAIN__"}'
+```
+
+详细配置请参考:[Callback Provider 配置文档](providers/callback.md)
+
+## 域名配置参数
+
+### `--ipv4 [DOMAIN...]`
+
+需要更新IPv4记录的域名列表。
+
+- **默认值**: `[]`(不更新IPv4地址)
+- **示例**:
+  - `--ipv4 example.com` (单个域名)
+  - `--ipv4 example.com --ipv4 subdomain.example.com` (多个域名)
+
+### `--ipv6 [DOMAIN...]`
+
+需要更新IPv6记录的域名列表。
+
+- **默认值**: `[]`(不更新IPv6地址)
+- **示例**:
+  - `--ipv6 example.com` (单个域名)
+  - `--ipv6 example.com --ipv6 ipv6.example.com` (多个域名)
+
+## IP获取方式参数
+
+### `--index4 [Rule...]`
+
+IPv4地址获取方式。
+
+- **默认值**: `default`
+- **可选值**:
+  - 数字(`0`,`1`,`2`...): 第N个网卡IP
+  - `default`: 系统访问外网默认IP
+  - `public`: 使用公网IP(通过API查询)
+  - `url:{URL}`: 从指定URL获取IP
+  - `regex:{PATTERN}`: 使用正则表达式匹配本地网络配置中的IP
+  - `cmd:{COMMAND}`: 执行指定命令并使用其输出作为IP
+  - `shell:{COMMAND}`: 使用系统shell运行命令并使用其输出作为IP
+- **示例**:
+  - `--index4 0` (第一个网卡)
+  - `--index4 public` (公网IP)
+  - `--index4 "url:http://ip.sb"` (从URL获取)
+  - `--index4 "regex:192\\.168\\.*"` (匹配192.168开头的IP)
+  - `--index4 public --index4 0` (先尝试获取公网IP,失败则使用第一个网卡)
+
+### `--index6 [Rule...]`
+
+IPv6地址获取方式,用法同`--index4`。
+
+## 网络配置参数
+
+### `--ttl TTL`
+
+DNS解析TTL时间(秒)。
+
+- **默认值**: `null`(使用DNS服务商默认设置)
+- **示例**:
+  - `--ttl 600` (10分钟)
+  - `--ttl 3600` (1小时)
+
+### `--proxy [PROXY...]`
+
+HTTP代理设置,支持多代理轮换。
+
+- **默认值**: 无(DIRECT 直连)
+- **示例**:
+  - `--proxy 127.0.0.1:1080` (单个代理)
+  - `--proxy 127.0.0.1:1080 --proxy DIRECT` (多个代理,逐个尝试)
+
+## 系统配置参数
+
+### `--cache {true|false|PATH}`
+
+启用缓存以减少API请求。
+
+- **默认值**: `true`
+- **可选值**:
+  - `true`: 启用缓存,使用默认路径
+  - `false`: 禁用缓存
+  - 文件路径: 自定义缓存文件位置
+- **示例**:
+  - `--cache` (启用默认缓存)
+  - `--cache=false` (禁用缓存)
+  - `--cache=/path/to/ddns.cache` (自定义缓存路径)
+
+### `--ssl {true|false|auto|PATH}`
+
+SSL证书验证方式,控制HTTPS连接的证书验证行为。
+
+- **默认值**: `auto`
+- **可选值**:
+  - `true`: 强制验证SSL证书(最安全)
+  - `false`: 禁用SSL证书验证(最不安全)
+  - `auto`: 优先验证,SSL证书错误时自动降级(不安全)
+  - 文件路径: 使用指定路径的自定义CA证书(最安全)
+- **示例**:
+  - `--ssl true` (强制验证)
+  - `--ssl false` (禁用验证)
+  - `--ssl auto` (自动降级)
+  - `--ssl /etc/ssl/certs/ca-certificates.crt` (自定义CA证书)
+
+### `--debug`
+
+启用调试模式(等同于设置`--log_level=DEBUG`)。
+
+- **说明**: 此参数仅作为命令行参数有效,配置文件中的同名设置无效
+- **示例**: `--debug`
+
+## 日志配置参数
+
+### `--log_level {CRITICAL|FATAL|ERROR|WARN|WARNING|INFO|DEBUG|NOTSET}`
+
+设置日志级别。
+
+- **默认值**: `INFO`
+- **示例**:
+  - `--log_level=DEBUG` (调试模式)
+  - `--log_level=ERROR` (仅显示错误)
+
+### `--log_file LOGFILE`
+
+设置日志文件路径。
+
+- **默认值**: 无(输出到控制台)
+- **示例**:
+  - `--log_file=/var/log/ddns.log`
+  - `--log_file=./ddns.log`
+
+### `--log_datefmt FORMAT`
+
+设置日期时间格式字符串(参考Python time.strftime()格式)。
+
+- **默认值**: `%Y-%m-%dT%H:%M:%S`
+- **示例**:
+  - `--log_datefmt="%Y-%m-%d %H:%M:%S"`
+  - `--log_datefmt="%m-%d %H:%M:%S"`
+
+## 常用命令示例
+
+### 基本使用
+
+```bash
+# 使用默认配置文件
+ddns
+
+# 使用指定配置文件
+ddns -c /path/to/config.json
+
+# 使用多个配置文件
+ddns -c cloudflare.json -c dnspod.json
+
+# 生成新的配置文件
+ddns --new-config config.json
+```
+
+### 直接命令行配置
+
+```bash
+# 最简单的配置
+ddns --dns dnspod --id 12345 --token mytokenkey --ipv4 example.com
+
+# 启用调试模式
+ddns --dns cloudflare --id [email protected] --token API_TOKEN --ipv4 example.com --debug
+
+# 多域名配置(空格分隔)
+ddns --dns cloudflare --id [email protected] --token API_TOKEN \
+     --ipv4 example.com www.example.com --ipv6 example.com
+
+# 多域名配置(重复参数)
+ddns --dns cloudflare --id [email protected] --token API_TOKEN \
+     --ipv4 example.com --ipv4 www.example.com --ipv6 example.com
+```
+
+### 高级配置示例
+
+```bash
+# 完整配置示例(包含代理、TTL、IP获取方式等) - 使用空格分隔
+ddns --dns cloudflare --id [email protected] --token API_TOKEN \
+     --ipv4 example.com www.example.com \
+     --index4 public "regex:2001:.*" \
+     --ttl 300 --proxy 127.0.0.1:1080 DIRECT \
+     --cache=/var/cache/ddns.cache \
+     --log_level=INFO --log_file=/var/log/ddns.log
+
+# 完整配置示例 - 使用重复参数
+ddns --dns cloudflare --id [email protected] --token API_TOKEN \
+     --ipv4 example.com --ipv4 www.example.com \
+     --index4 public --index6 "regex:2001:.*" \
+     --ttl 300 --proxy 127.0.0.1:1080 --proxy DIRECT \
+     --cache=/var/cache/ddns.cache \
+     --log_level=INFO --log_file=/var/log/ddns.log
+
+# 使用线路解析
+ddns --dns dnspod --id 12345 --token mytokenkey \
+     --ipv4 telecom.example.com --line 电信
+
+# 禁用缓存和SSL验证
+ddns --dns alidns --id ACCESS_KEY --token SECRET_KEY \
+     --ipv4 example.com --no-cache --no-ssl
+```
+
+## 注意事项
+
+### 优先级
+
+**命令行参数优先级**: 命令行参数具有最高优先级,会覆盖配置文件和环境变量中的设置。
+
+### 引号
+
+**引号使用**: 对于需要空格或特殊字符的参数值,请使用引号包围,例如:`--log_format="%(asctime)s: %(message)s"`。
+
+### 列表参数
+
+**列表参数配置**: 对于多值参数(如`--ipv4`、`--ipv6`、`--index4`、`--index6`、`--proxy`等),支持两种指定方式:
+
+   ```bash
+   # ✅ 方式一:重复参数名(推荐)
+   ddns --ipv4 example.com --ipv4 sub.example.com --ipv4 api.example.com
+   ddns --index4=public --index4=0 --index4="regex:192\\.168\\..*"
+
+   # ✅ 方式二:空格分隔
+   ddns --ipv4 example.com sub.example.com api.example.com
+   ddns --index4 public 0 "regex:192\\.168\\..*"
+   
+   ddns --ipv4=example.com,sub.example.com      # 不支持等号加逗号
+   ```
+
+### 调试模式
+
+**调试模式**: `--debug`参数仅在命令行中有效,配置文件中的debug设置将被忽略。
+
+### 正则表达式
+
+**正则表达式**: 使用正则表达式时需要适当转义特殊字符,建议使用引号包围,例如:`--index4 "regex:192\\.168\\..*"`。

+ 553 - 0
doc/config/env.en.md

@@ -0,0 +1,553 @@
+# DDNS Environment Variables Configuration
+
+## Overview
+
+DDNS supports configuration through environment variables with the following priority order: **[Command Line Arguments](cli.en.md) > [Configuration File](json.en.md) > Environment Variables**
+
+All environment variables use the `DDNS_` prefix followed by the parameter name (recommended uppercase).
+
+> `export DDNS_xxx="xxx"` command applies to the current host
+> `docker run -e DDNS_xxx="xxx"` command applies to the container
+
+## Complete Environment Variables List
+
+| Environment Variable     | Accepted Values                                                                                     | Description                              | Example                                                     |
+|--------------------------|------------------------------------------------------------------------------------------------------|------------------------------------------|-------------------------------------------------------------|
+| `DDNS_CONFIG`            | File path, supports comma or semicolon-separated multiple paths                                    | Specify config file path, supports multiple files | `DDNS_CONFIG="config.json"` or `DDNS_CONFIG="cloudflare.json,dnspod.json"` |
+| `DDNS_DNS`               | `51dns`, `alidns`, `aliesa`, `callback`, `cloudflare`, `debug`, `dnscom`, `dnspod_com`, `dnspod`, `edgeone`, `he`, `huaweidns`, `noip`, `tencentcloud` | [DNS Provider](./providers/README.en.md)    | `DDNS_DNS=cloudflare`                                       |
+| `DDNS_ID`                | Depends on the provider                                                                              | API account or ID                        | `DDNS_ID="[email protected]"`                                |
+| `DDNS_TOKEN`             | Depends on the provider                                                                              | API token or secret                      | `DDNS_TOKEN="abcdef123456"`                                 |
+| `DDNS_ENDPOINT`          | URL (starting with http or https)                                                                   | Custom API endpoint                       | `DDNS_ENDPOINT=https://api.dns.cn`                          |
+| `DDNS_IPV4`              | Domains as array or comma-separated string                                                           | List of IPv4 domains                      | `DDNS_IPV4='["t.com","4.t.com"]'`                           |
+| `DDNS_IPV6`              | Domains as array or comma-separated string                                                           | List of IPv6 domains                      | `DDNS_IPV6=t.com,6.t.com`                                   |
+| `DDNS_INDEX4`            | Number, `default`, `public`, `url:`, `regex:`, `cmd:`, `shell:`, or an array of them                | IPv4 address detection methods            | `DDNS_INDEX4="[0,'regex:192.168.*']"`                       |
+| `DDNS_INDEX6`            | Number, `default`, `public`, `url:`, `regex:`, `cmd:`, `shell:`, or an array of them                | IPv6 address detection methods            | `DDNS_INDEX6=public`                                        |
+| `DDNS_TTL`               | Integer (seconds), varies by provider                                                                | DNS record TTL                            | `DDNS_TTL=600`                                              |
+| `DDNS_LINE`              | ISP line such as: 电信, 联通, 移动, or provider-specific values                                     | DNS resolution line                       | `DDNS_LINE=电信`                                            |
+| `DDNS_PROXY`             | IP:port or `DIRECT`, multiple values separated by semicolons                                        | HTTP proxy settings                       | `DDNS_PROXY="127.0.0.1:1080;DIRECT"`                        |
+| `DDNS_CACHE`             | `true`, `false`, or file path                                                                        | Enable or specify cache file              | `DDNS_CACHE="/tmp/cache"`                                   |
+| `DDNS_SSL`               | `true`, `false`, `auto`, or file path                                                                | SSL verification mode or certificate path | `DDNS_SSL=false`<br>`DDNS_SSL=/path/ca.crt`                 |
+| `DDNS_LOG_LEVEL`         | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`                                                     | Logging level                             | `DDNS_LOG_LEVEL="DEBUG"`                                    |
+| `DDNS_LOG_FILE`          | File path                                                                                            | Output log file (default: stdout)         | `DDNS_LOG_FILE="/tmp/ddns.log"`                             |
+| `DDNS_LOG_FORMAT`        | Python logging format string                                                                         | Log format template                       | `DDNS_LOG_FORMAT="%(message)s"`                             |
+| `DDNS_LOG_DATEFMT`       | Date-time format string                                                                              | Log timestamp format                      | `DDNS_LOG_DATEFMT="%m-%d %H:%M"`                            |
+
+## Basic Configuration Parameters
+
+### Configuration File Path
+
+#### DDNS_CONFIG
+
+- **Type**: String
+- **Required**: No
+- **Default**: Search in default paths (`config.json`, `~/.ddns/config.json`, etc.)
+- **Format**: Single file path or multiple file paths (separated by commas or semicolons)
+- **Description**: Specify configuration file path, supports multiple configuration files
+- **Examples**:
+
+  ```bash
+  # Single configuration file
+  export DDNS_CONFIG="config.json"
+  export DDNS_CONFIG="/path/to/ddns.json"
+  
+  # Multiple configuration files 
+  export DDNS_CONFIG="/etc/ddns/cloudflare.json,./dnspod.json"
+  ```
+
+### Authentication Information
+
+#### DDNS_ID
+
+- **Type**: String
+- **Required**: Yes (optional for some DNS providers)
+- **Description**: API access ID or user identifier
+- **Examples**:
+
+  ```bash
+  # Cloudflare (email address)
+  export DDNS_ID="[email protected]"
+  
+  # DNSPod (numeric ID)
+  export DDNS_ID="12345"
+  
+  # Alibaba Cloud (Access Key ID)
+  export DDNS_ID="LTAI4xxxxxxxxxxxxx"
+  
+  # HE.net (can be empty)
+  export DDNS_ID=""
+  ```
+
+#### DDNS_TOKEN
+
+- **Type**: String
+- **Required**: Yes
+- **Description**: API authorization token or key
+- **Examples**:
+
+  ```bash
+  # General API token
+  export DDNS_TOKEN="abcdef1234567890"
+  
+  # Cloudflare API token
+  export DDNS_TOKEN="1234567890abcdef_example_token"
+  
+  # Alibaba Cloud Secret Key
+  export DDNS_TOKEN="secretkey1234567890"
+  ```
+
+### DNS Provider
+
+#### DDNS_DNS
+
+- **Type**: String
+- **Required**: No
+- **Default**: `dnspod`
+- **Available Values**: `51dns`, `alidns`, `aliesa`, `callback`, `cloudflare`, `debug`, `dnscom`, `dnspod`, `dnspod_com`, `edgeone`, `he`, `huaweidns`, `noip`, `tencentcloud`
+- **Description**: DNS service provider
+- **Examples**:
+
+  ```bash
+  export DDNS_DNS="cloudflare"
+  export DDNS_DNS="alidns"
+  export DDNS_DNS="dnspod"
+  ```
+
+#### DDNS_ENDPOINT
+
+- **Type**: String
+- **Required**: No
+- **Default**: None (uses default API endpoint for each DNS provider)
+- **Description**: API endpoint URL for custom or private deployments
+- **Examples**:
+
+  ```bash
+  # Custom Cloudflare endpoint
+  export DDNS_ENDPOINT="https://api.private-cloudflare.com"
+  
+  # Private DNSPod deployment
+  export DDNS_ENDPOINT="https://internal-dns-api.company.com"
+  
+  # Local testing endpoint
+  export DDNS_ENDPOINT="http://localhost:8080/api"
+  ```
+
+### Custom Callback Configuration
+
+When using `DDNS_DNS="callback"`, configure custom callbacks with these environment variables:
+
+- **DDNS_ID**: Callback URL address with variable substitution support
+- **DDNS_TOKEN**: POST request parameters (JSON string), empty for GET requests
+
+For detailed configuration, see: [Callback Provider Configuration Documentation](providers/callback.en.md)
+
+**Examples**:
+
+```bash
+# GET method callback
+export DDNS_DNS="callback"
+export DDNS_ID="https://api.example.com/ddns?domain=__DOMAIN__&ip=__IP__"
+export DDNS_TOKEN=""
+
+# POST method callback (JSON string)
+export DDNS_DNS="callback"
+export DDNS_ID="https://api.example.com/ddns"
+export DDNS_TOKEN='{"api_key": "your_key", "domain": "__DOMAIN__", "ip": "__IP__"}'
+```
+
+**Supported Variable Substitutions**:
+
+- `__DOMAIN__`: Full domain name
+- `__IP__`: IP address (IPv4 or IPv6)
+- `__RECORDTYPE__`: DNS record type
+- `__TTL__`: Time to live (seconds)
+- `__LINE__`: Resolution line
+- `__TIMESTAMP__`: Current timestamp
+
+## Domain Configuration
+
+### IPv4 Domain List
+
+#### DDNS_IPV4
+
+- **Type**: Array (supports JSON/Python format)
+- **Required**: No
+- **Default**: `[]`
+- **Description**: List of domains requiring IPv4 record updates
+- **Examples**:
+
+  ```bash
+  # JSON array format (recommended)
+  export DDNS_IPV4='["example.com", "www.example.com", "api.example.com"]'
+  
+  # Python list format
+  export DDNS_IPV4="['example.com', 'www.example.com']"
+  
+  # Comma-separated string
+  export DDNS_IPV4="example.com,www.example.com"
+  
+  # Single domain
+  export DDNS_IPV4="example.com"
+  ```
+
+### IPv6 Domain List
+
+#### DDNS_IPV6
+
+- **Type**: Array (supports JSON/Python format)
+- **Required**: No
+- **Default**: `[]`
+- **Description**: List of domains requiring IPv6 record updates
+- **Examples**:
+
+  ```bash
+  # JSON array format
+  export DDNS_IPV6='["example.com", "ipv6.example.com"]'
+  
+  # Comma-separated string
+  export DDNS_IPV6="example.com,ipv6.example.com"
+  
+  # Single domain
+  export DDNS_IPV6="ipv6.example.com"
+  ```
+
+## IP Detection Methods
+
+### IPv4 Detection Method
+
+#### DDNS_INDEX4
+
+- **Type**: String or Array
+- **Required**: No
+- **Default**: `["default"]` (uses system's default external IP)
+- **Description**: IPv4 address detection methods. Supports comma `,` or semicolon `;` separated string format
+- **Special Note**: When value contains `regex:`, `cmd:`, or `shell:` prefix, separator splitting is not supported; the entire string is treated as a single configuration item
+- **Examples**:
+
+  ```bash
+  # Use public IP detection
+  export DDNS_INDEX4="public"
+  
+  # Multiple methods with fallback
+  export DDNS_INDEX4='["public", "default"]'
+  
+  # Network interface index
+  export DDNS_INDEX4="0"  # First network interface
+  export DDNS_INDEX4="1"  # Second network interface
+  
+  # Custom URL
+  export DDNS_INDEX4="url:https://api.ipify.org"
+  
+  # Regex pattern (no splitting)
+  export DDNS_INDEX4="regex:192\\.168\\..*"
+  
+  # Command execution (no splitting)
+  export DDNS_INDEX4="cmd:hostname -I | awk '{print \$1}'"
+  
+  # Shell command (no splitting)
+  export DDNS_INDEX4="shell:ip route get 8.8.8.8 | awk '{print \$7}'"
+  ```
+
+### IPv6 Detection Method
+
+#### DDNS_INDEX6
+
+- **Type**: String or Array
+- **Required**: No
+- **Default**: `["default"]` (uses system's default external IPv6)
+- **Description**: IPv6 address detection methods
+- **Examples**:
+
+  ```bash
+  # Use public IPv6 detection
+  export DDNS_INDEX6="public"
+  
+  # Network interface index
+  export DDNS_INDEX6="0"
+  
+  # Custom IPv6 detection URL
+  export DDNS_INDEX6="url:https://api6.ipify.org"
+  
+  # Multiple methods
+  export DDNS_INDEX6='["public", "default"]'
+  ```
+
+## DNS Configuration
+
+### TTL Setting
+
+#### DDNS_TTL
+
+- **Type**: Integer
+- **Required**: No
+- **Default**: None (uses DNS provider's default)
+- **Description**: DNS record TTL (Time To Live) in seconds
+- **Examples**:
+
+  ```bash
+  # 5 minutes
+  export DDNS_TTL="300"
+  
+  # 10 minutes (commonly used)
+  export DDNS_TTL="600"
+  
+  # 1 hour
+  export DDNS_TTL="3600"
+  ```
+
+### Resolution Line
+
+#### DDNS_LINE
+
+- **Type**: String
+- **Required**: No
+- **Default**: None (uses default line)
+- **Description**: DNS resolution line, ISP line selection
+- **Examples**:
+
+  ```bash
+  # Default line
+  export DDNS_LINE="default"
+  
+  # China Telecom
+  export DDNS_LINE="telecom"
+  
+  # China Unicom
+  export DDNS_LINE="unicom"
+  
+  # China Mobile
+  export DDNS_LINE="mobile"
+  
+  # Overseas
+  export DDNS_LINE="overseas"
+  ```
+
+## Network Configuration
+
+### Proxy Settings
+
+#### DDNS_PROXY
+
+- **Type**: Array or String
+- **Required**: No
+- **Default**: None (no proxy)
+- **Description**: HTTP proxy settings, tries multiple proxies until success
+- **Examples**:
+
+  ```bash
+  # Single proxy
+  export DDNS_PROXY="127.0.0.1:1080"
+  
+  # Multiple proxies with fallback
+  export DDNS_PROXY="127.0.0.1:1080;127.0.0.1:8080;DIRECT"
+  
+  # JSON array format
+  export DDNS_PROXY='["127.0.0.1:1080", "DIRECT"]'
+  
+  # SOCKS proxy
+  export DDNS_PROXY="socks5://127.0.0.1:1080"
+  
+  # HTTP proxy with authentication
+  export DDNS_PROXY="http://user:[email protected]:8080"
+  ```
+
+### Cache Configuration
+
+#### DDNS_CACHE
+
+- **Type**: Boolean or String
+- **Required**: No
+- **Default**: `true`
+- **Description**: Cache settings to avoid frequent updates
+- **Examples**:
+
+  ```bash
+  # Enable cache (default location)
+  export DDNS_CACHE="true"
+  
+  # Disable cache
+  export DDNS_CACHE="false"
+  
+  # Custom cache file path
+  export DDNS_CACHE="/var/cache/ddns/cache.json"
+  
+  # Use temporary directory
+  export DDNS_CACHE="/tmp/ddns.cache"
+  ```
+
+## Logging Configuration
+
+### Log Level
+
+#### DDNS_LOG_LEVEL
+
+- **Type**: String
+- **Required**: No
+- **Default**: `INFO`
+- **Available Values**: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
+- **Description**: Log level
+- **Examples**:
+
+  ```bash
+  # Debug mode (most verbose)
+  export DDNS_LOG_LEVEL="DEBUG"
+  
+  # Normal operation
+  export DDNS_LOG_LEVEL="INFO"
+  
+  # Warnings only
+  export DDNS_LOG_LEVEL="WARNING"
+  
+  # Errors only
+  export DDNS_LOG_LEVEL="ERROR"
+  ```
+
+### Log File
+
+#### DDNS_LOG_FILE
+
+- **Type**: String
+- **Required**: No
+- **Default**: None (outputs to console)
+- **Description**: Log file path
+- **Examples**:
+
+  ```bash
+  # System log directory
+  export DDNS_LOG_FILE="/var/log/ddns.log"
+  
+  # User home directory
+  export DDNS_LOG_FILE="$HOME/ddns.log"
+  
+  # Temporary directory
+  export DDNS_LOG_FILE="/tmp/ddns.log"
+  ```
+
+### Log Format
+
+#### DDNS_LOG_FORMAT
+
+- **Type**: String
+- **Required**: No
+- **Default**: `%(asctime)s %(levelname)s [%(module)s]: %(message)s`
+- **Description**: Log format string
+- **Examples**:
+
+  ```bash
+  # Simple format
+  export DDNS_LOG_FORMAT="%(asctime)s: %(message)s"
+  
+  # Detailed format
+  export DDNS_LOG_FORMAT="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
+  
+  # JSON format
+  export DDNS_LOG_FORMAT='{"time": "%(asctime)s", "level": "%(levelname)s", "message": "%(message)s"}'
+  ```
+
+#### DDNS_LOG_DATEFMT
+
+- **Type**: String
+- **Required**: No
+- **Default**: `%Y-%m-%dT%H:%M:%S`
+- **Description**: Date time format string
+- **Examples**:
+
+  ```bash
+  # ISO format (default)
+  export DDNS_LOG_DATEFMT="%Y-%m-%dT%H:%M:%S"
+  
+  # Standard format
+  export DDNS_LOG_DATEFMT="%Y-%m-%d %H:%M:%S"
+  
+  # Short format
+  export DDNS_LOG_DATEFMT="%m/%d %H:%M:%S"
+  ```
+
+## Complete Configuration Examples
+
+### Basic Configuration
+
+```bash
+# Basic Cloudflare configuration
+export DDNS_DNS="cloudflare"
+export DDNS_ID="[email protected]"
+export DDNS_TOKEN="your_cloudflare_token"
+export DDNS_IPV4="example.com"
+```
+
+### Advanced Configuration
+
+```bash
+# Advanced configuration with multiple domains and custom settings
+export DDNS_DNS="cloudflare"
+export DDNS_TOKEN="your_api_token"
+export DDNS_IPV4='["example.com", "www.example.com", "api.example.com"]'
+export DDNS_IPV6='["ipv6.example.com"]'
+export DDNS_INDEX4="public"
+export DDNS_INDEX6="public"
+export DDNS_TTL="600"
+export DDNS_PROXY="127.0.0.1:1080;DIRECT"
+export DDNS_CACHE="/var/cache/ddns.json"
+export DDNS_LOG_LEVEL="DEBUG"
+export DDNS_LOG_FILE="/var/log/ddns.log"
+```
+
+### Provider-Specific Examples
+
+#### DNSPod Configuration
+
+```bash
+export DDNS_DNS="dnspod"
+export DDNS_ID="12345"
+export DDNS_TOKEN="your_dnspod_token"
+export DDNS_IPV4="example.com"
+export DDNS_LINE="默认"
+```
+
+#### Alibaba Cloud DNS Configuration
+
+```bash
+export DDNS_DNS="alidns"
+export DDNS_ID="LTAI4xxxxxxxxxxxxx"
+export DDNS_TOKEN="your_secret_key"
+export DDNS_IPV4="example.com"
+export DDNS_LINE="default"
+```
+
+#### Custom Callback Configuration
+
+```bash
+export DDNS_DNS="callback"
+export DDNS_ID="https://api.example.com/webhook?domain=__DOMAIN__&ip=__IP__"
+export DDNS_TOKEN=""
+export DDNS_IPV4="example.com"
+```
+
+## Standard Environment Variables Support
+
+DDNS also supports some standard environment variables commonly used in system environments:
+
+| Standard Variable | DDNS Equivalent | Description |
+|------------------|-----------------|-------------|
+| `HTTP_PROXY` | `DDNS_PROXY` | HTTP proxy server |
+| `HTTPS_PROXY` | `DDNS_PROXY` | HTTPS proxy server |
+| `NO_PROXY` | - | Bypass proxy for these hosts |
+| `PYTHONHTTPSVERIFY` | `DDNS_SSL` | Python HTTPS verification |
+
+**Note**: DDNS-specific variables take priority over standard environment variables.
+
+## Configuration Validation
+
+When using environment variables, DDNS will validate the configuration and provide error messages for invalid values:
+
+- **DNS Provider**: Must be one of the supported providers
+- **Domains**: Must be valid domain names
+- **TTL**: Must be a positive integer
+- **Log Level**: Must be a valid log level
+- **File Paths**: Must be accessible file paths
+
+## See Also
+
+- [Command Line Arguments](cli.en.md)
+- [JSON Configuration File](json.en.md)
+- [Docker Usage](docker.en.md)
+- [Provider-specific Configuration](providers/)

+ 414 - 0
doc/config/env.md

@@ -0,0 +1,414 @@
+# DDNS 环境变量配置文档
+
+## 概述
+
+DDNS 支持通过环境变量进行配置,环境变量的优先级为:**[命令行参数](cli.md) > [配置文件](json.md) > 环境变量**
+
+所有环境变量都以 `DDNS_` 为前缀,后跟参数名(推荐全大写),对象和属性分隔符用`_`分割。
+
+> export DDNS_XXX="xxx"  命令作用于当前主机
+> docker run -e DDNS_XXX="xxx" 命令作用于容器内
+
+## 环境变量完整参数列表
+
+| 环境变量               | 参数格式                                                                                             | 描述                              | 示例                                                     |
+|------------------------|------------------------------------------------------------------------------------------------------|-----------------------------------|----------------------------------------------------------|
+| `DDNS_CONFIG`          | 文件路径,支持逗号或分号分隔多个路径                                                                | 指定配置文件路径,支持多个配置文件 | `DDNS_CONFIG="config.json"` 或 `DDNS_CONFIG="cloudflare.json,dnspod.json"` |
+| `DDNS_DNS`             | `51dns`、`alidns`、`aliesa`、`callback`、`cloudflare`、`debug`、`dnscom`、`dnspod_com`、`dnspod`、`edgeone`、`he`、`huaweidns`、`noip`、`tencentcloud` | [DNS 服务商](./providers/README.md) | `DDNS_DNS=cloudflare`                                    |
+| `DDNS_ID`              | 依 DNS 服务商而定                                                                                   | API 账号 或 ID                    | `DDNS_ID="[email protected]"`                             |
+| `DDNS_TOKEN`           | 依 DNS 服务商而定                                                                                   | API 授权令牌或 Secret             | `DDNS_TOKEN="abcdef123456"`                              |
+| `DDNS_ENDPOINT`        | URL(http 或 https 协议)                                                                           | 自定义 API 地址                   | `DDNS_ENDPOINT=https://api.dns.cn`                       |
+| `DDNS_IPV4`            | 域名,数组或逗号分隔字符串                                                                          | IPv4 域名列表                     | `DDNS_IPV4='["t.com","4.t.com"]'`                        |
+| `DDNS_IPV6`            | 域名,数组或逗号分隔字符串                                                                          | IPv6 域名列表                     | `DDNS_IPV6=t.com,6.t.com`                                |
+| `DDNS_INDEX4`          | 数字、default、public、url:、regex:、cmd:、shell:,可为数组                                        | IPv4 获取方式                     | `DDNS_INDEX4="[0,'regex:192.168.*']"`                    |
+| `DDNS_INDEX6`          | 数字、default、public、url:、regex:、cmd:、shell:,可为数组                                        | IPv6 获取方式                     | `DDNS_INDEX6=public`                                     |
+| `DDNS_TTL`             | 整数(单位:秒),依服务商而定                                                                     | 设置 DNS TTL                      | `DDNS_TTL=600`                                           |
+| `DDNS_LINE`            | 依服务商而定,如:电信、移动                                                                        | DNS 解析线路                      | `DDNS_LINE=电信`                                         |
+| `DDNS_PROXY`           | IP:端口 或 DIRECT,支持多代理数组或分号分隔                                                         | HTTP 代理设置                     | `DDNS_PROXY="127.0.0.1:1080;DIRECT"`                     |
+| `DDNS_CACHE`           | true、false 或文件路径                                                                              | 启用缓存或指定缓存文件路径        | `DDNS_CACHE="/tmp/cache"`                                |
+| `DDNS_SSL`             | true、false、auto 或文件路径                                                                         | 设置 SSL 验证方式或指定证书路径   | `DDNS_SSL=false`<br>`DDNS_SSL=/path/ca.crt`              |
+| `DDNS_LOG_LEVEL`       | DEBUG、INFO、WARNING、ERROR、CRITICAL                                                               | 设置日志等级                      | `DDNS_LOG_LEVEL="DEBUG"`                                 |
+| `DDNS_LOG_FILE`        | 文件路径                                                                                            | 设置日志输出文件(默认输出到终端)| `DDNS_LOG_FILE="/tmp/ddns.log"`                          |
+| `DDNS_LOG_FORMAT`      | Python logging 格式模板                                                                             | 设置日志格式                      | `DDNS_LOG_FORMAT="%(message)s"`                          |
+| `DDNS_LOG_DATEFMT`     | 日期时间格式字符串                                                                                  | 设置日志时间格式                  | `DDNS_LOG_DATEFMT="%m-%d %H:%M"`                         |
+
+> **注意**: 数组确认字符串引号,可打印出来查看
+
+## 基础配置参数
+
+### 配置文件路径
+
+#### DDNS_CONFIG
+
+- **类型**: 字符串
+- **必需**: 否
+- **默认值**: 按默认路径搜索(`config.json`、`~/.ddns/config.json`等)
+- **格式**: 单个文件路径或多个文件路径(用逗号或分号分隔)
+- **说明**: 指定配置文件路径,支持多个配置文件同时使用
+- **示例**:
+
+  ```bash
+  # 单个配置文件
+  export DDNS_CONFIG="config.json"
+  export DDNS_CONFIG="/path/to/ddns.json"
+  
+  # 多个配置文件径
+  export DDNS_CONFIG="/etc/ddns/cloudflare.json,./dnspod.json"
+  ```
+
+### DNS 服务商
+
+#### DDNS_DNS
+
+- **类型**: 字符串
+- **必需**: 否
+- **默认值**: `dnspod`
+- **可选值**: `51dns`, `alidns`, `aliesa`, `callback`, `cloudflare`, `debug`, `dnscom`, `dnspod`, `dnspod_com`, `edgeone`, `he`, `huaweidns`, `noip`, `tencentcloud`
+- **说明**: DNS 服务提供商
+- **示例**:
+
+  ```bash
+  export DDNS_DNS="alidns"        # 阿里云 DNS
+  export DDNS_DNS="aliesa"        # 阿里云企业版 DNS
+  export DDNS_DNS="cloudflare"    # CloudFlare
+  export DDNS_DNS="dnspod"        # DNSPod 国内版
+  export DDNS_DNS="dnspod_com"    # DNSPod 国际版
+  export DDNS_DNS="dnscom"        # DNS.COM
+  export DDNS_DNS="51dns"         # 51DNS (DNS.COM别名)
+  export DDNS_DNS="he"            # HE.net
+  export DDNS_DNS="huaweidns"     # 华为云 DNS
+  export DDNS_DNS="noip"          # NoIP
+  export DDNS_DNS="tencentcloud"  # 腾讯云 DNS
+  export DDNS_DNS="edgeone"       # 腾讯云 EdgeOne
+  export DDNS_DNS="callback"      # 自定义回调
+  export DDNS_DNS="debug"         # 调试模式
+  ```
+
+#### DDNS_ENDPOINT
+
+- **类型**: 字符串
+- **必需**: 否
+- **默认值**: 无(使用各DNS服务商的默认API端点)
+- **说明**: API端点URL,用于自定义或私有部署的API地址
+- **示例**:
+
+  ```bash
+  export DDNS_ENDPOINT="https://api.example.com"     # 自定义API端点
+  export DDNS_ENDPOINT="https://private.dns.com"     # 私有部署的DNS API
+  export DDNS_ENDPOINT=""                             # 使用默认端点
+  ```
+
+## 域名配置
+
+### IPv4 域名列表
+
+#### DDNS_IPV4
+
+- **类型**: 数组(支持 JSON/python 格式)
+- **必需**: 否
+- **默认值**: `[]`
+- **说明**: 需要更新 IPv4 记录的域名列表
+- **示例**:
+
+  ```bash
+  # JSON 数组格式(推荐)
+  export DDNS_IPV4='["example.com", "sub.example.com"]'
+  
+  # 单个域名
+  export DDNS_IPV4="example.com"
+  
+  # 禁用 IPv4 更新
+  export DDNS_IPV4="[]"
+  ```
+
+## IP 获取方式
+
+### IPv4 获取方式
+
+#### DDNS_INDEX4
+
+- **类型**: 字符串或数组
+- **必需**: 否
+- **默认值**: `["default"]` (使用系统默认外网IP)
+- **说明**: IPv4 地址获取方式。支持逗号`,`或分号`;`分隔的字符串格式
+- **特殊说明**: 当值包含 `regex:`、`cmd:` 或 `shell:` 前缀时,不支持分隔符分割,整个字符串作为单一配置项
+- **示例**:
+
+  ```bash
+  # 默认方式(系统默认外网 IP)
+  export DDNS_INDEX4="default"
+  
+  # 公网 IP
+  export DDNS_INDEX4="public"
+  
+  # 指定网卡(第 0 个网卡)
+  export DDNS_INDEX4="0"
+  
+  # 自定义 URL 获取
+  export DDNS_INDEX4="url:http://ip.sb"
+  
+  # 正则匹配(注意转义)- 不支持分割
+  export DDNS_INDEX4="regex:192\\.168\\..*"
+  
+  # 执行命令 - 不支持分割
+  export DDNS_INDEX4="cmd:curl -s http://ipv4.icanhazip.com"
+  
+  # Shell 命令 - 不支持分割
+  export DDNS_INDEX4="shell:ip route get 8.8.8.8 | awk '{print \$7}'"
+  
+  # 逗号分隔多种方式(仅限无特殊前缀时)
+  export DDNS_INDEX4="public,default"
+  
+  # 包含逗号的正则表达式(整体作为单一配置)
+  export DDNS_INDEX4="regex:192\\.168\\..*,10\\..*"
+  
+  # 多种方式组合(JSON 数组)
+  export DDNS_INDEX4='["public", "regex:172\\..*"]'
+  
+  # 禁用 IPv4 获取
+  export DDNS_INDEX4="false"
+  ```
+
+## 网络配置
+
+### 代理设置
+
+#### DDNS_PROXY
+
+- **类型**: 数组(支持 JSON 格式或分号分隔)
+- **必需**: 否
+- **默认值**: 无
+- **说明**: HTTP 代理设置,支持多代理轮换
+- **示例**:
+
+  ```bash
+  # 单个代理
+  export DDNS_PROXY="http://127.0.0.1:1080"
+  
+  # 多个代理(JSON 数组格式)
+  export DDNS_PROXY='["http://proxy1:8080", "http://proxy2:8080", "DIRECT"]'
+  
+  # 分号分隔格式
+  export DDNS_PROXY="http://proxy1:8080;http://proxy2:8080;DIRECT"
+  
+  # DIRECT 表示直连
+  export DDNS_PROXY="DIRECT"
+  ```
+
+## 系统配置
+
+### 缓存设置
+
+#### DDNS_CACHE
+
+- **类型**: 布尔值或字符串
+- **必需**: 否
+- **默认值**: `true`
+- **说明**: 启用缓存以减少 API 请求
+- **示例**:
+
+  ```bash
+  # 启用缓存(默认路径)
+  export DDNS_CACHE="true"
+  
+  # 禁用缓存
+  export DDNS_CACHE="false"
+  
+  # 自定义缓存文件路径
+  export DDNS_CACHE="/path/to/ddns.cache"
+  ```
+
+### SSL证书验证
+
+#### DDNS_SSL
+
+- **类型**: 字符串或布尔值
+- **必需**: 否
+- **默认值**: `"auto"`
+- **说明**: SSL证书验证方式,控制HTTPS连接的证书验证行为
+- **可选值**:
+  - `"true"`: 强制验证SSL证书(最安全)
+  - `"false"`: 禁用SSL证书验证(最不安全)
+  - `"auto"`: 优先验证,SSL证书错误时自动降级(不安全)
+  - 文件路径: 使用指定路径的自定义CA证书(最安全)
+- **示例**:
+
+  ```bash
+  export DDNS_SSL="true"     # 强制验证SSL证书
+  export DDNS_SSL="false"    # 禁用SSL验证(不推荐)
+  export DDNS_SSL="auto"     # 自动降级模式
+  export DDNS_SSL="/etc/ssl/certs/ca-certificates.crt"  # 自定义CA证书
+  ```
+
+### 日志配置
+
+#### DDNS_LOG_LEVEL
+
+- **类型**: 字符串
+- **必需**: 否
+- **默认值**: `INFO`
+- **可选值**: `CRITICAL`, `FATAL`, `ERROR`, `WARN`, `WARNING`, `INFO`, `DEBUG`, `NOTSET`
+- **说明**: 日志级别
+- **示例**:
+
+  ```bash
+  export DDNS_LOG_LEVEL="DEBUG"    # 调试模式
+  export DDNS_LOG_LEVEL="INFO"     # 信息模式
+  export DDNS_LOG_LEVEL="ERROR"    # 仅错误
+  ```
+
+#### DDNS_LOG_FILE
+
+- **类型**: 字符串
+- **必需**: 否
+- **默认值**: 无(输出到控制台)
+- **说明**: 日志文件路径
+- **示例**:
+
+  ```bash
+  export DDNS_LOG_FILE="/var/log/ddns.log"
+  export DDNS_LOG_FILE="./ddns.log"
+  ```
+
+#### DDNS_LOG_FORMAT
+
+- **类型**: 字符串
+- **必需**: 否
+- **默认值**: `%(asctime)s %(levelname)s [%(module)s]: %(message)s`
+- **说明**: 日志格式字符串,参考Python logging模块的格式化语法
+- **示例**:
+
+  ```bash
+  # 默认格式(含模块名)
+  export DDNS_LOG_FORMAT="%(asctime)s %(levelname)s [%(module)s]: %(message)s"
+  
+  # 包含文件名和行号(debug模式下默认格式)
+  export DDNS_LOG_FORMAT="%(asctime)s %(levelname)s [%(filename)s:%(lineno)d]: %(message)s"
+  
+  # 简单格式
+  export DDNS_LOG_FORMAT="%(levelname)s: %(message)s"
+  ```
+
+#### DDNS_LOG_DATEFMT
+
+- **类型**: 字符串
+- **必需**: 否
+- **默认值**: `%Y-%m-%dT%H:%M:%S`
+- **说明**: 日期时间格式字符串,参考Python time.strftime()的格式化语法
+- **示例**:
+
+  ```bash
+  # ISO 格式(默认)
+  export DDNS_LOG_DATEFMT="%Y-%m-%dT%H:%M:%S"
+  
+  # 简短格式
+  export DDNS_LOG_DATEFMT="%m-%d %H:%M:%S"
+  
+  # 标准格式
+  export DDNS_LOG_DATEFMT="%Y-%m-%d %H:%M:%S"
+  ```
+
+## 使用示例
+
+### Docker 环境变量示例
+
+```bash
+docker run -d \
+  -e DDNS_DNS=dnspod \
+  -e DDNS_ID=12345 \
+  -e DDNS_TOKEN=your_token_here \
+  -e DDNS_IPV4=example.com \
+  -e DDNS_IPV6='["ipv6.example.com","example.com"]' \
+  -e DDNS_INDEX4=["public", 0] \
+  -e DDNS_INDEX6=public \
+  -e DDNS_TTL=600 \
+  -e DDNS_LOG_LEVEL=INFO \
+  -e DDNS_LOG_FORMAT="%(asctime)s %(levelname)s [%(module)s]: %(message)s" \
+  -e DDNS_LOG_DATEFMT="%Y-%m-%dT%H:%M:%S" \
+  --network host \
+  newfuture/ddns
+```
+
+### 复杂配置示例
+
+```bash
+#!/bin/bash
+# 阿里云 DNS 高级配置
+export DDNS_DNS="alidns"
+export DDNS_ID="your_access_key_id"
+export DDNS_TOKEN="your_access_key_secret"
+
+# 多域名配置
+export DDNS_IPV4='["ddns.example.com", "home.example.com", "server.example.com"]'
+export DDNS_IPV6='["ipv6.example.com"]'
+
+# 多种 IP 获取方式
+export DDNS_INDEX4='["public", "regex:192\\.168\\.1\\..*", "cmd:curl -s ipv4.icanhazip.com"]'
+export DDNS_INDEX6="public"
+
+# 代理和缓存配置
+export DDNS_PROXY='["http://proxy.example.com:8080", "DIRECT"]'
+export DDNS_CACHE="/home/user/.ddns_cache"
+
+# 日志配置
+export DDNS_LOG_LEVEL="DEBUG"
+export DDNS_LOG_FILE="/var/log/ddns.log"
+export DDNS_LOG_FORMAT="%(asctime)s %(levelname)s [%(filename)s:%(lineno)d]: %(message)s"
+export DDNS_LOG_DATEFMT="%Y-%m-%d %H:%M:%S"
+
+# TTL 设置
+export DDNS_TTL="300"
+
+# 运行
+ddns
+```
+
+## 注意事项
+
+1. **数组参数格式**: `index4`, `index6`, `ipv4`, `ipv6`, `proxy` 等数组参数支持两种格式:
+   - JSON 数组格式:`'["item1", "item2"]'`(推荐)
+   - 逗号分隔格式:`"item1,item2"`
+
+2. **特殊前缀规则**: 对于 `index4` 和 `index6` 参数:
+   - 当值包含 `regex:`、`cmd:` 或 `shell:` 前缀时,整个字符串将作为单一配置项,不会按分隔符分割
+   - 例如:`"regex:192\\.168\\..*,10\\..*"` 会被视为一个完整的正则表达式,而不是两个配置项
+   - 这是因为这些前缀的值内部可能包含逗号或分号,分割会破坏配置的完整性
+
+3. **配置优先级和字段覆盖关系**:
+
+   DDNS工具中的配置优先级顺序为:**命令行参数 > JSON配置文件 > 环境变量**
+
+   - **命令行参数**: 优先级最高,会覆盖JSON配置文件和环境变量中的相同设置
+   - **JSON配置文件**: 优先级中等,会覆盖环境变量中的设置,但会被命令行参数覆盖
+   - **环境变量**: 优先级最低,当命令行参数和JSON配置文件中都没有相应设置时使用
+
+   举例说明:
+
+   ```
+   # 环境变量设置
+   export DDNS_TTL="600"
+   
+   # JSON配置文件内容
+   {
+     "ttl": 300
+   }
+   
+   # 命令行参数
+   ddns --ttl 900
+   ```
+
+   在上述例子中:
+   - 最终生效的是命令行参数值:`ttl=900`
+   - 如果不提供命令行参数,则使用JSON配置文件值:`ttl=300`
+   - 如果JSON配置和命令行参数都不提供,则使用环境变量值:`ttl=600`
+
+   另外,JSON配置文件中明确设置为`null`的值会覆盖环境变量设置,相当于未设置该值。
+
+4. **大小写兼容**: 环境变量名支持大写、小写或混合大小写
+
+5. **安全提醒**:
+   - 请妥善保管 `DDNS_TOKEN` 等敏感信息
+   - 在脚本中使用时避免明文存储
+   - 考虑使用 `.env` 文件或密钥管理系统
+
+6. **调试建议**: 出现问题时,可设置 `DDNS_LOG_LEVEL=DEBUG` 获取详细日志信息

+ 288 - 0
doc/config/json.en.md

@@ -0,0 +1,288 @@
+# DDNS JSON Configuration File Reference
+
+This document provides detailed information about the JSON configuration file format and parameters for the DDNS tool. JSON configuration files have priority between command line arguments and environment variables.
+
+## Basic Usage
+
+By default, DDNS looks for a `config.json` file in the current directory. You can also use the `-c` parameter to specify a configuration file path:
+
+* Current directory `config.json` (note that Docker runtime directory is `/ddns/`)
+* Current user directory `~/.ddns/config.json`
+* Linux system directory `/etc/ddns/config.json`
+
+> Note: When using configuration files in Docker, you need to mount the configuration file to the container's `/ddns/` directory through volume mapping. For details, please refer to the [Docker documentation](docker.en.md).
+
+```bash
+# Generate configuration file
+ddns --new-config
+# Specify parameters and configuration file
+ddns --dns dnspod --ipv4 ddns.newfuture.cc --new-config config.json
+
+# Use specified configuration file
+ddns -c /path/to/config.json
+# Or use Python source code
+python -m ddns -c /path/to/config.json
+
+# Use multiple configuration files
+ddns -c cloudflare.json -c dnspod.json
+# Or via environment variables
+export DDNS_CONFIG="cloudflare.json,dnspod.json"
+ddns
+```
+
+## JSON Schema
+
+DDNS configuration files follow JSON Schema standards. It's recommended to add the `$schema` field to your configuration file for editor auto-completion and validation features:
+
+Since v4.1, configuration files support single-line comments.
+
+```json
+{
+  "$schema": "https://ddns.newfuture.cc/schema/v4.1.json"
+}
+```
+
+## Schema
+
+Configuration Parameters Table
+
+| Key Name | Type | Required | Default Value | Parameter Description | Notes |
+| :------: | :--: | :------: | :-----------: | :------------------: | ----- |
+| dns | string | No | None | DNS Provider | Available values: 51dns, alidns, aliesa, callback, cloudflare, debug, dnscom, dnspod_com, dnspod, edgeone, he, huaweidns, namesilo, noip, tencentcloud |
+| id | string | Yes | None | API Access ID | Configure according to provider documentation (e.g., AccessKeyID) |
+| token | string | Yes | None | API Authorization Token | Configure according to provider documentation (e.g., AccessSecret) |
+| endpoint | string | No | None | API Endpoint URL | For custom or private deployment API addresses, uses default endpoint when empty |
+| ipv4 | array | No | `[]` | IPv4 Domain List | |
+| ipv6 | array | No | `[]` | IPv6 Domain List | |
+| index4 | string\|int\|array | No | `["default"]` | IPv4 Retrieval Method | [See details below](#index4-index6) |
+| index6 | string\|int\|array | No | `["default"]` | IPv6 Retrieval Method | [See details below](#index4-index6) |
+| ttl | number | No | `null` | DNS TTL Time | In seconds, uses DNS default policy when not set |
+| line | string | No | `null` | DNS Resolution Line | ISP line selection, supported values depend on DNS provider |
+| proxy | string\|array | No | None | HTTP Proxy | Try multiple proxies sequentially until success, `DIRECT` for direct connection |
+| ssl | string\|boolean | No | `"auto"` | SSL Verification Method | `true` (force verification), `false` (disable verification), `"auto"` (auto downgrade) or custom CA certificate file path |
+| cache | string\|bool | No | `true` | Enable Record Caching | Enable to avoid frequent updates, default location is `ddns.{hash}.cache` in temp directory, or specify custom path |
+| log | object | No | `null` | Log Configuration | Log configuration object, supports `level`, `file`, `format`, `datefmt` parameters |
+
+### dns
+
+The `dns` parameter specifies the DNS provider identifier. For supported values, please refer to the [Provider List](providers/README.en.md):
+
+> When in debug mode and no dns parameter is configured, the debug provider is used.
+
+### id and token
+
+The `id` and `token` parameters are used for API authentication. Their specific meaning and format depend on the selected DNS provider.
+
+### endpoint
+
+The `endpoint` parameter is used to specify a custom API endpoint. Most providers have default endpoints, so modification is not needed unless there are special requirements.
+
+Special cases include:
+
+* Providers with regional deployment (such as Tencent Cloud, Alibaba Cloud, etc.) need to specify the corresponding regional API endpoint.
+* **Private Cloud Deployment**: If you're using a privately deployed DNS service, you need to specify the corresponding private API endpoint address.
+* **Proxy Forwarding**: If you're using a third-party API proxy service, you need to specify the proxy URL.
+
+### ipv4-ipv6
+
+The `ipv4` and `ipv6` parameters specify the DNS record names to be updated, which can be domain or subdomain lists. You can use array format to specify multiple records.
+
+Supported formats:
+
+* When empty, the corresponding IP type DNS records will not be updated.
+* **Single domain**: `"ddns.newfuture.cc"`
+* **Multiple domains**: `["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"]`
+
+### index4-index6
+
+The `index4` and `index6` parameters are used to specify the method for obtaining IP addresses. The following values can be used:
+
+Supported types:
+
+* `false` indicates prohibition of updating the corresponding IP type DNS records
+* **Numbers** (such as `0`, `1`, `2`...): Use the IP address of the Nth network interface
+* `"default"`: System's default IP for external network access
+* `"public"`: Use public IP (queried through API)
+* `"url:http..."`: Get IP through specified URL, e.g., `"url:http://ip.sb"`
+* `"regex:xxx"`: Use regular expression to match IP in local network configuration, e.g., `"regex:192\\.168\\..*"`
+  * Note: Backslashes need to be escaped in JSON, e.g., `"regex:10\\.00\\..*"` matches IPs starting with `10.00.`
+* `"cmd:xxx"`: Execute specified command and use its output as IP
+* `"shell:xxx"`: Use system shell to run command and use its output as IP
+
+Configuration examples:
+
+```json
+{
+    "index4": ["public", "url:http://ipv4.icanhazip.com"], // Prefer public IP, fallback to specified URL
+    "index6": ["shell:ip route", "regex:2003:.*"], // Use shell command, fallback to regex matching IPv6 addresses
+    "index4": [0, "public"], // Use first network interface IP, fallback to public IP
+    "index6": "public", // Use public IPv6 address
+    "index4": false // Disable IPv4 record updates
+}
+```
+
+### ttl
+
+The `ttl` parameter specifies the Time To Live (TTL) for DNS records in seconds. The default value is `null`, which means using the DNS provider's default TTL policy.
+The specific value range and default value depend on the selected DNS provider.
+
+### line
+
+The `line` parameter is used to specify DNS resolution lines. Supported values depend on the selected DNS provider.
+
+### proxy
+
+The `proxy` parameter is used to set HTTP proxy, which can be a single proxy address or an array of multiple proxy addresses. The following formats are supported:
+
+Proxy types:
+
+* http: `"http://<proxy_host>:<proxy_port>"`
+* https: `"https://<proxy_host>:<proxy_port>"`
+* No proxy: `"DIRECT"`
+
+Configuration examples:
+
+```json
+{
+    "proxy": "http://127.0.0.1:1080", // Single proxy address
+    "proxy": ["http://127.0.0.1:1080","DIRECT"], // Try proxy first, fallback to direct connection
+    "proxy": null // No proxy
+}
+```
+
+> Note: If `proxy` is configured, the proxy only applies to provider requests; IP retrieval APIs will not use the proxy parameter.
+
+### ssl
+
+The `ssl` parameter is used to configure SSL verification method. The following values are supported:
+
+* `"auto"`: Auto downgrade to not verify SSL certificates (less secure)
+* `true`: Force SSL certificate verification
+* `false`: Disable SSL verification (insecure)
+* `"/path/to/ca.crt"`: Specify custom CA certificate file
+
+> Note: If `ssl` is configured, all API requests, including provider and IP retrieval APIs, will use this configuration.
+
+### cache
+
+The `cache` parameter is used to configure DNS record caching method. The following values are supported:
+
+* `true`: Enable caching, default location is `ddns.{hash}.cache` in the temporary directory
+* `false`: Disable caching
+* `"/path/to/cache.file"`: Specify custom cache file path
+
+### log
+
+The `log` parameter is used to configure logging. It's an object that supports the following fields:
+
+| Key Name | Type | Required | Default Value | Description |
+| :------: | :--: | :------: | :-----------: | :---------: |
+| level | string | No | `INFO` | Log level |
+| file | string | No | None | Log file path |
+| format | string | No | Auto-adjusted | Log format string |
+| datefmt | string | No | `%Y-%m-%dT%H:%M:%S` | Date time format |
+
+## Configuration Examples
+
+### Single-Provider Format
+
+```json
+{
+  "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
+  "id": "12345",
+  "token": "mytokenkey",
+  "dns": "cloudflare",
+  "ipv4": ["ddns.newfuture.cc"],
+  "ipv6": ["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"],
+  "index4": ["public", "regex:192\\.168\\.1\\..*"],
+  "index6": "public",
+  "ttl": 300,
+  "proxy": ["http://127.0.0.1:1080", "DIRECT"],
+  "ssl": "auto",
+  "cache": "/var/cache/ddns.cache",
+  "log": {
+    "level": "DEBUG",
+    "file": "/var/log/ddns.log",
+    "datefmt": "%Y-%m-%d %H:%M:%S"
+  }
+}
+```
+
+### Multi-Provider Format
+
+Starting from v4.1.0, you can define multiple DNS providers in a single configuration file using the new `providers` array format:
+
+```json
+{
+  "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
+  "ssl": "auto",
+  "cache": true,
+  "log": {"level": "INFO", "file": "/var/log/ddns.log"},
+  "providers": [
+    {
+      "provider": "cloudflare",
+      "id": "[email protected]",
+      "token": "cloudflare-token",
+      "ipv4": ["test1.example.com"],
+      "ttl": 300
+    },
+    {
+      "provider": "dnspod",
+      "id": "[email protected]",
+      "token": "dnspod-token",
+      "ipv4": ["test2.example.com"],
+      "ttl": 600
+    }
+  ]
+}
+```
+
+#### v4.1 Format Features
+
+* **Global Configuration Inheritance**: All configuration items outside `providers` (such as `ssl`, `cache`, `log`, etc.) serve as global settings and are inherited by all providers
+* **Provider Override**: Configuration within each provider can override corresponding global settings
+* **provider Field**: Required field that specifies the DNS provider type (equivalent to the `dns` field in traditional format)
+* **Full Compatibility**: Supports all configuration parameters from traditional format
+* **Nested Object Flattening**: Nested objects within providers are automatically flattened during processing
+
+#### Conflict Check
+
+* `providers` and `dns` fields cannot coexist
+* When using multiple providers, `ipv4` or `ipv6` fields cannot be used in global configuration
+  * Each provider must contain a `name` field
+  * Global (outer) level must not contain `ipv4` or `ipv6` fields
+
+## Configuration Priority and Field Override Relationships
+
+The configuration priority order in the DDNS tool is: **Command Line Arguments > JSON Configuration File > Environment Variables**.
+
+* **Command Line Arguments**: Highest priority, will override the same settings in JSON configuration files and environment variables
+* **JSON Configuration File**: Between command line arguments and environment variables, will override settings in environment variables
+* **Environment Variables**: Lowest priority, used when there are no corresponding settings in command line arguments and JSON configuration files
+
+### Configuration Override Example
+
+Assuming the following configuration:
+
+1. **Environment Variable**: `DDNS_TTL=600`
+2. **JSON Configuration File**: `"ttl": 300`
+3. **Command Line Argument**: `--ttl 900`
+
+The final effective value is from the command line argument: `ttl=900`
+
+If no command line argument is provided, the JSON configuration value is used: `ttl=300`
+
+### Special Cases
+
+* When a value in the JSON configuration file is explicitly set to `null`, it will override environment variable settings, equivalent to not setting that value
+* When a key is missing from the JSON configuration file, the corresponding environment variable will be attempted
+* Some parameters (such as `debug`) are only effective under specific configuration methods: the `debug` parameter is only effective in command line, settings in JSON configuration will be ignored
+
+## Notes
+
+1. Configuration files use UTF-8 encoding without BOM
+2. All key names in JSON are case-sensitive
+3. For strings that need to use backslashes (such as regular expressions) in configuration files, double escaping is required
+4. The `debug` parameter is ineffective when set in configuration files, only supports command line parameter `--debug`
+5. A template configuration file will be automatically generated in the current directory on first run
+6. It's recommended to use editors that support JSON Schema (such as VSCode) to edit configuration files for auto-completion and validation features

+ 291 - 0
doc/config/json.md

@@ -0,0 +1,291 @@
+---
+title: DDNS JSON配置文件参考
+description: 了解DDNS工具的JSON配置文件格式和参数,如何使用配置文件以及配置文件的优先级
+---
+
+本文档详细说明DDNS工具的JSON配置文件格式和参数。JSON配置文件优先级介于命令行参数和环境变量之间。
+
+## 基本用法
+
+默认情况下,DDNS会在当前目录查找`config.json`文件。您也可以使用`-c`参数指定配置文件路径:
+
+* 当前目录 `config.json` (注意Docker运行目录是 `/ddns/`)
+* 当前用户目录 `~/.ddns/config.json`
+* Linux当前系统 `/etc/ddns/config.json`
+
+> 注意:在Docker中使用配置文件时,需要通过卷映射将配置文件挂载到容器的`/ddns/`目录。详情请参考[Docker使用文档](docker.md)。
+
+```bash
+# 生成配置文件
+ddns --new-config
+# 指定参数和配置文件
+ddns --dns dnspod --ipv4 ddns.newfuture.cc --new-config config.json
+
+# 使用指定配置文件
+ddns -c /path/to/config.json
+# 或者使用Python源码
+python -m ddns -c /path/to/config.json
+
+# 使用多个配置文件
+ddns -c cloudflare.json -c dnspod.json
+# 或通过环境变量
+export DDNS_CONFIG="cloudflare.json,dnspod.json"
+ddns
+```
+
+## JSON模式
+
+DDNS配置文件遵循JSON模式(Schema),推荐在配置文件中添加`$schema`字段以获得编辑器的自动补全和验证功能:
+
+自v4.1.0版本开始,配置文件支持单行注释。
+
+```json
+{
+  "$schema": "https://ddns.newfuture.cc/schema/v4.0.json"
+}
+```
+
+## Schema
+
+配置参数表
+
+|  键名    |        类型        | 必需 |   默认值    |    参数说明          | 备注                                                                                                         |
+| :------: | :----------------: | :--: | :---------: | :---------------: | ------------------------------------------------------------------------------------------------------------ |
+|  dns     |       string       |  否  |     无      |    DNS服务商      | 可选值: 51dns, alidns, aliesa, callback, cloudflare, debug, dnscom, dnspod_com, dnspod, edgeone, he, huaweidns, namesilo, noip, tencentcloud |
+|   id     |       string       |  是  |     无      |   API 访问 ID    | 请根据服务商说明配置(如 AccessKeyID)  |
+|  token   |       string       |  是  |     无      |  API 授权令牌     | 请根据服务商说明配置(如 AccessSecret)  |
+| endpoint |       string       |  否  |     无      |   API端点URL      | 用于自定义或私有部署的API地址,为空时使用默认端点                                                           |
+|  ipv4    |       array        |  否  |    `[]`     |   IPv4域名列表    |  |
+|  ipv6    |       array        |  否  |    `[]`     |   IPv6域名列表    | |
+| index4   | string\|int\|array |  否  | `["default"]` |   IPv4获取方式    | [详见下方说明](#index4-index6)|
+| index6   | string\|int\|array |  否  | `["default"]` |   IPv6获取方式    | [详见下方说明](#index4-index6)|
+|  ttl     |       number       |  否  |   `null`    | DNS TTL时间     | 单位为秒,不设置则采用DNS默认策略|
+|  line    |       string       |  否  |   `null`    | DNS解析线路       | ISP线路选择,支持的值视DNS服务商而定 |
+|  proxy   | string\|array      |  否  |     无      | HTTP代理          | 多代理逐个尝试直到成功,`DIRECT`为直连                                                                      |
+|   ssl    | string\|boolean    |  否  |  `"auto"`   | SSL验证方式    | `true`(强制验证)、`false`(禁用验证)、`"auto"`(自动降级)或自定义CA证书文件路径                          |
+|  cache   |    string\|bool    |  否  |   `true`    | 是否缓存记录       | 正常情况打开避免频繁更新,默认位置为临时目录下`ddns.{hash}.cache`,也可以指定具体路径                              |
+|  log     |       object       |  否  |   `null`    | 日志配置  | 日志配置对象,支持`level`、`file`、`format`、`datefmt`参数                                                |
+
+### dns
+
+`dns`参数指定使用的DNS服务商标识,支持以下值, 请参考 [服务商列表](providers/README.md):
+
+> 当 debug 模式,且未配置dns参数时,使用 debug provider。
+
+### id-token
+
+`id`和`token`参数用于API认证,具体含义和格式取决于所选的DNS服务商。
+
+### endpoint
+
+`endpoint`参数用于指定自定义API端点,大多数服务商都有默认端点,除非有特殊需求,否则不需要修改。
+
+特殊情况包括:
+
+* 不同区域部署的服务商(如腾讯云、阿里云等)需要指定对应区域的API端点。
+* **私有云部署**:如果您使用的是私有部署的DNS服务,需要指定相应的私有API端点地址。
+* **代理转发**:如果您使用第三方API代理服务,需要指定代理的URL。
+
+### ipv4-ipv6
+
+`ipv4`和`ipv6`参数指定需要更新的DNS记录名称,可以是域名或子域名列表。可以使用数组形式指定多个记录。
+
+支持格式
+
+* 无值时,表示不更新对应类型的DNS记录。
+* **单个域名**:`"ddns.newfuture.cc"`
+* **多个域名**:`["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"]`
+
+### index4-index6
+
+`index4`和`index6`参数用于指定获取IP地址的方式,可以使用以下值:
+
+支持类型:
+
+* `false`表示禁止更新相应IP类型的DNS记录
+* **数字**(如`0`、`1`、`2`...):表示使用第N个网卡的IP地址
+* `"default"`:系统访问外网的默认IP
+* `"public"`:使用公网IP(通过API查询)
+* `"url:http..."`:通过指定URL获取IP,例如`"url:http://ip.sb"`
+* `"regex:xxx"`:使用正则表达式匹配本地网络配置中的IP,例如`"regex:192\\.168\\..*"`
+  * 注意:JSON中反斜杠需要转义,如`"regex:10\\.00\\..*"`表示匹配`10.00.`开头的IP
+* `"cmd:xxx"`:执行指定命令并使用其输出作为IP
+* `"shell:xxx"`:使用系统shell运行命令并使用其输出作为IP
+
+配置示例:
+
+```json
+{
+    "index4": ["public", "url:http://ipv4.icanhazip.com"], // 优先使用公网IP,失败后使用指定URL获取
+    "index6": ["shell:ip route", "regex:2003:.*"], // 使用shell命令,失败换成正则匹配IPv6地址
+    "index4": [0, "public"], // 使用第一个网卡IP,失败换成公网IP
+    "index6": "public", // 使用公网IPv6地址
+    "index4": false // 禁止更新IPv4记录
+}
+```
+
+### ttl
+
+`ttl`参数指定DNS记录的生存时间(TTL),单位为秒。默认值为`null`,表示使用DNS服务商的默认TTL策略。
+具体取值范围和默认值取决于所选的DNS服务商。
+
+### line
+
+`line`参数用于指定DNS解析线路,支持的值取决于所选的DNS服务商。
+
+### proxy
+
+`proxy`参数用于设置HTTP代理,可以是单个代理地址或多个代理地址的数组。支持以下格式:
+
+代理类型:
+
+* http: `"http://<proxy_host>:<proxy_port>"`
+* https: `"https://<proxy_host>:<proxy_port>"`
+* 不使用代理: `"DIRECT"`
+
+配置示例
+
+```json
+{
+    "proxy": "http://127.0.0.1:1080", // 单个代理地址
+    "proxy": ["http://127.0.0.1:1080","DIRECT"],// 先尝试代理,失败不使用代理
+    "proxy": null // 不使用代理
+}
+```
+
+> 注意:如果配置了`proxy`,代理只对provider请求有效,获取IP的API不会使用proxy参数。
+
+### ssl
+
+`ssl`参数用于配置SSL验证方式,支持以下值:
+
+* `"auto"`:自动降级到不验证SSL证书(不太安全)
+* `true`:强制验证SSL证书
+* `false`:禁用SSL验证 (不安全)
+* `"/path/to/ca.crt"`,用于指定自定义的CA证书文件
+
+> 注意:如果配置了`ssl`,则所有API请求,包括 provider 和 IP 获取 API 都会使用该配置。
+
+### cache
+
+`cache`参数用于配置DNS记录的缓存方式,支持以下值:
+
+* `true`:启用缓存,默认位置为临时目录下的`ddns.{hash}.cache`
+* `false`:禁用缓存
+* `"/path/to/cache.file"`:指定自定义缓存文件路径
+
+### log
+
+`log`参数用于配置日志记录,是一个对象,支持以下字段:
+
+|  键名   |   类型   | 必需 |     默认值            |    说明    |
+| :-----: | :------: | :--: | :-----------------: | :--------: |
+|  level  |  string  |  否  |       `INFO`        | 日志级别   |
+|  file   |  string  |  否  |         无          | 日志文件路径 |
+| format  |  string  |  否  |    自动调整          | 日志格式字符串 |
+| datefmt |  string  |  否  | `%Y-%m-%dT%H:%M:%S` | 日期时间格式 |
+
+## 配置示例
+
+### 单Provider格式
+
+```json
+{
+  "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
+  "id": "12345",
+  "token": "mytokenkey",
+  "dns": "cloudflare",
+  "ipv4": ["ddns.newfuture.cc"],
+  "ipv6": ["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"],
+  "index4": ["public", "regex:192\\.168\\.1\\..*"],
+  "index6": "public",
+  "ttl": 300,
+  "proxy": ["http://127.0.0.1:1080", "DIRECT"],
+  "ssl": "auto",
+  "cache": "/var/cache/ddns.cache",
+  "log": {
+    "level": "DEBUG",
+    "file": "/var/log/ddns.log",
+    "datefmt": "%Y-%m-%d %H:%M:%S"
+  }
+}
+```
+
+### 多Provider格式
+
+从v4.1.0版本开始,支持在单个配置文件中定义多个DNS Provider,使用新的 `providers` 数组格式:
+
+```json
+{
+  "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
+  "ssl": "auto",
+  "cache": true,
+  "log": {"level": "INFO", "file": "/var/log/ddns.log"},
+  "providers": [
+    {
+      "provider": "cloudflare",
+      "id": "[email protected]",
+      "token": "cloudflare-token",
+      "ipv4": ["test1.example.com"],
+      "ttl": 300
+    },
+    {
+      "provider": "dnspod",
+      "id": "[email protected]",
+      "token": "dnspod-token",
+      "ipv4": ["test2.example.com"],
+      "ttl": 600
+    }
+  ]
+}
+```
+
+#### v4.1格式特性
+
+* **全局配置继承**: `providers` 外的所有配置项(如 `ssl`, `cache`, `log` 等)作为全局设置,会被所有provider继承
+* **provider覆盖**: 每个provider内的配置可以覆盖相应的全局设置
+* **provider字段**: 必须字段,指定DNS服务商类型(等同于传统格式中的 `dns` 字段)
+* **完整兼容**: 支持所有传统格式中的配置参数
+* **嵌套对象扁平化**: provider内的嵌套对象会被自动扁平化处理
+
+#### 冲突检查
+
+* `providers` 和 `dns` 字段不能同时存在
+* 多providers时,不能在全局配置中使用 `ipv4` 或 `ipv6` 字段
+  * 每个provider必须包含 `provider` 字段
+  * 外层(global)不得包含 `ipv4`或者 `ipv6` 字段
+
+## 配置优先级和字段覆盖关系
+
+DDNS工具中的配置优先级顺序为:**命令行参数 > JSON配置文件 > 环境变量**。
+
+* **命令行参数**:优先级最高,会覆盖JSON配置文件和环境变量中的相同设置
+* **JSON配置文件**:介于命令行参数和环境变量之间,会覆盖环境变量中的设置
+* **环境变量**:优先级最低,当命令行参数和JSON配置文件中都没有相应设置时使用
+
+### 配置覆盖示例
+
+假设有以下配置:
+
+1. **环境变量**:`DDNS_TTL=600`
+2. **JSON配置文件**:`"ttl": 300`
+3. **命令行参数**:`--ttl 900`
+
+最终生效的是命令行参数的值:`ttl=900`
+
+如果没有提供命令行参数,则使用JSON配置值:`ttl=300`
+
+### 特殊情况
+
+* 当JSON配置文件中某个值明确设为`null`时,将覆盖环境变量设置,相当于未设置该值
+* 当JSON配置文件中缺少某个键时,会尝试使用对应的环境变量
+* 某些参数(如`debug`)仅在特定配置方式下有效:`debug`参数只在命令行中有效,JSON配置中的设置会被忽略
+
+## 注意事项
+
+1. 配置文件使用UTF-8编码,不包含BOM标记
+2. JSON中所有键名区分大小写
+3. 在配置文件中,对于需要使用反斜杠的字符串(如正则表达式),需要进行双重转义
+4. `debug`参数在配置文件中设置无效,仅支持命令行参数`--debug`
+5. 首次运行时会在当前目录自动生成一个模板配置文件
+6. 推荐使用支持JSONSchema的编辑器(如VSCode)编辑配置文件,可获得自动补全和验证功能

+ 3 - 3
doc/dev/config.en.md

@@ -114,9 +114,9 @@ class Config(object):
 
 Update the relevant documentation files:
 
-- `doc/cli.en.md` - Add CLI parameter documentation
-- `doc/env.en.md` - Add environment variable documentation  
-- `doc/json.en.md` - Add JSON configuration documentation
+- `doc/config/cli.en.md` - Add CLI parameter documentation
+- `doc/config/env.en.md` - Add environment variable documentation  
+- `doc/config/json.en.md` - Add JSON configuration documentation
 
 ## Configuration Value Processing
 

+ 9 - 9
doc/docker.en.md

@@ -6,9 +6,9 @@
   - Built-in scheduler, automatic updates every 5 minutes by default
   - No external dependencies, ready to use, optimized performance with low resource usage
 - Configuration Methods:
-  - [CLI Command Line Parameters](cli.en.md)
-  - [JSON Configuration File](json.en.md)
-  - [Environment Variables](env.en.md)
+  - [CLI Command Line Parameters](config/cli.en.md)
+  - [JSON Configuration File](config/json.en.md)
+  - [Environment Variables](config/env.en.md)
 
 ## Image Information
 
@@ -56,7 +56,7 @@ DDNS Docker image supports three configuration methods: command line, environmen
 
 ### Using Command Line Parameters (CLI)
 
-You can refer to the [CLI parameter documentation](cli.en.md) for a detailed parameter list.
+You can refer to the [CLI parameter documentation](config/cli.en.md) for a detailed parameter list.
 In this case, `docker run -v /local/config/:/ddns/ --name=ddns --network=host newfuture/ddns` is equivalent to the `ddns` command line and will not execute scheduled tasks.
 
 This method is suitable for one-time runs or debugging scenarios. Parameters are identical to DDNS command line parameters.
@@ -79,7 +79,7 @@ docker run -d -v /host/config/:/ddns/ newfuture/ddns
 ```
 
 Where `/host/config/` is your local directory containing `config.json`.
-For details on `config.json` content, refer to [JSON Configuration File Documentation](json.en.md).
+For details on `config.json` content, refer to [JSON Configuration File Documentation](config/json.en.md).
 
 ### Using Environment Variables (ENV)
 
@@ -99,7 +99,7 @@ docker run -d \
   newfuture/ddns
 ```
 
-To learn about all supported environment variables, please refer to [Environment Variable Configuration Documentation](env.en.md).
+To learn about all supported environment variables, please refer to [Environment Variable Configuration Documentation](config/env.en.md).
 
 ## Network Modes
 
@@ -293,9 +293,9 @@ RUN chmod +x /bin/custom-script.sh
 
 - [DDNS GitHub Repository](https://github.com/NewFuture/DDNS)
 - [Docker Hub - newfuture/ddns](https://hub.docker.com/r/newfuture/ddns)
-- [Environment Variable Configuration Details](env.en.md)
-- [JSON Configuration File Details](json.en.md)
-- [Command Line Parameter Details](cli.en.md)
+- [Environment Variable Configuration Details](config/env.en.md)
+- [JSON Configuration File Details](config/json.en.md)
+- [Command Line Parameter Details](config/cli.en.md)
 
 ## Configuration Examples for Different DNS Providers
 

+ 9 - 9
doc/docker.md

@@ -6,9 +6,9 @@
   - 内置定时任务,默认每 5 分钟自动更新一次
   - 无需外部依赖,开箱即用, 性能优化,资源占用低
 - 配置方式:
-  - [CLI 命令行参数](cli.md)
-  - [JSON 配置文件](json.md)
-  - [Env 环境变量](env.md)
+  - [CLI 命令行参数](config/cli.md)
+  - [JSON 配置文件](config/json.md)
+  - [Env 环境变量](config/env.md)
 
 ## 镜像说明
 
@@ -56,7 +56,7 @@ DDNS Docker 镜像支持三种配置方式:命令行,环境变量和配置
 
 ### 使用命令行参数 CLI
 
-可以参考[命令行参数说明](cli.md)获取详细的参数列表。
+可以参考[命令行参数说明](config/cli.md)获取详细的参数列表。
 此时 `docker run -v /local/config/:/ddns/  --name=ddns --network=host newfuture/ddns` 就相当于 `ddns` 命令行,不会执行定时任务。
 
 此方式适合需要一次性运行或调试的场景, 参数与 DDNS 命令行参数一致。
@@ -79,7 +79,7 @@ docker run -d -v /host/config/:/ddns/ newfuture/ddns
 ```
 
 其中 `/host/config/` 是您本地包含 `config.json` 的目录。
-详见 `config.json` 的内容可以参考 [JSON 配置文件说明](json.md)。
+详见 `config.json` 的内容可以参考 [JSON 配置文件说明](config/json.md)。
 
 ### 使用环境变量 ENV
 
@@ -99,7 +99,7 @@ docker run -d \
   newfuture/ddns
 ```
 
-想要了解所有支持的环境变量,请参考[环境变量配置说明](env.md)。
+想要了解所有支持的环境变量,请参考[环境变量配置说明](config/env.md)。
 
 ## 网络模式
 
@@ -293,6 +293,6 @@ RUN chmod +x /bin/custom-script.sh
 
 - [DDNS GitHub 主页](https://github.com/NewFuture/DDNS)
 - [Docker Hub - newfuture/ddns](https://hub.docker.com/r/newfuture/ddns)
-- [环境变量配置详情](env.md)
-- [JSON 配置文件详情](json.md)
-- [命令行参数详情](cli.md)
+- [环境变量配置详情](config/env.md)
+- [JSON 配置文件详情](config/json.md)
+- [命令行参数详情](config/cli.md)

+ 3 - 531
doc/env.en.md

@@ -1,533 +1,5 @@
-# DDNS Environment Variables Configuration
+# Environment Variables Documentation
 
-## Overview
+This file has been moved to: [config/env.en.md](config/env.en.md)
 
-DDNS supports configuration through environment variables with the following priority order: **[Command Line Arguments](cli.en.md) > [Configuration File](json.en.md) > Environment Variables**
-
-All environment variables use the `DDNS_` prefix followed by the parameter name (recommended uppercase).
-
-> `export DDNS_xxx="xxx"` command applies to the current host
-> `docker run -e DDNS_xxx="xxx"` command applies to the container
-
-## Complete Environment Variables List
-
-| Environment Variable     | Accepted Values                                                                                     | Description                              | Example                                                     |
-|--------------------------|------------------------------------------------------------------------------------------------------|------------------------------------------|-------------------------------------------------------------|
-| `DDNS_DNS`               | `51dns`, `alidns`, `aliesa`, `callback`, `cloudflare`, `debug`, `dnscom`, `dnspod_com`, `dnspod`, `edgeone`, `he`, `huaweidns`, `noip`, `tencentcloud` | [DNS Provider](./providers/README.en.md)    | `DDNS_DNS=cloudflare`                                       |
-| `DDNS_ID`                | Depends on the provider                                                                              | API account or ID                        | `DDNS_ID="[email protected]"`                                |
-| `DDNS_TOKEN`             | Depends on the provider                                                                              | API token or secret                      | `DDNS_TOKEN="abcdef123456"`                                 |
-| `DDNS_ENDPOINT`          | URL (starting with http or https)                                                                   | Custom API endpoint                       | `DDNS_ENDPOINT=https://api.dns.cn`                          |
-| `DDNS_IPV4`              | Domains as array or comma-separated string                                                           | List of IPv4 domains                      | `DDNS_IPV4='["t.com","4.t.com"]'`                           |
-| `DDNS_IPV6`              | Domains as array or comma-separated string                                                           | List of IPv6 domains                      | `DDNS_IPV6=t.com,6.t.com`                                   |
-| `DDNS_INDEX4`            | Number, `default`, `public`, `url:`, `regex:`, `cmd:`, `shell:`, or an array of them                | IPv4 address detection methods            | `DDNS_INDEX4="[0,'regex:192.168.*']"`                       |
-| `DDNS_INDEX6`            | Number, `default`, `public`, `url:`, `regex:`, `cmd:`, `shell:`, or an array of them                | IPv6 address detection methods            | `DDNS_INDEX6=public`                                        |
-| `DDNS_TTL`               | Integer (seconds), varies by provider                                                                | DNS record TTL                            | `DDNS_TTL=600`                                              |
-| `DDNS_LINE`              | ISP line such as: 电信, 联通, 移动, or provider-specific values                                     | DNS resolution line                       | `DDNS_LINE=电信`                                            |
-| `DDNS_PROXY`             | IP:port or `DIRECT`, multiple values separated by semicolons                                        | HTTP proxy settings                       | `DDNS_PROXY="127.0.0.1:1080;DIRECT"`                        |
-| `DDNS_CACHE`             | `true`, `false`, or file path                                                                        | Enable or specify cache file              | `DDNS_CACHE="/tmp/cache"`                                   |
-| `DDNS_SSL`               | `true`, `false`, `auto`, or file path                                                                | SSL verification mode or certificate path | `DDNS_SSL=false`<br>`DDNS_SSL=/path/ca.crt`                 |
-| `DDNS_LOG_LEVEL`         | `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`                                                     | Logging level                             | `DDNS_LOG_LEVEL="DEBUG"`                                    |
-| `DDNS_LOG_FILE`          | File path                                                                                            | Output log file (default: stdout)         | `DDNS_LOG_FILE="/tmp/ddns.log"`                             |
-| `DDNS_LOG_FORMAT`        | Python logging format string                                                                         | Log format template                       | `DDNS_LOG_FORMAT="%(message)s"`                             |
-| `DDNS_LOG_DATEFMT`       | Date-time format string                                                                              | Log timestamp format                      | `DDNS_LOG_DATEFMT="%m-%d %H:%M"`                            |
-
-
-## Basic Configuration Parameters
-
-### Authentication Information
-
-#### DDNS_ID
-
-- **Type**: String
-- **Required**: Yes (optional for some DNS providers)
-- **Description**: API access ID or user identifier
-- **Examples**:
-
-  ```bash
-  # Cloudflare (email address)
-  export DDNS_ID="[email protected]"
-  
-  # DNSPod (numeric ID)
-  export DDNS_ID="12345"
-  
-  # Alibaba Cloud (Access Key ID)
-  export DDNS_ID="LTAI4xxxxxxxxxxxxx"
-  
-  # HE.net (can be empty)
-  export DDNS_ID=""
-  ```
-
-#### DDNS_TOKEN
-
-- **Type**: String
-- **Required**: Yes
-- **Description**: API authorization token or key
-- **Examples**:
-
-  ```bash
-  # General API token
-  export DDNS_TOKEN="abcdef1234567890"
-  
-  # Cloudflare API token
-  export DDNS_TOKEN="1234567890abcdef_example_token"
-  
-  # Alibaba Cloud Secret Key
-  export DDNS_TOKEN="secretkey1234567890"
-  ```
-
-### DNS Provider
-
-#### DDNS_DNS
-
-- **Type**: String
-- **Required**: No
-- **Default**: `dnspod`
-- **Available Values**: `51dns`, `alidns`, `aliesa`, `callback`, `cloudflare`, `debug`, `dnscom`, `dnspod`, `dnspod_com`, `edgeone`, `he`, `huaweidns`, `noip`, `tencentcloud`
-- **Description**: DNS service provider
-- **Examples**:
-
-  ```bash
-  export DDNS_DNS="cloudflare"
-  export DDNS_DNS="alidns"
-  export DDNS_DNS="dnspod"
-  ```
-
-#### DDNS_ENDPOINT
-
-- **Type**: String
-- **Required**: No
-- **Default**: None (uses default API endpoint for each DNS provider)
-- **Description**: API endpoint URL for custom or private deployments
-- **Examples**:
-
-  ```bash
-  # Custom Cloudflare endpoint
-  export DDNS_ENDPOINT="https://api.private-cloudflare.com"
-  
-  # Private DNSPod deployment
-  export DDNS_ENDPOINT="https://internal-dns-api.company.com"
-  
-  # Local testing endpoint
-  export DDNS_ENDPOINT="http://localhost:8080/api"
-  ```
-
-### Custom Callback Configuration
-
-When using `DDNS_DNS="callback"`, configure custom callbacks with these environment variables:
-
-- **DDNS_ID**: Callback URL address with variable substitution support
-- **DDNS_TOKEN**: POST request parameters (JSON string), empty for GET requests
-
-For detailed configuration, see: [Callback Provider Configuration Documentation](providers/callback.en.md)
-
-**Examples**:
-
-```bash
-# GET method callback
-export DDNS_DNS="callback"
-export DDNS_ID="https://api.example.com/ddns?domain=__DOMAIN__&ip=__IP__"
-export DDNS_TOKEN=""
-
-# POST method callback (JSON string)
-export DDNS_DNS="callback"
-export DDNS_ID="https://api.example.com/ddns"
-export DDNS_TOKEN='{"api_key": "your_key", "domain": "__DOMAIN__", "ip": "__IP__"}'
-```
-
-**Supported Variable Substitutions**:
-
-- `__DOMAIN__`: Full domain name
-- `__IP__`: IP address (IPv4 or IPv6)
-- `__RECORDTYPE__`: DNS record type
-- `__TTL__`: Time to live (seconds)
-- `__LINE__`: Resolution line
-- `__TIMESTAMP__`: Current timestamp
-
-## Domain Configuration
-
-### IPv4 Domain List
-
-#### DDNS_IPV4
-
-- **Type**: Array (supports JSON/Python format)
-- **Required**: No
-- **Default**: `[]`
-- **Description**: List of domains requiring IPv4 record updates
-- **Examples**:
-
-  ```bash
-  # JSON array format (recommended)
-  export DDNS_IPV4='["example.com", "www.example.com", "api.example.com"]'
-  
-  # Python list format
-  export DDNS_IPV4="['example.com', 'www.example.com']"
-  
-  # Comma-separated string
-  export DDNS_IPV4="example.com,www.example.com"
-  
-  # Single domain
-  export DDNS_IPV4="example.com"
-  ```
-
-### IPv6 Domain List
-
-#### DDNS_IPV6
-
-- **Type**: Array (supports JSON/Python format)
-- **Required**: No
-- **Default**: `[]`
-- **Description**: List of domains requiring IPv6 record updates
-- **Examples**:
-
-  ```bash
-  # JSON array format
-  export DDNS_IPV6='["example.com", "ipv6.example.com"]'
-  
-  # Comma-separated string
-  export DDNS_IPV6="example.com,ipv6.example.com"
-  
-  # Single domain
-  export DDNS_IPV6="ipv6.example.com"
-  ```
-
-## IP Detection Methods
-
-### IPv4 Detection Method
-
-#### DDNS_INDEX4
-
-- **Type**: String or Array
-- **Required**: No
-- **Default**: `["default"]` (uses system's default external IP)
-- **Description**: IPv4 address detection methods. Supports comma `,` or semicolon `;` separated string format
-- **Special Note**: When value contains `regex:`, `cmd:`, or `shell:` prefix, separator splitting is not supported; the entire string is treated as a single configuration item
-- **Examples**:
-
-  ```bash
-  # Use public IP detection
-  export DDNS_INDEX4="public"
-  
-  # Multiple methods with fallback
-  export DDNS_INDEX4='["public", "default"]'
-  
-  # Network interface index
-  export DDNS_INDEX4="0"  # First network interface
-  export DDNS_INDEX4="1"  # Second network interface
-  
-  # Custom URL
-  export DDNS_INDEX4="url:https://api.ipify.org"
-  
-  # Regex pattern (no splitting)
-  export DDNS_INDEX4="regex:192\\.168\\..*"
-  
-  # Command execution (no splitting)
-  export DDNS_INDEX4="cmd:hostname -I | awk '{print \$1}'"
-  
-  # Shell command (no splitting)
-  export DDNS_INDEX4="shell:ip route get 8.8.8.8 | awk '{print \$7}'"
-  ```
-
-### IPv6 Detection Method
-
-#### DDNS_INDEX6
-
-- **Type**: String or Array
-- **Required**: No
-- **Default**: `["default"]` (uses system's default external IPv6)
-- **Description**: IPv6 address detection methods
-- **Examples**:
-
-  ```bash
-  # Use public IPv6 detection
-  export DDNS_INDEX6="public"
-  
-  # Network interface index
-  export DDNS_INDEX6="0"
-  
-  # Custom IPv6 detection URL
-  export DDNS_INDEX6="url:https://api6.ipify.org"
-  
-  # Multiple methods
-  export DDNS_INDEX6='["public", "default"]'
-  ```
-
-## DNS Configuration
-
-### TTL Setting
-
-#### DDNS_TTL
-
-- **Type**: Integer
-- **Required**: No
-- **Default**: None (uses DNS provider's default)
-- **Description**: DNS record TTL (Time To Live) in seconds
-- **Examples**:
-
-  ```bash
-  # 5 minutes
-  export DDNS_TTL="300"
-  
-  # 10 minutes (commonly used)
-  export DDNS_TTL="600"
-  
-  # 1 hour
-  export DDNS_TTL="3600"
-  ```
-
-### Resolution Line
-
-#### DDNS_LINE
-
-- **Type**: String
-- **Required**: No
-- **Default**: None (uses default line)
-- **Description**: DNS resolution line, ISP line selection
-- **Examples**:
-
-  ```bash
-  # Default line
-  export DDNS_LINE="default"
-  
-  # China Telecom
-  export DDNS_LINE="telecom"
-  
-  # China Unicom
-  export DDNS_LINE="unicom"
-  
-  # China Mobile
-  export DDNS_LINE="mobile"
-  
-  # Overseas
-  export DDNS_LINE="overseas"
-  ```
-
-## Network Configuration
-
-### Proxy Settings
-
-#### DDNS_PROXY
-
-- **Type**: Array or String
-- **Required**: No
-- **Default**: None (no proxy)
-- **Description**: HTTP proxy settings, tries multiple proxies until success
-- **Examples**:
-
-  ```bash
-  # Single proxy
-  export DDNS_PROXY="127.0.0.1:1080"
-  
-  # Multiple proxies with fallback
-  export DDNS_PROXY="127.0.0.1:1080;127.0.0.1:8080;DIRECT"
-  
-  # JSON array format
-  export DDNS_PROXY='["127.0.0.1:1080", "DIRECT"]'
-  
-  # SOCKS proxy
-  export DDNS_PROXY="socks5://127.0.0.1:1080"
-  
-  # HTTP proxy with authentication
-  export DDNS_PROXY="http://user:[email protected]:8080"
-  ```
-
-### Cache Configuration
-
-#### DDNS_CACHE
-
-- **Type**: Boolean or String
-- **Required**: No
-- **Default**: `true`
-- **Description**: Cache settings to avoid frequent updates
-- **Examples**:
-
-  ```bash
-  # Enable cache (default location)
-  export DDNS_CACHE="true"
-  
-  # Disable cache
-  export DDNS_CACHE="false"
-  
-  # Custom cache file path
-  export DDNS_CACHE="/var/cache/ddns/cache.json"
-  
-  # Use temporary directory
-  export DDNS_CACHE="/tmp/ddns.cache"
-  ```
-
-## Logging Configuration
-
-### Log Level
-
-#### DDNS_LOG_LEVEL
-
-- **Type**: String
-- **Required**: No
-- **Default**: `INFO`
-- **Available Values**: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
-- **Description**: Log level
-- **Examples**:
-
-  ```bash
-  # Debug mode (most verbose)
-  export DDNS_LOG_LEVEL="DEBUG"
-  
-  # Normal operation
-  export DDNS_LOG_LEVEL="INFO"
-  
-  # Warnings only
-  export DDNS_LOG_LEVEL="WARNING"
-  
-  # Errors only
-  export DDNS_LOG_LEVEL="ERROR"
-  ```
-
-### Log File
-
-#### DDNS_LOG_FILE
-
-- **Type**: String
-- **Required**: No
-- **Default**: None (outputs to console)
-- **Description**: Log file path
-- **Examples**:
-
-  ```bash
-  # System log directory
-  export DDNS_LOG_FILE="/var/log/ddns.log"
-  
-  # User home directory
-  export DDNS_LOG_FILE="$HOME/ddns.log"
-  
-  # Temporary directory
-  export DDNS_LOG_FILE="/tmp/ddns.log"
-  ```
-
-### Log Format
-
-#### DDNS_LOG_FORMAT
-
-- **Type**: String
-- **Required**: No
-- **Default**: `%(asctime)s %(levelname)s [%(module)s]: %(message)s`
-- **Description**: Log format string
-- **Examples**:
-
-  ```bash
-  # Simple format
-  export DDNS_LOG_FORMAT="%(asctime)s: %(message)s"
-  
-  # Detailed format
-  export DDNS_LOG_FORMAT="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
-  
-  # JSON format
-  export DDNS_LOG_FORMAT='{"time": "%(asctime)s", "level": "%(levelname)s", "message": "%(message)s"}'
-  ```
-
-#### DDNS_LOG_DATEFMT
-
-- **Type**: String
-- **Required**: No
-- **Default**: `%Y-%m-%dT%H:%M:%S`
-- **Description**: Date time format string
-- **Examples**:
-
-  ```bash
-  # ISO format (default)
-  export DDNS_LOG_DATEFMT="%Y-%m-%dT%H:%M:%S"
-  
-  # Standard format
-  export DDNS_LOG_DATEFMT="%Y-%m-%d %H:%M:%S"
-  
-  # Short format
-  export DDNS_LOG_DATEFMT="%m/%d %H:%M:%S"
-  ```
-
-## Complete Configuration Examples
-
-### Basic Configuration
-
-```bash
-# Basic Cloudflare configuration
-export DDNS_DNS="cloudflare"
-export DDNS_ID="[email protected]"
-export DDNS_TOKEN="your_cloudflare_token"
-export DDNS_IPV4="example.com"
-```
-
-### Advanced Configuration
-
-```bash
-# Advanced configuration with multiple domains and custom settings
-export DDNS_DNS="cloudflare"
-export DDNS_TOKEN="your_api_token"
-export DDNS_IPV4='["example.com", "www.example.com", "api.example.com"]'
-export DDNS_IPV6='["ipv6.example.com"]'
-export DDNS_INDEX4="public"
-export DDNS_INDEX6="public"
-export DDNS_TTL="600"
-export DDNS_PROXY="127.0.0.1:1080;DIRECT"
-export DDNS_CACHE="/var/cache/ddns.json"
-export DDNS_LOG_LEVEL="DEBUG"
-export DDNS_LOG_FILE="/var/log/ddns.log"
-```
-
-### Provider-Specific Examples
-
-#### DNSPod Configuration
-
-```bash
-export DDNS_DNS="dnspod"
-export DDNS_ID="12345"
-export DDNS_TOKEN="your_dnspod_token"
-export DDNS_IPV4="example.com"
-export DDNS_LINE="默认"
-```
-
-#### Alibaba Cloud DNS Configuration
-
-```bash
-export DDNS_DNS="alidns"
-export DDNS_ID="LTAI4xxxxxxxxxxxxx"
-export DDNS_TOKEN="your_secret_key"
-export DDNS_IPV4="example.com"
-export DDNS_LINE="default"
-```
-
-#### Custom Callback Configuration
-
-```bash
-export DDNS_DNS="callback"
-export DDNS_ID="https://api.example.com/webhook?domain=__DOMAIN__&ip=__IP__"
-export DDNS_TOKEN=""
-export DDNS_IPV4="example.com"
-```
-
-## Standard Environment Variables Support
-
-DDNS also supports some standard environment variables commonly used in system environments:
-
-| Standard Variable | DDNS Equivalent | Description |
-|------------------|-----------------|-------------|
-| `HTTP_PROXY` | `DDNS_PROXY` | HTTP proxy server |
-| `HTTPS_PROXY` | `DDNS_PROXY` | HTTPS proxy server |
-| `NO_PROXY` | - | Bypass proxy for these hosts |
-| `PYTHONHTTPSVERIFY` | `DDNS_SSL` | Python HTTPS verification |
-
-**Note**: DDNS-specific variables take priority over standard environment variables.
-
-## Configuration Validation
-
-When using environment variables, DDNS will validate the configuration and provide error messages for invalid values:
-
-- **DNS Provider**: Must be one of the supported providers
-- **Domains**: Must be valid domain names
-- **TTL**: Must be a positive integer
-- **Log Level**: Must be a valid log level
-- **File Paths**: Must be accessible file paths
-
-## See Also
-
-- [Command Line Arguments](cli.en.md)
-- [JSON Configuration File](json.en.md)
-- [Docker Usage](docker.en.md)
-- [Provider-specific Configuration](providers/)
+Please update your bookmarks and links to use the new location.

+ 3 - 392
doc/env.md

@@ -1,394 +1,5 @@
-# DDNS 环境变量配置文档
+# 环境变量文档
 
-## 概述
+此文件已移动至:[config/env.md](config/env.md)
 
-DDNS 支持通过环境变量进行配置,环境变量的优先级为:**[命令行参数](cli.md) > [配置文件](json.md) > 环境变量**
-
-所有环境变量都以 `DDNS_` 为前缀,后跟参数名(推荐全大写),对象和属性分隔符用`_`分割。
-
-> export DDNS_XXX="xxx"  命令作用于当前主机
-> docker run -e DDNS_XXX="xxx" 命令作用于容器内
-
-## 环境变量完整参数列表
-
-| 环境变量               | 参数格式                                                                                             | 描述                              | 示例                                                     |
-|------------------------|------------------------------------------------------------------------------------------------------|-----------------------------------|----------------------------------------------------------|
-| `DDNS_DNS`             | `51dns`、`alidns`、`aliesa`、`callback`、`cloudflare`、`debug`、`dnscom`、`dnspod_com`、`dnspod`、`edgeone`、`he`、`huaweidns`、`noip`、`tencentcloud` | [DNS 服务商](./providers/README.md) | `DDNS_DNS=cloudflare`                                    |
-| `DDNS_ID`              | 依 DNS 服务商而定                                                                                   | API 账号 或 ID                    | `DDNS_ID="[email protected]"`                             |
-| `DDNS_TOKEN`           | 依 DNS 服务商而定                                                                                   | API 授权令牌或 Secret             | `DDNS_TOKEN="abcdef123456"`                              |
-| `DDNS_ENDPOINT`        | URL(http 或 https 协议)                                                                           | 自定义 API 地址                   | `DDNS_ENDPOINT=https://api.dns.cn`                       |
-| `DDNS_IPV4`            | 域名,数组或逗号分隔字符串                                                                          | IPv4 域名列表                     | `DDNS_IPV4='["t.com","4.t.com"]'`                        |
-| `DDNS_IPV6`            | 域名,数组或逗号分隔字符串                                                                          | IPv6 域名列表                     | `DDNS_IPV6=t.com,6.t.com`                                |
-| `DDNS_INDEX4`          | 数字、default、public、url:、regex:、cmd:、shell:,可为数组                                        | IPv4 获取方式                     | `DDNS_INDEX4="[0,'regex:192.168.*']"`                    |
-| `DDNS_INDEX6`          | 数字、default、public、url:、regex:、cmd:、shell:,可为数组                                        | IPv6 获取方式                     | `DDNS_INDEX6=public`                                     |
-| `DDNS_TTL`             | 整数(单位:秒),依服务商而定                                                                     | 设置 DNS TTL                      | `DDNS_TTL=600`                                           |
-| `DDNS_LINE`            | 依服务商而定,如:电信、移动                                                                        | DNS 解析线路                      | `DDNS_LINE=电信`                                         |
-| `DDNS_PROXY`           | IP:端口 或 DIRECT,支持多代理数组或分号分隔                                                         | HTTP 代理设置                     | `DDNS_PROXY="127.0.0.1:1080;DIRECT"`                     |
-| `DDNS_CACHE`           | true、false 或文件路径                                                                              | 启用缓存或指定缓存文件路径        | `DDNS_CACHE="/tmp/cache"`                                |
-| `DDNS_SSL`             | true、false、auto 或文件路径                                                                         | 设置 SSL 验证方式或指定证书路径   | `DDNS_SSL=false`<br>`DDNS_SSL=/path/ca.crt`              |
-| `DDNS_LOG_LEVEL`       | DEBUG、INFO、WARNING、ERROR、CRITICAL                                                               | 设置日志等级                      | `DDNS_LOG_LEVEL="DEBUG"`                                 |
-| `DDNS_LOG_FILE`        | 文件路径                                                                                            | 设置日志输出文件(默认输出到终端)| `DDNS_LOG_FILE="/tmp/ddns.log"`                          |
-| `DDNS_LOG_FORMAT`      | Python logging 格式模板                                                                             | 设置日志格式                      | `DDNS_LOG_FORMAT="%(message)s"`                          |
-| `DDNS_LOG_DATEFMT`     | 日期时间格式字符串                                                                                  | 设置日志时间格式                  | `DDNS_LOG_DATEFMT="%m-%d %H:%M"`                         |
-
-> **注意**: 数组确认字符串引号,可打印出来查看
-
-## 基础配置参数
-
-### DNS 服务商
-
-#### DDNS_DNS
-
-- **类型**: 字符串
-- **必需**: 否
-- **默认值**: `dnspod`
-- **可选值**: `51dns`, `alidns`, `aliesa`, `callback`, `cloudflare`, `debug`, `dnscom`, `dnspod`, `dnspod_com`, `edgeone`, `he`, `huaweidns`, `noip`, `tencentcloud`
-- **说明**: DNS 服务提供商
-- **示例**:
-
-  ```bash
-  export DDNS_DNS="alidns"        # 阿里云 DNS
-  export DDNS_DNS="aliesa"        # 阿里云企业版 DNS
-  export DDNS_DNS="cloudflare"    # CloudFlare
-  export DDNS_DNS="dnspod"        # DNSPod 国内版
-  export DDNS_DNS="dnspod_com"    # DNSPod 国际版
-  export DDNS_DNS="dnscom"        # DNS.COM
-  export DDNS_DNS="51dns"         # 51DNS (DNS.COM别名)
-  export DDNS_DNS="he"            # HE.net
-  export DDNS_DNS="huaweidns"     # 华为云 DNS
-  export DDNS_DNS="noip"          # NoIP
-  export DDNS_DNS="tencentcloud"  # 腾讯云 DNS
-  export DDNS_DNS="edgeone"       # 腾讯云 EdgeOne
-  export DDNS_DNS="callback"      # 自定义回调
-  export DDNS_DNS="debug"         # 调试模式
-  ```
-
-#### DDNS_ENDPOINT
-
-- **类型**: 字符串
-- **必需**: 否
-- **默认值**: 无(使用各DNS服务商的默认API端点)
-- **说明**: API端点URL,用于自定义或私有部署的API地址
-- **示例**:
-
-  ```bash
-  export DDNS_ENDPOINT="https://api.example.com"     # 自定义API端点
-  export DDNS_ENDPOINT="https://private.dns.com"     # 私有部署的DNS API
-  export DDNS_ENDPOINT=""                             # 使用默认端点
-  ```
-
-## 域名配置
-
-### IPv4 域名列表
-
-#### DDNS_IPV4
-
-- **类型**: 数组(支持 JSON/python 格式)
-- **必需**: 否
-- **默认值**: `[]`
-- **说明**: 需要更新 IPv4 记录的域名列表
-- **示例**:
-
-  ```bash
-  # JSON 数组格式(推荐)
-  export DDNS_IPV4='["example.com", "sub.example.com"]'
-  
-  # 单个域名
-  export DDNS_IPV4="example.com"
-  
-  # 禁用 IPv4 更新
-  export DDNS_IPV4="[]"
-  ```
-
-
-## IP 获取方式
-
-### IPv4 获取方式
-
-#### DDNS_INDEX4
-
-- **类型**: 字符串或数组
-- **必需**: 否
-- **默认值**: `["default"]` (使用系统默认外网IP)
-- **说明**: IPv4 地址获取方式。支持逗号`,`或分号`;`分隔的字符串格式
-- **特殊说明**: 当值包含 `regex:`、`cmd:` 或 `shell:` 前缀时,不支持分隔符分割,整个字符串作为单一配置项
-- **示例**:
-
-  ```bash
-  # 默认方式(系统默认外网 IP)
-  export DDNS_INDEX4="default"
-  
-  # 公网 IP
-  export DDNS_INDEX4="public"
-  
-  # 指定网卡(第 0 个网卡)
-  export DDNS_INDEX4="0"
-  
-  # 自定义 URL 获取
-  export DDNS_INDEX4="url:http://ip.sb"
-  
-  # 正则匹配(注意转义)- 不支持分割
-  export DDNS_INDEX4="regex:192\\.168\\..*"
-  
-  # 执行命令 - 不支持分割
-  export DDNS_INDEX4="cmd:curl -s http://ipv4.icanhazip.com"
-  
-  # Shell 命令 - 不支持分割
-  export DDNS_INDEX4="shell:ip route get 8.8.8.8 | awk '{print \$7}'"
-  
-  # 逗号分隔多种方式(仅限无特殊前缀时)
-  export DDNS_INDEX4="public,default"
-  
-  # 包含逗号的正则表达式(整体作为单一配置)
-  export DDNS_INDEX4="regex:192\\.168\\..*,10\\..*"
-  
-  # 多种方式组合(JSON 数组)
-  export DDNS_INDEX4='["public", "regex:172\\..*"]'
-  
-  # 禁用 IPv4 获取
-  export DDNS_INDEX4="false"
-  ```
-
-## 网络配置
-
-### 代理设置
-
-#### DDNS_PROXY
-
-- **类型**: 数组(支持 JSON 格式或分号分隔)
-- **必需**: 否
-- **默认值**: 无
-- **说明**: HTTP 代理设置,支持多代理轮换
-- **示例**:
-
-  ```bash
-  # 单个代理
-  export DDNS_PROXY="http://127.0.0.1:1080"
-  
-  # 多个代理(JSON 数组格式)
-  export DDNS_PROXY='["http://proxy1:8080", "http://proxy2:8080", "DIRECT"]'
-  
-  # 分号分隔格式
-  export DDNS_PROXY="http://proxy1:8080;http://proxy2:8080;DIRECT"
-  
-  # DIRECT 表示直连
-  export DDNS_PROXY="DIRECT"
-  ```
-
-## 系统配置
-
-### 缓存设置
-
-#### DDNS_CACHE
-
-- **类型**: 布尔值或字符串
-- **必需**: 否
-- **默认值**: `true`
-- **说明**: 启用缓存以减少 API 请求
-- **示例**:
-
-  ```bash
-  # 启用缓存(默认路径)
-  export DDNS_CACHE="true"
-  
-  # 禁用缓存
-  export DDNS_CACHE="false"
-  
-  # 自定义缓存文件路径
-  export DDNS_CACHE="/path/to/ddns.cache"
-  ```
-
-### SSL证书验证
-
-#### DDNS_SSL
-
-- **类型**: 字符串或布尔值
-- **必需**: 否
-- **默认值**: `"auto"`
-- **说明**: SSL证书验证方式,控制HTTPS连接的证书验证行为
-- **可选值**:
-  - `"true"`: 强制验证SSL证书(最安全)
-  - `"false"`: 禁用SSL证书验证(最不安全)
-  - `"auto"`: 优先验证,SSL证书错误时自动降级(不安全)
-  - 文件路径: 使用指定路径的自定义CA证书(最安全)
-- **示例**:
-
-  ```bash
-  export DDNS_SSL="true"     # 强制验证SSL证书
-  export DDNS_SSL="false"    # 禁用SSL验证(不推荐)
-  export DDNS_SSL="auto"     # 自动降级模式
-  export DDNS_SSL="/etc/ssl/certs/ca-certificates.crt"  # 自定义CA证书
-  ```
-
-### 日志配置
-
-#### DDNS_LOG_LEVEL
-
-- **类型**: 字符串
-- **必需**: 否
-- **默认值**: `INFO`
-- **可选值**: `CRITICAL`, `FATAL`, `ERROR`, `WARN`, `WARNING`, `INFO`, `DEBUG`, `NOTSET`
-- **说明**: 日志级别
-- **示例**:
-
-  ```bash
-  export DDNS_LOG_LEVEL="DEBUG"    # 调试模式
-  export DDNS_LOG_LEVEL="INFO"     # 信息模式
-  export DDNS_LOG_LEVEL="ERROR"    # 仅错误
-  ```
-
-#### DDNS_LOG_FILE
-
-- **类型**: 字符串
-- **必需**: 否
-- **默认值**: 无(输出到控制台)
-- **说明**: 日志文件路径
-- **示例**:
-
-  ```bash
-  export DDNS_LOG_FILE="/var/log/ddns.log"
-  export DDNS_LOG_FILE="./ddns.log"
-  ```
-
-#### DDNS_LOG_FORMAT
-
-- **类型**: 字符串
-- **必需**: 否
-- **默认值**: `%(asctime)s %(levelname)s [%(module)s]: %(message)s`
-- **说明**: 日志格式字符串,参考Python logging模块的格式化语法
-- **示例**:
-
-  ```bash
-  # 默认格式(含模块名)
-  export DDNS_LOG_FORMAT="%(asctime)s %(levelname)s [%(module)s]: %(message)s"
-  
-  # 包含文件名和行号(debug模式下默认格式)
-  export DDNS_LOG_FORMAT="%(asctime)s %(levelname)s [%(filename)s:%(lineno)d]: %(message)s"
-  
-  # 简单格式
-  export DDNS_LOG_FORMAT="%(levelname)s: %(message)s"
-  ```
-
-#### DDNS_LOG_DATEFMT
-
-- **类型**: 字符串
-- **必需**: 否
-- **默认值**: `%Y-%m-%dT%H:%M:%S`
-- **说明**: 日期时间格式字符串,参考Python time.strftime()的格式化语法
-- **示例**:
-
-  ```bash
-  # ISO 格式(默认)
-  export DDNS_LOG_DATEFMT="%Y-%m-%dT%H:%M:%S"
-  
-  # 简短格式
-  export DDNS_LOG_DATEFMT="%m-%d %H:%M:%S"
-  
-  # 标准格式
-  export DDNS_LOG_DATEFMT="%Y-%m-%d %H:%M:%S"
-  ```
-
-## 使用示例
-
-### Docker 环境变量示例
-
-```bash
-docker run -d \
-  -e DDNS_DNS=dnspod \
-  -e DDNS_ID=12345 \
-  -e DDNS_TOKEN=your_token_here \
-  -e DDNS_IPV4=example.com \
-  -e DDNS_IPV6='["ipv6.example.com","example.com"]' \
-  -e DDNS_INDEX4=["public", 0] \
-  -e DDNS_INDEX6=public \
-  -e DDNS_TTL=600 \
-  -e DDNS_LOG_LEVEL=INFO \
-  -e DDNS_LOG_FORMAT="%(asctime)s %(levelname)s [%(module)s]: %(message)s" \
-  -e DDNS_LOG_DATEFMT="%Y-%m-%dT%H:%M:%S" \
-  --network host \
-  newfuture/ddns
-```
-
-### 复杂配置示例
-
-```bash
-#!/bin/bash
-# 阿里云 DNS 高级配置
-export DDNS_DNS="alidns"
-export DDNS_ID="your_access_key_id"
-export DDNS_TOKEN="your_access_key_secret"
-
-# 多域名配置
-export DDNS_IPV4='["ddns.example.com", "home.example.com", "server.example.com"]'
-export DDNS_IPV6='["ipv6.example.com"]'
-
-# 多种 IP 获取方式
-export DDNS_INDEX4='["public", "regex:192\\.168\\.1\\..*", "cmd:curl -s ipv4.icanhazip.com"]'
-export DDNS_INDEX6="public"
-
-# 代理和缓存配置
-export DDNS_PROXY='["http://proxy.example.com:8080", "DIRECT"]'
-export DDNS_CACHE="/home/user/.ddns_cache"
-
-# 日志配置
-export DDNS_LOG_LEVEL="DEBUG"
-export DDNS_LOG_FILE="/var/log/ddns.log"
-export DDNS_LOG_FORMAT="%(asctime)s %(levelname)s [%(filename)s:%(lineno)d]: %(message)s"
-export DDNS_LOG_DATEFMT="%Y-%m-%d %H:%M:%S"
-
-# TTL 设置
-export DDNS_TTL="300"
-
-# 运行
-ddns
-```
-
-## 注意事项
-
-1. **数组参数格式**: `index4`, `index6`, `ipv4`, `ipv6`, `proxy` 等数组参数支持两种格式:
-   - JSON 数组格式:`'["item1", "item2"]'`(推荐)
-   - 逗号分隔格式:`"item1,item2"`
-
-2. **特殊前缀规则**: 对于 `index4` 和 `index6` 参数:
-   - 当值包含 `regex:`、`cmd:` 或 `shell:` 前缀时,整个字符串将作为单一配置项,不会按分隔符分割
-   - 例如:`"regex:192\\.168\\..*,10\\..*"` 会被视为一个完整的正则表达式,而不是两个配置项
-   - 这是因为这些前缀的值内部可能包含逗号或分号,分割会破坏配置的完整性
-
-3. **配置优先级和字段覆盖关系**:
-
-   DDNS工具中的配置优先级顺序为:**命令行参数 > JSON配置文件 > 环境变量**
-
-   - **命令行参数**: 优先级最高,会覆盖JSON配置文件和环境变量中的相同设置
-   - **JSON配置文件**: 优先级中等,会覆盖环境变量中的设置,但会被命令行参数覆盖
-   - **环境变量**: 优先级最低,当命令行参数和JSON配置文件中都没有相应设置时使用
-
-   举例说明:
-
-   ```
-   # 环境变量设置
-   export DDNS_TTL="600"
-   
-   # JSON配置文件内容
-   {
-     "ttl": 300
-   }
-   
-   # 命令行参数
-   ddns --ttl 900
-   ```
-
-   在上述例子中:
-   - 最终生效的是命令行参数值:`ttl=900`
-   - 如果不提供命令行参数,则使用JSON配置文件值:`ttl=300`
-   - 如果JSON配置和命令行参数都不提供,则使用环境变量值:`ttl=600`
-
-   另外,JSON配置文件中明确设置为`null`的值会覆盖环境变量设置,相当于未设置该值。
-
-4. **大小写兼容**: 环境变量名支持大写、小写或混合大小写
-
-5. **安全提醒**:
-   - 请妥善保管 `DDNS_TOKEN` 等敏感信息
-   - 在脚本中使用时避免明文存储
-   - 考虑使用 `.env` 文件或密钥管理系统
-
-6. **调试建议**: 出现问题时,可设置 `DDNS_LOG_LEVEL=DEBUG` 获取详细日志信息
+请更新您的书签和链接以使用新位置。

+ 3 - 230
doc/json.en.md

@@ -1,232 +1,5 @@
-# DDNS JSON Configuration File Reference
+# JSON Configuration Documentation
 
-This document provides detailed information about the JSON configuration file format and parameters for the DDNS tool. JSON configuration files have priority between command line arguments and environment variables.
+This file has been moved to: [config/json.en.md](config/json.en.md)
 
-## Basic Usage
-
-By default, DDNS looks for a `config.json` file in the current directory. You can also use the `-c` parameter to specify a configuration file path:
-
-* Current directory `config.json` (note that Docker runtime directory is `/ddns/`)
-* Current user directory `~/.ddns/config.json`
-* Linux system directory `/etc/ddns/config.json`
-
-> Note: When using configuration files in Docker, you need to mount the configuration file to the container's `/ddns/` directory through volume mapping. For details, please refer to the [Docker documentation](docker.en.md).
-
-```bash
-# Generate configuration file
-ddns --new-config
-# Specify parameters and configuration file
-ddns --dns dnspod --ipv4 ddns.newfuture.cc --new-config config.json
-
-# Use specified configuration file
-ddns -c /path/to/config.json
-# Or use Python source code
-python -m ddns -c /path/to/config.json
-```
-
-## JSON Schema
-
-DDNS configuration files follow JSON Schema standards. It's recommended to add the `$schema` field to your configuration file for editor auto-completion and validation features:
-
-Since v4.1.0, configuration files support single-line comments.
-
-```json
-{
-  "$schema": "https://ddns.newfuture.cc/schema/v4.0.json"
-}
-```
-
-## Schema
-
-Configuration Parameters Table
-
-| Key Name | Type | Required | Default Value | Parameter Description | Notes |
-| :------: | :--: | :------: | :-----------: | :------------------: | ----- |
-| dns | string | No | None | DNS Provider | Available values: 51dns, alidns, aliesa, callback, cloudflare, debug, dnscom, dnspod_com, dnspod, edgeone, he, huaweidns, namesilo, noip, tencentcloud |
-| id | string | Yes | None | API Access ID | Configure according to provider documentation (e.g., AccessKeyID) |
-| token | string | Yes | None | API Authorization Token | Configure according to provider documentation (e.g., AccessSecret) |
-| endpoint | string | No | None | API Endpoint URL | For custom or private deployment API addresses, uses default endpoint when empty |
-| ipv4 | array | No | `[]` | IPv4 Domain List | |
-| ipv6 | array | No | `[]` | IPv6 Domain List | |
-| index4 | string\|int\|array | No | `["default"]` | IPv4 Retrieval Method | [See details below](#ipv4-ipv6) |
-| index6 | string\|int\|array | No | `["default"]` | IPv6 Retrieval Method | [See details below](#ipv4-ipv6) |
-| ttl | number | No | `null` | DNS TTL Time | In seconds, uses DNS default policy when not set |
-| line | string | No | `null` | DNS Resolution Line | ISP line selection, supported values depend on DNS provider |
-
-### dns
-
-The `dns` parameter specifies the DNS provider identifier. For supported values, please refer to the [Provider List](providers/README.en.md):
-
-> When in debug mode and no dns parameter is configured, the debug provider is used.
-
-### id and token
-
-The `id` and `token` parameters are used for API authentication. Their specific meaning and format depend on the selected DNS provider.
-
-### endpoint
-
-The `endpoint` parameter is used to specify a custom API endpoint. Most providers have default endpoints, so modification is not needed unless there are special requirements.
-
-Special cases include:
-
-* Providers with regional deployment (such as Tencent Cloud, Alibaba Cloud, etc.) need to specify the corresponding regional API endpoint.
-* **Private Cloud Deployment**: If you're using a privately deployed DNS service, you need to specify the corresponding private API endpoint address.
-* **Proxy Forwarding**: If you're using a third-party API proxy service, you need to specify the proxy URL.
-
-### ipv4-ipv6
-
-The `ipv4` and `ipv6` parameters specify the DNS record names to be updated, which can be domain or subdomain lists. You can use array format to specify multiple records.
-
-Supported formats:
-
-* When empty, the corresponding IP type DNS records will not be updated.
-* **Single domain**: `"ddns.newfuture.cc"`
-* **Multiple domains**: `["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"]`
-
-### index4-index6
-
-The `index4` and `index6` parameters are used to specify the method for obtaining IP addresses. The following values can be used:
-
-Supported types:
-
-* `false` indicates prohibition of updating the corresponding IP type DNS records
-* **Numbers** (such as `0`, `1`, `2`...): Use the IP address of the Nth network interface
-* `"default"`: System's default IP for external network access
-* `"public"`: Use public IP (queried through API)
-* `"url:http..."`: Get IP through specified URL, e.g., `"url:http://ip.sb"`
-* `"regex:xxx"`: Use regular expression to match IP in local network configuration, e.g., `"regex:192\\.168\\..*"`
-  * Note: Backslashes need to be escaped in JSON, e.g., `"regex:10\\.00\\..*"` matches IPs starting with `10.00.`
-* `"cmd:xxx"`: Execute specified command and use its output as IP
-* `"shell:xxx"`: Use system shell to run command and use its output as IP
-
-Configuration examples:
-
-```json
-{
-    "index4": ["public", "url:http://ipv4.icanhazip.com"], // Prefer public IP, fallback to specified URL
-    "index6": ["shell:ip route", "regex:2003:.*"], // Use shell command, fallback to regex matching IPv6 addresses
-    "index4": [0, "public"], // Use first network interface IP, fallback to public IP
-    "index6": "public", // Use public IPv6 address
-    "index4": false // Disable IPv4 record updates
-}
-```
-
-### ttl
-
-The `ttl` parameter specifies the Time To Live (TTL) for DNS records in seconds. The default value is `null`, which means using the DNS provider's default TTL policy.
-The specific value range and default value depend on the selected DNS provider.
-
-### line
-
-The `line` parameter is used to specify DNS resolution lines. Supported values depend on the selected DNS provider.
-
-### proxy
-
-The `proxy` parameter is used to set HTTP proxy, which can be a single proxy address or an array of multiple proxy addresses. The following formats are supported:
-
-Proxy types:
-
-* http: `"http://<proxy_host>:<proxy_port>"`
-* https: `"https://<proxy_host>:<proxy_port>"`
-* No proxy: `"DIRECT"`
-
-Configuration examples:
-
-```json
-{
-    "proxy": "http://127.0.0.1:1080", // Single proxy address
-    "proxy": ["http://127.0.0.1:1080","DIRECT"], // Try proxy first, fallback to direct connection
-    "proxy": null // No proxy
-}
-```
-
-> Note: If `proxy` is configured, the proxy only applies to provider requests; IP retrieval APIs will not use the proxy parameter.
-
-### ssl
-
-The `ssl` parameter is used to configure SSL verification method. The following values are supported:
-
-* `"auto"`: Auto downgrade to not verify SSL certificates (less secure)
-* `true`: Force SSL certificate verification
-* `false`: Disable SSL verification (insecure)
-* `"/path/to/ca.crt"`: Specify custom CA certificate file
-
-> Note: If `ssl` is configured, all API requests, including provider and IP retrieval APIs, will use this configuration.
-
-### cache
-
-The `cache` parameter is used to configure DNS record caching method. The following values are supported:
-
-* `true`: Enable caching, default location is `ddns.{hash}.cache` in the temporary directory
-* `false`: Disable caching
-* `"/path/to/cache.file"`: Specify custom cache file path
-
-### log
-
-The `log` parameter is used to configure logging. It's an object that supports the following fields:
-
-| Key Name | Type | Required | Default Value | Description |
-| :------: | :--: | :------: | :-----------: | :---------: |
-| level | string | No | `INFO` | Log level |
-| file | string | No | None | Log file path |
-| format | string | No | Auto-adjusted | Log format string |
-| datefmt | string | No | `%Y-%m-%dT%H:%M:%S` | Date time format |
-
-## Configuration Example
-
-```json
-{
-  "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
-  "id": "12345",
-  "token": "mytokenkey",
-  "dns": "cloudflare",
-  "ipv4": ["ddns.newfuture.cc"],
-  "ipv6": ["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"],
-  "index4": ["public", "regex:192\\.168\\.1\\..*"],
-  "index6": "public",
-  "ttl": 300,
-  "proxy": ["http://127.0.0.1:1080", "DIRECT"],
-  "ssl": "auto",
-  "cache": "/var/cache/ddns.cache",
-  "log": {
-    "level": "DEBUG",
-    "file": "/var/log/ddns.log",
-    "datefmt": "%Y-%m-%d %H:%M:%S"
-  }
-}
-```
-
-## Configuration Priority and Field Override Relationships
-
-The configuration priority order in the DDNS tool is: **Command Line Arguments > JSON Configuration File > Environment Variables**.
-
-* **Command Line Arguments**: Highest priority, will override the same settings in JSON configuration files and environment variables
-* **JSON Configuration File**: Between command line arguments and environment variables, will override settings in environment variables
-* **Environment Variables**: Lowest priority, used when there are no corresponding settings in command line arguments and JSON configuration files
-
-### Configuration Override Example
-
-Assuming the following configuration:
-
-1. **Environment Variable**: `DDNS_TTL=600`
-2. **JSON Configuration File**: `"ttl": 300`
-3. **Command Line Argument**: `--ttl 900`
-
-The final effective value is from the command line argument: `ttl=900`
-
-If no command line argument is provided, the JSON configuration value is used: `ttl=300`
-
-### Special Cases
-
-* When a value in the JSON configuration file is explicitly set to `null`, it will override environment variable settings, equivalent to not setting that value
-* When a key is missing from the JSON configuration file, the corresponding environment variable will be attempted
-* Some parameters (such as `debug`) are only effective under specific configuration methods: the `debug` parameter is only effective in command line, settings in JSON configuration will be ignored
-
-## Notes
-
-1. Configuration files use UTF-8 encoding without BOM
-2. All key names in JSON are case-sensitive
-3. For strings that need to use backslashes (such as regular expressions) in configuration files, double escaping is required
-4. The `debug` parameter is ineffective when set in configuration files, only supports command line parameter `--debug`
-5. A template configuration file will be automatically generated in the current directory on first run
-6. It's recommended to use editors that support JSON Schema (such as VSCode) to edit configuration files for auto-completion and validation features
+Please update your bookmarks and links to use the new location.

+ 3 - 234
doc/json.md

@@ -1,236 +1,5 @@
-# DDNS JSON配置文件参考
+# JSON 配置文档
 
-本文档详细说明DDNS工具的JSON配置文件格式和参数。JSON配置文件优先级介于命令行参数和环境变量之间。
+此文件已移动至:[config/json.md](config/json.md)
 
-## 基本用法
-
-默认情况下,DDNS会在当前目录查找`config.json`文件。您也可以使用`-c`参数指定配置文件路径:
-
-* 当前目录 `config.json` (注意Docker运行目录是 `/ddns/`)
-* 当前用户目录 `~/.ddns/config.json`
-* Linux当前系统 `/etc/ddns/config.json`
-
-> 注意:在Docker中使用配置文件时,需要通过卷映射将配置文件挂载到容器的`/ddns/`目录。详情请参考[Docker使用文档](docker.md)。
-
-```bash
-# 生成配置文件
-ddns --new-config
-# 指定参数和配置文件
-ddns --dns dnspod --ipv4 ddns.newfuture.cc --new-config config.json
-
-# 使用指定配置文件
-ddns -c /path/to/config.json
-# 或者使用Python源码
-python -m ddns -c /path/to/config.json
-```
-
-## JSON模式
-
-DDNS配置文件遵循JSON模式(Schema),推荐在配置文件中添加`$schema`字段以获得编辑器的自动补全和验证功能:
-
-自v4.1.0版本开始,配置文件支持单行注释。
-
-```json
-{
-  "$schema": "https://ddns.newfuture.cc/schema/v4.0.json"
-}
-```
-
-## Schema
-
-配置参数表
-
-|  键名    |        类型        | 必需 |   默认值    |    参数说明          | 备注                                                                                                         |
-| :------: | :----------------: | :--: | :---------: | :---------------: | ------------------------------------------------------------------------------------------------------------ |
-|  dns     |       string       |  否  |     无      |    DNS服务商      | 可选值: 51dns, alidns, aliesa, callback, cloudflare, debug, dnscom, dnspod_com, dnspod, edgeone, he, huaweidns, namesilo, noip, tencentcloud |
-|   id     |       string       |  是  |     无      |   API 访问 ID    | 请根据服务商说明配置(如 AccessKeyID)  |
-|  token   |       string       |  是  |     无      |  API 授权令牌     | 请根据服务商说明配置(如 AccessSecret)  |
-| endpoint |       string       |  否  |     无      |   API端点URL      | 用于自定义或私有部署的API地址,为空时使用默认端点                                                           |
-|  ipv4    |       array        |  否  |    `[]`     |   IPv4域名列表    |  |
-|  ipv6    |       array        |  否  |    `[]`     |   IPv6域名列表    | |
-| index4   | string\|int\|array |  否  | `["default"]` |   IPv4获取方式    | [详见下方说明](#ipv4-ipv6)|
-| index6   | string\|int\|array |  否  | `["default"]` |   IPv6获取方式    | [详见下方说明](#ipv4-ipv6)|
-|  ttl     |       number       |  否  |   `null`    | DNS TTL时间     | 单位为秒,不设置则采用DNS默认策略|
-|  line    |       string       |  否  |   `null`    | DNS解析线路       | ISP线路选择,支持的值视DNS服务商而定 |
-|  proxy   | string\|array      |  否  |     无      | HTTP代理          | 多代理逐个尝试直到成功,`DIRECT`为直连                                                                      |
-|   ssl    | string\|boolean    |  否  |  `"auto"`   | SSL验证方式    | `true`(强制验证)、`false`(禁用验证)、`"auto"`(自动降级)或自定义CA证书文件路径                          |
-|  cache   |    string\|bool    |  否  |   `true`    | 是否缓存记录       | 正常情况打开避免频繁更新,默认位置为临时目录下`ddns.{hash}.cache`,也可以指定具体路径                              |
-|  log     |       object       |  否  |   `null`    | 日志配置  | 日志配置对象,支持`level`、`file`、`format`、`datefmt`参数                                                |
-
-### dns
-
-`dns`参数指定使用的DNS服务商标识,支持以下值, 请参考 [服务商列表](providers/README.md):
-
-> 当 debug 模式,且未配置dns参数时,使用 debug provider。
-
-### id-token
-
-`id`和`token`参数用于API认证,具体含义和格式取决于所选的DNS服务商。
-
-### endpoint
-
-`endpoint`参数用于指定自定义API端点,大多数服务商都有默认端点,除非有特殊需求,否则不需要修改。
-
-特殊情况包括:
-
-* 不同区域部署的服务商(如腾讯云、阿里云等)需要指定对应区域的API端点。
-* **私有云部署**:如果您使用的是私有部署的DNS服务,需要指定相应的私有API端点地址。
-* **代理转发**:如果您使用第三方API代理服务,需要指定代理的URL。
-
-### ipv4-ipv6
-
-`ipv4`和`ipv6`参数指定需要更新的DNS记录名称,可以是域名或子域名列表。可以使用数组形式指定多个记录。
-
-支持格式
-
-* 无值时,表示不更新对应类型的DNS记录。
-* **单个域名**:`"ddns.newfuture.cc"`
-* **多个域名**:`["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"]`
-
-### index4-index6
-
-`index4`和`index6`参数用于指定获取IP地址的方式,可以使用以下值:
-
-支持类型:
-
-* `false`表示禁止更新相应IP类型的DNS记录
-* **数字**(如`0`、`1`、`2`...):表示使用第N个网卡的IP地址
-* `"default"`:系统访问外网的默认IP
-* `"public"`:使用公网IP(通过API查询)
-* `"url:http..."`:通过指定URL获取IP,例如`"url:http://ip.sb"`
-* `"regex:xxx"`:使用正则表达式匹配本地网络配置中的IP,例如`"regex:192\\.168\\..*"`
-  * 注意:JSON中反斜杠需要转义,如`"regex:10\\.00\\..*"`表示匹配`10.00.`开头的IP
-* `"cmd:xxx"`:执行指定命令并使用其输出作为IP
-* `"shell:xxx"`:使用系统shell运行命令并使用其输出作为IP
-
-配置示例:
-
-```json
-{
-    "index4": ["public", "url:http://ipv4.icanhazip.com"], // 优先使用公网IP,失败后使用指定URL获取
-    "index6": ["shell:ip route", "regex:2003:.*"], // 使用shell命令,失败换成正则匹配IPv6地址
-    "index4": [0, "public"], // 使用第一个网卡IP,失败换成公网IP
-    "index6": "public", // 使用公网IPv6地址
-    "index4": false // 禁止更新IPv4记录
-}
-```
-
-### ttl
-
-`ttl`参数指定DNS记录的生存时间(TTL),单位为秒。默认值为`null`,表示使用DNS服务商的默认TTL策略。
-具体取值范围和默认值取决于所选的DNS服务商。
-
-### line
-
-`line`参数用于指定DNS解析线路,支持的值取决于所选的DNS服务商。
-
-### proxy
-
-`proxy`参数用于设置HTTP代理,可以是单个代理地址或多个代理地址的数组。支持以下格式:
-
-代理类型:
-
-* http: `"http://<proxy_host>:<proxy_port>"`
-* https: `"https://<proxy_host>:<proxy_port>"`
-* 不使用代理: `"DIRECT"`
-
-配置示例
-
-```json
-{
-    "proxy": "http://127.0.0.1:1080", // 单个代理地址
-    "proxy": ["http://127.0.0.1:1080","DIRECT"],// 先尝试代理,失败不使用代理
-    "proxy": null // 不使用代理
-}
-```
-
-> 注意:如果配置了`proxy`,代理只对provider请求有效,获取IP的API不会使用proxy参数。
-
-### ssl
-
-`ssl`参数用于配置SSL验证方式,支持以下值:
-
-* `"auto"`:自动降级到不验证SSL证书(不太安全)
-* `true`:强制验证SSL证书
-* `false`:禁用SSL验证 (不安全)
-* `"/path/to/ca.crt"`,用于指定自定义的CA证书文件
-
-> 注意:如果配置了`ssl`,则所有API请求,包括 provider 和 IP 获取 API 都会使用该配置。
-
-### cache
-
-`cache`参数用于配置DNS记录的缓存方式,支持以下值:
-
-* `true`:启用缓存,默认位置为临时目录下的`ddns.{hash}.cache`
-* `false`:禁用缓存
-* `"/path/to/cache.file"`:指定自定义缓存文件路径
-
-### log
-
-`log`参数用于配置日志记录,是一个对象,支持以下字段:
-
-|  键名   |   类型   | 必需 |     默认值            |    说明    |
-| :-----: | :------: | :--: | :-----------------: | :--------: |
-|  level  |  string  |  否  |       `INFO`        | 日志级别   |
-|  file   |  string  |  否  |         无          | 日志文件路径 |
-| format  |  string  |  否  |    自动调整          | 日志格式字符串 |
-| datefmt |  string  |  否  | `%Y-%m-%dT%H:%M:%S` | 日期时间格式 |
-
-## 配置示例
-
-```json
-{
-  "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
-  "id": "12345",
-  "token": "mytokenkey",
-  "dns": "cloudflare",
-  "ipv4": ["ddns.newfuture.cc"],
-  "ipv6": ["ddns.newfuture.cc", "ipv6.ddns.newfuture.cc"],
-  "index4": ["public", "regex:192\\.168\\.1\\..*"],
-  "index6": "public",
-  "ttl": 300,
-  "proxy": ["http://127.0.0.1:1080", "DIRECT"],
-  "ssl": "auto",
-  "cache": "/var/cache/ddns.cache",
-  "log": {
-    "level": "DEBUG",
-    "file": "/var/log/ddns.log",
-    "datefmt": "%Y-%m-%d %H:%M:%S"
-  }
-}
-```
-
-## 配置优先级和字段覆盖关系
-
-DDNS工具中的配置优先级顺序为:**命令行参数 > JSON配置文件 > 环境变量**。
-
-* **命令行参数**:优先级最高,会覆盖JSON配置文件和环境变量中的相同设置
-* **JSON配置文件**:介于命令行参数和环境变量之间,会覆盖环境变量中的设置
-* **环境变量**:优先级最低,当命令行参数和JSON配置文件中都没有相应设置时使用
-
-### 配置覆盖示例
-
-假设有以下配置:
-
-1. **环境变量**:`DDNS_TTL=600`
-2. **JSON配置文件**:`"ttl": 300`
-3. **命令行参数**:`--ttl 900`
-
-最终生效的是命令行参数的值:`ttl=900`
-
-如果没有提供命令行参数,则使用JSON配置值:`ttl=300`
-
-### 特殊情况
-
-* 当JSON配置文件中某个值明确设为`null`时,将覆盖环境变量设置,相当于未设置该值
-* 当JSON配置文件中缺少某个键时,会尝试使用对应的环境变量
-* 某些参数(如`debug`)仅在特定配置方式下有效:`debug`参数只在命令行中有效,JSON配置中的设置会被忽略
-
-## 注意事项
-
-1. 配置文件使用UTF-8编码,不包含BOM标记
-2. JSON中所有键名区分大小写
-3. 在配置文件中,对于需要使用反斜杠的字符串(如正则表达式),需要进行双重转义
-4. `debug`参数在配置文件中设置无效,仅支持命令行参数`--debug`
-5. 首次运行时会在当前目录自动生成一个模板配置文件
-6. 推荐使用支持JSONSchema的编辑器(如VSCode)编辑配置文件,可获得自动补全和验证功能
+请更新您的书签和链接以使用新位置。

+ 4 - 4
doc/providers/51dns.en.md

@@ -53,16 +53,16 @@ Official Website: <https://www.51dns.com/>
 | dns       | Provider ID      | String         | `dnscom`                           | None      | Provider       |
 | id        | Authentication ID| String         | 51DNS API Key                      | None      | Provider       |
 | token     | Authentication Key| String        | 51DNS Secret Key                   | None      | Provider       |
-| index4    | IPv4 source      | Array          | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config  |
-| index6    | IPv6 source      | Array          | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config  |
+| index4    | IPv4 source      | Array          | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config  |
+| index6    | IPv6 source      | Array          | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config  |
 | ipv4      | IPv4 domains     | Array          | Domain list                        | None      | Common Config  |
 | ipv6      | IPv6 domains     | Array          | Domain list                        | None      | Common Config  |
 | line      | Resolution line  | String         | [See below](#line)                 | `1`       | Provider       |
 | ttl       | TTL time         | Integer (seconds) | [See below](#ttl)               | `600`     | Provider       |
-| proxy     | Proxy settings   | Array          | [Reference](../json.en.md#proxy)   | None      | Common Network |
+| proxy     | Proxy settings   | Array          | [Reference](../config/json.en.md#proxy)   | None      | Common Network |
 | ssl       | SSL verification | Boolean/String | `"auto"`, `true`, `false`          | `auto`    | Common Network |
 | cache     | Cache settings   | Boolean/String | `true`, `false`, `filepath`        | `true`    | Common Config  |
-| log       | Log configuration| Object         | [Reference](../json.en.md#log)     | None      | Common Config  |
+| log       | Log configuration| Object         | [Reference](../config/json.en.md#log)     | None      | Common Config  |
 
 > **Parameter Type Description**:  
 >

+ 4 - 4
doc/providers/51dns.md

@@ -53,16 +53,16 @@
 | dns     | 服务商标识   | 字符串         | `dnscom`                           | 无        | 服务商参数 |
 | id      | 认证 ID      | 字符串         | 51DNS API Key                      | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | 51DNS Secret Key                   | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | line    | 解析线路      | 字符串         | [参考下方](#line)                   | `1`       | 服务商参数 |
 | ttl     | TTL 时间      | 整数(秒)     | [参考下方](#ttl)                    | `600`     | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 75 - 9
doc/providers/README.en.md

@@ -11,7 +11,7 @@ This directory contains detailed configuration guides for various DNS providers.
 | `callback` | Custom API (Webhook) | [callback 中文文档](callback.md) | [callback English Doc](callback.en.md) | Custom HTTP API |
 | `cloudflare` | [Cloudflare](https://www.cloudflare.com/) | [cloudflare 中文文档](cloudflare.md) | [cloudflare English Doc](cloudflare.en.md) | Global CDN and DNS service |
 | `debug` | Debug Provider | [debug 中文文档](debug.md) | [debug English Doc](debug.en.md) | IP address printing for debugging |
-| `dnscom` | [DNS.COM](https://www.dns.com/) | [51dns 中文文档](51dns.md) | [dnscom English Doc](51dns.en.md) | ⚠️ Pending verification |
+| `dnscom` | [DNS.COM](https://www.dns.com/) | [51dns 中文文档](51dns.md) | [51DNS English Doc](51dns.en.md) | ⚠️ Pending verification |
 | `dnspod_com` | [DNSPod Global](https://www.dnspod.com/) | [dnspod_com 中文文档](dnspod_com.md) | [dnspod_com English Doc](dnspod_com.en.md) | ⚠️ Pending verification |
 | `dnspod` | [DNSPod China](https://www.dnspod.cn/) | [dnspod 中文文档](dnspod.md) | [dnspod English Doc](dnspod.en.md) | Largest DNS provider in China |
 | `he` | [HE.net](https://dns.he.net/) | [he 中文文档](he.md) | [he English Doc](he.en.md) | ⚠️ Pending verification, no auto-record creation |
@@ -26,14 +26,14 @@ This directory contains detailed configuration guides for various DNS providers.
 
 Most providers support automatic creation of non-existent DNS records, with exceptions:
 
-- **he**: Does not support automatic record creation, records must be manually created in the control panel
-- **noip**: Does not support automatic record creation, records must be manually created in the control panel
+- ⚠️**he**: Does not support automatic record creation, records must be manually created in the control panel
+- ⚠️**noip**: Does not support automatic record creation, records must be manually created in the control panel
 
 ## 📝 Configuration Examples
 
 ### Command Line Configuration
 
-[CLI provides command line configuration](../cli.en.md), here are some common command line examples:
+[CLI provides command line configuration](../config/cli.en.md), here are some common command line examples:
 
 ```bash
 # DNSPod China
@@ -54,7 +54,9 @@ ddns --dns noip --id your_username --token your_password --ipv4 ddns.newfuture.c
 
 ### JSON Configuration File
 
-[JSON configuration file](../json.en.md) provides a more flexible configuration method, here are some common JSON configuration examples:
+[JSON configuration file](../config/json.en.md) provides a more flexible configuration method, here are some common JSON configuration examples:
+
+#### Traditional Single-Provider Format
 
 ```json
 {
@@ -68,9 +70,73 @@ ddns --dns noip --id your_username --token your_password --ipv4 ddns.newfuture.c
 }
 ```
 
+#### Multi-Provider Format
+
+```json
+{
+  "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
+  "ssl": "auto",
+  "cache": true,
+  "log": {"level": "INFO"},
+  "providers": [
+    {
+      "provider": "cloudflare",
+      "id": "[email protected]",
+      "token": "cloudflare-token",
+      "ipv4": ["cf.example.com"],
+      "ttl": 300
+    },
+    {
+      "provider": "dnspod", 
+      "id": "12345",
+      "token": "dnspod-token",
+      "ipv4": ["dnspod.example.com"],
+      "ttl": 600
+    }
+  ]
+}
+```
+
+### Multiple Configuration Files Method
+
+#### Command Line Specification
+
+```bash
+# Use multiple independent configuration files
+ddns -c cloudflare.json -c dnspod.json -c alidns.json
+
+# Use environment variable to specify multiple configuration files
+export DDNS_CONFIG="cloudflare.json,dnspod.json,alidns.json"
+ddns
+```
+
+#### Multiple Configuration Files Example
+
+**cloudflare.json**:
+
+```json
+{
+  "dns": "cloudflare",
+  "id": "[email protected]",
+  "token": "your-cloudflare-token",
+  "ipv4": ["cf.example.com"]
+}
+```
+
+**dnspod.json**:
+
+```json
+{
+  "dns": "dnspod",
+  "id": "12345", 
+  "token": "your-dnspod-token",
+  "ipv4": ["dnspod.example.com"]
+}
+```
+
 ### Environment Variable Configuration
 
-[Environment variable configuration](../env.en.md) provides another configuration method, here are some common environment variable examples:
+[Environment variable configuration](../config/env.en.md) provides another configuration method, here are some common environment variable examples:
 
 ```bash
 export DDNS_DNS=dnspod
@@ -83,9 +149,9 @@ ddns --debug
 
 ## 📚 Related Documentation
 
-- [Command Line Configuration](../cli.en.md) - Detailed command line parameter documentation
-- [JSON Configuration](../json.en.md) - JSON configuration file format documentation
-- [Environment Variable Configuration](../env.en.md) - Environment variable configuration method
+- [Command Line Configuration](../config/cli.en.md) - Detailed command line parameter documentation
+- [JSON Configuration](../config/json.en.md) - JSON configuration file format documentation
+- [Environment Variable Configuration](../config/env.en.md) - Environment variable configuration method
 - [Provider Development Guide](../dev/provider.en.md) - How to develop new providers
 - [JSON Schema](../../schema/v4.0.json) - Configuration file validation schema
 

+ 81 - 15
doc/providers/README.md

@@ -6,20 +6,20 @@
 
 | Provider | 服务商 | 配置文档 | 英文文档 | 特点 |
 |----------|--------|----------|----------|------|
-| `alidns` | [阿里云 DNS](https://dns.console.aliyun.com/) | [alidns 中文文档](alidns.md) | [alidns English Doc](alidns.en.md) | 阿里云生态集成 |
-| `aliesa` | [阿里云 ESA](https://esa.console.aliyun.com/) | [aliesa 中文文档](aliesa.md) | [aliesa English Doc](aliesa.en.md) | 阿里云边缘安全加速 |
+| `alidns` | [阿里云DNS](https://dns.console.aliyun.com/) | [alidns 中文文档](alidns.md) | [alidns English Doc](alidns.en.md) | 阿里云生态集成 |
+| `aliesa` | [阿里云ESA](https://esa.console.aliyun.com/) | [aliesa 中文文档](aliesa.md) | [aliesa English Doc](aliesa.en.md) | 阿里云边缘安全加速 |
 | `callback` | 自定义API (Webhook) | [callback 中文文档](callback.md) | [callback English Doc](callback.en.md) | 自定义HTTP API |
 | `cloudflare` | [Cloudflare](https://www.cloudflare.com/) | [cloudflare 中文文档](cloudflare.md) | [cloudflare English Doc](cloudflare.en.md) | 全球CDN和DNS服务 |
-| `debug` | 调试Provider | [debug 中文文档](debug.md) | [debug English Doc](debug.en.md) | 仅打印IP地址,用于调试 |
+| `debug` | 调试Provider | [debug 中文文档](debug.md) | [debug English Doc](debug.en.md) | 仅打印IP地址,用于调试|
 | `dnscom`(51dns) | [51DNS](https://www.51dns.com/) | [51dns 中文文档](51dns.md) | [51dns English Doc](51dns.en.md) | ⚠️ 等待验证  |
 | `dnspod_com` | [DNSPod Global](https://www.dnspod.com/) | [dnspod_com 中文文档](dnspod_com.md) | [dnspod_com English Doc](dnspod_com.en.md) | ⚠️ 等待验证  |
-| `dnspod` | [DNSPod 中国版](https://www.dnspod.cn/) | [dnspod 中文文档](dnspod.md) | [dnspod English Doc](dnspod.en.md) | 国内最大DNS服务商 |
+| `dnspod` | [DNSPod 中国版](https://www.dnspod.cn/) | [dnspod 中文文档](dnspod.md) | [dnspod English Doc](dnspod.en.md) | 国内最大DNS服务商|
 | `he` | [HE.net](https://dns.he.net/) | [he 中文文档](he.md) | [he English Doc](he.en.md) | ⚠️ 等待验证,不支持自动创建记录 |
 | `huaweidns` | [华为云 DNS](https://www.huaweicloud.com/product/dns.html) | [huaweidns 中文文档](huaweidns.md) | [huaweidns English Doc](huaweidns.en.md) | ⚠️ 等待验证 |
 | `namesilo` | [NameSilo](https://www.namesilo.com/) | [namesilo 中文文档](namesilo.md) | [namesilo English Doc](namesilo.en.md) | ⚠️ 等待验证 |
 | `noip` | [No-IP](https://www.noip.com/) | [noip 中文文档](noip.md) | [noip English Doc](noip.en.md) | 不支持自动创建记录 |
-| `tencentcloud` | [腾讯云 DNSPod](https://cloud.tencent.com/product/dns) | [tencentcloud 中文文档](tencentcloud.md) | [tencentcloud English Doc](tencentcloud.en.md) | 腾讯云DNSPod服务 |
-| `edgeone` | [腾讯云 EdgeOne](https://cloud.tencent.com/product/teo) | [edgeone 中文文档](edgeone.md) | [edgeone English Doc](edgeone.en.md) | 腾讯云边缘安全加速平台 |
+| `tencentcloud` | [腾讯云DNSPod](https://cloud.tencent.com/product/dns) | [tencentcloud 中文文档](tencentcloud.md) | [tencentcloud English Doc](tencentcloud.en.md) | 腾讯云DNSPod服务 |
+| `edgeone` | [腾讯云EdgeOne](https://cloud.tencent.com/product/teo) | [edgeone 中文文档](edgeone.md) | [edgeone English Doc](edgeone.en.md) | 腾讯云边缘安全加速平台 |
 
 > 添加新的Provider, [创建Issue,并按照模板填好链接](https://github.com/NewFuture/DDNS/issues/new?template=new-dns-provider.md)
 
@@ -27,14 +27,14 @@
 
 大部分provider支持自动创建不存在的DNS记录,但有例外:
 
--  **he**: 不支持自动创建记录,需要手动在控制面板中预先创建
--  **noip**: 不支持自动创建记录,需要手动在控制面板中预先创建
+- ⚠️ **he**: 不支持自动创建记录,需要手动在控制面板中预先创建
+- ⚠️ **noip**: 不支持自动创建记录,需要手动在控制面板中预先创建
 
 ## 📝 配置示例
 
 ### 命令行配置
 
-[cli 提供了命令行配置方式](../cli.md),以下是一些常用的命令行示例:
+[cli 提供了命令行配置方式](../config/cli.md),以下是一些常用的命令行示例:
 
 ```bash
 # DNSPod中国版
@@ -58,7 +58,9 @@ ddns --dns noip --id your_username --token your_password --ipv4 ddns.newfuture.c
 
 ### JSON配置文件
 
-[JSON配置文件](../json.md)提供了更灵活的配置方式,以下是一些常用的JSON配置示例:
+[JSON配置文件](../config/json.md)提供了更灵活的配置方式,以下是一些常用的JSON配置示例:
+
+#### 单Provider格式
 
 ```json
 {
@@ -72,9 +74,73 @@ ddns --dns noip --id your_username --token your_password --ipv4 ddns.newfuture.c
 }
 ```
 
+#### 多Provider格式
+
+```json
+{
+  "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
+  "ssl": "auto",
+  "cache": true,
+  "log": {"level": "INFO"},
+  "providers": [
+    {
+      "provider": "cloudflare",
+      "id": "[email protected]",
+      "token": "cloudflare-token",
+      "ipv4": ["cf.example.com"],
+      "ttl": 300
+    },
+    {
+      "provider": "dnspod", 
+      "id": "12345",
+      "token": "dnspod-token",
+      "ipv4": ["dnspod.example.com"],
+      "ttl": 600
+    }
+  ]
+}
+```
+
+### 多配置文件方式
+
+#### 命令行指定多个配置文件
+
+```bash
+# 使用多个独立的配置文件
+ddns -c cloudflare.json -c dnspod.json -c alidns.json
+
+# 使用环境变量指定多个配置文件
+export DDNS_CONFIG="cloudflare.json,dnspod.json,alidns.json"
+ddns
+```
+
+#### 多配置文件示例
+
+**cloudflare.json**:
+
+```json
+{
+  "dns": "cloudflare",
+  "id": "[email protected]",
+  "token": "your-cloudflare-token",
+  "ipv4": ["cf.example.com"]
+}
+```
+
+**dnspod.json**:
+
+```json
+{
+  "dns": "dnspod",
+  "id": "12345", 
+  "token": "your-dnspod-token",
+  "ipv4": ["dnspod.example.com"]
+}
+```
+
 ### 环境变量配置
 
-[环境变量配置](../env.md)提供了另一种配置方式,以下是一些常用的环境变量示例:
+[环境变量配置](../config/env.md)提供了另一种配置方式,以下是一些常用的环境变量示例:
 
 ```bash
 export DDNS_DNS=dnspod
@@ -87,12 +153,12 @@ ddns --debug
 
 ## 📚 相关文档
 
-- [命令行配置](../cli.md) - 命令行参数详细说明
-- [JSON配置](../json.md) - JSON配置文件格式说明  
-- [环境变量配置](../env.md) - 环境变量配置方式
+- [命令行配置](../config/cli.md) - 命令行参数详细说明
+- [JSON配置](../config/json.md) - JSON配置文件格式说明  
+- [环境变量配置](../config/env.md) - 环境变量配置方式
 - [Provider开发指南](../dev/provider.md) - 如何开发新的provider
 - [JSON Schema](../../schema/v4.0.json) - 配置文件验证架构
 
 ---
 
-如有疑问或需要帮助,请查看 [FAQ](../../README.md#FAQ) 或在 [GitHub Issues](https://github.com/NewFuture/DDNS/issues) 中提问。
+如有疑问或需要帮助,请查看[FAQ](../../README.md#FAQ) 或在 [GitHub Issues](https://github.com/NewFuture/DDNS/issues) 中提问。

+ 4 - 4
doc/providers/alidns.en.md

@@ -65,17 +65,17 @@ You can view and configure permissions in the [RAM Console](https://ram.console.
 | dns | Provider identifier | String | `alidns` | None | Provider Parameter |
 | id | Authentication ID | String | Alibaba Cloud AccessKey ID | None | Provider Parameter |
 | token | Authentication key | String | Alibaba Cloud AccessKey Secret | None | Provider Parameter |
-| index4 | IPv4 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
-| index6 | IPv6 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index4 | IPv4 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index6 | IPv6 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
 | ipv4 | IPv4 domains | Array | Domain list | None | Common Config |
 | ipv6 | IPv6 domains | Array | Domain list | None | Common Config |
 | endpoint | API endpoint | URL | [See below](#endpoint) | `https://alidns.aliyuncs.com` | Provider Parameter |
 | line | Resolution line | String | [See below](#ttl) | `default` | Provider Parameter |
 | ttl | TTL time | Integer (seconds) | [See below](#line)| None | Provider Parameter |
-| proxy | Proxy settings | Array | [Reference](../json.en.md#proxy) | None | Common Network |
+| proxy | Proxy settings | Array | [Reference](../config/json.en.md#proxy) | None | Common Network |
 | ssl | SSL verification | Boolean/String | `auto`, `true`, `false` | `auto` | Common Network |
 | cache | Cache settings | Boolean/String | `true`, `false`, `filepath` | `true` | Common Config |
-| log | Log configuration | Object | [Reference](../json.en.md#log) | None | Common Config |
+| log | Log configuration | Object | [Reference](../config/json.en.md#log) | None | Common Config |
 
 > **Parameter Type Description**:
 >

+ 4 - 4
doc/providers/alidns.md

@@ -65,17 +65,17 @@
 | dns     | 服务商标识   | 字符串         | `alidns`                           | 无        | 服务商参数 |
 | id      | 认证 ID      | 字符串         | 阿里云 AccessKey ID                 | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | 阿里云 AccessKey Secret             | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | endpoint| API 端点      | URL            | [参考下方](#endpoint)              | `https://alidns.aliyuncs.com` | 服务商参数 |
 | line    | 解析线路      | 字符串         | [参考下方](#line)                   | `default`        | 服务商参数 |
 | ttl     | TTL 时间      | 整数(秒)     | [参考下方](#ttl)                    | 无        | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 4 - 4
doc/providers/aliesa.en.md

@@ -64,16 +64,16 @@ You can view and configure permissions in the [RAM Console](https://ram.console.
 | dns | Provider identifier | String | `aliesa` | None | Provider Parameter |
 | id | Authentication ID | String | Alibaba Cloud AccessKey ID | None | Provider Parameter |
 | token | Authentication key | String | Alibaba Cloud AccessKey Secret | None | Provider Parameter |
-| index4 | IPv4 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
-| index6 | IPv6 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index4 | IPv4 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index6 | IPv6 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
 | ipv4 | IPv4 domains | Array | Domain list | None | Common Config |
 | ipv6 | IPv6 domains | Array | Domain list | None | Common Config |
 | endpoint | API endpoint | URL | [See below](#endpoint) | `https://esa.cn-hangzhou.aliyuncs.com` | Provider Parameter |
 | ttl | TTL time | Integer (seconds) | 1-86400 | None | Provider Parameter |
-| proxy | Proxy settings | Array | [Reference](../json.en.md#proxy) | None | Common Network |
+| proxy | Proxy settings | Array | [Reference](../config/json.en.md#proxy) | None | Common Network |
 | ssl | SSL verification | Boolean/String | `auto`, `true`, `false` | `auto` | Common Network |
 | cache | Cache settings | Boolean/String | `true`, `false`, `filepath` | `true` | Common Config |
-| log | Log configuration | Object | [Reference](../json.en.md#log) | None | Common Config |
+| log | Log configuration | Object | [Reference](../config/json.en.md#log) | None | Common Config |
 
 > **Parameter Type Description**:
 >

+ 4 - 4
doc/providers/aliesa.md

@@ -68,16 +68,16 @@
 | dns     | 服务商标识   | 字符串         | `aliesa`                           | 无        | 服务商参数 |
 | id      | 认证 ID      | 字符串         | 阿里云 AccessKey ID                 | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | 阿里云 AccessKey Secret             | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考](../json.md#ipv4-ipv6)       | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考](../json.md#ipv4-ipv6)       | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考](../config/json.md#ipv4-ipv6)       | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考](../config/json.md#ipv4-ipv6)       | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | endpoint| API 端点      | URL            | [参考下方](#endpoint)                           | `https://esa.cn-hangzhou.aliyuncs.com`         | 服务商参数 |
 | ttl     | TTL 时间      | 整数(秒)     | 30~86400                           | 1(自动)        | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考](../json.md#proxy)           | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考](../config/json.md#proxy)           | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `auto`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 6 - 6
doc/providers/callback.en.md

@@ -31,14 +31,14 @@ Callback Provider is a universal custom callback interface that allows you to fo
 
 | Parameter | Description | Type | Range/Options | Default | Parameter Type |
 | :-------: | :---------- | :--- | :------------ | :------ | :------------- |
-| index4 | IPv4 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
-| index6 | IPv6 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index4 | IPv4 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index6 | IPv6 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
 | ipv4 | IPv4 domains | Array | Domain list | None | Common Config |
 | ipv6 | IPv6 domains | Array | Domain list | None | Common Config |
-| proxy | Proxy settings | Array | [Reference](../json.en.md#proxy) | None | Common Network |
+| proxy | Proxy settings | Array | [Reference](../config/json.en.md#proxy) | None | Common Network |
 | ssl | SSL verification | Boolean/String | `"auto"`, `true`, `false` | `auto` | Common Network |
 | cache | Cache settings | Boolean/String | `true`, `false`, `filepath` | `true` | Common Config |
-| log | Log configuration | Object | [Reference](../json.en.md#log) | None | Common Config |
+| log | Log configuration | Object | [Reference](../config/json.en.md#log) | None | Common Config |
 
 ## Request Methods
 
@@ -164,6 +164,6 @@ curl -X POST "https://httpbin.org/post" \
 ## Related Links
 
 - [DDNS Project Homepage](../../README.md)
-- [Configuration File Format](../json.en.md)
-- [Command Line Usage](../cli.en.md)
+- [Configuration File Format](../config/json.en.md)
+- [Command Line Usage](../config/cli.en.md)
 - [Developer Guide](../dev/provider.en.md)

+ 6 - 6
doc/providers/callback.md

@@ -31,14 +31,14 @@ Callback Provider 是一个通用的自定义回调接口,允许您将 DDNS 
 
 | 参数    | 说明         | 类型           | 取值范围/选项                       | 默认值    | 参数类型   |
 | :-----: | :----------- | :------------- | :--------------------------------- | :-------- | :--------- |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 ## 请求方式
 
@@ -162,6 +162,6 @@ curl -X POST "https://httpbin.org/post" \
 ## 相关链接
 
 - [DDNS 项目首页](../../README.md)
-- [配置文件格式](../json.md)
-- [命令行使用](../cli.md)
+- [配置文件格式](../config/json.md)
+- [命令行使用](../config/cli.md)
 - [开发者指南](../dev/provider.md)

+ 4 - 4
doc/providers/cloudflare.en.md

@@ -89,15 +89,15 @@ You can view and configure permissions in [Cloudflare API Token Management](http
 | dns | Provider identifier | String | `cloudflare` | None | Provider Parameter |
 | id | Authentication email | String | Cloudflare account email (Global API Key only) | None | Provider Parameter |
 | token | Authentication key | String | Cloudflare API Token or Global API Key | None | Provider Parameter |
-| index4 | IPv4 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
-| index6 | IPv6 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index4 | IPv4 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index6 | IPv6 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
 | ipv4 | IPv4 domains | Array | Domain list | None | Common Config |
 | ipv6 | IPv6 domains | Array | Domain list | None | Common Config |
 | ttl | TTL time | Integer (seconds) | [Reference below](#ttl) | `300/auto` | Provider Parameter |
-| proxy | Proxy settings | Array | [Reference](../json.en.md#proxy) | None | Common Network |
+| proxy | Proxy settings | Array | [Reference](../config/json.en.md#proxy) | None | Common Network |
 | ssl | SSL verification | Boolean/String | `"auto"`, `true`, `false` | `auto` | Common Network |
 | cache | Cache settings | Boolean/String | `true`, `false`, `filepath` | `true` | Common Config |
-| log | Log configuration | Object | [Reference](../json.en.md#log) | None | Common Config |
+| log | Log configuration | Object | [Reference](../config/json.en.md#log) | None | Common Config |
 
 > **Parameter Type Description**:
 >

+ 4 - 4
doc/providers/cloudflare.md

@@ -89,15 +89,15 @@ API Token 方式更安全,支持精细化权限控制,是 Cloudflare 推荐
 | dns     | 服务商标识   | 字符串         | `cloudflare`                       | 无        | 服务商参数 |
 | id      | 认证邮箱     | 字符串         | Cloudflare 账户邮箱(仅 Global API Key) | 无   | 服务商参数 |
 | token   | 认证密钥     | 字符串         | Cloudflare API Token 或 Global API Key | 无  | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ttl     | TTL 时间      | 整数(秒)     | [参考下方](#ttl)                    | 300/auto | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 6 - 6
doc/providers/debug.en.md

@@ -47,12 +47,12 @@ Debug Provider does not require any authentication information, no need to confi
 | Parameter | Description | Type | Range/Options | Default | Parameter Type |
 | :-------: | :---------- | :--- | :------------ | :------ | :------------- |
 | dns | Provider identifier | String | `debug` | None | Provider Parameter |
-| index4 | IPv4 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
-| index6 | IPv6 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
-| proxy | Proxy settings | Array | [Reference](../json.en.md#proxy) | None | Common Network |
+| index4 | IPv4 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index6 | IPv6 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
+| proxy | Proxy settings | Array | [Reference](../config/json.en.md#proxy) | None | Common Network |
 | ssl | SSL verification | Boolean/String | `"auto"`, `true`, `false` | `auto` | Common Network |
 | cache | Cache settings | Boolean/String | `true`, `false`, `filepath` | `false` | Common Config |
-| log | Log configuration | Object | [Reference](../json.en.md#log) | None | Common Config |
+| log | Log configuration | Object | [Reference](../config/json.en.md#log) | None | Common Config |
 
 > **Parameter Type Description**:
 >
@@ -92,6 +92,6 @@ Debug Provider also simulates some common error scenarios to help test error han
 ## Support and Resources
 
 - [DDNS Project Documentation](../../README.md)
-- [Configuration File Format](../json.en.md)
-- [Command Line Usage Guide](../cli.en.md)
+- [Configuration File Format](../config/json.en.md)
+- [Command Line Usage Guide](../config/cli.en.md)
 - [Developer Guide](../dev/provider.en.md)

+ 6 - 6
doc/providers/debug.md

@@ -47,12 +47,12 @@ Debug Provider 不需要任何认证信息,无需配置 `id` 和 `token` 参
 | 参数    | 说明         | 类型           | 取值范围/选项                       | 默认值    | 参数类型   |
 | :-----: | :----------- | :------------- | :--------------------------------- | :-------- | :--------- |
 | dns     | 服务商标识   | 字符串         | `debug`                            | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `false`   | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >
@@ -92,6 +92,6 @@ Debug Provider 也会模拟一些常见错误场景,帮助测试错误处理
 ## 支持与资源
 
 - [DDNS 项目文档](../../README.md)
-- [配置文件格式说明](../json.md)
-- [命令行使用指南](../cli.md)
+- [配置文件格式说明](../config/json.md)
+- [命令行使用指南](../config/cli.md)
 - [开发者指南](../dev/provider.md)

+ 4 - 4
doc/providers/dnspod.en.md

@@ -72,16 +72,16 @@ For users using Tencent Cloud AccessKey, please refer to [Tencent Cloud DNSPod C
 | dns | Provider identifier | String | `dnspod` | None | Provider Parameter |
 | id | Authentication ID | String | DNSPod API Token ID or email | None | Provider Parameter |
 | token | Authentication key | String | DNSPod API Token secret or password | None | Provider Parameter |
-| index4 | IPv4 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
-| index6 | IPv6 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index4 | IPv4 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index6 | IPv6 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
 | ipv4 | IPv4 domains | Array | Domain list | None | Common Config |
 | ipv6 | IPv6 domains | Array | Domain list | None | Common Config |
 | line | Resolution line | String | [Reference below](#line) | `默认` | Provider Parameter |
 | ttl | TTL time | Integer (seconds) | [Reference below](#ttl) | `600` | Provider Parameter |
-| proxy | Proxy settings | Array | [Reference](../json.en.md#proxy) | None | Common Network |
+| proxy | Proxy settings | Array | [Reference](../config/json.en.md#proxy) | None | Common Network |
 | ssl | SSL verification | Boolean/String | `"auto"`, `true`, `false` | `auto` | Common Network |
 | cache | Cache settings | Boolean/String | `true`, `false`, `filepath` | `true` | Common Config |
-| log | Log configuration | Object | [Reference](../json.en.md#log) | None | Common Config |
+| log | Log configuration | Object | [Reference](../config/json.en.md#log) | None | Common Config |
 
 > **Parameter Type Description**:
 >

+ 4 - 4
doc/providers/dnspod.md

@@ -70,16 +70,16 @@ API Token 方式更安全,是 DNSPod 推荐的集成方法。
 | dns     | 服务商标识   | 字符串         | `dnspod`                           | 无        | 服务商参数 |
 | id      | 认证 ID      | 字符串         | DNSPod API Token ID 或邮箱         | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | DNSPod API Token 密钥或密码        | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | line    | 解析线路      | 字符串         | [参考下方](#line)                   | `默认`    | 服务商参数 |
 | ttl     | TTL 时间      | 整数(秒)     | [参考下方](#ttl)                    | `600`     | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 4 - 4
doc/providers/dnspod_com.en.md

@@ -65,16 +65,16 @@ Uses DNSPod account email and password. Lower security, only recommended for spe
 | dns | Provider identifier | String | `dnspod_com` | None | Provider Parameter |
 | id | Authentication ID | String | DNSPod API Token ID or email | None | Provider Parameter |
 | token | Authentication key | String | DNSPod API Token secret or password | None | Provider Parameter |
-| index4 | IPv4 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
-| index6 | IPv6 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index4 | IPv4 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
+| index6 | IPv6 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Config |
 | ipv4 | IPv4 domains | Array | Domain list | None | Common Config |
 | ipv6 | IPv6 domains | Array | Domain list | None | Common Config |
 | line | Resolution line | String | [Reference below](#line) | `default` | Provider Parameter |
 | ttl | TTL time | Integer (seconds) | [Reference below](#ttl) | `600` | Provider Parameter |
-| proxy | Proxy settings | Array | [Reference](../json.en.md#proxy) | None | Common Network |
+| proxy | Proxy settings | Array | [Reference](../config/json.en.md#proxy) | None | Common Network |
 | ssl | SSL verification | Boolean/String | `"auto"`, `true`, `false` | `auto` | Common Network |
 | cache | Cache settings | Boolean/String | `true`, `false`, `filepath` | `true` | Common Config |
-| log | Log configuration | Object | [Reference](../json.en.md#log) | None | Common Config |
+| log | Log configuration | Object | [Reference](../config/json.en.md#log) | None | Common Config |
 
 > **Parameter Type Description**:
 >

+ 4 - 4
doc/providers/dnspod_com.md

@@ -70,16 +70,16 @@ API Token 方式更安全,是 DNSPod 推荐的集成方法。
 | dns     | 服务商标识   | 字符串         | `dnspod_com`                       | 无        | 服务商参数 |
 | id      | 认证 ID      | 字符串         | DNSPod API Token ID 或邮箱         | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | DNSPod API Token 密钥或密码        | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | line    | 解析线路      | 字符串         | [参考下方](#line)                   | `default` | 服务商参数 |
 | ttl     | TTL 时间      | 整数(秒)     | [参考下方](#ttl)                    | `600`     | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 4 - 4
doc/providers/edgeone.en.md

@@ -66,15 +66,15 @@ Permissions can be viewed and configured in [Access Management](https://console.
 | dns       | Provider ID       | String         | `edgeone`                              | None      | Provider       |
 | id        | Authentication ID | String         | Tencent Cloud SecretId                 | None      | Provider       |
 | token     | Authentication Key| String         | Tencent Cloud SecretKey                | None      | Provider       |
-| index4    | IPv4 Source       | Array          | [Reference](../json.en.md#ipv4-ipv6)  | `default` | Common Config  |
-| index6    | IPv6 Source       | Array          | [Reference](../json.en.md#ipv4-ipv6)  | `default` | Common Config  |
+| index4    | IPv4 Source       | Array          | [Reference](../config/json.en.md#ipv4-ipv6)  | `default` | Common Config  |
+| index6    | IPv6 Source       | Array          | [Reference](../config/json.en.md#ipv4-ipv6)  | `default` | Common Config  |
 | ipv4      | IPv4 Domains      | Array          | Domain list                            | None      | Common Config  |
 | ipv6      | IPv6 Domains      | Array          | Domain list                            | None      | Common Config  |
 | endpoint  | API Endpoint      | URL            | [Reference below](#endpoint)           | `https://teo.tencentcloudapi.com` | Provider  |
-| proxy     | Proxy Settings    | Array          | [Reference](../json.en.md#proxy)       | None      | Common Network |
+| proxy     | Proxy Settings    | Array          | [Reference](../config/json.en.md#proxy)       | None      | Common Network |
 | ssl       | SSL Verification  | Boolean/String | `"auto"`, `true`, `false`              | `auto`    | Common Network |
 | cache     | Cache Settings    | Boolean/String | `true`, `false`, `filepath`            | `true`    | Common Config  |
-| log       | Log Configuration | Object         | [Reference](../json.en.md#log)        | None      | Common Config  |
+| log       | Log Configuration | Object         | [Reference](../config/json.en.md#log)        | None      | Common Config  |
 
 > **Parameter Type Description**:  
 >

+ 4 - 4
doc/providers/edgeone.md

@@ -66,15 +66,15 @@
 | dns     | 服务商标识   | 字符串         | `edgeone`                          | 无        | 服务商参数 |
 | id      | 认证 ID      | 字符串         | 腾讯云 SecretId                    | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | 腾讯云 SecretKey                   | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | endpoint| API 端点      | URL            | [参考下方](#endpoint)              | `https://teo.tencentcloudapi.com` | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 4 - 4
doc/providers/he.md

@@ -51,14 +51,14 @@ HE.net 使用专门的动态 DNS 密码进行认证,不使用账户登录密
 | :-----: | :----------- | :------------- | :--------------------------------- | :-------- | :--------- |
 | dns     | 服务商标识   | 字符串         | `he`                               | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | HE.net DDNS 密码               | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 4 - 4
doc/providers/huaweidns.en.md

@@ -67,17 +67,17 @@ You can view and configure permissions in [Identity and Access Management](https
 | dns       | Provider ID      | String         | `huaweidns`                            | None                           | Provider Param |
 | id        | Authentication ID| String         | Huawei Cloud Access Key ID             | None                           | Provider Param |
 | token     | Authentication Key| String        | Huawei Cloud Secret Access Key         | None                           | Provider Param |
-| index4    | IPv4 Source      | Array          | [Reference](../json.en.md#ipv4-ipv6)  | `default`                      | Common Config  |
-| index6    | IPv6 Source      | Array          | [Reference](../json.en.md#ipv4-ipv6)  | `default`                      | Common Config  |
+| index4    | IPv4 Source      | Array          | [Reference](../config/json.en.md#ipv4-ipv6)  | `default`                      | Common Config  |
+| index6    | IPv6 Source      | Array          | [Reference](../config/json.en.md#ipv4-ipv6)  | `default`                      | Common Config  |
 | ipv4      | IPv4 Domain      | Array          | Domain list                            | None                           | Common Config  |
 | ipv6      | IPv6 Domain      | Array          | Domain list                            | None                           | Common Config  |
 | endpoint  | API Endpoint     | URL            | [Reference below](#endpoint)           | `https://dns.myhuaweicloud.com`| Provider Param |
 | line      | Resolution Line  | String         | [Reference below](#line)               | `default`                      | Provider Param |
 | ttl       | TTL Time         | Integer (seconds)| 1~2147483647                         | `300`                          | Provider Param |
-| proxy     | Proxy Settings   | Array          | [Reference](../json.en.md#proxy)      | None                           | Common Network |
+| proxy     | Proxy Settings   | Array          | [Reference](../config/json.en.md#proxy)      | None                           | Common Network |
 | ssl       | SSL Verification | Boolean/String | `"auto"`, `true`, `false`              | `auto`                         | Common Network |
 | cache     | Cache Settings   | Boolean/String | `true`, `false`, `filepath`            | `true`                         | Common Config  |
-| log       | Log Config       | Object         | [Reference](../json.en.md#log)        | None                           | Common Config  |
+| log       | Log Config       | Object         | [Reference](../config/json.en.md#log)        | None                           | Common Config  |
 
 > **Parameter Type Description**:
 >

+ 4 - 4
doc/providers/huaweidns.md

@@ -67,17 +67,17 @@
 | dns     | 服务商标识   | 字符串         | `huaweidns`                        | 无        | 服务商参数 |
 | id      | 认证 ID      | 字符串         | 华为云 Access Key ID               | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | 华为云 Secret Access Key           | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | endpoint| API 端点      | URL            | [参考下方](#endpoint)              | `https://dns.myhuaweicloud.com` | 服务商参数 |
 | line    | 解析线路      | 字符串         | [参考下方](#line)                   | `default` | 服务商参数 |
 | ttl     | TTL 时间      | 整数(秒)     | 1~2147483647                   | `300`     | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 4 - 4
doc/providers/namesilo.en.md

@@ -53,15 +53,15 @@ NameSilo uses API Key for authentication, which is the only authentication metho
 | :-------: | :--------------- | :------------- | :------------------------------------- | :-------- | :------------- |
 | dns       | Provider ID      | String         | `namesilo`                             | None      | Provider Param |
 | token     | Authentication Key| String        | NameSilo API Key                       | None      | Provider Param |
-| index4    | IPv4 Source      | Array          | [Reference](../json.en.md#ipv4-ipv6)  | `default` | Common Config  |
-| index6    | IPv6 Source      | Array          | [Reference](../json.en.md#ipv4-ipv6)  | `default` | Common Config  |
+| index4    | IPv4 Source      | Array          | [Reference](../config/json.en.md#ipv4-ipv6)  | `default` | Common Config  |
+| index6    | IPv6 Source      | Array          | [Reference](../config/json.en.md#ipv4-ipv6)  | `default` | Common Config  |
 | ipv4      | IPv4 Domain      | Array          | Domain list                            | None      | Common Config  |
 | ipv6      | IPv6 Domain      | Array          | Domain list                            | None      | Common Config  |
 | ttl       | TTL Time         | Integer (seconds)| 300 ~ 2592000                       | `7200`    | Provider Param |
-| proxy     | Proxy Settings   | Array          | [Reference](../json.en.md#proxy)      | None      | Common Network |
+| proxy     | Proxy Settings   | Array          | [Reference](../config/json.en.md#proxy)      | None      | Common Network |
 | ssl       | SSL Verification | Boolean/String | `"auto"`, `true`, `false`              | `auto`    | Common Network |
 | cache     | Cache Settings   | Boolean/String | `true`, `false`, `filepath`            | `true`    | Common Config  |
-| log       | Log Config       | Object         | [Reference](../json.en.md#log)        | None      | Common Config  |
+| log       | Log Config       | Object         | [Reference](../config/json.en.md#log)        | None      | Common Config  |
 
 > **Parameter Type Description**:
 >

+ 4 - 4
doc/providers/namesilo.md

@@ -53,15 +53,15 @@ NameSilo 使用 API Key 进行身份验证,这是唯一的认证方式。
 | :-----: | :----------- | :------------- | :--------------------------------- | :-------- | :--------- |
 | dns     | 服务商标识   | 字符串         | `namesilo`                         | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | NameSilo API Key                   | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ttl     | TTL 时间      | 整数(秒)     | 300 ~ 2592000                | `7200`    | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 4 - 4
doc/providers/noip.en.md

@@ -71,14 +71,14 @@ Use No-IP account username and password for authentication, which is the simples
 | dns       | Provider ID      | String         | `noip`                                 | None                          | Provider Param |
 | id        | Authentication ID| String         | No-IP username or DDNS ID              | None                          | Provider Param |
 | token     | Authentication Key| String        | No-IP password or DDNS KEY             | None                          | Provider Param |
-| index4    | IPv4 Source      | Array          | [Reference](../json.en.md#ipv4-ipv6)  | `default`                     | Common Config  |
-| index6    | IPv6 Source      | Array          | [Reference](../json.en.md#ipv4-ipv6)  | `default`                     | Common Config  |
+| index4    | IPv4 Source      | Array          | [Reference](../config/json.en.md#ipv4-ipv6)  | `default`                     | Common Config  |
+| index6    | IPv6 Source      | Array          | [Reference](../config/json.en.md#ipv4-ipv6)  | `default`                     | Common Config  |
 | ipv4      | IPv4 Domain      | Array          | Domain list                            | `all.ddnskey.com`             | Common Config  |
 | ipv6      | IPv6 Domain      | Array          | Domain list                            | `all.ddnskey.com`             | Common Config  |
-| proxy     | Proxy Settings   | Array          | [Reference](../json.en.md#proxy)      | None                          | Common Network |
+| proxy     | Proxy Settings   | Array          | [Reference](../config/json.en.md#proxy)      | None                          | Common Network |
 | ssl       | SSL Verification | Boolean/String | `"auto"`, `true`, `false`              | `auto`                        | Common Network |
 | cache     | Cache Settings   | Boolean/String | `true`, `false`, `filepath`            | `true`                        | Common Config  |
-| log       | Log Config       | Object         | [Reference](../json.en.md#log)        | None                          | Common Config  |
+| log       | Log Config       | Object         | [Reference](../config/json.en.md#log)        | None                          | Common Config  |
 
 > **Parameter Type Description**:
 >

+ 4 - 4
doc/providers/noip.md

@@ -71,14 +71,14 @@ No-IP 是流行的动态 DNS 服务提供商,支持标准的 DDNS 动态更新
 | dns     | 服务商标识   | 字符串         | `noip`                             | 无        | 服务商参数 |
 | id      | 认证 ID      | 字符串         | No-IP 用户名或 DDNS ID             | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | No-IP 密码或 DDNS KEY              | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | `all.ddnskey.com`        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | `all.ddnskey.com`        | 公用配置   |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 4 - 4
doc/providers/tencentcloud.en.md

@@ -68,17 +68,17 @@ The simplest and quickest way to obtain keys
 | dns | Provider identifier | String | `tencentcloud` | None | Provider Parameter |
 | id | Authentication ID | String | TencentCloud SecretId | None | Provider Parameter |
 | token | Authentication key | String | TencentCloud SecretKey | None | Provider Parameter |
-| index4 | IPv4 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Configuration |
-| index6 | IPv6 source | Array | [Reference](../json.en.md#ipv4-ipv6) | `default` | Common Configuration |
+| index4 | IPv4 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Configuration |
+| index6 | IPv6 source | Array | [Reference](../config/json.en.md#ipv4-ipv6) | `default` | Common Configuration |
 | ipv4 | IPv4 domains | Array | Domain list | None | Common Configuration |
 | ipv6 | IPv6 domains | Array | Domain list | None | Common Configuration |
 | endpoint | API endpoint | URL | [See below](#endpoint) | `https://dnspod.tencentcloudapi.com` | Provider Parameter |
 | line | Resolution line | String | [See below](#line) | `默认` | Provider Parameter |
 | ttl | TTL time | Integer (seconds) | [See below](#ttl) | `600` | Provider Parameter |
-| proxy | Proxy settings | Array | [Reference](../json.en.md#proxy) | None | Common Network |
+| proxy | Proxy settings | Array | [Reference](../config/json.en.md#proxy) | None | Common Network |
 | ssl | SSL verification | Boolean/String | `"auto"`, `true`, `false` | `auto` | Common Network |
 | cache | Cache settings | Boolean/String | `true`, `false`, `filepath` | `true` | Common Configuration |
-| log | Log configuration | Object | [Reference](../json.en.md#log) | None | Common Configuration |
+| log | Log configuration | Object | [Reference](../config/json.en.md#log) | None | Common Configuration |
 
 > **Parameter Type Description**:  
 >

+ 4 - 4
doc/providers/tencentcloud.md

@@ -75,17 +75,17 @@
 | dns     | 服务商标识   | 字符串         | `tencentcloud`                     | 无        | 服务商参数 |
 | id      | 认证 ID      | 字符串         | 腾讯云 SecretId                    | 无        | 服务商参数 |
 | token   | 认证密钥     | 字符串         | 腾讯云 SecretKey                   | 无        | 服务商参数 |
-| index4  | IPv4 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)  | `default` | 公用配置   |
-| index6  | IPv6 来源     | 数组           | [参考配置](../json.md#ipv4-ipv6)   | `default` | 公用配置   |
+| index4  | IPv4 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)  | `default` | 公用配置   |
+| index6  | IPv6 来源     | 数组           | [参考配置](../config/json.md#ipv4-ipv6)   | `default` | 公用配置   |
 | ipv4    | IPv4 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | ipv6    | IPv6 域名     | 数组           | 域名列表                           | 无        | 公用配置   |
 | endpoint| API 端点      | URL            | [参考下方](#endpoint)              | `https://dnspod.tencentcloudapi.com` | 服务商参数 |
 | line    | 解析线路      | 字符串         | [参考下方](#line)                   | `默认`    | 服务商参数 |
 | ttl     | TTL 时间      | 整数(秒)     | [参考下方](#ttl)                    | `600`     | 服务商参数 |
-| proxy   | 代理设置      | 数组           | [参考配置](../json.md#proxy)        | 无        | 公用网络   |
+| proxy   | 代理设置      | 数组           | [参考配置](../config/json.md#proxy)        | 无        | 公用网络   |
 | ssl     | SSL 验证方式  | 布尔/字符串    | `"auto"`、`true`、`false`            | `auto`    | 公用网络   |
 | cache   | 缓存设置      | 布尔/字符串    | `true`、`false`、`filepath`        | `true`    | 公用配置   |
-| log     | 日志配置      | 对象           | [参考配置](../json.md#log)             | 无        | 公用配置   |
+| log     | 日志配置      | 对象           | [参考配置](../config/json.md#log)             | 无        | 公用配置   |
 
 > **参数类型说明**:  
 >

+ 554 - 0
schema/v4.1.json

@@ -0,0 +1,554 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema",
+  "$id": "https://ddns.newfuture.cc/schema/v4.1.json",
+  "description": "DNS 配置文件 https://github.com/NewFuture/DDNS",
+  "type": "object",
+  "properties": {
+    "$schema": {
+      "type": "string",
+      "title": "please use https://ddns.newfuture.cc/schema/v4.1.json",
+      "description": "请更换为 https://ddns.newfuture.cc/schema/v4.1.json",
+      "default": "https://ddns.newfuture.cc/schema/v4.1.json",
+      "enum": [
+        "https://ddns.newfuture.cc/schema/v4.1.json",
+        "http://ddns.newfuture.cc/schema/v4.1.json",
+        "./schema/v4.1.json"
+      ]
+    },
+    "providers": {
+      "$id": "/properties/providers",
+      "type": "array",
+      "title": "DNS Providers List",
+      "description": "DNS服务提供商列表,支持多个不同的DNS服务商",
+      "items": {
+        "type": "object",
+        "properties": {
+          "provider": {
+            "type": "string",
+            "title": "DNS Provider Name",
+            "description": "dns服务商:阿里为alidns,阿里ESA为aliesa,DNS.COM为dnscom,DNSPOD国际版为(dnspod_com),cloudflare,HE.net为he,华为DNS为huaweidns,NameSilo为namesilo,腾讯云为tencentcloud,腾讯云EdgeOne为edgeone,自定义回调为callback",
+            "enum": [
+              "51dns",
+              "alidns",
+              "aliesa",
+              "callback",
+              "cloudflare",
+              "debug",
+              "dnscom",
+              "dnspod_com",
+              "dnspod",
+              "edgeone",
+              "he",
+              "huaweidns",
+              "namesilo",
+              "noip",
+              "tencentcloud"
+            ]
+          },
+          "id": {
+            "type": [
+              "string",
+              "null"
+            ],
+            "title": "ID or Email",
+            "description": "DNS服务API认证的ID或者邮箱"
+          },
+          "token": {
+            "type": "string",
+            "title": "API Token",
+            "description": "DNS服务商的访问Token或者Key"
+          },
+          "endpoint": {
+            "type": [
+              "string",
+              "null"
+            ],
+            "title": "API Endpoint",
+            "description": "DNS服务商的API端点URL,用于自定义或私有部署的API地址",
+            "default": null
+          },
+          "ipv4": {
+            "title": "IPv4 domain list",
+            "description": "待更新的IPv4 域名列表",
+            "type": "array",
+            "uniqueItems": true,
+            "items": {
+              "title": "ipv4 domain for DDNS",
+              "type": "string",
+              "pattern": "^(?:\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,18}$"
+            }
+          },
+          "ipv6": {
+            "type": "array",
+            "title": "IPv6 domain list",
+            "description": "待更新的IPv6 域名列表",
+            "uniqueItems": true,
+            "items": {
+              "title": "The ipv6 domain for DDNS",
+              "type": "string",
+              "pattern": "^(?:\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,18}$"
+            }
+          },
+          "index4": {
+            "type": [
+              "string",
+              "integer",
+              "boolean",
+              "array"
+            ],
+            "items": {
+              "type": [
+                "string",
+                "integer"
+              ],
+              "minimum": 0
+            },
+            "uniqueItems": true,
+            "minItems": 1,
+            "minimum": 0,
+            "title": "IPv4 address Setting",
+            "description": "本机 IPv4 获取方式设置,支持数组、字符串(逗号/分号分隔)等多种格式",
+            "default": [
+              "default"
+            ]
+          },
+          "index6": {
+            "type": [
+              "string",
+              "integer",
+              "boolean",
+              "array"
+            ],
+            "items": {
+              "type": [
+                "string",
+                "integer"
+              ],
+              "minimum": 0
+            },
+            "uniqueItems": true,
+            "minItems": 1,
+            "minimum": 0,
+            "title": "IPv6 address Setting",
+            "description": "本机 IPv6 获取方式设置,支持数组、字符串(逗号/分号分隔)等多种格式",
+            "default": [
+              "default"
+            ]
+          },
+          "ttl": {
+            "type": [
+              "number",
+              "null"
+            ],
+            "title": "TTL",
+            "description": "设置DNS TTL,默认不填读取DNS服务商的配置",
+            "default": null
+          },
+          "line": {
+            "type": [
+              "string",
+              "null"
+            ],
+            "title": "DNS Line/Route",
+            "description": "DNS线路设置,如电信、联通、移动等,支持中文和英文线路名称",
+            "default": null
+          },
+          "cache": {
+            "type": [
+              "string",
+              "boolean"
+            ],
+            "title": "Enable Cache",
+            "description": "是否启用缓存记录以避免频繁更新",
+            "default": true,
+            "examples": [
+              true,
+              false,
+              "/path/to/cache/ddns.cache"
+            ]
+          },
+          "log": {
+            "type": "object",
+            "title": "Log Config",
+            "description": "日志配置,仅支持设置日志级别",
+            "properties": {
+              "level": {
+                "type": "string",
+                "title": "Log Level",
+                "description": "日志级别,如 DEBUG、INFO、WARNING、ERROR、CRITICAL",
+                "default": "INFO",
+                "enum": [
+                  "DEBUG",
+                  "INFO",
+                  "WARNING",
+                  "ERROR",
+                  "CRITICAL"
+                ]
+              }
+            },
+            "required": [],
+            "additionalProperties": false
+          }
+        },
+        "required": [
+          "provider"
+        ],
+        "additionalProperties": false
+      }
+    },
+    "id": {
+      "$id": "/properties/id",
+      "type": [
+        "string",
+        "null"
+      ],
+      "title": "ID or Email",
+      "description": "DNS服务API认证的ID或者邮箱"
+    },
+    "token": {
+      "$id": "/properties/token",
+      "type": "string",
+      "title": "API Token",
+      "description": "DNS服务商的访问Token或者Key"
+    },
+    "endpoint": {
+      "$id": "/properties/endpoint",
+      "type": [
+        "string",
+        "null"
+      ],
+      "title": "API Endpoint",
+      "description": "DNS服务商的API端点URL,用于自定义或私有部署的API地址",
+      "default": null,
+      "examples": [
+        "https://dnsapi.com",
+        null
+      ]
+    },
+    "dns": {
+      "$id": "/properties/dns",
+      "type": "string",
+      "title": "DNS Provider",
+      "description": "dns服务商:阿里为alidns,阿里ESA为aliesa,DNS.COM为dnscom,DNSPOD国际版为(dnspod_com),cloudflare,HE.net为he,华为DNS为huaweidns,NameSilo为namesilo,腾讯云为tencentcloud,腾讯云EdgeOne为edgeone,自定义回调为callback",
+      "default": "dnspod",
+      "examples": [
+        "dnspod",
+        "alidns",
+        "cloudflare"
+      ],
+      "enum": [
+        "51dns",
+        "alidns",
+        "aliesa",
+        "callback",
+        "cloudflare",
+        "debug",
+        "dnscom",
+        "dnspod_com",
+        "dnspod",
+        "edgeone",
+        "he",
+        "huaweidns",
+        "namesilo",
+        "noip",
+        "tencentcloud"
+      ]
+    },
+    "ipv4": {
+      "$id": "/properties/ipv4",
+      "title": "IPv4 domain list",
+      "description": "待更新的IPv4 域名列表",
+      "type": "array",
+      "uniqueItems": true,
+      "items": {
+        "$id": "/properties/ipv4/items",
+        "title": "ipv4 domain for DDNS",
+        "type": "string",
+        "pattern": "^(?:\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,18}$",
+        "examples": [
+          "newfuture.cc",
+          "ipv4.example.newfuture.cc"
+        ]
+      }
+    },
+    "ipv6": {
+      "$id": "/properties/ipv6",
+      "type": "array",
+      "title": "IPv6 domain list",
+      "description": "待更新的IPv6 域名列表",
+      "uniqueItems": true,
+      "items": {
+        "$id": "/properties/ipv6/items",
+        "title": "The ipv6 domain for DDNS",
+        "type": "string",
+        "pattern": "^(?:\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,18}$",
+        "examples": [
+          "newfuture.cc",
+          "ipv6.example.newfuture.cc"
+        ]
+      }
+    },
+    "index4": {
+      "$id": "/properties/index4",
+      "type": [
+        "string",
+        "integer",
+        "boolean",
+        "array"
+      ],
+      "items": {
+        "type": [
+          "string",
+          "integer"
+        ],
+        "minimum": 0
+      },
+      "uniqueItems": true,
+      "minItems": 1,
+      "minimum": 0,
+      "title": "IPv4 address Setting",
+      "description": "本机 IPv4 获取方式设置,支持数组、字符串(逗号/分号分隔)等多种格式",
+      "default": [
+        "default"
+      ],
+      "examples": [
+        "default",
+        "public",
+        0,
+        "192\\\\.168\\\\..*",
+        "public,regex:192\\\\.168\\\\..*",
+        [
+          "public",
+          "default"
+        ],
+        false
+      ]
+    },
+    "index6": {
+      "$id": "/properties/index6",
+      "type": [
+        "string",
+        "integer",
+        "boolean",
+        "array"
+      ],
+      "items": {
+        "type": [
+          "string",
+          "integer"
+        ],
+        "minimum": 0
+      },
+      "uniqueItems": true,
+      "minItems": 1,
+      "minimum": 0,
+      "title": "IPv6 address Setting",
+      "description": "本机 IPv6 获取方式设置,支持数组、字符串(逗号/分号分隔)等多种格式",
+      "default": [
+        "default"
+      ],
+      "examples": [
+        "default",
+        "public",
+        0,
+        1,
+        "2404:f801:10:.*",
+        "public;regex:2404:f801:.*",
+        [
+          "public",
+          "default"
+        ],
+        false
+      ]
+    },
+    "ttl": {
+      "$id": "/properties/ttl",
+      "type": [
+        "number",
+        "null"
+      ],
+      "title": "TTL",
+      "description": "设置DNS TTL,默认不填读取DNS服务商的配置",
+      "default": null,
+      "examples": [
+        600,
+        null
+      ]
+    },
+    "line": {
+      "$id": "/properties/line",
+      "type": [
+        "string",
+        "null"
+      ],
+      "title": "DNS Line/Route",
+      "description": "DNS线路设置,如电信、联通、移动等,支持中文和英文线路名称",
+      "default": null,
+      "examples": [
+        "telecom",
+        "电信",
+        "default",
+        "默认"
+      ]
+    },
+    "proxy": {
+      "$id": "/properties/proxy",
+      "type": [
+        "string",
+        "null",
+        "array"
+      ],
+      "title": "HTTP Proxy Setting",
+      "description": "DIRECT表示直连,多个代理分号(;)分割逐个尝试直到成功",
+      "pattern": "^[a-zA-Z0-9\\-;_:\\.]*$",
+      "examples": [
+        "127.0.0.1:1080;DIRECT"
+      ],
+      "uniqueItems": true,
+      "items": {
+        "$id": "/properties/ipv4/items",
+        "title": "ipv4 domain for DDNS",
+        "type": "string",
+        "pattern": "^[a-zA-Z0-9\\-_:\\.]*$",
+        "examples": [
+          "127.0.0.1:1080"
+        ]
+      }
+    },
+    "cache": {
+      "$id": "/properties/cache",
+      "type": [
+        "string",
+        "boolean"
+      ],
+      "title": "Enable Cache",
+      "description": "是否启用缓存记录以避免频繁更新",
+      "default": true,
+      "examples": [
+        true,
+        false,
+        "/path/to/cache/ddns.cache"
+      ]
+    },
+    "ssl": {
+      "$id": "/properties/ssl",
+      "type": [
+        "string",
+        "boolean"
+      ],
+      "title": "SSL/TLS Setting",
+      "description": "SSL/TLS连接设置,auto表示自动检测,true强制使用SSL,false禁用SSL",
+      "default": "auto",
+      "examples": [
+        "auto",
+        true,
+        false
+      ]
+    },
+    "log": {
+      "$id": "/properties/log",
+      "type": "object",
+      "title": "Log Config",
+      "description": "日志配置,支持自定义日志级别、输出位置、格式和日期格式。可通过命令行 --log.level, --log.file, --log.format, --log.datefmt 或环境变量 DDNS_LOG_LEVEL, DDNS_LOG_FILE, DDNS_LOG_FORMAT, DDNS_LOG_DATEFMT 设置。",
+      "properties": {
+        "level": {
+          "type": "string",
+          "title": "Log Level",
+          "description": "日志级别,如 DEBUG、INFO、WARNING、ERROR、CRITICAL",
+          "default": "INFO",
+          "enum": [
+            "DEBUG",
+            "INFO",
+            "WARNING",
+            "ERROR",
+            "CRITICAL"
+          ]
+        },
+        "file": {
+          "type": [
+            "string",
+            "null"
+          ],
+          "title": "Log Output File",
+          "description": "日志输出文件路径,留空或为null时输出到控制台"
+        },
+        "format": {
+          "type": [
+            "string",
+            "null"
+          ],
+          "title": "Log Format",
+          "description": "日志格式,参考Python logging模块的格式字符串",
+          "default": "%(asctime)s %(levelname)s [%(module)s]: %(message)s"
+        },
+        "datefmt": {
+          "type": [
+            "string",
+            "null"
+          ],
+          "title": "Date Format",
+          "description": "日期时间格式,参考Python time.strftime()的格式字符串",
+          "default": "%Y-%m-%dT%H:%M:%S"
+        }
+      },
+      "required": [],
+      "additionalProperties": false
+    }
+  },
+  "not": {
+    "allOf": [
+      {
+        "required": [
+          "providers"
+        ]
+      },
+      {
+        "anyOf": [
+          {
+            "required": [
+              "dns"
+            ]
+          },
+          {
+            "required": [
+              "id"
+            ]
+          },
+          {
+            "required": [
+              "token"
+            ]
+          },
+          {
+            "required": [
+              "ipv4"
+            ]
+          },
+          {
+            "required": [
+              "ipv6"
+            ]
+          },
+          {
+            "required": [
+              "endpoint"
+            ]
+          }
+        ]
+      }
+    ]
+  },
+  "anyOf": [
+    {
+      "required": [
+        "token"
+      ]
+    },
+    {
+      "required": [
+        "providers"
+      ]
+    }
+  ],
+  "additionalProperties": false
+}

+ 3 - 3
tests/__init__.py

@@ -8,11 +8,11 @@ import os
 import unittest
 
 try:
-    from unittest.mock import patch, MagicMock
+    from unittest.mock import patch, MagicMock, call
 except ImportError:  # Python 2
-    from mock import patch, MagicMock  # type: ignore
+    from mock import patch, MagicMock, call  # type: ignore
 
-__all__ = ["patch", "MagicMock", "unittest"]
+__all__ = ["patch", "MagicMock", "unittest", "call"]
 
 # 添加当前目录到 Python 路径,这样就可以直接导入 test_base
 current_dir = os.path.dirname(__file__)

+ 1 - 1
tests/config/callback.json

@@ -4,7 +4,7 @@
   "id": "https://httpbin.org/post?test=ddns&domain=__DOMAIN__&ip=__IP__&type=__RECORDTYPE__&timestamp=__TIMESTAMP__",
   "token": "{\"api_key\": \"test_e2e\", \"domain\": \"__DOMAIN__\", \"ip_address\": \"__IP__\", \"record_type\": \"__RECORDTYPE__\", \"ttl\": \"__TTL__\", \"line\": \"__LINE__\", \"timestamp\": \"__TIMESTAMP__\", \"event\": \"ddns_update\", \"version\": \"v4.0\", \"source\": \"ddns_client_e2e_test\"}",
   "ipv4": [
-    "test.example.com"
+    "ddns.newfuture.cc"
   ],
   "index4": [
     "url:http://api.ipify.cn",

+ 31 - 0
tests/config/multi-provider.json

@@ -0,0 +1,31 @@
+{
+    "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
+    "ssl": "auto",
+    "cache": false,
+    "log": {
+        "level": "DEBUG"
+    },
+    "providers": [
+        {
+            "provider": "debug",
+            "index4": "default",
+            "ipv4": "test1.example.com",
+            "ttl": 300
+        },
+        {
+            "provider": "debug",
+            "index4": [
+                "public"
+            ],
+            "ipv4": [
+                "test2.example.com"
+            ],
+            "ttl": 600,
+            "cache": true,
+            "endpoint": null,
+            "log": {
+                "level": "INFO"
+            }
+        }
+    ]
+}

+ 2 - 1
tests/config/noip.json

@@ -5,7 +5,7 @@
     "token": "TEST", # Token for authentication, can be empty for NoIP
     "endpoint": "https://httpbin.org/base64/Z29vZCAxOTIuMTY4LjEuMQ==?",
     "ipv4": [
-        "test.example.com"
+        "ddns.newfuture.cc"
     ],
     "index4": [
         "public" // 公网IP
@@ -13,6 +13,7 @@
     "ttl": 300,
     "proxy": null,
     "cache": false, // Disable caching for NoIP
+    "ssl": false,
     "log": {
         "level": "DEBUG",
         "datefmt": "%m-%d %H:%M:%S"

+ 1 - 0
tests/test_cache.py

@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+# type: ignore[index,operator,assignment]
 """
 Test cases for cache module
 

+ 13 - 2
tests/test_config_cli.py

@@ -194,7 +194,7 @@ class TestCliConfig(unittest.TestCase):
 
         sys.argv = ["ddns", "--config", "/path/to/config.json"]
         config = load_config("Test DDNS", "Test doc", "1.0.0", "2025-07-04")
-        self.assertEqual(config["config"], "/path/to/config.json")
+        self.assertEqual(config["config"], ["/path/to/config.json"])
 
     def test_load_config_index_rules(self):
         sys.argv = [
@@ -397,10 +397,21 @@ class TestCliConfig(unittest.TestCase):
             "~/.ssl/cert.pem",
         ]
         config = load_config("Test DDNS", "Test doc", "1.0.0", "2025-07-04")
-        self.assertEqual(config["config"], "/absolute/path/config.json")
+        self.assertEqual(config["config"], ["/absolute/path/config.json"])
         self.assertEqual(config["log_file"], "./relative/path/ddns.log")
         self.assertEqual(config["ssl"], "~/.ssl/cert.pem")
 
+        # Test multiple configs
+        sys.argv = [
+            "ddns",
+            "--config",
+            "/path/to/config1.json",
+            "--config",
+            "/path/to/config2.json",
+        ]
+        config = load_config("Test DDNS", "Test doc", "1.0.0", "2025-07-04")
+        self.assertEqual(config["config"], ["/path/to/config1.json", "/path/to/config2.json"])
+
         # Test numeric strings
         sys.argv = ["ddns", "--id", "123456", "--token", "987654321", "--line", "100"]
         config = load_config("Test DDNS", "Test doc", "1.0.0", "2025-07-04")

+ 180 - 1
tests/test_config_file.py

@@ -1,4 +1,5 @@
 # coding=utf-8
+# type: ignore[index,operator,assignment]
 """
 Unit tests for ddns.config.file module
 @author: GitHub Copilot
@@ -10,9 +11,20 @@ import shutil
 import os
 import json
 import io
-from io import StringIO
+import sys
 from ddns.config.file import load_config, save_config
 
+# Python 2/3 compatibility
+if sys.version_info[0] >= 3:
+    from io import StringIO
+
+    unicode = str
+else:
+    try:
+        from StringIO import StringIO
+    except ImportError:
+        from io import StringIO
+
 FileNotFoundError = globals().get("FileNotFoundError", IOError)
 PermissionError = globals().get("PermissionError", IOError)
 
@@ -26,6 +38,7 @@ class TestConfigFile(unittest.TestCase):
         self.addCleanup(shutil.rmtree, self.temp_dir, ignore_errors=True)
 
         # Capture stdout and stderr output for testing
+        # Use unicode-compatible StringIO for Python 2/3 compatibility
         self.stdout_capture = StringIO()
         self.stderr_capture = StringIO()
         self.original_stdout = __import__("sys").stdout
@@ -567,6 +580,172 @@ class TestConfigFile(unittest.TestCase):
         self.assertEqual(loaded_config["metadata_author"], "test")
         self.assertTrue(loaded_config["metadata_enabled"])
 
+    def test_load_config_v41_providers_format(self):
+        """Test loading configuration with v4.1 providers format"""
+        config_data = {
+            "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
+            "ssl": "auto",
+            "cache": True,
+            "log": {"level": "INFO", "file": "/var/log/ddns.log"},
+            "providers": [
+                {
+                    "provider": "cloudflare",
+                    "id": "[email protected]",
+                    "token": "token1",
+                    "ipv4": ["test1.example.com"],
+                    "ttl": 300,
+                },
+                {
+                    "provider": "dnspod",
+                    "id": "[email protected]",
+                    "token": "token2",
+                    "ipv4": ["test2.example.com"],
+                    "ttl": 600,
+                },
+            ],
+        }
+
+        config_file = self.create_test_file("v41_providers.json", config_data)
+        loaded_configs = load_config(config_file)
+
+        # Should return a list of configs
+        self.assertIsInstance(loaded_configs, list)
+        self.assertEqual(len(loaded_configs), 2)
+
+        # Test first provider config
+        config1 = loaded_configs[0]
+        self.assertEqual(config1["dns"], "cloudflare")  # name mapped to dns
+        self.assertEqual(config1["id"], "[email protected]")
+        self.assertEqual(config1["token"], "token1")
+        self.assertEqual(config1["ipv4"], ["test1.example.com"])
+        self.assertEqual(config1["ttl"], 300)
+
+        # Test global configs are inherited
+        self.assertEqual(config1["ssl"], "auto")
+        self.assertTrue(config1["cache"])
+        self.assertEqual(config1["log_level"], "INFO")
+        self.assertEqual(config1["log_file"], "/var/log/ddns.log")
+
+        # Test second provider config
+        config2 = loaded_configs[1]
+        self.assertEqual(config2["dns"], "dnspod")  # name mapped to dns
+        self.assertEqual(config2["id"], "[email protected]")
+        self.assertEqual(config2["token"], "token2")
+        self.assertEqual(config2["ipv4"], ["test2.example.com"])
+        self.assertEqual(config2["ttl"], 600)
+
+        # Test global configs are inherited in second config too
+        self.assertEqual(config2["ssl"], "auto")
+        self.assertTrue(config2["cache"])
+        self.assertEqual(config2["log_level"], "INFO")
+        self.assertEqual(config2["log_file"], "/var/log/ddns.log")
+
+    def test_load_config_v41_providers_conflict_with_dns(self):
+        """Test loading configuration where providers and dns fields conflict"""
+        import ddns.config.file
+
+        original_stderr = ddns.config.file.stderr
+        ddns.config.file.stderr = self.stderr_capture
+
+        try:
+            config_data = {
+                "dns": "cloudflare",  # Should conflict with providers
+                "providers": [{"provider": "dnspod", "token": "test_token"}],
+            }
+
+            config_file = self.create_test_file("conflict.json", config_data)
+
+            with self.assertRaises(ValueError) as context:
+                load_config(config_file)
+
+            self.assertIn("providers and dns fields conflict", str(context.exception))
+
+            # Verify error message in stderr
+            stderr_output = self.stderr_capture.getvalue()
+            self.assertIn("'providers' and 'dns' fields cannot be used simultaneously", stderr_output)
+        finally:
+            ddns.config.file.stderr = original_stderr
+
+    def test_load_config_v41_providers_missing_name(self):
+        """Test loading configuration where provider is missing name field"""
+        import ddns.config.file
+
+        original_stderr = ddns.config.file.stderr
+        ddns.config.file.stderr = self.stderr_capture
+
+        try:
+            config_data = {
+                "providers": [
+                    {
+                        "id": "[email protected]",
+                        "token": "test_token",
+                        # Missing "provider" field
+                    }
+                ]
+            }
+
+            config_file = self.create_test_file("missing_name.json", config_data)
+
+            with self.assertRaises(ValueError) as context:
+                load_config(config_file)
+
+            self.assertIn("provider missing provider field", str(context.exception))
+
+            # Verify error message in stderr
+            stderr_output = self.stderr_capture.getvalue()
+            self.assertIn("Each provider must have a 'provider' field", stderr_output)
+        finally:
+            ddns.config.file.stderr = original_stderr
+
+    def test_load_config_v41_providers_single_provider(self):
+        """Test loading configuration with single provider in v4.1 format"""
+        config_data = {
+            "ssl": False,
+            "providers": [{"provider": "debug", "token": "dummy_token", "ipv4": ["test.example.com"]}],
+        }
+
+        config_file = self.create_test_file("single_provider.json", config_data)
+        loaded_configs = load_config(config_file)
+
+        # Should return a list with one config
+        self.assertIsInstance(loaded_configs, list)
+        self.assertEqual(len(loaded_configs), 1)
+
+        config = loaded_configs[0]
+        self.assertEqual(config["dns"], "debug")
+        self.assertEqual(config["token"], "dummy_token")
+        self.assertEqual(config["ipv4"], ["test.example.com"])
+        self.assertFalse(config["ssl"])  # Global config inherited
+
+    def test_load_config_v41_providers_with_nested_objects(self):
+        """Test loading v4.1 providers format with nested objects in providers"""
+        config_data = {
+            "cache": True,
+            "providers": [
+                {
+                    "provider": "cloudflare",
+                    "token": "test_token",
+                    "custom": {"setting1": "value1", "setting2": "value2"},
+                }
+            ],
+        }
+
+        config_file = self.create_test_file("providers_nested.json", config_data)
+        loaded_configs = load_config(config_file)
+
+        self.assertIsInstance(loaded_configs, list)
+        self.assertEqual(len(loaded_configs), 1)
+
+        config = loaded_configs[0]
+        self.assertEqual(config["dns"], "cloudflare")
+        self.assertEqual(config["token"], "test_token")
+        self.assertTrue(config["cache"])
+
+        # Test nested objects in provider config are flattened
+        self.assertEqual(config["custom_setting1"], "value1")
+        self.assertEqual(config["custom_setting2"], "value2")
+        self.assertNotIn("custom", config)
+
 
 if __name__ == "__main__":
     unittest.main()

+ 43 - 21
tests/test_config_init.py

@@ -1,17 +1,19 @@
 # coding=utf-8
+# type: ignore[index,operator,assignment]
 """
 Unit tests for ddns.config.__init__ module
 @author: GitHub Copilot
 """
 
-from __init__ import unittest, patch, MagicMock
+from __init__ import unittest, patch, MagicMock, call
+
 import os
 import tempfile
 import shutil
 import json
 import sys
 import ddns.config
-from ddns.config import load_config, Config
+from ddns.config import load_configs, Config
 from io import StringIO, BytesIO  # For capturing stdout in Python2 and Python3
 
 
@@ -68,11 +70,11 @@ class TestConfigInit(unittest.TestCase):
 
     def test_module_exports(self):
         """Test that module exports are correct"""
-        expected_exports = ["load_config", "Config"]
+        expected_exports = ["load_configs", "Config"]
         self.assertEqual(ddns.config.__all__, expected_exports)
-        self.assertTrue(hasattr(ddns.config, "load_config"))
+        self.assertTrue(hasattr(ddns.config, "load_configs"))
         self.assertTrue(hasattr(ddns.config, "Config"))
-        self.assertEqual(ddns.config.load_config, load_config)
+        self.assertEqual(ddns.config.load_configs, load_configs)
         self.assertEqual(ddns.config.Config, Config)
 
     def test_load_config_basic_integration(self):
@@ -85,7 +87,8 @@ class TestConfigInit(unittest.TestCase):
 
         # Test loading with CLI args
         with patch("sys.argv", ["ddns", "--config", config_path, "--id", "test_id"]):
-            result = load_config(self.test_description, self.test_version, self.test_date)
+            results = load_configs(self.test_description, self.test_version, self.test_date)
+            result = results[0]
             self.assertIsInstance(result, Config)
             self.assertEqual(result.dns, "debug")
             self.assertEqual(result.id, "test_id")  # CLI overrides
@@ -134,7 +137,8 @@ class TestConfigInit(unittest.TestCase):
             json.dump(config_content, f)
 
         with patch("sys.argv", ["ddns", "--config", config_path]):
-            result = load_config(self.test_description, self.test_version, self.test_date)
+            results = load_configs(self.test_description, self.test_version, self.test_date)
+            result = results[0]
             self.assertEqual(result.dns, "cloudflare")
             self.assertEqual(result.id, "custom_id")
 
@@ -146,7 +150,8 @@ class TestConfigInit(unittest.TestCase):
 
         with patch.dict(os.environ, {"DDNS_CONFIG": env_config_path}):
             with patch("sys.argv", ["ddns"]):
-                result = load_config(self.test_description, self.test_version, self.test_date)
+                results = load_configs(self.test_description, self.test_version, self.test_date)
+                result = results[0]
                 self.assertEqual(result.dns, "alidns")
                 self.assertEqual(result.id, "env_id")
 
@@ -174,7 +179,7 @@ class TestConfigInit(unittest.TestCase):
             mock_exists.side_effect = lambda path: path == config_path
             mock_json.return_value = {"id": "{}_id".format(location_type)}
 
-            result = load_config(self.test_description, self.test_version, self.test_date)
+            result = load_configs(self.test_description, self.test_version, self.test_date)[0]
             mock_json.assert_called_with(config_path)
             self.assertEqual(result.id, "{}_id".format(location_type))
 
@@ -182,14 +187,15 @@ class TestConfigInit(unittest.TestCase):
         """Test load_config when config files don't exist"""
         # Test case 1: No config file but provide minimal CLI args
         with patch("sys.argv", ["ddns", "--dns", "debug", "--id", "test", "--token", "test"]):
-            result = load_config(self.test_description, self.test_version, self.test_date)
+            results = load_configs(self.test_description, self.test_version, self.test_date)
+            result = results[0]
             self.assertEqual(result.dns, "debug")
             self.assertEqual(result.id, "test")
 
         # Test case 2: Specified config file doesn't exist should exit
         with patch("sys.argv", ["ddns", "--config", "/nonexistent/config.json", "--dns", "debug"]):
             with self.assertRaises(SystemExit):
-                load_config(self.test_description, self.test_version, self.test_date)
+                load_configs(self.test_description, self.test_version, self.test_date)
 
     def test_load_config_doc_string_format_integration(self):
         """Test that doc string is properly formatted with version and date"""
@@ -200,7 +206,8 @@ class TestConfigInit(unittest.TestCase):
             json.dump(config_content, f)
 
         with patch("sys.argv", ["ddns", "--config", config_path]):
-            result = load_config(self.test_description, self.test_version, self.test_date)
+            results = load_configs(self.test_description, self.test_version, self.test_date)
+            result = results[0]
             self.assertIsInstance(result, Config)
             self.assertEqual(result.dns, "debug")
 
@@ -221,13 +228,24 @@ class TestConfigInit(unittest.TestCase):
 
         with patch("ddns.config.Config") as mock_config_class:
             mock_config_instance = MagicMock()
+            mock_config_instance.log_format = None  # No custom format
+            mock_config_instance.log_level = 20  # INFO level
+            mock_config_instance.log_datefmt = "%Y-%m-%dT%H:%M:%S"
+            mock_config_instance.log_file = None  # No log file
+            mock_config_instance.dns = "cloudflare"  # Has DNS provider
             mock_config_class.return_value = mock_config_instance
 
-            result = load_config(self.test_description, self.test_version, self.test_date)
+            result = load_configs(self.test_description, self.test_version, self.test_date)[0]
+
+            # Should create both main config and global config
+            self.assertEqual(mock_config_class.call_count, 2)
 
-            mock_config_class.assert_called_once_with(
-                cli_config=cli_config, json_config=json_config, env_config=env_config
-            )
+            # Both calls should use the same parameters when there's only one config file
+            expected_calls = [
+                call(cli_config=cli_config, json_config=json_config, env_config=env_config),
+                call(cli_config=cli_config, json_config=json_config, env_config=env_config),
+            ]
+            mock_config_class.assert_has_calls(expected_calls, any_order=True)
             self.assertEqual(result, mock_config_instance)
 
     @patch("ddns.config.load_env_config")
@@ -252,7 +270,8 @@ class TestConfigInit(unittest.TestCase):
         mock_env.return_value = {"proxy": ["http://proxy.corp.com:8080"], "line": "default"}
         mock_exists.return_value = True
 
-        result = load_config(self.test_description, self.test_version, self.test_date)
+        results = load_configs(self.test_description, self.test_version, self.test_date)
+        result = results[0]
 
         self.assertIsInstance(result, Config)
         # CLI overrides
@@ -277,12 +296,14 @@ class TestConfigInit(unittest.TestCase):
             json.dump(config_content, f)
 
         with patch("sys.argv", ["ddns", "--config", config_path]):
-            result = load_config(self.test_description, self.test_version, self.test_date)
+            results = load_configs(self.test_description, self.test_version, self.test_date)
+            result = results[0]
             self.assertIsInstance(result, Config)
 
         # Test case 2: Empty string parameters but provide CLI DNS - no config files exist
         with patch("sys.argv", ["ddns", "--dns", "debug", "--id", "test", "--token", "test"]):
-            result = load_config("", "", "")
+            results = load_configs("", "", "")
+            result = results[0]
             self.assertIsInstance(result, Config)
 
         # Test case 3: Empty configurations should cause exit (edge case)
@@ -290,7 +311,7 @@ class TestConfigInit(unittest.TestCase):
         with patch("ddns.config.load_env_config", return_value={}):  # Empty env config
             with patch("sys.argv", ["ddns"]):  # No arguments at all
                 with self.assertRaises(SystemExit) as cm:
-                    load_config(self.test_description, self.test_version, self.test_date)
+                    load_configs(self.test_description, self.test_version, self.test_date)
                 self.assertEqual(cm.exception.code, 1)  # Should exit with error code 1
 
     def test_config_file_discovery_integration(self):
@@ -318,7 +339,8 @@ class TestConfigInit(unittest.TestCase):
 
         # Test that it can be auto-discovered when no explicit config is provided
         with patch("sys.argv", ["ddns"]):
-            result = load_config(self.test_description, self.test_version, self.test_date)
+            results = load_configs(self.test_description, self.test_version, self.test_date)
+            result = results[0]
             self.assertEqual(result.dns, "debug")
             self.assertEqual(result.id, "[email protected]")
             self.assertEqual(result.token, "auto123")

+ 107 - 0
tests/test_config_init_multi.py

@@ -0,0 +1,107 @@
+# coding=utf-8
+# type: ignore[index,operator,assignment]
+"""
+Unit tests for multi-config functionality
+@author: GitHub Copilot
+"""
+from __init__ import unittest, patch
+import tempfile
+import json
+import os
+import sys
+from ddns.config import load_configs
+from ddns.config.file import load_config as load_file_config
+
+
+class TestMultiConfig(unittest.TestCase):
+
+    def setUp(self):
+        self.temp_dir = tempfile.mkdtemp()
+        self.original_argv = sys.argv[:]
+
+    def tearDown(self):
+        sys.argv = self.original_argv
+        # Clean up temp directory
+        import shutil
+
+        shutil.rmtree(self.temp_dir, ignore_errors=True)
+
+    def test_file_loader_single_object(self):
+        """Test that file loader works with single object configs"""
+        config_data = {"dns": "cloudflare", "id": "[email protected]", "token": "secret123"}
+
+        config_path = os.path.join(self.temp_dir, "single_config.json")
+        with open(config_path, "w") as f:
+            json.dump(config_data, f)
+
+        result = load_file_config(config_path)
+        self.assertIsInstance(result, dict)
+        self.assertEqual(result["dns"], "cloudflare")
+        self.assertEqual(result["id"], "[email protected]")
+        self.assertEqual(result["token"], "secret123")
+
+    def test_cli_multiple_configs(self):
+        """Test CLI support for multiple config files"""
+        # Create two config files
+        config1_data = {"dns": "cloudflare", "id": "[email protected]", "token": "secret1"}
+        config2_data = {"dns": "dnspod", "id": "[email protected]", "token": "secret2"}
+
+        config1_path = os.path.join(self.temp_dir, "config1.json")
+        config2_path = os.path.join(self.temp_dir, "config2.json")
+
+        with open(config1_path, "w") as f:
+            json.dump(config1_data, f)
+        with open(config2_path, "w") as f:
+            json.dump(config2_data, f)
+
+        # Mock CLI args
+        sys.argv = ["ddns", "-c", config1_path, "-c", config2_path]
+
+        with patch("ddns.config.cli.load_config") as mock_cli:
+            mock_cli.return_value = {"config": [config1_path, config2_path]}
+
+            with patch("ddns.config.env.load_config") as mock_env:
+                mock_env.return_value = {}
+
+                configs = load_configs("test", "1.0", "2023-01-01")
+
+                self.assertEqual(len(configs), 2)
+                self.assertEqual(configs[0].dns, "cloudflare")
+                self.assertEqual(configs[1].dns, "dnspod")
+
+    def test_env_multiple_configs_integration(self):
+        """Test environment variable support for multiple config files using real CLI/env loading"""
+        # Create two config files
+        config1_data = {"dns": "debug", "id": "[email protected]", "token": "secret1"}
+        config2_data = {"dns": "debug", "id": "[email protected]", "token": "secret2"}
+
+        config1_path = os.path.join(self.temp_dir, "config1.json")
+        config2_path = os.path.join(self.temp_dir, "config2.json")
+
+        with open(config1_path, "w") as f:
+            json.dump(config1_data, f)
+        with open(config2_path, "w") as f:
+            json.dump(config2_data, f)
+
+        # Test via environment variable
+        old_env = os.environ.get("DDNS_CONFIG")
+        try:
+            os.environ["DDNS_CONFIG"] = "{},{}".format(config1_path, config2_path)
+            sys.argv = ["ddns"]
+
+            configs = load_configs("test", "1.0", "2023-01-01")
+
+            self.assertEqual(len(configs), 2)
+            self.assertEqual(configs[0].dns, "debug")
+            self.assertEqual(configs[1].dns, "debug")
+            self.assertEqual(configs[0].id, "[email protected]")
+            self.assertEqual(configs[1].id, "[email protected]")
+        finally:
+            if old_env is not None:
+                os.environ["DDNS_CONFIG"] = old_env
+            elif "DDNS_CONFIG" in os.environ:
+                del os.environ["DDNS_CONFIG"]
+
+
+if __name__ == "__main__":
+    unittest.main()

+ 264 - 0
tests/test_config_schema_v4_1.py

@@ -0,0 +1,264 @@
+# -*- coding:utf-8 -*-
+# type: ignore[index,operator,assignment]
+"""
+Integration test for all config formats including v4.1 providers
+@author: GitHub Copilot
+"""
+from __future__ import unicode_literals
+from __init__ import unittest
+import tempfile
+import shutil
+import os
+import json
+from ddns.config import load_configs
+
+
+class TestAllConfigFormatsIntegration(unittest.TestCase):
+    """Integration test for all supported config formats"""
+
+    def setUp(self):
+        """Set up test fixtures"""
+        self.temp_dir = tempfile.mkdtemp()
+        self.addCleanup(shutil.rmtree, self.temp_dir, ignore_errors=True)
+
+    def create_test_file(self, filename, content):
+        # type: (str, dict) -> str
+        """Helper method to create a test file with given content"""
+        file_path = os.path.join(self.temp_dir, filename)
+        with open(file_path, "w") as f:
+            if isinstance(content, dict):
+                f.write(json.dumps(content, indent=2))
+            else:
+                f.write(content)
+        return file_path
+
+    def test_all_config_formats_integration(self):
+        """Test loading v4.1 config formats"""
+        # Create single object config
+        single_config = {
+            "dns": "cloudflare",
+            "id": "[email protected]",
+            "token": "single_token",
+            "ipv4": ["single.example.com"],
+            "ssl": True,
+        }
+        single_file = self.create_test_file("single.json", single_config)
+
+        # Create v4.1 providers format
+        providers_config = {
+            "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
+            "ssl": "auto",
+            "cache": True,
+            "providers": [
+                {"provider": "debug", "token": "provider_token1", "ipv4": ["provider1.example.com"], "ttl": 300},
+                {"provider": "debug", "token": "provider_token2", "ipv4": ["provider2.example.com"], "ttl": 600},
+            ],
+        }
+        providers_file = self.create_test_file("providers.json", providers_config)
+
+        # Mock sys.argv to control CLI parsing
+        import sys
+
+        original_argv = sys.argv
+
+        try:
+            # Set fake argv with our config files
+            sys.argv = ["ddns", "-c", single_file, "-c", providers_file]
+
+            # Load all configs
+            all_configs = load_configs("test", "1.0.0", "2025-07-17")
+
+            # Should have 3 total configs: 1 single + 2 from providers
+            self.assertEqual(len(all_configs), 3)
+
+            # Test single config
+            self.assertEqual(all_configs[0].dns, "cloudflare")
+            self.assertEqual(all_configs[0].id, "[email protected]")
+            self.assertEqual(all_configs[0].ssl, True)
+
+            # Test first provider config
+            self.assertEqual(all_configs[1].dns, "debug")
+            self.assertEqual(all_configs[1].token, "provider_token1")
+            self.assertEqual(all_configs[1].ipv4, ["provider1.example.com"])
+            self.assertEqual(all_configs[1].ttl, 300)
+            # Inherited from global - handle Python 2.7 unicode strings
+            self.assertEqual(str(all_configs[1].ssl), "auto")
+            # Inherited from global
+            self.assertEqual(all_configs[1].cache, True)
+
+            # Test second provider config
+            self.assertEqual(all_configs[2].dns, "debug")
+            self.assertEqual(all_configs[2].token, "provider_token2")
+            self.assertEqual(all_configs[2].ipv4, ["provider2.example.com"])
+            self.assertEqual(all_configs[2].ttl, 600)
+            # Inherited from global - handle Python 2.7 unicode strings
+            self.assertEqual(str(all_configs[2].ssl), "auto")
+            # Inherited from global
+            self.assertEqual(all_configs[2].cache, True)
+
+        finally:
+            # Restore original argv
+            sys.argv = original_argv
+
+    def test_v41_backward_compatibility(self):
+        """Test that v4.1 format is backward compatible with existing
+        single config"""
+        # Create a traditional single config
+        old_config = {
+            "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
+            "dns": "cloudflare",
+            "id": "[email protected]",
+            "token": "old_token",
+            "ipv4": ["old.example.com"],
+            "ssl": "auto",
+        }
+        old_file = self.create_test_file("old_format.json", old_config)
+
+        # Mock sys.argv to control CLI parsing
+        import sys
+
+        original_argv = sys.argv
+
+        try:
+            # Set fake argv with our config file
+            sys.argv = ["ddns", "-c", old_file]
+
+            configs = load_configs("test", "1.0.0", "2025-01-01")
+
+            # Should load exactly one config
+            self.assertEqual(len(configs), 1)
+            config = configs[0]
+            self.assertEqual(config.dns, "cloudflare")
+            self.assertEqual(config.id, "[email protected]")
+            self.assertEqual(config.token, "old_token")
+            self.assertEqual(str(config.ssl), "auto")
+
+        finally:
+            sys.argv = original_argv
+
+    def test_v41_schema_reference(self):
+        """Test that save_config uses v4.1 schema by default"""
+        from ddns.config.file import save_config, load_config
+
+        test_config = {"dns": "debug", "token": "test"}
+        save_file = os.path.join(self.temp_dir, "new_config.json")
+
+        # Save config
+        result = save_config(save_file, test_config)
+        self.assertTrue(result)
+
+        # Load it back and check schema
+        loaded = load_config(save_file)
+        expected_schema = "https://ddns.newfuture.cc/schema/v4.1.json"
+        self.assertEqual(loaded["$schema"], expected_schema)
+        self.assertEqual(loaded["dns"], "debug")
+        self.assertEqual(loaded["token"], "test")
+
+    def test_v40_to_v41_compatibility(self):
+        """Test v4.0 config is compatible with v4.1 processing"""
+        from ddns.config.file import load_config
+
+        # Create v4.0 schema config
+        v40_config = {
+            "$schema": "https://ddns.newfuture.cc/schema/v4.0.json",
+            "dns": "cloudflare",
+            "id": "[email protected]",
+            "token": "v40_token",
+            "ipv4": ["v40.example.com"],
+            "ttl": 300,
+            "ssl": True,
+            "log": {"level": "DEBUG", "file": "test.log"},
+        }
+        v40_file = self.create_test_file("v40_config.json", v40_config)
+
+        # Load and check it processes correctly
+        loaded = load_config(v40_file)
+        self.assertEqual(loaded["dns"], "cloudflare")
+        self.assertEqual(loaded["id"], "[email protected]")
+        self.assertEqual(loaded["token"], "v40_token")
+        self.assertEqual(loaded["ipv4"], ["v40.example.com"])
+        self.assertEqual(loaded["ttl"], 300)
+        self.assertEqual(loaded["ssl"], True)
+        # Check flattened log properties
+        self.assertEqual(loaded["log_level"], "DEBUG")
+        self.assertEqual(loaded["log_file"], "test.log")
+
+    def test_v41_providers_complex_inheritance(self):
+        """Test complex inheritance scenarios in v4.1 providers format"""
+        from ddns.config.file import load_config
+
+        # Create complex v4.1 config with nested objects
+        complex_config = {
+            "$schema": "https://ddns.newfuture.cc/schema/v4.1.json",
+            "ssl": "auto",
+            "ttl": 600,
+            "cache": False,
+            "log": {"level": "INFO", "format": "[%(levelname)s] %(message)s"},
+            "providers": [
+                {
+                    "provider": "cloudflare",
+                    "id": "[email protected]",
+                    "token": "cf_token",
+                    "ipv4": ["cf.example.com"],
+                    "ttl": 300,  # Override global ttl
+                    "ssl": True,  # Override global ssl
+                },
+                {
+                    "provider": "debug",
+                    "token": "debug_token",
+                    "ipv4": ["debug.example.com"],
+                    # Uses global ttl and ssl
+                    "log": {"level": "DEBUG"},  # Override log level
+                },
+            ],
+        }
+        complex_file = self.create_test_file("complex_v41.json", complex_config)
+
+        # Load config
+        configs = load_config(complex_file)
+        self.assertEqual(len(configs), 2)
+
+        # Test first provider inheritance and overrides
+        cf_config = configs[0]
+        self.assertEqual(cf_config["dns"], "cloudflare")
+        self.assertEqual(cf_config["id"], "[email protected]")
+        self.assertEqual(cf_config["token"], "cf_token")
+        self.assertEqual(cf_config["ttl"], 300)  # Overridden
+        self.assertEqual(cf_config["ssl"], True)  # Overridden
+        self.assertEqual(cf_config["cache"], False)  # Inherited
+        self.assertEqual(cf_config["log_level"], "INFO")  # Inherited
+        self.assertEqual(cf_config["log_format"], "[%(levelname)s] %(message)s")
+
+        # Test second provider inheritance
+        debug_config = configs[1]
+        self.assertEqual(debug_config["dns"], "debug")
+        self.assertEqual(debug_config["token"], "debug_token")
+        self.assertEqual(debug_config["ttl"], 600)  # Inherited
+        self.assertEqual(debug_config["ssl"], "auto")  # Inherited
+        self.assertEqual(debug_config["cache"], False)  # Inherited
+        self.assertEqual(debug_config["log_level"], "DEBUG")  # Overridden
+        self.assertEqual(debug_config["log_format"], "[%(levelname)s] %(message)s")
+
+    def test_v41_providers_error_cases(self):
+        """Test error handling in v4.1 providers format"""
+        from ddns.config.file import load_config
+
+        # Test providers without provider field
+        invalid_config1 = {"providers": [{"id": "[email protected]", "token": "token"}]}
+        invalid_file1 = self.create_test_file("invalid1.json", invalid_config1)
+
+        with self.assertRaises(ValueError) as cm:
+            load_config(invalid_file1)
+        self.assertIn("provider missing provider field", str(cm.exception))
+
+        # Test dns and providers conflict
+        invalid_config2 = {"dns": "cloudflare", "providers": [{"provider": "debug", "token": "token"}]}
+        invalid_file2 = self.create_test_file("invalid2.json", invalid_config2)
+
+        with self.assertRaises(ValueError) as cm:
+            load_config(invalid_file2)
+        self.assertIn("providers and dns fields conflict", str(cm.exception))
+
+
+if __name__ == "__main__":
+    unittest.main()

+ 77 - 28
tests/test_util_http.py

@@ -1,12 +1,15 @@
 # coding=utf-8
+# type: ignore[index]
 """
 测试 ddns.util.http 模块
 Test ddns.util.http module
 """
 
 from __future__ import unicode_literals
-from __init__ import unittest
-import sys
+from __init__ import unittest, sys
+import json
+import socket
+
 from ddns.util.http import (
     HttpResponse,
     _decode_response_body,
@@ -53,8 +56,8 @@ class TestHttpResponse(unittest.TestCase):
         self.assertEqual(response.headers, headers)
         self.assertEqual(response.body, '{"test": true}')
 
-    def test_get_header_case_insensitive(self):
-        """测试get_header方法不区分大小写"""
+    def test_headers_get_case_insensitive(self):
+        """测试headers.get方法不区分大小写"""
 
         # 模拟 response.info() 对象,支持不区分大小写的 get 方法
         class MockHeaders:
@@ -71,13 +74,13 @@ class TestHttpResponse(unittest.TestCase):
         headers = MockHeaders()
         response = HttpResponse(200, "OK", headers, "test")
 
-        self.assertEqual(response.get_header("content-type"), "application/json")
-        self.assertEqual(response.get_header("Content-Type"), "application/json")
-        self.assertEqual(response.get_header("CONTENT-TYPE"), "application/json")
-        self.assertEqual(response.get_header("content-length"), "100")
+        self.assertEqual(response.headers.get("content-type"), "application/json")
+        self.assertEqual(response.headers.get("Content-Type"), "application/json")
+        self.assertEqual(response.headers.get("CONTENT-TYPE"), "application/json")
+        self.assertEqual(response.headers.get("content-length"), "100")
 
-    def test_get_header_not_found(self):
-        """测试get_header方法找不到头部时的默认值"""
+    def test_headers_get_not_found(self):
+        """测试headers.get方法找不到头部时的默认值"""
 
         class MockHeaders:
             def __init__(self):
@@ -92,11 +95,11 @@ class TestHttpResponse(unittest.TestCase):
         headers = MockHeaders()
         response = HttpResponse(200, "OK", headers, "test")
 
-        self.assertIsNone(response.get_header("Authorization"))
-        self.assertEqual(response.get_header("Authorization", "default"), "default")
+        self.assertIsNone(response.headers.get("Authorization"))
+        self.assertEqual(response.headers.get("Authorization", "default"), "default")
 
-    def test_get_header_first_match(self):
-        """测试get_header方法返回第一个匹配的头部"""
+    def test_headers_get_first_match(self):
+        """测试headers.get方法返回第一个匹配的头部"""
 
         class MockHeaders:
             def __init__(self):
@@ -111,7 +114,7 @@ class TestHttpResponse(unittest.TestCase):
         headers = MockHeaders()
         response = HttpResponse(200, "OK", headers, "test")
 
-        self.assertEqual(response.get_header("Set-Cookie"), "session=abc")
+        self.assertEqual(response.headers.get("Set-Cookie"), "session=abc")
 
 
 class TestDecodeResponseBody(unittest.TestCase):
@@ -181,18 +184,16 @@ class TestSendHttpRequest(unittest.TestCase):
 
         # 使用postman-echo.com提供的GET测试端点
         try:
-            response = send_http_request("GET", "https://postman-echo.com/get?test=ddns")
+            response = send_http_request("GET", "http://postman-echo.com/get?test=ddns")
             self.assertEqual(response.status, 200)
             self.assertIsNotNone(response.body)
             # 验证响应内容是JSON格式
-            import json
-
             data = json.loads(response.body)
             self.assertIn("args", data)
             self.assertIn("url", data)
             self.assertIn("test", data["args"])
             self.assertEqual(data["args"]["test"], "ddns")
-        except Exception as e:
+        except (socket.timeout, ConnectionError) as e:
             # 网络不可用时跳过测试
             self.skipTest("Network unavailable: {}".format(str(e)))
 
@@ -202,13 +203,11 @@ class TestSendHttpRequest(unittest.TestCase):
 
         try:
             # 使用postman-echo.com的基本GET端点,返回请求信息
-            response = send_http_request("GET", "https://postman-echo.com/get?format=json")
+            response = send_http_request("GET", "http://postman-echo.com/get?format=json")
             self.assertEqual(response.status, 200)
             self.assertIsNotNone(response.body)
 
             # 验证返回的是有效的JSON
-            import json
-
             data = json.loads(response.body)
             # postman-echo返回请求信息对象
             self.assertIn("args", data)
@@ -231,7 +230,7 @@ class TestSendHttpRequest(unittest.TestCase):
             }
 
             # 使用postman-echo模拟401认证失败响应
-            response = send_http_request("GET", "https://postman-echo.com/status/401", headers=headers)
+            response = send_http_request("GET", "http://postman-echo.com/status/401", headers=headers)
 
             # 应该返回401认证失败
             self.assertEqual(response.status, 401)
@@ -241,6 +240,33 @@ class TestSendHttpRequest(unittest.TestCase):
         except Exception as e:
             self.skipTest("Network unavailable: {}".format(str(e)))
 
+    def test_http_400_bad_request_handling(self):
+        """测试HTTP 400 Bad Request错误处理"""
+        from ddns.util.http import send_http_request
+
+        try:
+            # 使用postman-echo模拟400错误
+            response = send_http_request("GET", "http://postman-echo.com/status/400")
+
+            # 验证状态码为400
+            self.assertEqual(response.status, 400, "应该返回400 Bad Request状态码")
+
+            # 验证响应对象的完整性
+            self.assertIsNotNone(response.body, "400响应应该有响应体")
+            self.assertIsNotNone(response.headers, "400响应应该有响应头")
+            self.assertIsNotNone(response.reason, "400响应应该有状态原因")
+
+        except Exception as e:
+            # 网络问题时跳过测试
+            error_msg = str(e).lower()
+            if any(
+                keyword in error_msg for keyword in ["timeout", "connection", "resolution", "unreachable", "network"]
+            ):
+                self.skipTest("Network unavailable for HTTP 400 test: {}".format(str(e)))
+            else:
+                # 其他异常重新抛出
+                raise
+
     def test_dns_over_https_simulation(self):
         """测试DNS类型的API响应解析"""
         from ddns.util.http import send_http_request
@@ -250,13 +276,11 @@ class TestSendHttpRequest(unittest.TestCase):
 
             # 使用postman-echo模拟一个带有特定结构的JSON响应
             response = send_http_request(
-                "GET", "https://postman-echo.com/get?domain=example.com&type=A", headers=headers
+                "GET", "http://postman-echo.com/get?domain=example.com&type=A", headers=headers
             )
 
             self.assertEqual(response.status, 200)
 
-            import json
-
             data = json.loads(response.body)
             # postman-echo返回请求信息,包含args参数
             self.assertIn("args", data)
@@ -305,7 +329,7 @@ class TestSendHttpRequest(unittest.TestCase):
 
     def test_basic_auth_with_httpbin(self):
         """Test basic auth URL format and verification with URL-embedded authentication"""
-        from ddns.util.http import send_http_request, URLError
+        from ddns.util.http import send_http_request
 
         # Test with special credentials containing @ and . characters
         special_username = "[email protected]"
@@ -325,7 +349,7 @@ class TestSendHttpRequest(unittest.TestCase):
         # Try to make actual request
         try:
             response = send_http_request("GET", auth_url)
-        except (URLError, OSError, IOError) as e:
+        except (OSError, IOError) as e:
             # Skip for Network Exceptions (timeout, connection, etc.)
             raise unittest.SkipTest("Network error, skipping httpbin test: {0}".format(e))
             # Verify successful response if we get here
@@ -336,6 +360,31 @@ class TestSendHttpRequest(unittest.TestCase):
         self.assertIn("authenticated", response.body)
         self.assertIn("user", response.body)
 
+    def test_ssl_auto_fallback_real_network(self):
+        """测试SSL auto模式的真实网络自动降级行为"""
+        from ddns.util.http import send_http_request
+
+        test_url = "https://postman-echo.com/status/200"  # 使用postman-echo的测试站点
+
+        try:
+            # 1. 测试auto模式:应该自动降级成功
+            response_auto = send_http_request("GET", test_url, verify_ssl="auto")
+            self.assertEqual(response_auto.status, 200, "auto模式自动降级成功访问测试站点")
+            self.assertIsNotNone(response_auto.body)
+
+            # 2. 验证禁用SSL验证模式也能成功(作为对照)
+            response_false = send_http_request("GET", test_url, verify_ssl=False)
+            self.assertEqual(response_false.status, 200, "禁用SSL验证应该成功访问自签名证书站点")
+
+        except Exception as e:
+            # 网络问题时跳过测试
+            error_msg = str(e).lower()
+            if any(keyword in error_msg for keyword in ["timeout", "resolution", "unreachable"]):
+                self.skipTest("Network unavailable for SSL fallback test: {}".format(str(e)))
+            else:
+                # 其他异常重新抛出
+                raise
+
 
 if __name__ == "__main__":
     unittest.main()