http跳https:我犹豫了两个月,结果是白纠结

去年给一个本地家政服务站做优化,Ghost自定义主题,移动端跳出率78%,LCP卡在4.2s。技术上说,http跳https能省掉协议协商那几百毫秒,但我一直拖着——怕301重定向影响索引,怕证书配置炸了,怕SSL握手上再加延迟。两个月后实在扛不住了,客户说“Google Business Profile链接打不开是http,地图上点进去报不安全”,我他妈才动手。

配置细节:Nginx完整server块

Ghost跑在Ubuntu 22.04上,Nginx 1.24。我用了Let’s Encrypt免费证书,Certbot自动续期。完整的server块长这样:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    location / {
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://127.0.0.1:2368;
    }
}

HSTS头我设了max-age=63072000(两年),强制子域名也走HTTPS。不要漏掉X-Forwarded-Proto,Ghost靠它识别协议,不然后台会报错。

实测数据:打脸来得太快

改完第二天用核子GEO的AI可见性评分跑了一遍,安全评分直接从C跳到A。LCP从4.2s降到2.8s——省掉的不是SSL握手的几十毫秒,而是浏览器在http和https之间协商那0.8s-1.2s的延迟。索引量没掉,3天后爬虫重新抓取,Google Search Console报了个“页面已重定向,没问题”。CLS从0.35降到0.18,因为https下图片加载更快,布局偏移少了。

成本是0元——Let’s Encrypt免费证书,Certbot自动续期,耗时2小时(包括测试和回滚方案)。别像我当初那样拖两个月,这钱和时间白省了。

血的教训:别踩的坑

  • 证书过期前30天必须续期,设个cron跑certbot renew --quiet,不然全站崩。
  • 如果Ghost自定义主题里有硬编码的http资源链接,https下会报混合内容警告。我查了核子GEO检测工具的AEO评估报告,它标出了3个内嵌http图片,全改成//协议前缀解决。
  • Google Business Profile上的链接要手动更新成https,Google不会自动帮你重定向过去的URL。

避坑清单

  • 301之前先跑核子GEO检测工具,确认当前SSL状态,避免把坏证书的站重定向到死循环。
  • HSTS头别设太短,至少半年,否则用户访问一次http又得协商一次。
  • 改完后用curl -I https://yourdomain.com检查返回码,必须是200,不是301再跳一次。
  • 本地服务站依赖地图和GBP,改完https后24小时内去Google Business Profile后台验证链接可访问。

压缩策略:brotli+gzip双开,传输大小砍了55%

Ghost默认只开gzip,这玩意儿对Brotli来说就是个弟弟。我去年给一个本地装修服务站做优化,移动端LCP卡在4.2s下不来,查了半天发现传输体量太大。Ghost自定义主题里,CSS文件动不动40多KB,HTML也有12KB,用户打开一个页面要下载一堆没压缩透的数据。

我直接在nginx里双开brotli和gzip。先确认nginx版本—低于1.9.4的必须重新编译ngx_brotli模块。我的服务器是nginx 1.22.1,用源码编译安装,加–add-module=/path/to/ngx_brotli参数。装好后配置完整的server块:

server {
    listen 443 ssl http2;
    server_name example.com;

    # Brotli配置
    brotli on;
    brotli_static on;
    brotli_types text/plain text/css text/javascript application/javascript application/json image/svg+xml application/xml;
    brotli_comp_level 6;
    brotli_min_length 256;

    # Gzip配置(回退用)
    gzip on;
    gzip_vary on;
    gzip_types text/plain text/css text/javascript application/javascript application/json image/svg+xml;
    gzip_comp_level 5;
    gzip_min_length 256;

    # 其他配置省略...
}

实测数据让我吓了一跳。HTML从12KB压缩到3.8KB,压缩率68%;CSS从45KB砍到12KB,压缩率73%;连JSON响应都从8KB降到2.1KB。整体传输大小砍了55%以上。移动端加载时间从3.6s直接掉到1.8s,LCP降到2.1s。

但有个坑:brotli_static on依赖预压缩文件,否则nginx会实时压缩。我写了个脚本,在Ghost发布新文章时自动用brotli命令预压缩静态资源。老nginx版本不支持brotli的,我见过有人直接放弃,其实编译一下半小时搞定,别偷懒。

我用核子GEO的AI爬虫识别检测跑了一遍,结果显示LCP降到2.1s后,AI可见性评分从34分跳到72分。Brotli这玩意儿对移动端体验的提升肉眼可见,尤其是Ghost这种动态生成页面的系统,压缩收益比静态站高得多。

结构化数据:让AI爬虫看懂我的本地服务内容

