跳到正文
← 返回文章列表

网络 · 2026-08-01 · 5 分钟

从 Nginx 迁移到 Caddy

我的家庭内网中部署了若干 http 服务,为了使用方便,统一使用 Nginx 做了反代以及 https 证书分配,最近我发现 Caddy 在我的使用场景下比 Nginx 更简洁、方便管理。

After

我的家庭内网是在 2024 年搭建的,当时为了给 Nginx 反代配置 h3 和 https 证书自动更新,费了好大一番手脚。 尤其是这个 https 证书自动更新,更是让我吃了一番苦头。

刚开始我便尝试使用过 Traefik 和 Caddy,因为它们两可以自动托管并更新 https 证书。我的域名托管在 Cloudflare 上,因此需要通过 DNS-01 来生成证书。

但在初期的部署过程中,Traefik、Caddy、ACME.sh 都存在获取不到 DNS 记录导致超时的问题,我百般排查不得其解。

排查良久后认为是 DNS 的问题,使用 AI 结合 go-acme 做了一个生成 https 证书的网关程序:https://github.com/vhvy/acme-gateway-go 。

原理也很简单,在 Docker 容器内通过 iptables 劫持 lego 客户端的 DNS 请求,强制递归转发给 Cloudflare 的 DoH,以便获取最新的 DNS 记录信息。

问题虽然是解决了,但我总觉得这套配置太过冗余,直到前不久,我发现了 Caddy 的 propagation_timeout 参数。

Before

Caddy 的 propagation_timeout 参数可以跳过 DNS 传播检查,直接让 ACME 服务器去 Cloudflare 那边查询,免去了本地 DNS 各种异常的问题。

说干就干,结合 AI 花了半小时将 Nginx 迁移到了 Caddy,不得不说 Caddy 的配置真的是简洁,h3、websockets 不用任何额外配置,https 证书续期配置也非常方便,Caddy 真好用!

需要注意的是,Caddy 没有直接集成 Cloudflare 的 DNS Challenge 服务,需要手动编译,或者使用社区提供的 Docker 镜像: ghcr.io/caddy-dns/cloudflare

在内网环境下,还可以使用静态文件服务提供生成的泛域名证书,让一些不需要反代的服务如 Mikrotik Web 服务、群晖 NAS 等也可以方便的定时拉取并更新证书。

这里贴一下我的大概配置:

Docker compose 配置文件:

yaml
services:
  caddy:
    image: ghcr.io/caddy-dns/cloudflare:v0.2.4
    container_name: caddy
    restart: unless-stopped
    network_mode: host
    env_file: ./.env
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./data:/data
      - ./config:/config

Caddy 配置文件:

nginx
{
  email example@example.com
}

(cf) {
  tls {
    dns cloudflare {env.CF_API_TOKEN}
    propagation_delay 60s
    propagation_timeout -1
  }
}

(insecure_tls) {
  transport http {
    tls_insecure_skip_verify
  }
}

*.example.com {
  import cf
  abort
}

demo.example.com {
  reverse_proxy 192.168.1.111:36180
}

demo2.example.com {
  redir / /web 301
  reverse_proxy https://192.168.1.112:44233 {
    import insecure_tls
  }
}

# curl https://ssl.example.com/example.com/cert.key
# curl https://ssl.example.com/example.com/cert.crt

ssl.example.com {
  root * /data/caddy/certificates/acme-v02.api.letsencrypt.org-directory

  @cert {
    remote_ip 192.168.1.0/24
    header X-Token "THISISMYTOKEN"
    path_regexp c ^/([^/]+)/cert\.(crt|key)$
  }

  handle @cert {
    rewrite * /wildcard_.{re.c.1}/wildcard_.{re.c.1}.{re.c.2}
    file_server
  }

  handle {
    respond 404
  }
}
标签网络

评论