Skip to content

阿里云 ECS:从备案到域名能访问 ​

备案通过那天我以为就完事了,结果发现域名还是打不开。中间隔着一层云厂商的 ICP 域名拦截,再加上证书和站点配置两道关。这篇把整条链路按顺序记一遍。

结论先摆出来 ​

备案通过 ≠ 域名可用。完整的顺序是:

ICP 备案通过
   ↓
DNS 解析到服务器
   ↓
【关键】云厂商放行该域名     ← 少了这步,80 端口返回 403
   ↓
签发证书(覆盖域名)
   ↓
nginx 配域名站点
   ↓
能用

一、先确认 DNS 解析 ​

在阿里云云解析加两条 A 记录,@ 和 www 都指向同一台服务器的公网 IP:

主机记录记录类型记录值TTL
@A你的公网 IP10 分钟
wwwA你的公网 IP10 分钟

验证:

bash
nslookup example.cn 223.5.5.5
nslookup www.example.cn 8.8.8.8

TTL 默认 600 秒,实际几分钟内全网生效。

二、验证云厂商放行(最容易漏的一步) ​

这一步不做,后面签证书必失败。

大陆的 ECS 会按 HTTP 的 Host 头 / TLS 的 SNI 来拦截未备案域名:80 端口返回一个 403 的 Non-compliance ICP Filing 页面,443 直接重置 TLS 握手。

所以「域名能不能过」和「服务器有没有配好」是两回事,得单独验证:

bash
curl -s -m 20 -o /dev/null -w "%{http_code}\n" \
  -H "Host: example.cn" "http://你的公网IP/"
返回含义
301 / 200 / 302,且 Server: 是你的 nginx已放行,继续
403 且正文含 Non-compliance ICP Filing未放行,等或核对接入商

别在服务器上测

curl http://127.0.0.1/ 走的是本机回环,绕过了厂商网关,测不出拦截。 必须从外部、带上域名的 Host 头去打 80 端口。

顺带一个副作用:这套机制会让 sslip.io、DuckDNS 之类的免费域名在国内机器上完全不可用——它们过不了 Host 判定,只有按纯 IP 访问才行。

三、签证书 ​

先看清服务器上有几套 certbot:

bash
which -a certbot
systemctl cat certbot.service | grep ExecStart

有些机器 apt 装了一套、pip venv 里又装了一套,而 systemd 定时器指向的是后者。手动操作时必须用定时器同款,否则 renewal 配置的版本号会对不上。

签发(webroot 方式):

bash
certbot certonly --webroot -w /var/www/certbot \
  -d example.cn -d www.example.cn --cert-name example.cn \
  --key-type ecdsa --non-interactive --agree-tos \
  --deploy-hook "systemctl reload nginx"

--deploy-hook 会写进 renewal 配置,以后每次自动续期完都会 reload nginx。

证书不用买

个人站点用 Let's Encrypt 就够,90 天自动续期。需要买证书的场景只有三种:要通配符(*.example.cn)、要证书上显示主体名(OV/EV)、需要保险赔付。

阿里云/腾讯云的免费 DV 证书现在是 3 个月有效期、到期不支持续费只能重新申请,老老实实用 certbot 反而省事。

四、配 nginx ​

关键点:别把原有的 default_server 改掉。历史上按 IP 访问的那份配置通常占着 listen 80 default_server; server_name _;,新起一个不写 default_server 的域名配置文件与它并存:

  • 域名访问 → 精确匹配 server_name → 用域名证书
  • IP 直连 → 落到 default_server → 仍用原证书

这样两边互不干扰。

nginx
server {
    listen 80;
    listen [::]:80;
    server_name example.cn www.example.cn;

    # ACME 校验走这里;return 必须包在 location 里,
    # 写在 server 层会先于 location 匹配执行,把 ACME 路径也跳掉
    location /.well-known/acme-challenge/ { root /var/www/certbot; }
    location / { return 301 https://$host$request_uri; }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name example.cn www.example.cn;

    ssl_certificate     /etc/letsencrypt/live/example.cn/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.cn/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    root /var/www/site;
    index index.html;

    location / { try_files $uri $uri/ /index.html; }
}
bash
ln -sf /etc/nginx/sites-available/example-web /etc/nginx/sites-enabled/example-web
nginx -t && systemctl reload nginx

SPA 必加的一行

try_files $uri $uri/ /index.html; —— Vue / React / uni-app 打包出来是前端路由,不加这行刷新子页面会 404。

五、验收 ​

浏览器可能挂着代理,结果不可信。用直连 IP + 指定 SNI 的方式验,绕开代理:

python
import socket, ssl

ctx = ssl.create_default_context()          # 会真的校验信任链
raw = socket.create_connection(("你的公网IP", 443), timeout=15)
ss = ctx.wrap_socket(raw, server_hostname="example.cn")

cert = ss.getpeercert()
print(cert["subjectAltName"])               # SAN 必须含你的域名
print(cert["notAfter"])

ss.sendall(b"GET / HTTP/1.1\r\nHost: example.cn\r\nConnection: close\r\n\r\n")
print(ss.recv(200))

再加一步 HTTP 跳转检查,以及续期演练:

bash
curl -s -o /dev/null -w "%{http_code}\n" -H "Host: example.cn" http://你的公网IP/
certbot renew --dry-run --no-random-sleep-on-renew

renew 会"卡住"是正常的

certbot renew 默认带随机延迟(最长约 5.5 分钟),防雪崩用的。手动测试一定要加 --no-random-sleep-on-renew,否则会以为进程死了。

上线后的合规收尾 ​

事项要点
页脚备案号×ICP备xxxxxxxx号-N,必须链到 https://beian.miit.gov.cn/
公安联网备案自网络正式联通之日起 30 日内办理,平台 beian.mps.gov.cn
网站名称要和备案信息里的一致,明显不符会被要求整改

公安备案别只做主体

公安备案里主体审核通过只是第一步,**还必须提交「新办网站申请」**才会有备案号。

只备主体不备网站就是空壳主体,各省管局会定期公示清理,有的省份公示期只有 3 天,逾期直接注销。