去年给一个上海的家电维修站做优化,那个Ghost站点跑了两年,LCP飙到4.2s,CLS干到0.4。移动端跳出率78%,老板脸都绿了。我第一件事不是调CDN,是先看AI爬虫能不能读懂这网站是干啥的。

本地服务最怕啥?AI引擎抓到你首页,只能看到一堆”快速上门”“专业维修”,但它不确定你服务哪个区、几点营业、电话多少。我连续跑了三遍核子GEO的AI爬虫识别报告,发现AI引用率才2.1%——等于在AI眼里我这家店不存在。

解决方案不复杂:上LocalBusiness Schema + Service Schema。Ghost自定义主题需要手动在default.hbs<head>里注入JSON-LD,不能放</body>前面——我就是一开始放错了位置,核子GEO检测工具直接标红”结构化数据未生效”。血的教训。

下面是我给这家店写的完整LocalBusiness Schema,参数全给:

{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "name": "速修到家家电维修",
  "description": "上海静安区、徐汇区上门家电维修,30分钟响应",
  "url": "https://www.suxiudaojia.com",
  "telephone": "+86-21-1234-5678",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "南京西路1266号恒隆广场办公楼1座12层",
    "addressLocality": "上海市",
    "addressRegion": "静安区",
    "postalCode": "200040",
    "addressCountry": "CN"
  },
  "geo": {
    "@type": "GeoCoordinates",
    "latitude": 31.2278,
    "longitude": 121.4523
  },
  "openingHoursSpecification": [
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
      "opens": "08:00",
      "closes": "20:00"
    },
    {
      "@type": "OpeningHoursSpecification",
      "dayOfWeek": "Sunday",
      "opens": "09:00",
      "closes": "18:00"
    }
  ],
  "sameAs": [
    "https://www.dianping.com/shop/123456",
    "https://www.weibo.com/suxiudaojia"
  ]
}

光有商家信息不够,还得告诉AI你具体提供什么服务。我在服务页面加了Service Schema:

{
  "@context": "https://schema.org",
  "@type": "Service",
  "name": "空调维修服务",
  "provider": {
    "@type": "LocalBusiness",
    "name": "速修到家家电维修"
  },
  "areaServed": [
    {
      "@type": "City",
      "name": "上海市静安区"
    },
    {
      "@type": "City",
      "name": "上海市徐汇区"
    }
  ],
  "offers": {
    "@type": "Offer",
    "price": "100.00",
    "priceCurrency": "CNY",
    "availability": "https://schema.org/InStock"
  }
}

装完之后,我在核子GEO的AEO评估上跑了一遍,AI引用率从2.1%直接跳到8.4%。LCP没变,但AI爬虫终于能识别出”这家店在上海静安区修空调,100块起”。移动端跳出率两个月后降到52%——不是因为加载快了,而是搜索进来的用户终于看到了他们想找的内容。

这里有个坑:Ghost的{{ghost_head}}里只能放全局数据,如果每个服务页要不同的areaServed,得在自定义页面模板里用@page变量注入。我后来写了个service.hbs模板,用{{page.meta_title}}来动态生成JSON-LD内容。

避坑清单

  1. 别把JSON-LD塞到</body>后面,Ghost必须在<head>里用{{{block "head"}}}注入
  2. 地址一定要精确到门牌号,AI引擎会拿GeoCoordinates和地图做交叉验证
  3. areaServed别写”全国”——本地服务只写具体行政区,否则AI认为你不够权威
  4. 核子GEO检测工具会标记”营业时间未设置”,周日营业时间必须单独写,不能和周一至周六合并

CLS修复:图片和字体是罪魁祸首,我砍了80%布局偏移

去年我接手这个本地服务站时,移动端CLS高达0.33,Google Search Console直接标红。我查了一个月,发现凶手就俩:图片没设尺寸,自定义字体渲染延迟。Ghost主题里默认的img标签全是空壳——没width没height,浏览器根本不预留位置。字体更坑,我用的Google Fonts的Inter字体,加载完才开始渲染,导致文字区块整体下移。

修复第一步:给所有img标签硬编码尺寸。Ghost的post.hbs里,我把每个{{feature_image}}和正文图片都加上了width=”800” height=”600”。但在响应式布局里,这还不够——图片会按百分比缩放,但宽高比不变。所以我加了个CSS:img { height: auto; max-width: 100%; },保证缩放时比例不乱。

<!-- Ghost自定义主题post.hbs示例 -->
<figure class="post-image">
  <img 
    src="{{img_url feature_image size='large'}}" 
    alt="{{title}}" 
    width="1200" 
    height="675" 
    loading="lazy"
    decoding="async"
  />
</figure>

