静态站部署听起来没什么可配的:把 dist/ 扔进目录,指向它,完事。但真到上线那一步,我在这五个地方各卡过一次。
一、try_files 的写法
Astro 默认按目录输出,/blog/foo/ 对应 blog/foo/index.html。如果只写 try_files $uri =404,访问 /blog/foo/ 会 404,因为文件系统里没有叫 foo 的文件。
正确的写法是让 $uri/ 去找目录下的索引:
location / {
try_files $uri $uri/ =404;
}
index index.html;
二、404 要单独指定
=404 会返回 Nginx 自带的错误页,跟站点风格完全不搭。想用自己做的 404 页面:
error_page 404 /404.html;
location = /404.html {
internal;
}
internal 这句别省,否则别人可以直接访问 /404.html,搜索引擎也可能把它当正文收录。
三、带哈希的资源要长缓存
Astro 会把 JS/CSS 输出到 _astro/ 下,文件名带内容哈希。这类文件可以放心缓存一年:
location /_astro/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
但 HTML 不能这么干,否则改完文章用户看不到。静态站最省心的策略是:HTML 不缓存或短缓存,带哈希的资源长缓存。
四、Cloudflare 代理后要开 Full (strict)
这是我吃亏最多的一次。域名挂了 Cloudflare 的小云朵(代理模式)后,如果 SSL/TLS 模式选了 Flexible,Cloudflare 用 HTTP 回源,而源站又强制跳 HTTPS,就会无限重定向,浏览器报 ERR_TOO_MANY_REDIRECTS。
正确做法是让源站也有证书(certbot --nginx 一行就够),Cloudflare 侧设成 Full (strict)。这时日志里看到的全是 Cloudflare 的 IP,想拿真实 IP 需要装 ngx_http_realip_module 并信任 Cloudflare 的网段。
五、gzip 默认只压一部分类型
Nginx 默认的 gzip_types 不包含 application/json 和 image/svg+xml,RSS 和 sitemap 这类 XML 反而默认有。我习惯显式列全:
gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types text/plain text/css application/javascript application/json
application/xml image/svg+xml;
gzip_vary on;
完整的一段
把上面拼起来,一个静态站的 server 块大概长这样(证书路径由 certbot 自动写入):
server {
listen 80;
server_name example.com www.example.com;
root /var/www/site;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location /_astro/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
error_page 404 /404.html;
location = /404.html { internal; }
}
配置改完记得 nginx -t 再 systemctl reload nginx。直接 reload 一个语法错误的配置,站点会立刻挂掉,而这时候你往往正在 SSH 外面。