fix(i18n,404,nginx): broken-windows batch B2 from the external review
Deploy / build (push) Successful in 3m59s
Deploy / build (push) Successful in 3m59s
All items measured before/after with curl, on the origin and through Cloudflare: - /posts/zh/ answered 403 (directory with no index) -> nginx 301 to the new archive - /zh/posts/ 404'd -> new src/pages/zh/posts/index.astro (build 163 -> 165 pages) - ZH nav pointed "关于" at /zh/ and "文章" at /zh/ -> /zh/about/ and /zh/posts/ - og:locale was "en" on every Chinese page -> zh_CN, plus og:locale:alternate on both languages (EN pages now advertise zh_CN as well) - hreflang "zh" -> "zh-Hans"; <html lang> on ZH pages -> zh-Hans - no 404 page existed -> src/pages/404.astro, served by nginx with a 404 status so crawlers skip it, offering search + archive + the 3 newest posts - JSON-LD Person gained worksFor (Hoelee Enterprise); image still omitted until the author photo exists rather than pointing at a placeholder nginx: config moved from the stock image file to a host bind mount (/mnt/user/docker/nginx-hoelee-blog/conf.d/default.conf, Portainer stack 247 on endpoint 3), validated with nginx -t in a throwaway container before the redeploy. It also sets /_astro/* to immutable 1-year (hashed names) and HTML to must-revalidate; unhashed /og/*.png and /banners/*.png keep the default TTL on purpose. Note: the public HSTS and 16-day asset TTL come from Cloudflare zone settings, not from this nginx. Docs: ops-runbook.md (the nginx layer + why each rule), project-state.md (B2 entry and the two open Cloudflare items my token cannot write).
This commit is contained in:
1 parent
831d440661
commit
874c434576
6 files changed
+160
-6
No files matched your search
@@ -54,6 +54,31 @@ Overflow diagnosis (real numbers, not screenshot guessing): check `scrollWidth >
|
||||
|
||||
---
|
||||
|
||||
## nginx layer (unRaid container, Portainer stack 247)
|
||||
|
||||
The container `nginx-hoelee-blog` (`nginx:1.29-alpine`, host port 8081) had a **stock
|
||||
`default.conf`** until 2026-10-16, when the config became a bind mount:
|
||||
|
||||
- `/mnt/user/docker/nginx-hoelee-blog/conf.d/default.conf` → `/etc/nginx/conf.d/default.conf:ro`
|
||||
- Edits take effect after `docker exec nginx-hoelee-blog nginx -t && docker exec nginx-hoelee-blog nginx -s reload`
|
||||
(no restart needed). Validate a candidate file first in a throwaway container:
|
||||
`docker run --rm -v /mnt/user/docker/nginx-hoelee-blog/conf.d/default.conf:/etc/nginx/conf.d/default.conf:ro nginx:1.29-alpine nginx -t`
|
||||
- Stack: Portainer **DSM instance** (endpoint 3 = unRaid), stack id **247**. Read/update via
|
||||
`GET|PUT /api/stacks/247?endpointId=3`; PUT recreates the service (a few seconds of downtime).
|
||||
|
||||
What the conf adds, and why:
|
||||
|
||||
| Rule | Why |
|
||||
|---|---|
|
||||
| `location = /posts/zh/ { return 301 /zh/posts/; }` | Chinese posts live at `/posts/zh/<slug>/`, so the bare directory had no index and answered **403**. The Chinese archive is `/zh/posts/`. |
|
||||
| `error_page 404 /404.html;` + internal location | Astro builds `dist/404.html`. Without it, a broken link showed nginx's default page. Served with a 404 status so crawlers do not index it. |
|
||||
| `location /_astro/` → `max-age=31536000, immutable` | Astro hashes these filenames, so they can never go stale. `/og/*.png` and `/banners/*.png` are **not** hashed and are regenerated in place, so they deliberately keep Cloudflare's default TTL. |
|
||||
| HTML → `max-age=0, must-revalidate` | A deploy must be visible immediately; edge caching is controlled separately by the Cloudflare Cache Rule + the deploy purge step. |
|
||||
|
||||
Header note: the public `Strict-Transport-Security` and the default 16-day asset
|
||||
`Cache-Control` come from **Cloudflare zone settings**, not from this nginx (the origin
|
||||
sends no such headers). See `docs/project-state.md` §1 B2 for the open CF items.
|
||||
|
||||
## Hosting notes
|
||||
|
||||
- Static output = trivial to serve from any nginx/OpenLiteSpeed dir. Cloudflare in front gives CDN + HTTPS + DDoS.
|
||||
|
||||
Reference in new issue
Block a user