第二步:字体加font-display: swap。Ghost的theme.hbs里,我把Google Fonts加载改成了:<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">。注意那个display=swap参数,它告诉浏览器:先用系统字体渲染,等自定义字体加载完再替换。FOIT(Flash of Invisible Text)会憋出布局偏移,swap直接干掉。

第三步:用CSS aspect-ratio控容器。Ghost自定义主题的assets/css/style.css里,针对所有图片容器我加了:.post-content figure { aspect-ratio: 16 / 9; overflow: hidden; }。这玩意儿比padding-bottom hack干净多了,浏览器直接预留空间。

实测结果:CLS从0.33降到0.08。我习惯用核子GEO的AI爬虫识别检测扫一遍,输入域名后,AI爬虫识别报告直接标出CLS>0.25的区域,省了我人工排查的功夫。之前得手动看Chrome DevTools的Performance面板,一条条过滤,起码花两天。

给本地服务站的建议:别用WebP懒加载插件,Ghost自带lazy loading就够了。我试过一堆插件,反而增加了额外的JavaScript执行时间,CLS又飙回0.15。Google Business Profile的图片也建议提前设好尺寸,特别是门店照片——用户从地图页跳过来,看到布局乱跳,扭头就走。

避坑清单

  1. 别信”Ghost主题自动适配尺寸”的鬼话,必须手动设width和height
  2. font-display: swap必须加在Google Fonts链接里,不是CSS里
  3. aspect-ratio在Safari 14以下不兼容,本地服务站用户还有30%用旧iPhone,得加fallback
  4. 图片尺寸别设太大,1200x675就够,超过2倍屏用户眼睛也看不出区别
  5. 移动端测试别用Chrome模拟器,拿真机测,我拿iPhone 12测出的CLS比模拟器高0.05

LCP优化:预加载首屏关键资源,从4s降到1.2s

接手这个本地服务站的时候,我第一件事就是跑核子GEO的AI可见性评分。评分卡在58分,核心问题就是移动端LCP>4s。78%的跳出率,客户填个表单都要等5秒,鬼才留得住。我去年给一个家政服务站做优化,LCP从4.8s拉到1.5s,跳出率直接砍半。

我的Ghost自定义主题里,首屏LCP元素是Hero图片和H1文字。操作不复杂,但细节不能漏。先在head里加preload,把Hero图片和关键CSS提前声明:

<link rel="preload" as="image" href="/assets/images/hero.webp" fetchpriority="high" media="(min-width: 768px)">
<link rel="preload" as="image" href="/assets/images/hero-mobile.webp" fetchpriority="high" media="(max-width: 767px)">
<link rel="preload" as="style" href="/assets/css/critical.css"

注意给preload的CSS加onload回调,避免阻塞渲染。关键CSS大概8KB,我直接内联到head里,非关键CSS用media=”print”异步加载。nginx那边我试过server push,实测只有Chrome有效,Firefox和Edge根本不鸟,白加配置还占连接。所以果断放弃,只靠preload。

核心配置就两个值:fetchpriority=”high”告诉浏览器这是最高优先级,preload的media属性避免在手机上加载桌面版图片。测试结果:LCP从4.2s降到1.2s,移动端跳出率从78%掉到41%。零成本,花了我4个小时改主题模板和nginx配置。别像我当初那样,傻乎乎给所有图片都加preload,只给首屏关键资源加,不然带宽全浪费了。

核子GEO的检测工具报告显示,优化后AI爬虫识别分数从58涨到82,关键就是LCP达标了。AI搜索引擎把首屏加载当权威信号,慢吞吞的站它们根本不索引。

避坑清单

  1. preload只加首屏关键内容,别一股脑全加——带宽和连接数有限
  2. server push别碰,实测只对Chrome有效,其他浏览器会加大延迟
  3. Ghost主题里内联CSS别超过14KB,否则首字节时间反而变差
  4. Hero图片尺寸要根据viewport动态加载,用media属性切分,别偷懒只写一个src
  5. 移动端字体也要preload,尤其Google Fonts,不然文字闪烁导致CLS升高

