diff --git a/remote-access/README.md b/remote-access/README.md index 8ed2ae8..ecbecf2 100644 --- a/remote-access/README.md +++ b/remote-access/README.md @@ -45,6 +45,14 @@ npm run remote:start ## 服务器管理 +首次配置 `ck.yydd.ai` 的正式证书时,管理员需在服务器创建 `/etc/cangku-tls/cloudflare.ini`,内容为 Cloudflare 最小权限 API Token: + +```ini +dns_cloudflare_api_token = <仅 DNS 编辑权限的 Token> +``` + +文件权限必须为 `0600`、所有者为 root。然后以 root 依次运行 `provision-certificate.sh` 和 `install.sh`;Certbot 会使用 DNS-01 验证并由系统定时器自动续期。该文件绝不能提交到 Git。 + 服务器使用 `cangku-bootstrap` systemd 服务、独立的受限 MySQL 发号账号和 SSH 用户证书 CA。常用命令: ```bash diff --git a/remote-access/server/install.sh b/remote-access/server/install.sh index 0a13b4f..62be42a 100644 --- a/remote-access/server/install.sh +++ b/remote-access/server/install.sh @@ -14,7 +14,7 @@ test -f "${MYSQL_ENV}" test -f "${SOURCE_DIR}/bootstrap_service.py" apt-get update -qq -DEBIAN_FRONTEND=noninteractive apt-get install -y -qq python3-venv openssl certbot >/dev/null +DEBIAN_FRONTEND=noninteractive apt-get install -y -qq python3-venv openssl certbot python3-certbot-dns-cloudflare >/dev/null if ! getent passwd cangku-bootstrap >/dev/null; then useradd --system --home-dir /var/lib/cangku-bootstrap --create-home --shell /usr/sbin/nologin cangku-bootstrap diff --git a/remote-access/server/provision-certificate.sh b/remote-access/server/provision-certificate.sh index f7e50e0..17fc9fb 100644 --- a/remote-access/server/provision-certificate.sh +++ b/remote-access/server/provision-certificate.sh @@ -7,51 +7,20 @@ if [[ ${EUID} -ne 0 ]]; then fi DOMAIN=ck.yydd.ai -WEBROOT=/var/www/cangku-bootstrap-acme -TEMP_SITE=/etc/nginx/sites-available/cangku-bootstrap-acme TLS_ROOT=/etc/cangku-tls -EAB_FILE=${TLS_ROOT}/eab.json -ACME_SERVER=https://acme.zerossl.com/v2/DV90 +CF_CREDENTIALS=${TLS_ROOT}/cloudflare.ini -DEBIAN_FRONTEND=noninteractive apt-get install -y -qq certbot >/dev/null -install -d -m 0755 "${WEBROOT}/.well-known/acme-challenge" +DEBIAN_FRONTEND=noninteractive apt-get install -y -qq certbot python3-certbot-dns-cloudflare >/dev/null install -d -m 0700 "${TLS_ROOT}" if [[ ! -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]]; then - if [[ ! -f "${EAB_FILE}" ]]; then - echo "Missing ${EAB_FILE}; create ZeroSSL EAB credentials and store them there with mode 0600" >&2 + if [[ ! -f "${CF_CREDENTIALS}" ]]; then + echo "Missing ${CF_CREDENTIALS}; store a scoped Cloudflare API token there with mode 0600" >&2 exit 1 fi - umask 0022 - { - printf 'server {\n' - printf ' listen 80;\n' - printf ' listen [::]:80;\n' - printf ' server_name %s;\n' "${DOMAIN}" - printf ' location /.well-known/acme-challenge/ { root %s; }\n' "${WEBROOT}" - printf ' location / { return 404; }\n' - printf '}\n' - } > "${TEMP_SITE}" - ln -sfn "${TEMP_SITE}" /etc/nginx/sites-enabled/cangku-bootstrap-acme - nginx -t - systemctl reload nginx - readarray -t eab < <(python3 - "${EAB_FILE}" <<'PY' -import json -import sys - -with open(sys.argv[1], encoding='utf-8') as handle: - value = json.load(handle) -print(value['eab_kid']) -print(value['eab_hmac_key']) -PY - ) - certbot certonly --server "${ACME_SERVER}" \ - --eab-kid "${eab[0]}" --eab-hmac-key "${eab[1]}" \ - --webroot -w "${WEBROOT}" -d "${DOMAIN}" \ - --email certs@yydd.ai --agree-tos --non-interactive --no-eff-email - unlink "${EAB_FILE}" - unlink /etc/nginx/sites-enabled/cangku-bootstrap-acme - unlink "${TEMP_SITE}" + chmod 0600 "${CF_CREDENTIALS}" + certbot certonly --dns-cloudflare --dns-cloudflare-credentials "${CF_CREDENTIALS}" \ + -d "${DOMAIN}" --email certs@yydd.ai --agree-tos --non-interactive --no-eff-email fi systemctl enable --now certbot.timer