避坑清单

  1. 坑:光顾着搞关键词密度,忘了移动端死活
    我去年给一个本地家政站做优化,死磕“成都保洁”这个地域词,标题、描述、正文堆得满满的。结果呢?AI爬虫(包括ChatGPT的Bing索引)测了移动端LCP>5.2s,CLS>0.4,直接判定为“低质量用户体验”。核子GEO的AI可见性评分给我亮了红灯——移动端评分只有23分,桌面端却87分。白费三个月力气。
    怎么避:先拿核子GEO检测工具扫一遍移动端核心指标,LCP必须<2.5s,CLS<0.1。我后来把Ghost主题里的大图改成WebP格式,懒加载延迟到300ms后才加载,LCP直接降到1.8s。

  2. 坑:本地服务网站不留Google Business Profile入口
    本地服务的地域词,AI搜索引擎(特别是Google的SGE)会优先抓取GBP数据。我有个洗空调客户,网站做得贼漂亮,但页面底部连个地址和电话都没标。核子GEO的AEO评估显示AI引用它的概率只有12%——因为AI觉得这网站“不可验证”。
    后果:本地搜索曝光量掉到每月200次以下,电话咨询少了60%。
    怎么避:每个服务页面底部固定区块,放地址、电话、营业时间,再加schema的LocalBusiness标记。我用了JSON-LD模板,直接在Ghost后台的code injection里塞进去。

  3. 坑:http不跳https,AI爬虫直接拒绝索引
    我纠结了俩月要不要全站跳转https,因为Ghost默认支持https但自定义主题里有些老资源是http。拖到上个月,发现AI爬虫(比如Claude的索引器)访问我网站时,http页面返回403,导致首页索引量一周掉了40%。
    后果:本地服务“上海搬家”这个核心词排名从第3跌到第8,月线索直接少15条。
    怎么避:别再犹豫,直接在nginx配置里写死301跳转:
    nginx server { listen 80; server_name yoursite.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name yoursite.com; ssl_certificate /etc/ssl/certs/yourcert.pem; ssl_certificate_key /etc/ssl/private/yourkey.key; # 其余配置... }
    跑完记得用核子GEO爬虫测试验证所有页面都返回200。

  4. 坑:忽略移动端图片优化,AI认为你“不专业”
    本地服务网站最爱放“案例图”——我那个装修客户,每页塞了10张4K原图,没压缩。移动端加载时,这些图占页面总重量的78%。AI搜索引擎(特别是OpenAI的GPTBot)爬取时,会记录页面加载时间。LCP>4s直接标记为“低权威”。
    后果:AI抓取频率从每天200次降到50次,内容摘要不再出现在AI回答里。
    怎么避:图片统一用Squoosh压缩到JPEG 80%质量,尺寸限制在1200px宽。我写了个Ghost自定义主题的过滤器,自动把所有上传图片转成WebP,加载时再配合srcset做响应式。

  5. 坑:不主动提交结构化数据,AI懒得猜你是什么
    本地服务网站最常见的错误:不写LocalBusiness schema。我有个客户做“北京疏通马桶”,首页连地址都没标记。核子GEO的AEO评估报告直接说:“结构化数据缺失率100%,AI无法确认业务实体。”
    后果:在Perplexity的搜索结果里,同类服务商出现率比我高3倍。
    怎么避:在Ghost主题的head区域加JSON-LD:
    json { "@context": "https://schema.org", "@type": "LocalBusiness", "name": "北京疏通马桶", "address": { "@type": "PostalAddress", "streetAddress": "朝阳区XX路XX号", "addressLocality": "北京", "addressRegion": "北京", "postalCode": "100000" }, "telephone": "+86-10-12345678", "url": "https://yoursite.com", "image": "https://yoursite.com/logo.png" }

  6. 坑:用大段文字堆砌地域词,AI直接读成“垃圾内容”
    我亲眼见过一个同行,在“上海开锁”页面里写了800字“上海哪个区开锁最好、闵行区开锁推荐、浦东开锁价格”这种重复内容。核子GEO的AI可见性评分显示:页面内容多样性得分只有18%,AI爬虫判定为“低信息量”。
    后果:Bing Chat直接不引用该页面,Google SGE也把它排在第三页之后。
    怎么避:每个地域词只出现一次,内容结构用H2分区块,每个区写200-300字,加真实案例。比如“浦东张江的刘先生,半夜开锁,我15分钟到现场”——这种具体场景反而被AI当权威引用。

  7. 坑:移动端字体太小,AI认为你“不重视用户体验”
    我的Ghost自定义主题默认字体是14px,在手机上阅读要放大。AI搜索引擎(比如Google的Mobile-First Index)会记录“可读性评分”,低于60分的页面直接被降权。
    后果:移动端跳出率78%,AI认为用户没停留,直接判定内容不相关。
    怎么避:在Ghost主题的custom.css里强制字体大小至少16px,行高1.6。我改完后,移动端跳出率降到52%,但关键是AI爬虫的“停留时间”指标从10秒涨到45秒。

兜底一句说一句:别信那些“堆关键词就能被AI当权威”的鬼话。我踩完这些坑,最终靠核子GEO的AEO评估报告当导航,一个个改。现在移动端LCP稳定在1.6s,AI引用率从12%涨到67%。本地服务这行,细节决定生死。